生产环境 LAMP 系统:Lighttpd + PHP + MySQL

来自 Alpine Linux

在生产环境 web 中,LAMP 指的是安装并集成的 Linux + Apache + Mysql + Php,但如今,Apache 正越来越多地被 NginxLighttpd 替代,而 MySQL 也正被 MariaDB 替代。LAMP 文档包括

1. Web 服务器:Lighttpd

lighttpd 是一个简单、符合标准、安全且灵活的 web 服务器。Nginx 是最常用的,因为它易于被 ISP 面板软件管理,但 lighttpd 性能更佳。Nginx 无法处理 fast-cgi 程序。有关 lighttpd 的更多信息,请查阅 Production Web server: Lighttpd wiki 页面。

Lighttpd 安装

生产环境将仅处理所需的软件包。因此不允许使用文档或管理器

  1. 运行 apk 以安装所需的软件包
apk add lighttpd gamin

Lighttpd php 预配置

  1. 创建 htdos 公共 web 根目录
  2. 将默认端口更改为生产环境端口,http 使用端口 80
  3. 使用 FAM 样式 (gamin) 文件更改监视器,提高性能,仅在 3.4 到 3.8 版本中!!!
  4. 使用 linux 事件处理程序,由于 Alpine 仅限 linux,因此可提高性能
  5. 将服务添加到默认运行级别,而不是启动时启动,因为需要先激活网络
  6. 启动 web 服务器服务
  7. 在配置文件中启用 mod_status
  8. 更改配置文件中的路径,我们使用混淆来提高安全性
  9. 重启服务以在浏览器中查看更改
mkdir -p /var/www/localhost/htdocs/stats /var/log/lighttpd /var/lib/lighttpd

sed -i -r 's#\#.*server.port.*=.*#server.port          = 80#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#\#.*server.event-handler = "linux-sysepoll".*#server.event-handler = "linux-sysepoll"#g' /etc/lighttpd/lighttpd.conf

chown -R lighttpd:lighttpd /var/www/localhost/

chown -R lighttpd:lighttpd /var/lib/lighttpd

chown -R lighttpd:lighttpd /var/log/lighttpd

rc-update add lighttpd default

rc-service lighttpd restart

echo "it works" > /var/www/localhost/htdocs/index.html

sed -i -r 's#\#.*mod_status.*,.*#    "mod_status",#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*status.status-url.*=.*#status.status-url  = "/stats/server-status"#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*status.config-url.*=.*#status.config-url  = "/stats/server-config"#g' /etc/lighttpd/lighttpd.conf

rc-service lighttpd restart

为了测试,打开浏览器并访问 http://<webserveripaddres>。您将看到“it works”。“webserveripaddres”是您的设置/服务器机器的 ip 地址。

Alpine linux 存在一个问题,FAM (gamin) 仅作为 lighttpd 服务激活,这在 docker 中有意义,但在服务器上,如果 FAM (gamin) 同时也被其他服务需要,则可能会出现问题。

可选: alpine 打包器一团糟,最近移除了 FAM,因此较旧版本的 alpine 可以使用编译后的 FAM 软件包,命令为 sed -i -r 's#.*server.stat-cache-engine.*=.*# server.stat-cache-engine = "fam"#g' /etc/lighttpd/lighttpd.conf

2. php 脚本:PHP fpm

在 Alpine 中,有两种主要的动态网页编程语言:PHP 和 LUA。Alpine 是极简主义的,因此在大多数情况下不需要所有 PHP 软件包。必须启用两个存储库(main 和 community)。这里我们解释生产环境中最常见的用法。

PHP 安装

此材料已过时...

更新到更新或通用的 php 版本 (讨论)

