nginx
nginx (发音为 "engine X"),是由 Igor Sysoev 于 2005 年编写的免费、开源、高性能 HTTP web 服务器和反向代理服务器,以及 IMAP/POP3 代理服务器。nginx 以其稳定性、丰富的功能集、简单的配置和低资源消耗而闻名。
本文介绍如何设置 nginx 以及如何选择性地通过 #FastCGI 与 PHP 集成。
安装
安装以下软件包之一
- nginx-mainline - 主线分支:新功能、更新、错误修复。
- nginx - 稳定分支:仅重大错误修复。
- angieAUR - nginx 的分支和替代品,具有更多功能。
- freenginx-mainlineAUR - 保留 nginx 免费和开放开发的替代品(主线分支)。
- freenginx-libresslAUR - 保留 nginx 免费和开放开发的替代品(带有 LibreSSL 支持的主线分支)。
- freenginxAUR - 保留 nginx 免费和开放开发的替代品(稳定分支)。
建议使用主线分支。使用稳定分支的主要原因是您担心新功能可能带来的影响,例如与第三方模块不兼容或在新功能中无意引入错误。
对于基于 chroot 的安装以获得额外的安全性,请参阅 #在 chroot 中安装。
运行
启动/启用 nginx.service
或 angie.service
(如果您使用 Angie)。
在 http://127.0.0.1 提供的默认页面是 /usr/share/nginx/html/index.html
。
配置
nginx 的入门步骤在初学者指南中描述。您可以通过编辑 /etc/nginx/
中的文件来修改配置。主配置文件位于 /etc/nginx/nginx.conf
。
更多详细信息和示例可以在官方文档中找到。
以下示例涵盖了最常见的用例。假设您使用默认的文档位置 (/usr/share/nginx/html
)。如果不是这种情况,请替换为您的路径。
配置示例
/etc/nginx/nginx.conf
user http; worker_processes auto; worker_cpu_affinity auto; events { worker_connections 1024; } http { charset utf-8; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 4096; client_max_body_size 16M; # MIME include mime.types; default_type application/octet-stream; # logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # load configs include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
常规配置
进程和连接
您应该为 worker_processes
选择一个合适的值。此设置最终定义了 nginx 将接受多少连接以及它将能够利用多少处理器。通常,将其设置为系统中硬件线程的数量是一个好的开始。或者,worker_processes
自版本 1.3.8 和 1.2.5 以来接受 auto
值,这将尝试自动检测最佳值(来源)。
nginx 将接受的最大连接数由 max_clients = worker_processes * worker_connections
给出。
以其他用户身份运行
默认情况下,nginx 以 root
身份运行主进程,并以用户 http
身份运行工作进程。要以其他用户身份运行工作进程,请更改 nginx.conf
中的 user
指令
/etc/nginx/nginx.conf
user user [group];
如果省略组,则使用名称与 user 相同的组。
服务器块
可以使用 server
块来服务多个域。这些与 Apache HTTP 服务器中的“VirtualHosts”相当。另请参阅上游示例。
在下面的示例中,服务器侦听两个域 domainname1.tld
和 domainname2.tld
的 IPv4 和 IPv6 端口 80 上的传入连接
/etc/nginx/nginx.conf
... server { listen 80; listen [::]:80; server_name domainname1.tld; root /usr/share/nginx/domainname1.tld/html; location / { index index.php index.html index.htm; } } server { listen 80; listen [::]:80; server_name domainname2.tld; root /usr/share/nginx/domainname2.tld/html; ... }
重启 nginx.service
以应用任何更改。
管理服务器条目
可以将不同的 server
块放在不同的文件中。这允许您轻松地启用或禁用某些站点。
对于使用 sites-enabled
和 sites-available
方法,创建以下目录
# mkdir /etc/nginx/sites-available # mkdir /etc/nginx/sites-enabled
在 sites-available
目录中创建一个文件,其中包含一个或多个服务器块
/etc/nginx/sites-available/example.conf
server { listen 443 ssl; listen [::]:443 ssl; http2 on; ... }
将 include sites-enabled/*;
附加到 http
块的末尾
/etc/nginx/nginx.conf
http { ... include sites-enabled/*; }
要启用站点,只需创建一个符号链接
# ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/example.conf
要禁用站点,请取消链接活动的符号链接
# unlink /etc/nginx/sites-enabled/example.conf
重载/重启 nginx.service
以启用对站点配置的更改。
TLS
OpenSSL 提供 TLS 支持,并在 Arch 安装上默认安装。
- 您可能需要在配置 SSL 之前先阅读 ngx_http_ssl_module 文档。
- Let’s Encrypt 是一个免费、自动化和开放的证书颁发机构。有一个插件可用于直接从命令行请求有效的 SSL 证书和自动配置。
- Mozilla 还有一个有用的 TLS 文章以及一个自动化工具,可帮助创建更安全的配置。
创建一个私钥和自签名证书。这对于大多数不需要 CSR 的安装来说已经足够了
# mkdir /etc/nginx/ssl # cd /etc/nginx/ssl # openssl req -new -x509 -nodes -newkey rsa:4096 -keyout server.key -out server.crt -days 1095 # chmod 400 server.key # chmod 444 server.crt
-days
开关是可选的,RSA 密钥大小可以低至 2048(默认值)。如果您需要创建 CSR,请按照以下说明而不是上述说明进行操作
# mkdir /etc/nginx/ssl # cd /etc/nginx/ssl # openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out server.key # chmod 400 server.key # openssl req -new -sha256 -key server.key -out server.csr # openssl x509 -req -days 1095 -in server.csr -signkey server.key -out server.crt
带有 TLS 的 /etc/nginx/nginx.conf
的起点是 Mozilla 的 SSL 配置生成器。
重启 nginx.service
以应用任何更改。
每用户目录
要复制 Apache 样式的 ~user
URL 到用户的 ~/public_html
目录,请尝试以下操作。(注意:如果同时使用以下两个规则,则更具体的 PHP 规则必须放在前面。)
/etc/nginx/nginx.conf
... server { ... # PHP in user directories, e.g. http://example.com/~user/test.php location ~ ^/~(.+?)(/.+\.php)$ { alias /home/$1/public_html$2; fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } # User directories, e.g. http://example.com/~user/ location ~ ^/~(.+?)(/.*)?$ { alias /home/$1/public_html$2; index index.html index.htm; autoindex on; } ... } ...
有关 nginx
的 PHP 配置的更多信息,请参阅 #PHP 实现。
重启 nginx.service
以启用新配置。
FastCGI
FastCGI,也称为 FCGI,是一种用于将交互式程序与 Web 服务器连接的协议。FastCGI 是早期 通用网关接口 (CGI) 的变体;FastCGI 的主要目标是减少与连接 Web 服务器和 CGI 程序相关的开销,从而使服务器能够一次处理更多网页请求。
FastCGI 技术被引入 nginx 中,以与许多外部工具(例如 Perl、PHP 和 Python)一起工作。
PHP 实现
PHP-FPM 是作为 PHP 的 FastCGI 服务器运行的推荐解决方案。
安装 php-fpm 并确保 PHP 已正确安装和配置。PHP-FPM 的主配置文件是 /etc/php/php-fpm.conf
。对于基本用法,默认配置应该足够了。
最后,启动/启用 php-fpm.service
。
您也可以使用 php-legacy-fpm 代替,请参阅 #使用 php-legacy。
- 如果您以其他用户身份运行 nginx,请确保 PHP-FPM 套接字文件可由此用户访问,或使用 TCP 套接字。
- 如果您在 chroot 环境中运行 nginx(chroot 是
/srv/nginx-jail
,网页在/srv/nginx-jail/www
中提供),则必须修改文件/etc/php/php-fpm.conf
以在池部分(默认的是[www]
)中包含chroot = /srv/nginx-jail
和listen = /srv/nginx-jail/run/php-fpm/php-fpm.sock
指令。如果缺少套接字文件的目录,请创建它。此外,对于动态链接到依赖项的模块,您需要将这些依赖项复制到 chroot(例如,对于 php-imagick,您需要将 ImageMagick 库复制到 chroot,但不需要复制 imagick.so 本身)。
nginx 配置
当提供 PHP Web 应用程序时,应在每个 服务器块 [2] 中包含 PHP-FPM 的 location
,例如
/etc/nginx/sites-available/example.conf
server { root /usr/share/nginx/html; location / { index index.html index.htm index.php; } location ~ \.php$ { # 404 try_files $fastcgi_script_name =404; # default fastcgi_params include fastcgi_params; # fastcgi settings fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; # fastcgi params fastcgi_param DOCUMENT_ROOT $realpath_root; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; #fastcgi_param PHP_ADMIN_VALUE "open_basedir=$base/:/usr/lib/php/:/tmp/"; } }
如果需要使用 PHP 处理其他扩展名(例如 .html 和 .htm)
location ~ [^/]\.(php|html|htm)(/|$) { ... }
还应在 /etc/php/php-fpm.d/www.conf
中显式添加 PHP-FPM 中非 .php 扩展名的处理
security.limit_extensions = .php .html .htm
fastcgi_pass
参数,因为它必须是 FastCGI 服务器在其配置文件中定义的 TCP 或 Unix 套接字。php-fpm
的默认(Unix)套接字是fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
您可以使用常见的 TCP 套接字,非默认,
fastcgi_pass 127.0.0.1:9000;但是,Unix 域套接字应该更快。
server
块使用相同的 PHP-FPM 配置,可以使用 php_fastcgi.conf
配置文件来简化管理/etc/nginx/php_fastcgi.conf
location ~ \.php$ { # 404 try_files $fastcgi_script_name =404; # default fastcgi_params include fastcgi_params; # fastcgi settings ... }
要为特定服务器启用 PHP 支持,只需包含 php_fastcgi.conf
配置文件
/etc/nginx/sites-available/example.conf
server { server_name example.com; ... include /etc/nginx/php_fastcgi.conf; }
测试配置
如果配置已更改,您需要重启 php-fpm.service
和 nginx.service
单元以应用更改。
要测试 FastCGI 实现,请在 root
文件夹中创建一个新的 PHP 文件,其中包含
<?php phpinfo(); ?>
在浏览器中导航到此文件,您应该会看到包含当前 PHP 配置的信息页面。
CGI 实现
CGI 应用程序需要此实现。
fcgiwrap
安装 fcgiwrap。配置通过编辑 fcgiwrap.socket
完成。启用并启动 fcgiwrap.socket
。
多工作线程
如果您想生成多个工作线程,建议您使用 multiwatchAUR,它将负责重启崩溃的子进程。您需要使用 spawn-fcgi
来创建 Unix 套接字,因为 multiwatch 似乎无法处理 systemd 创建的套接字,即使 fcgiwrap 本身在单元文件中直接调用时也没有任何问题。
覆盖单元 fcgiwrap.service
(以及 fcgiwrap.socket
单元,如果存在),并修改 ExecStart
行以满足您的需求。这是一个使用 multiwatchAUR 的单元文件。确保未启动或启用 fcgiwrap.socket
,因为它会与此单元冲突
/etc/systemd/system/fcgiwrap.service
[Unit] Description=Simple CGI Server After=nss-user-lookup.target [Service] ExecStartPre=/bin/rm -f /run/fcgiwrap.socket ExecStart=/usr/bin/spawn-fcgi -u http -g http -s /run/fcgiwrap.sock -n -- /usr/bin/multiwatch -f 10 -- /usr/sbin/fcgiwrap ExecStartPost=/usr/bin/chmod 660 /run/fcgiwrap.sock PrivateTmp=true Restart=on-failure [Install] WantedBy=multi-user.target
调整 -f 10
以更改生成的子进程数。
spawn-fcgi
使用 -M 660
选项时看到的奇怪行为,ExecStartPost
行是必需的。设置了错误的模式。这可能是个错误?nginx 配置
在 /etc/nginx
中,将文件 fastcgi_params
复制到 fcgiwrap_params
。在 fcgiwrap_params
中,注释或删除设置 SCRIPT_NAME
和 DOCUMENT_ROOT
的行。
在每个提供 CGI Web 应用程序的 server
块内,应出现类似于以下的 location
块
location ~ \.cgi$ { include fcgiwrap_params; fastcgi_param DOCUMENT_ROOT /srv/www/cgi-bin/; fastcgi_param SCRIPT_NAME myscript.cgi; fastcgi_pass unix:/run/fcgiwrap.sock; }
fcgiwrap
的默认套接字文件是 /run/fcgiwrap.sock
。
使用 fastcgi_param SCRIPT_FILENAME /srv/www/cgi-bin/myscript.cgi
是设置 DOCUMENT_ROOT
和 SCRIPT_NAME
的快捷替代方法。如果您使用 SCRIPT_FILENAME
,您也不需要将 fastcgi_params
复制到 fcgiwrap_params
并注释掉 DOCUMENT_ROOT
和 SCRIPT_NAME
行。
如果您一直收到 502 - bad Gateway
错误,您应该检查您的 CGI 应用程序是否首先声明了以下内容的 mime 类型。对于 HTML,这需要是 Content-type: text/html
。
如果您收到 403 错误,请确保 http
用户可以读取和执行 CGI 可执行文件,并且每个父文件夹都可以被 http
用户读取。
在 chroot 中安装
在 chroot 中安装 nginx 增加了额外的安全层。为了获得最大的安全性,chroot 应仅包含运行 nginx 服务器所需的文件,并且所有文件都应具有尽可能严格的权限,例如,尽可能多地归 root 所有,诸如 /usr/bin
之类的目录应不可读且不可写等。
Arch 默认带有 http
用户和组,它们将运行服务器。chroot 将在 /srv/http
中。
在 jail.pl gist 中提供了一个 PERL 脚本来创建此 jail。您可以使用该脚本,也可以按照本文中的说明进行操作。它期望以 root 身份运行。您需要取消注释一行,然后它才会进行任何更改。
创建必要的设备
nginx 需要 /dev/null
、/dev/random
和 /dev/urandom
。要在 chroot 中安装这些设备,请创建 /dev/
目录并使用 mknod 添加设备。避免挂载所有 /dev/
,以确保即使 chroot 被破坏,攻击者也必须突破 chroot 才能访问重要的设备(如 /dev/sda1
)。
- 确保
/srv/http
在没有 nodev 选项的情况下挂载 - 请参阅 mknod(1) 和
ls -l /dev/{null,random,urandom}
以更好地理解 mknod 选项。
# export JAIL=/srv/http # mkdir $JAIL/dev # mknod -m 0666 $JAIL/dev/null c 1 3 # mknod -m 0666 $JAIL/dev/random c 1 8 # mknod -m 0444 $JAIL/dev/urandom c 1 9
创建必要的目录
nginx 需要大量文件才能正常运行。在复制它们之前,请创建文件夹来存储它们。这假设您的 nginx 文档根目录将是 /srv/http/www
。
# mkdir -p $JAIL/etc/nginx/logs # mkdir -p $JAIL/usr/{lib,bin} # mkdir -p $JAIL/usr/share/nginx # mkdir -p $JAIL/var/{log,lib}/nginx # mkdir -p $JAIL/www/cgi-bin # mkdir -p $JAIL/{run,tmp} # cd $JAIL; ln -s usr/lib lib # cd $JAIL; ln -s usr/lib lib64 # cd $JAIL/usr; ln -s lib lib64
然后将 $JAIL/tmp
和 $JAIL/run
挂载为 tmpfs。大小应受到限制,以确保攻击者无法耗尽所有 RAM。
# mount -t tmpfs none $JAIL/run -o 'noexec,size=1M' # mount -t tmpfs none $JAIL/tmp -o 'noexec,size=100M'
为了在重启后保持挂载,应将以下条目添加到 /etc/fstab
/etc/fstab
tmpfs /srv/http/run tmpfs rw,noexec,relatime,size=1024k 0 0 tmpfs /srv/http/tmp tmpfs rw,noexec,relatime,size=102400k 0 0
填充 chroot
首先复制容易的文件。
# cp -r /usr/share/nginx/* $JAIL/usr/share/nginx # cp -r /usr/share/nginx/html/* $JAIL/www # cp /usr/bin/nginx $JAIL/usr/bin/ # cp -r /var/lib/nginx $JAIL/var/lib/nginx
现在复制所需的库。使用 ldd 列出它们,然后将它们全部复制到正确的位置。复制优于硬链接,以确保即使攻击者获得对文件的写入权限,他们也无法破坏或更改真正的系统文件。
$ ldd /usr/bin/nginx
linux-vdso.so.1 (0x00007fffc41fe000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f57ec3e8000) libcrypt.so.1 => /usr/lib/libcrypt.so.1 (0x00007f57ec1b1000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f57ebead000) libm.so.6 => /usr/lib/libm.so.6 (0x00007f57ebbaf000) libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007f57eb94c000) libssl.so.1.0.0 => /usr/lib/libssl.so.1.0.0 (0x00007f57eb6e0000) libcrypto.so.1.0.0 => /usr/lib/libcrypto.so.1.0.0 (0x00007f57eb2d6000) libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f57eb0d2000) libz.so.1 => /usr/lib/libz.so.1 (0x00007f57eaebc000) libGeoIP.so.1 => /usr/lib/libGeoIP.so.1 (0x00007f57eac8d000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f57eaa77000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f57ea6ca000) /lib64/ld-linux-x86-64.so.2 (0x00007f57ec604000)
对于位于 /usr/lib
中的文件,您可以尝试以下单行命令
# cp $(ldd /usr/bin/nginx | grep /usr/lib/ | sed -sre 's/(.+)(\/usr\/lib\/\S+).+/\2/g') $JAIL/usr/lib
以下命令用于 ld-linux-x86-64.so
# cp /lib64/ld-linux-x86-64.so.2 $JAIL/lib
linux-vdso.so
:它不是真正的库,并且不存在于 /usr/lib
中。复制一些其他必要的库和系统文件。
# cp /usr/lib/libnss_* $JAIL/usr/lib # cp -rfvL /etc/{services,localtime,nsswitch.conf,nscd.conf,protocols,hosts,ld.so.cache,ld.so.conf,resolv.conf,host.conf,nginx} $JAIL/etc
为 chroot 创建受限的用户/组文件。这样,就 chroot 所知,只有 chroot 功能所需的用户存在,并且如果攻击者获得对 chroot 的访问权限,则不会泄漏任何系统用户/组。
$JAIL/etc/group
http:x:33: nobody:x:99:
$JAIL/etc/passwd
http:x:33:33:http:/:/bin/false nobody:x:99:99:nobody:/:/bin/false
$JAIL/etc/shadow
http:x:14871:::::: nobody:x:14871::::::
$JAIL/etc/gshadow
http::: nobody:::
# touch $JAIL/etc/shells # touch $JAIL/run/nginx.pid
最后,设置非常严格的权限。尽可能多地归 root 所有并设置为不可写。
# chown -R root:root $JAIL/ # chown -R http:http $JAIL/www # chown -R http:http $JAIL/etc/nginx # chown -R http:http $JAIL/var/{log,lib}/nginx # chown http:http $JAIL/run/nginx.pid # find $JAIL/ -gid 0 -uid 0 -type d -print | xargs chmod -rw # find $JAIL/ -gid 0 -uid 0 -type d -print | xargs chmod +x # find $JAIL/etc -gid 0 -uid 0 -type f -print | xargs chmod -x # find $JAIL/usr/bin -type f -print | xargs chmod ug+rx # find $JAIL/ -group http -user http -print | xargs chmod o-rwx # chmod +rw $JAIL/tmp # chmod +rw $JAIL/run
如果您的服务器将绑定端口 80(或范围 [1-1023] 中的任何其他端口),请授予 chroot 可执行文件在没有 root 权限的情况下绑定这些端口的权限。
# setcap 'cap_net_bind_service=+ep' $JAIL/usr/bin/nginx
修改 nginx.service 以启动 chroot
覆盖单元 nginx.service
。升级 nginx 不会修改您的自定义 .service 文件。
必须更改 systemd 单元以在 chroot 中以 http 用户身份启动 nginx,并将 PID 文件存储在 chroot 中。
/etc/systemd/system/nginx.service
[Unit] Description=A high performance web server and a reverse proxy server After=network.target [Service] Type=forking PIDFile=/srv/http/run/nginx.pid ExecStartPre=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -t -q -g 'pid /run/nginx.pid; daemon on; master_process on;' ExecStart=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' ExecReload=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' -s reload ExecStop=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid;' -s quit [Install] WantedBy=multi-user.target
您现在可以安全地删除非 chrooted nginx 安装。
# pacman -Rsc nginx
如果您不删除非 chrooted nginx 安装,您可能需要确保正在运行的 nginx 进程实际上是 chrooted 进程。您可以通过检查 /proc/PID/root
符号链接到哪里来做到这一点。它应该链接到 /srv/http
而不是 /
。
# ps -C nginx | awk '{print $1}' | sed 1d | while read -r PID; do ls -l /proc/$PID/root; done
技巧和窍门
使用 systemd 以非特权用户运行
为 nginx.service
使用放置式单元文件,并在 [Service]
下设置 User
和可选的 Group
选项
/etc/systemd/system/nginx.service.d/user.conf
[Service] User=user Group=group
我们可以加强服务以防止权限提升
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... NoNewPrivileges=yes
然后我们需要确保 user
有权访问它需要的一切。按照以下子节操作,然后启动 nginx。
端口
默认情况下,Linux 不允许非 root
进程绑定到 1024 以下的端口。可以使用 1024 以上的端口
/etc/nginx/nginx.conf
server { listen 8080; }
或者,您可以授予 nginx 进程 CAP_NET_BIND_SERVICE 功能,使其能够绑定到 1024 以下的端口
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... CapabilityBoundingSet= CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities= AmbientCapabilities=CAP_NET_BIND_SERVICE
或者,您可以使用 systemd 套接字激活。在这种情况下,systemd 将侦听端口,并在建立连接时,生成 nginx 并将套接字作为文件描述符传递。这意味着 nginx 不需要特殊功能,因为套接字在启动时已经存在。这依赖于 nginx 用于传递套接字的内部环境变量[3],因此未获得官方支持。无需设置 CapabilityBoundingSet
和 AmbientCapabilities
,编辑服务覆盖以设置 NGINX
环境变量,以告知 nginx 套接字将作为哪些文件描述符传递
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... Environment=NGINX=3:4;
每个侦听端口将有一个套接字,从文件描述符 3 开始,因此在本例中,我们告诉 nginx 期望有两个套接字。现在创建一个 nginx.socket
单元,指定要侦听的端口
/etc/systemd/system/nginx.socket
[Socket] ListenStream=0.0.0.0:80 ListenStream=0.0.0.0:443 After=network.target Requires=network.target [Install] WantedBy=sockets.target
套接字将按照此单元中定义的顺序传递,因此端口 80 将是文件描述符 3,端口 443 将是文件描述符 4。如果您之前启用或启动了该服务,您现在应该停止它,并启用 nginx.socket
。当您的系统启动时,nginx 将不会运行,而是在您在浏览器中访问网站时启动。有了这个,您可以进一步加强服务;例如,在许多情况下,您现在可以在服务文件中设置 PrivateNetwork=True
,阻止 nginx 访问外部网络,因为 systemd 创建的套接字足以通过网络提供网站服务。请注意,这将在 nginx 服务的日志中打印警告:2020/08/29 19:33:20 [notice] 254#254: using inherited sockets from "3:4;"
PID 文件
nginx 编译为默认使用 /run/nginx.pid
,user 无法写入该文件。我们可以创建一个 user 可以写入的目录,并将 PID 文件放在那里。例如,可以使用 RuntimeDirectory
(systemd.exec(5))来完成此操作。
编辑 nginx.service
以配置 PID 文件
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... RuntimeDirectory=nginx PIDFile=/run/nginx/nginx.pid ExecStart= ExecStart=/usr/bin/nginx -g 'pid /run/nginx/nginx.pid; error_log stderr;' ExecReload= ExecReload=/usr/bin/nginx -s reload -g 'pid /run/nginx/nginx.pid; error_log stderr;'
/var/lib/nginx
nginx 默认编译为将临时文件存储在 /var/lib/nginx
中。
$ nginx -V
查看所有编译时选项你可以通过例如使用 StateDirectory
(systemd.exec(5)) 来赋予user 对此目录的写入权限
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... StateDirectory=nginx
/var/log/nginx
nginx 默认编译为将访问日志存储在 /var/log/nginx
中。
你可以通过例如使用 LogsDirectory
(systemd.exec(5)) 来赋予user 对此目录的写入权限
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... LogsDirectory=nginx
使用 systemd 运行用户服务
如果你想运行一个完全由非特权用户控制和配置的服务器实例,请考虑使用 nginx-user-serviceAUR。
systemd 的替代脚本
在纯 systemd 上,你可以获得 chroot + systemd 的优势。[4] 基于设置 user group 和 pid 以及
/etc/nginx/nginx.conf
user http; pid /run/nginx.pid;
文件的绝对路径是 /srv/http/etc/nginx/nginx.conf
。
/etc/systemd/system/nginx.service
[Unit] Description=nginx (Chroot) After=network.target [Service] Type=forking PIDFile=/srv/http/run/nginx.pid RootDirectory=/srv/http ExecStartPre=/usr/bin/nginx -t -c /etc/nginx/nginx.conf ExecStart=/usr/bin/nginx -c /etc/nginx/nginx.conf ExecReload=/usr/bin/nginx -c /etc/nginx/nginx.conf -s reload ExecStop=/usr/bin/nginx -c /etc/nginx/nginx.conf -s stop [Install] WantedBy=multi-user.target
没有必要设置默认位置,nginx 默认加载 -c /etc/nginx/nginx.conf
,但这是一个好主意。
或者,你可以仅将 ExecStart
作为 chroot 运行,并将参数 RootDirectoryStartOnly
设置为 yes
(参见 systemd.service(5)) 或者在挂载点之前作为有效路径或 systemd 路径启动它(参见 systemd.path(5)) 是可用的。
/etc/systemd/system/nginx.path
[Unit] Description=nginx (Chroot) path [Path] PathExists=/srv/http/site/Public_html [Install] WantedBy=default.target
启用 创建的 nginx.path
并在 /etc/systemd/system/nginx.service
中将 WantedBy=default.target
更改为 WantedBy=nginx.path
。
单元文件中的 PIDFile
允许 systemd 监控进程(需要绝对路径)。如果不需要,你可以更改为默认的 oneshot 类型,并从单元文件中删除引用。
Nginx 美化器
nginxbeautifierAUR 是一个用于美化和格式化 nginx 配置文件的命令行工具。
更好的标头管理
Nginx 有一个相当违反直觉的标头管理系统,其中标头只能在一个上下文中定义,任何其他标头都会被忽略。为了解决这个问题,我们可以安装 headers-more-nginx 模块。
安装 软件包 nginx-mod-headers-more 软件包。这会将模块安装到 /usr/lib/nginx/modules
目录。
要加载模块,请将以下内容添加到主 nginx 配置文件的顶部。
/etc/nginx/nginx.conf
load_module "/usr/lib/nginx/modules/ngx_http_headers_more_filter_module.so"; ...
基本身份验证
基本身份验证需要创建密码文件。密码文件可以使用 apache 软件包提供的 htpasswd
程序或使用 nginx_passwdAUR 进行管理,后者提供了 nginx-passwd
- 详细信息请参见 GitHub 源代码
使用 php-legacy
安装 php-legacy-fpm 而不是 php-fpm,并确保 PHP 已正确安装和配置。
PHP-LEGACY-FPM 的主配置文件是 /etc/php-legacy/php-fpm.conf
。对于基本用法,默认配置应该足够了。
fastcgi_pass
参数的 Unix 套接字也需要调整,通常是
fastcgi_pass unix:/run/php-fpm-legacy/php-fpm.sock;
然后 启动/启用 php-legacy-fpm.service
。
故障排除
配置验证
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
这是因为 FastCGI 服务器尚未启动,或者使用的套接字权限错误。
尝试 此答案 以修复 502 错误。
在 Arch Linux 中,上述链接中提到的配置文件是 /etc/php/php-fpm.conf
。
错误:未指定输入文件
1. 验证 /etc/php/php.ini
中的变量 open_basedir
是否包含在 nginx.conf
中指定为 root
参数的正确路径(通常是 /usr/share/nginx/
)。当使用 PHP-FPM 作为 PHP 的 FastCGI 服务器时,你可以在 nginx.conf
中旨在处理 PHP 文件的 location
代码块中添加 fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";
。
2. 另一种情况是,nginx.conf
中 location ~ \.php$
部分中的 root
参数错误。确保 root
指向与同一服务器中 location /
中相同的目录。或者你可以将 root 设置为全局的,不要在任何 location 部分中定义它。
3. 检查权限:例如,用户/组为 http
,目录为 755
,文件为 644
。记住到 html
目录的整个路径都应具有正确的权限。参见 文件权限和属性#批量 chmod 以批量修改目录树。
4. 你没有包含脚本完整路径的 SCRIPT_FILENAME
。如果 nginx 的配置 (fastcgi_param SCRIPT_FILENAME
) 正确,则此类错误意味着 PHP 未能加载请求的脚本。通常这只是一个权限问题,你可以以 root 身份运行 php-cgi
# spawn-fcgi -a 127.0.0.1 -p 9000 -f /usr/bin/php-cgi
或者你应该创建一个组和用户来启动 php-cgi
# groupadd www # useradd -g www www # chmod +w /srv/www/nginx/html # chown -R www:www /srv/www/nginx/html # spawn-fcgi -a 127.0.0.1 -p 9000 -u www -g www -f /usr/bin/php-cgi
5. 如果你正在使用 chrooted nginx 运行 php-fpm,请确保在 /etc/php-fpm/php-fpm.d/www.conf
(或在旧版本上为 /etc/php-fpm/php-fpm.conf
)中正确设置了 chroot
警告:无法构建最佳 types_hash
当启动 nginx.service
时,进程可能会记录消息
[warn] 18872#18872: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
要修复此警告,请增加 http
代码块内这些键的值 [5] [6]
/etc/nginx/nginx.conf
http { types_hash_max_size 4096; server_names_hash_bucket_size 128; ... }
无法分配请求的地址
来自 nginx.service
单元状态 的完整错误是
[emerg] 460#460: bind() to A.B.C.D:443 failed (99: Cannot assign requested address)
即使你的 nginx 单元文件配置为在 systemd 的 network.target
之后运行,nginx 也可能尝试监听已配置但尚未添加到任何接口的地址。通过手动为 nginx 启动 来验证是否是这种情况(从而显示 IP 地址已正确配置)。配置 nginx 监听任何地址将解决此问题。现在,如果你的用例需要监听特定地址,一种可能的解决方案是重新配置 systemd。
要在所有配置的网络设备启动并分配 IP 地址后启动 nginx,请将 network-online.target
附加到 nginx.service
中的 After=
,并启动/启用 systemd-networkd-wait-online.service
。