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
。