apk add php7 php7-bcmath php7-bz2 php7-ctype php7-curl php7-dom php7-enchant php7-exif php7-fpm php7-gd php7-gettext php7-gmp php7-iconv php7-imap php7-intl php7-json php7-mbstring php7-opcache php7-openssl php7-phar php7-posix php7-pspell php7-recode php7-session php7-simplexml php7-sockets php7-sysvmsg php7-sysvsem php7-sysvshm php7-tidy php7-xml php7-xmlreader php7-xmlrpc php7-xmlwriter php7-xsl php7-zip php7-sqlite3
注意: 以下软件包仅适用于特定情况。仅在需要时安装它们(尤其是 php-pear),例如,cacticacti-php7 依赖于 php7,但您必须安装 cacti 软件包,所有依赖项必须预先从 stable 安装。
apk add php7-pgsql php7-mysqli php7-mysqlnd php7-snmp php7-soap php7-ldap php7-pcntl php7-pear php7-shmop php7-wddx php7-cgi php7-pdo php7-snmp php7-tokenizer 
注意: 以下软件包仅用于以特定方式使用 php 进行数据库访问。仅在您需要它们时才安装它们(特别是 php--pdo 软件包)。例如,cacticacti-php7 依赖于 php7-mysqli,但您必须仅安装 cacti 软件包,所有依赖项(如 php7php7-mysqli)必须预先从 stable 安装。
apk add php7-dba php7-sqlite3 php7-mysqli php7-mysqlnd php7-pgsql php7-pdo_dblib php7-pdo_odbc php7-pdo_pgsql php7-pdo_sqlite 

一个特殊情况是 php7-odbc。与能够让 php 仅连接到特定数据库的其他软件包不同,unixodbc 是一种通用的连接方式。最重要的区别是,例如,php7-mysqli 软件包具有更好的函数来通过 php 管理数据。

PHP 全局配置

  1. 使用 fix.pathinfo
  2. 关闭安全模式
  3. 如果发生错误,则不公开 php 代码
  4. 将执行的内存限制设置为 536Mb(大多数服务器的内存至少为 1 GB)
  5. 将上传大小设置为最大 128Mb。
  6. 根据最大上传大小限制,将 POST 最大大小设置为 256Mb。
  7. 开启 URL 打开方法
  8. 将默认字符集设置为 UTF-8 以提高兼容性
  9. 增加执行时间和输入时间。
sed -i -r 's|.*cgi.fix_pathinfo=.*|cgi.fix_pathinfo=1|g' /etc/php*/php.ini
sed -i -r 's#.*safe_mode =.*#safe_mode = Off#g' /etc/php*/php.ini
sed -i -r 's#.*expose_php =.*#expose_php = Off#g' /etc/php*/php.ini
sed -i -r 's#memory_limit =.*#memory_limit = 536M#g' /etc/php*/php.ini
sed -i -r 's#upload_max_filesize =.*#upload_max_filesize = 128M#g' /etc/php*/php.ini
sed -i -r 's#post_max_size =.*#post_max_size = 256M#g' /etc/php*/php.ini
sed -i -r 's#^file_uploads =.*#file_uploads = On#g' /etc/php*/php.ini
sed -i -r 's#^max_file_uploads =.*#max_file_uploads = 12#g' /etc/php*/php.ini
sed -i -r 's#^allow_url_fopen = .*#allow_url_fopen = On#g' /etc/php*/php.ini
sed -i -r 's#^.default_charset =.*#default_charset = "UTF-8"#g' /etc/php*/php.ini
sed -i -r 's#^.max_execution_time =.*#max_execution_time = 150#g' /etc/php*/php.ini
sed -i -r 's#^max_input_time =.*#max_input_time = 90#g' /etc/php*/php.ini

PHP-FPM 配置

  1. 为 php 套接字和 pid 文件创建目录,必须与 openrc 定义的目录相同!
  2. 在配置文件中设置套接字路径,必须与 openrc 定义的路径相同!
  3. 在配置文件中设置 pid 文件路径,必须与 openrc 定义的路径相同!
mkdir -p /var/run/php-fpm7/

