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接受多少连接和它会使用多少处理器。通常来说,把它设置成你系统里的硬件线程数就好了。可选的是,自从 1.3.8 和 1.2.5版本以后, worker_processes
接受 auto
作为值了,它会自动检测最优值 (source)。
nginx的最大连接数有下面的公式给出max_clients = worker_processes * worker_connections
。
不同用户间的使用[编辑 | 编辑源代码]
默认的,nginx包 用 root
身份运行主进程而用http
用户运行worker进程。如果要用其它用户运行worker进程,改变nginx.conf
里的user
参数就好了:
/etc/nginx/nginx.conf
user user [group];
如果组(group)忽略不写的话,就会用和user相同的名字来代替。
server代码块[编辑 | 编辑源代码]
通过使用 server
模块,可以实现服务多个域名。这些模块可以类比为Apache HTTP Server中的"VirtualHosts"。也可查阅上游文献。
下面的例子,服务器监听IPv4和IPv6的80端口的进入流量的两个域名,分别是domainname1.tld
和domainname2.tld
:
/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; ... }
Restart(重启) nginx.service
来让改变的配置生效。
确保主机名是可以被设置好的DNS服务器比如BIND 或者 dnsmasq解析的,或者可以查看下网络配置#Local network hostname resolution。
管理服务器入口[编辑 | 编辑源代码]
把不同的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
Reload/restart nginx.service
来让配置生效。
TLS[编辑 | 编辑源代码]
OpenSSL 提供了TLS支持并且默认在Arch系统安装时安装了。
- 你可能需要在配置SSL之前阅读 ngx_http_ssl_module 文档。
- Let’s Encrypt 是一个免费的、自动的、开放的证书颁发机构。有一个插件可以从命令行请求有效的证书并自动配置。
- 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配置生成器。
Restart nginx.service
来让配置生效。
分用户目录[编辑 | 编辑源代码]
如果要复制Apache式的 ~user
URLs 到用户的 ~/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; } ... } ...
查阅 #PHP实现来阅读更多 nginx
的PHP配置。
Restart nginx.service
来启用新配置。
FastCGI[编辑 | 编辑源代码]
FastCGI, 也叫 FCGI, 是适用于web服务器和交互式程序的接口的协议. FastCGI 是早期的 Common Gateway Interface (CGI)的变种; FastCGI的主要目的是减少CGI程序和web服务器交互的开销,来允许服务器同时处理更多网页请求.
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
, web页面在/srv/nginx-jail/www
), 你必须修改文件/etc/php/php-fpm.conf
,把chroot = /srv/nginx-jail
和listen = /srv/nginx-jail/run/php-fpm/php-fpm.sock
两行加入到指令部分 (默认是[www]
). 如果缺少的话请为套接字文件创建目录。此外, 动态链接到依赖的模块,你需要将这些依赖复制到(比如. 对于php-imagick, 你需要复制ImageMagic的库复制到chroot, 而不是imagick.so他自己).
nginx 配置[编辑 | 编辑源代码]
当服务一个PHP web程序时,一个PHP-FPM的location
应该包括在 #server代码块里 [2],比如.:
/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 and .htm):
location ~ [^/]\.(php|html|htm)(/|$) { ... }
非 .php 的PHP-FPM扩展处理都需要被直接加入到 /etc/php/php-fpm.d/www.conf
:
security.limit_extensions = .php .html .htm
fastcgi_pass
参数, 因为它被选定的FastCGI服务器在它的配置文件里定义TCP或Unix套接字. 对应php-fpm
的default (Unix) 套接字是 是:
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
你可能想要使用常见的 TCP 套接字, not default,
fastcgi_pass 127.0.0.1:9000;Unix 的域名套接字应该会快一点.
server
块来启用PHP支持, 创建一个 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支持, 只需要简单的加入 include php.conf
就好了:
/etc/nginx/sites-available/example.conf
server { server_name example.com; ... include /etc/nginx/php_fastcgi.conf; }
测试配置[编辑 | 编辑源代码]
你需要restart php-fpm.service
和 nginx.service
服务单元来让配置生效,如果配置之前被改变过的话.
测试FastCGI实现, 在root
目录下创建一个新的PHP文件,内容是:
<?php phpinfo(); ?>
把这个文件用浏览器打开,你应该就可以看到现在的PHP配置的信息页了.
CGI 实现[编辑 | 编辑源代码]
这个实现是CGI程序所需要的.
fcgiwrap[编辑 | 编辑源代码]
安装 fcgiwrap包. 配置文件是 /usr/lib/systemd/system/fcgiwrap.socket
. 启用 并且 启动 fcgiwrap.socket
.
多个工人线程[编辑 | 编辑源代码]
如果你想生成多个工人线程建议你使用multiwatchAUR, 它会处理崩溃的子进程. 如果你需要使用spawn-fcgi
来创建Unix套接字,因为multiwatch无法处理systemd创建的套接字,尽管fcgiwarp它自己在单元文件中直接调用页没有任何问题.
覆盖 fcgiwrap.service
(和fcgiwrap.socket
单元, 如果存在的话), 修改ExecStart
行到满足你需要的地方. 下面是使用multiwatchAUR的单元文件. 确保fcgiwrap.socket
没有被start(开始)或enable(启用), 因为他会和这些单元冲突:
/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
来改变生成的子进程的数量.
ExecStartPost
行是需要的,因为当为spawn-fcgi
使用-M 660
参数选项时会出现奇怪的情况.这有可能是一个Bugnginx配置[编辑 | 编辑源代码]
在每个服务了一个CGI程序的server
块内都应该有一个像下面的 location
块:
location ~ \.cgi$ { root /path/to/server/cgi-bin; fastcgi_pass unix:/run/fcgiwrap.sock; include fastcgi.conf; }
fcgiwrap
的默认套接字文件是/run/fcgiwrap.sock
.
如果你一直出现 502 - bad Gateway
错误,你应该检查你的CGI程序是否宣告了下面内容的mime类型。如果是html,他应该是Content-type: text/html
.
如果你遇到 403 错误,请确保 CGI 可执行文件对 http
用户可读且可执行,并且每个父文件夹对 http
用户可读。
在chroot环境下安装[编辑 | 编辑源代码]
在chroot环境里运行nginx是有一个额外的安全层的。为了最大化安全性,chroot环境应该只包括nginx服务器需要的文件,并且所有的文件都应该尽可能有严格的权限,比如像/usr/bin
这样的文件夹应该不可读和不可写。
Arch默认有一个http
用户和组来运行服务器,chroot将会在/srv/http
。
创建这个监狱(指chroot环境)的PERL脚本能在jail.pl gist找到。你可以直接用那个脚本或者跟着这篇文章的指示继续阅读下去。它应该用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。大小应该限制确保攻击者无法吃掉所有的内存。
# 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里的nginx之前修改,以http用户的身份,将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
你现在可以安全的写在非chroot环境下的nginx安装.
# pacman -Rsc nginx
如果你不移除非chroot环境的nginx安装,你可能想要确认运行的nginx是不是chroot环境里的, 你可以查询 /proc/PID/root
链接到哪里. 如果链接到 /srv/http
而不是/
那运行的就是chroot环境下的nginx.
# ps -C nginx | awk '{print $1}' | sed 1d | while read -r PID; do ls -l /proc/$PID/root; done
建议和技巧[编辑 | 编辑源代码]
使用 systemd 以非特权用户身份运行[编辑 | 编辑源代码]
使用 drop-in unit file 为 nginx.service
设置 User
和可选的 Group
选项,放在 [Service]
下:
/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] 基于设置 用户组 和 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
,但这仍然是一个好主意。
作为可选项,你可以在chroot环境下仅仅运行 ExecStart
,RootDirectoryStartOnly
参数要设置为yes
(参见 systemd.service(5)),或者在挂载点生效前启用它,或者使用一个 systemd路径。
/etc/systemd/system/nginx.path
[Unit] Description=nginx (Chroot) path [Path] PathExists=/srv/http/site/Public_html [Install] WantedBy=default.target
Enable(启用)创建的nginx.path
然后把 /etc/systemd/system/nginx.service
里的WantedBy=default.target
变成 WantedBy=nginx.path
。
单元文件里的PID文件
允许systemd监控进程(需要绝对路径)。如果这不是你想要的,你可以改变默认的“一击”类型,然后删除单元文件里的参照。
Nginx Beautifier (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
。
Error: No input file specified[编辑 | 编辑源代码]
1. 确定/etc/php/php.ini
里的 open_basedir
变量包含正确的路径,要和 nginx.conf
(通常在/usr/share/nginx/
)里的root
变量一致. 当使用PHP-FPM 作为PHP的FastCGI服务器时, 你可以添加 fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";
到nginx.conf
里的 location
代码块里,它能处理PHP文件.
2. 另一种情况是, nginx.conf
文件里,location ~ \.php$
代码块里的错误的 root
变量. 确保root
指向相同服务器里的location /
的同样的目录. 或者你直接把root设为全局,不要把它定义到任何地方
3. 检查权限: 比如. http
是用户/组, 755
是目录权限,644
是文件权限. 记住,到html
目录的路径目录也必须有相同的权限. 可以查看 File permissions and attributes#Bulk 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. 如果你是在chroot的环境下的nginx运行php-fpm,确保/etc/php-fpm/php-fpm.d/www.conf
里的chroot
设置正确(或者 /etc/php-fpm/php-fpm.conf
如果是旧版本的话)
Warning: Could not build optimal 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 单元文件配置为在 network.target
之后运行,nginx 可能仍然会尝试监听一个已配置但尚未添加到任何接口的地址。通过手动 start (启动)nginx 来验证这种情况(从而确保 IP 地址配置正确)。配置 nginx 监听任何地址都会解决这个问题。如果你的使用场景需要监听特定地址,一个可能的解决方案是重新配置 systemd。
在所有配置的网络设备启动并分配 IP 地址后启动 nginx,在 nginx.service
中将 network-online.target
附加到 After=
,然后 start/enable systemd-networkd-wait-online.service
。