chown lighttpd:root /var/run/php-fpm7

sed -i -r 's|^.*listen =.*|listen = /run/php-fpm7/php7-fpm.sock|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^pid =.*|pid = /run/php-fpm7/php7-fpm.pid|g' /etc/php*/php-fpm.conf

sed -i -r 's|^.*listen.mode =.*|listen.mode = 0640|g' /etc/php*/php-fpm.d/www.conf

rc-update add php-fpm7 default

service php-fpm7 restart


PHP-FPM 定义了一个主进程,每个服务请求都有一个进程池。默认情况下,只有一个进程池,www。

默认值对于启动来说是好的,但稍后需要进行调整。最佳方法是静态方法,但需要进行测试才能获得正确的配置。

Lighttpd + PHP-FPM

web 服务器带有一个最小化的配置文件,因此我们必须处理所有必需的设置

  1. 在配置文件中启用 mod_alias,cgi 文件安全需要特定的路径
  2. 确保仅通过 cgi 禁用 fastcgi-php 模块
  3. 然后启用 fastcgi-php-fpm 特定模块
  4. 使用套接字在本地服务器中编写更好的 php 处理程序方法
  5. 配置 php 也使用套接字进行本地直接连接
  6. 重启服务以在浏览器中查看更改
mkdir -p /var/www/localhost/cgi-bin

sed -i -r 's#\#.*mod_alias.*,.*#    "mod_alias",#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_cgi.conf".*#   include "mod_cgi.conf"#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_fastcgi.conf".*#\#   include "mod_fastcgi.conf"#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_fastcgi_fpm.conf".*#   include "mod_fastcgi_fpm.conf"#g' /etc/lighttpd/lighttpd.conf

sed -e '/index-file.names/ s/^#*/#/' -i /etc/lighttpd/lighttpd.conf

cat > /etc/lighttpd/mod_fastcgi_fpm.conf << EOF
server.modules += ( "mod_fastcgi" )
index-file.names += ( "index.php" )
fastcgi.server = (
    ".php" => (
      "localhost" => (
        "socket"                => "/var/run/php-fpm7/php7-fpm.sock",
        "broken-scriptfilename" => "enable"
      ))
)
EOF

sed -i -r 's|^.*listen =.*|listen = /var/run/php-fpm7/php7-fpm.sock|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^.*listen.owner = .*|listen.owner = lighttpd|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^.*listen.group = .*|listen.group = lighttpd|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^.*listen.mode = .*|listen.mode = 0660|g' /etc/php*/php-fpm.d/www.conf

rc-service php-fpm7 restart

rc-service lighttpd restart

echo "<?php echo phpinfo(); ?>" > /var/www/localhost/htdocs/info.php

为了测试,打开浏览器并访问 http://<webserveripaddres>/info.php。您将看到生产环境中使用的信息。 向破解者提供过多信息是没有意义的。“webserveripaddres”是您的设置/服务器机器的 ip 地址。

之后,所有 php 文件都将比使用基于主机的文件处理得更快。/var/www/localhost/cgi-bin 目录将在 http://localhost/cgi-bin/ 路径下显示。

多 PHP-FPM 集群

正如我们所说,FPM 由进程池管理,但连接可以通过网络或直接 n 套接字进行。对于可以处理平均请求数量的典型服务器的配置是使用套接字和 localhost。为了实现高可用性,需要 1000Mbps 的 CAT6 有线网络连接以及以轮询模式进行网络连接的 php-fpm。

PHP FPM 池将位于特定的机器上,而 web 服务器将简单地连接到这些装有 PHP 的机器以服务 PHP 页面。结果是由 lighttpd web 服务器集群对抗其他 PHP-FPM 进程集群。PHP 代码可以在所有 web 服务器上相同,并且可以连接到单个数据库。

在 Linux 控制台上,更改是,例如,两台机器 10.10.1.10 和 10.10.2.10 都安装了 php 和 lighttpd,因此每台机器都将设置另一台机器的 php

mkdir -p /var/www/localhost/cgi-bin

sed -i -r 's#\#.*mod_alias.*,.*#    "mod_alias",#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_cgi.conf".*#   include "mod_cgi.conf"#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_fastcgi.conf".*#\#   include "mod_fastcgi.conf"#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_fastcgi_fpm.conf".*#   include "mod_fastcgi_fpm.conf"#g' /etc/lighttpd/lighttpd.conf

cat > /etc/lighttpd/mod_fastcgi_fpm.conf << EOF
server.modules += ( "mod_fastcgi" )
index-file.names += ( "index.php" )
fastcgi.server = ( ".php" => 
  (
    ( "host" => "10.10.1.10",
      "port" => 9000
    ),
    ( "host" => "10.10.2.10",
      "port" => 9000 )
    )
  )
EOF

sed -i -r 's|^.*listen =.*|listen = 9000|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^.*listen.owner = .*|listen.owner = lighttpd|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^.*listen.group = .*|listen.group = lighttpd|g' /etc/php*/php-fpm.d/www.conf

sed -i -r 's|^.*listen.mode = .*|listen.mode = 0660|g' /etc/php*/php-fpm.d/www.conf

rc-service php-fpm7 restart

rc-service lighttpd restart

echo "<?php echo phpinfo(); ?>" > /var/www/localhost/htdocs/info.php

3. DBMS 部分:mysql/mariadb

Alpine Linux 具有虚拟的对应软件包,适用于那些未从 mysql 更改为 mariadb 的软件包。

安装

请注意,用户 mysql 是在软件包安装期间创建的。在初始化部分,将在数据库初始化中创建两个用户:rootmysql,并且只有当它们在各自的系统帐户中时,它们才能连接到数据库服务。

apk add mysql mysql-client

初始化

位于 /var/lib/mysqldatadir 必须由 mysql 用户和组拥有。您可以修改此行为,但您必须编辑 /etc/init.d 目录下的服务文件。此外,您需要在配置文件中的 [mysqld] 部分下设置 datadir=<YOUR_DATADIR>

  1. 初始化主 mysql 数据库,并将数据目录标准化为 rc 脚本的 /var/lib/mysql
  2. 然后初始化服务,此时启用 root 帐户和套接字连接,无需密码
  3. 通过分配适当的密码来设置 root 帐户。这纯粹是杞人忧天。下一步就是这样做!
  4. 运行 mysql_secure_installation 来设置和初始化安装
  5. 设置管理其他用户和数据库的权限
  6. 运行 mysql_secure_installation 脚本并回答问题(见下文)
mysql_install_db --user=mysql --datadir=/var/lib/mysql

rc-service mariadb start

mysqladmin -u root password toor

mysql_secure_installation

  1. 输入 root 用户的当前密码(无密码则直接回车): 必须提供,因为我们之前设置过。正确响应是 OK, successfully used password, moving on...
  2. 切换到 unix_socket 身份验证 [Y/n] 必须禁用此项,因此回答 NO,响应将是 ... skipping.
  3. 更改 root 密码? [Y/n] 如果您提供了好的密码,则只需按“n”,否则请更改密码!
  4. 移除匿名用户? [Y/n] 在任何情况下,生产系统都必须移除它,因此回答 Y,正确的响应应为 ... Success!
  5. 禁止 root 用户远程登录? [Y/n] 务必回答 Y,正确的响应应为 ... Success!
  6. 移除测试数据库以及对其的访问权限? [Y/n] 应该移除,因此回答 Y,正确的响应应为 ... Success!
  7. 现在重新加载权限表? [Y/n] 回答 Y,正确的响应应为 ... Success!

在回答完所有问题后.. 使用 rc-service mariadb restart 重启服务

配置

较新的 Alpine 系统软件包可以在独立文件中进行设置。在任何情况下,这些命令始终有效,对于不适用的情况,它们将忽略输出。有关更多信息,请参阅 MariaDB wiki 页面的 MariaDB 配置文件 部分。

  • 在较旧的 Alpine 系统上,您必须设置配置文件以将 MAX ALLOWED PACKETS 设置为最小的适当数量
  • 仅在只有一台服务器或不期望来自其他服务器的连接的情况下才允许本地连接
  • 将默认字符集设置为 UTF8MB4(MariaDB 11.8 和 MySQL 8 的默认设置)
  • 添加启动服务进程,但不要将其设置为启动进程,因为网络需要已在运行。
  • 重启服务以应用更改。
sed -i "s|.*max_allowed_packet\s*=.*|max_allowed_packet = 100M|g" /etc/mysql/my.cnf
sed -i "s|.*max_allowed_packet\s*=.*|max_allowed_packet = 100M|g" /etc/my.cnf.d/mariadb-server.cnf

sed -i "s|.*bind-address\s*=.*|bind-address=127.0.0.1|g" /etc/mysql/my.cnf
sed -i "s|.*bind-address\s*=.*|bind-address=127.0.0.1|g" /etc/my.cnf.d/mariadb-server.cnf

cat > /etc/my.cnf.d/mariadb-server-default-charset.cnf << EOF
[client]
default-character-set = utf8mb4

[mysqld]
collation_server = utf8mb4_unicode_ci
character_set_server = utf8mb4

[mysql]
default-character-set = utf8mb4
EOF

rc-service mariadb restart

rc-update add mariadb default

升级: 如果您在升级后无法运行任何 mysql 命令,那是因为 MySQL 无法启动。尝试使用 mysqld_safe --datadir=/var/lib/mysql/ 命令在安全模式下运行 MySQL,然后运行 mysql_upgrade -u root -p 脚本。有关更多信息,请参阅 MariaDB wiki 页面的 MariaDB 升级部分

adminer:Web 前端管理

Adminer 是一个简单的独立工具,比 PhpMysqladmin 快很多倍,PhpMysqladmin 很棒,但存在太多安全问题和许多复杂的设置。我们需要一个更简单、更独立的解决方案。一个易于管理和升级的解决方案。

请注意,这需要以 web 服务器、php 脚本和 mysql/mariadb 引擎配置并运行的前几节为先决条件


mkdir -p /var/www/webapps/adminer

wget https://github.com/vrana/adminer/releases/download/v4.7.6/adminer-4.7.6.php -O /var/www/webapps/adminer/adminer-4.7.6.php

ln -s adminer-4.7.6.php /var/www/webapps/adminer/index.php

cat > /etc/lighttpd/mod_adminer.conf << EOF
# NOTE: this requires mod_alias
alias.url += (
     "/adminer/"	    =>	    "/var/www/webapps/adminer/"
)
$HTTP["url"] =~ "^/adminer/" {
    # disable directory listings
    dir-listing.activate = "disable"
}
EOF

sed -i -r 's#\#.*mod_alias.*,.*#    "mod_alias",#g' /etc/lighttpd/lighttpd.conf

sed -i -r 's#.*include "mod_cgi.conf".*#   include "mod_cgi.conf"#g' /etc/lighttpd/lighttpd.conf

checkssl="";checkssl=$(grep 'include "mod_adminer.conf' /etc/lighttpd/lighttpd.conf);[[ "$checkssl" != "" ]] && echo listo || sed -i -r 's#.*include "mod_cgi.conf".*#include "mod_cgi.conf"\ninclude "mod_adminer.conf"#g' /etc/lighttpd/lighttpd.conf

rc-service lighttpd restart

管理员必须使用确切的 URL http://<ipaddress>/adminer/index.php。有两个原因:没有目录列表,并且 web 服务器上没有直接的 PHP 索引引用,所有这些都是出于偏执的安全设置。