Nginx

出自 Arch Linux 中文维基

Nginx (讀作"engine X") 由Igor Sysoev(俄羅斯)於2005年編寫,是一個免費、開源、高性能的HTTP伺服器和反向代理,也可以作為一個IMAP/POP3代理伺服器。Nginx因為穩定,豐富的功能集,配置簡單,資源占用低而聞名世界。

這篇文章描述了如何設置nginx並且如何通過#FastCGI集成PHP.

安裝[編輯 | 編輯原始碼]

安裝nginx-mainline (主線(mainline)分支:新功能,更新,bug解決) 或者 nginx (穩定分支: 只是bug解決).

推薦使用主線分支。使用穩定分支的主要原因是擔心新功能的造成的不良影響,比如與第三方模塊不兼容或者開發者疏忽導致引入新功能時出現bug.

注意: 所有在official repositories可用的模塊都需要nginx(與nginx-mainline相反)作為依賴.你可能需要在下決定選nginx還是nginx-mainline前,先查看下模塊名單。nginx-mainline的模塊能在Arch User Repository找到.

對於在基於chroot環境下的額外安全性,可查閱#在chroot環境下安裝.

啟動[編輯 | 編輯原始碼]

啟動/啟用 nginx.service.

默認在 http://127.0.0.1 頁面服務的頁面是 /usr/share/nginx/html/index.html.

配置[編輯 | 編輯原始碼]

安裝nginx後的第一步該幹什麼寫在用戶手冊裡了. 你可以通過編輯在/etc/nginx/下的文件來修改配置。主配置文件在/etc/nginx/nginx.conf.

更多細節和例子,你可以在 https://wiki.nginx.org/Configuration官方文檔找到.

下面的例子包含了最常見的使用案例.我們假定你使用的是默認文件路徑(/usr/share/nginx/html). 如果你改了路徑,用你自己的路徑替代.

提示:DigitalOcean 提供了一個 Nginx 配置工具

配置例子[編輯 | 編輯原始碼]

/etc/nginx/nginx.conf
user http;
worker_processes auto;
worker_cpu_affinity auto;

events {
    multi_accept on;
    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.

不同用戶間的使用[編輯 | 編輯原始碼]

默認的, nginxroot 身份運行主進程而用http用戶運行worker進程. 如果要用其它用戶運行worker進程, 改變nginx.conf裡的user參數就好了:

/etc/nginx/nginx.conf
user user [group];

如果組(group)忽略不寫的話,就會用和user相同的名字來代替

提示:其實也可以使用systemdroot身份在沒有任何東西運行的情況下運行nginx . 可以看 #使用 systemd無權限運行.

server代碼塊[編輯 | 編輯原始碼]

通過使用 server 模塊,可以實現服務多個域名. 這些模塊可以類比為Apache HTTP Server中的"VirtualHosts" . 也可查閱 上游文獻.

下面的例子,伺服器監聽IPv4和IPv6的80埠的進入流量的兩個域名,分別是domainname1.domdomainname2.dom:

/etc/nginx/nginx.conf
...
server {
    listen 80;
    listen [::]:80;
    server_name domainname1.dom;
    root /usr/share/nginx/domainname1.dom/html;
    location / {
       index index.php index.html index.htm;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name domainname2.dom;
    root /usr/share/nginx/domainname2.dom/html;
    ...
}
...

Restart(重啟) nginx.service 來讓改變的配置生效.

確保主機名是可以被設置好的DNS伺服器比如BIND 或者 dnsmasq解析的,或者可以查看下網絡配置#Local network hostname resolution.

管理伺服器入口[編輯 | 編輯原始碼]

把不同的server模塊放到不同的文件裡是可能的.這樣的話可以讓你很輕易的開啟和禁用特定的站點.

創建以下文件夾:

# mkdir /etc/nginx/sites-available
# mkdir /etc/nginx/sites-enabled

sites-available文件夾下創建一個文件包含一個或更多伺服器模塊:

/etc/nginx/sites-available/example.conf
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
}

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[編輯 | 編輯原始碼]

本文或本章節的語言、語法或風格需要改進。參考:Help:Style

原因:不要僅僅把 OpenSSL#Certificates的配置搬過來.(在Talk:Nginx討論)

OpenSSL 提供了TLS支持並且默認在Arch系統安裝時安裝了.

提示:
  • 你可能需要在配置SSL之前閱讀 ngx_http_ssl_module文檔.
  • Let’s Encrypt 時一個免費的、自動的、開放的證書頒發機構.有一個插件可以從茉莉花請求有效的證書並自動配置的.
  • Mozilla有一篇有用的 TLS文章,也有一個自動化工具來創建一個更安全的配置.
警告: 如果你打算實現TLS, 你必須知道一些變化和實現 仍然被攻擊時很脆弱[1]. 如果想知道TLS內現存的漏洞和怎樣用合適的方法到nginx上,可訪問 https://weakdh.org/sysadmin.html

創建一個私鑰和自簽名的證書,這對大多數不需要 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
注意: 如果你需要更多的 openssl選項, 可以閱讀 openssl(1ssl)擴展文檔.

使用TLS的 /etc/nginx/nginx.conf 的基本例子:

/etc/nginx/nginx.conf
http {
    ...
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ..

    # Redirect to HTTPS
    server {
        listen 80;
        server_name localhost;
        return 301 https://$host$request_uri;
    }

    server {
        #listen 80; # Uncomment to also listen for HTTP requests
        listen 443 ssl http2; # HTTP/2 is only possible when using SSL
        server_name localhost;

        ssl_certificate ssl/server.crt;
        ssl_certificate_key ssl/server.key;

        root /usr/share/nginx/html;
        location / {
            index index.html index.htm;
        }
    }
}

Restart nginx.service 來讓配置生效.

分用戶目錄[編輯 | 編輯原始碼]

如果要複製Apache式的 ~user URLs 到用戶的 ~/public_html 目錄, 可以嘗試下面的. (Note: 如果下面的兩個規則都用了的話一定要把更清楚地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配置.

重啟 nginx.service 來啟用新配置.

FastCGI[編輯 | 編輯原始碼]

FastCGI, 也叫 FCGI, 是適用於web伺服器和交互式程序的接口的協議. FastCGI 是早期的 Common Gateway Interface (CGI)的變種; FastCGI的主要目的是減少CGI程序和web伺服器交互的開銷,來允許伺服器同時處理更多網頁請求.

FastCGI技術被引進nginx是為了與許多外部工具,比如. Perl, PHP and Python

PHP實現[編輯 | 編輯原始碼]

PHP-FPM 是建議使用的用作PHP的FastCGI伺服器的解決方案.

安裝(安裝) php-fpm 然後確保 PHP 被安裝配置正確. PHP-FPM的主要配置文件是 /etc/php/php-fpm.conf. 基礎使用的話默認配置就足夠了.

最後, enablestart php-fpm.service.

注意:
  • 如果你 用不同的用戶運行nginx, 確保PHP-FPM套接字文件能被這個用戶訪問,或者通過一個TCP套接字.
  • 如果你在chroot的環境下運行nginx (chroot 是 /srv/nginx-jail, web頁面在 /srv/nginx-jail/www), 你必須修改文件 /etc/php/php-fpm.conf ,把 chroot /srv/nginx-jaillisten = /srv/nginx-jail/run/php-fpm/php-fpm.sock 兩行加入到指令部分 (默認是[www]). 如果缺少的話請為套接字文件創建目錄。此外, 動態連結到依賴的模塊,你需要將這些依賴複製到(比如. 對於php-imagick, 你需要複製ImageMagic的庫複製到chroot, 而不是imagick.so他自己).
  • php-fpm 7.4.0 開始, php-fpm.service 定義了 ProtectHome=true,限制了對 /home, /root/run/user 下文件的訪問,會產生 No input file specified. 錯誤 FS#64683#comment184136
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;
    }

    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-fpmdefault (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.servicenginx.service 服務單元來讓配置生效,如果配置之前被改變過的話.

測試FastCGI實現, 在root目錄下創建一個新的PHP文件,內容是:

<?php phpinfo(); ?>

把這個文件用瀏覽器打開,你應該就可以看到現在的PHP配置的信息頁了.

CGI 實現[編輯 | 編輯原始碼]

這個實現是CGI程序所需要的.

fcgiwrap[編輯 | 編輯原始碼]

安裝 fcgiwrap. 配置文件是 /usr/lib/systemd/system/fcgiwrap.socket. Enable 並且 start fcgiwrap.socket.

多個工人線程[編輯 | 編輯原始碼]

如果你想生成多個工人線程建議你使用multiwatchAUR, 它會處理崩潰的子進程. 如果你需要使用spawn-fcgi 來創建Unix套接字,因為multiwatch無法處理systemd創建的套接字,儘管fcgiwarp它自己在單元文件中直接調用頁沒有任何問題.

/usr/lib/systemd/system/fcgiwrap.service 複製單元文件到 /etc/systemd/system/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參數選項時會出現奇怪的情況.這有可能是一個Bug
nginx配置[編輯 | 編輯原始碼]

在每個服務了一個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.

在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創建嚴格的 user/group文件. 這樣只有chroot正常工作所需要的用戶才會被chroot知道,其他的users/groups並不會被洩露給攻擊者,如果他們已經獲取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

最後設置權限。應該儘可能把權限設置為不可寫 be owned by root and set unwritable.

# 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單元文件之前, 把它複製進 /etc/systemd/system/ 因為這裡的單元文件的優先級比 /usr/lib/systemd/system/高. 這樣更新nginx就不會修改你自定義的 .service 文件.

# cp /usr/lib/systemd/system/nginx.service /etc/systemd/system/nginx.service

systemd單元必須在開啟chroot裡的nginx之前修改,以http用戶的身份,將pid文件放到chroot裡.

注意: 我不確定pid文件是否需要被放到chroot裡.
/etc/systemd/system/nginx.service
 [Unit]
 Description=A high performance web server and a reverse proxy server
 After=syslog.target 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
注意: 用pacman升級nginx並不會升級chroot裡的nginx。如果你要升級的話可能需要手動重複上面的步驟。不要忘記更新它連結的庫.

你現在可以安全的寫在非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無權限運行[編輯 | 編輯原始碼]

編輯 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
提示:查看 systemd.exec(5) 獲取更多限權選項.

然後我們需要確保 user(即前面設置的用戶)有權限做它需要做的事:

Port
Linux默認不允許非root用戶的進程綁定低於1024的埠,高於1024的埠可以用:
/etc/nginx/nginx.conf
server {
        listen 8080;
}
提示:如果你想nginx可以訪問80或者443埠,配置你的firewall(防火牆)來重定向從80或者443的請求到nginx監聽的埠.

或者你可以提升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
PID文件
nginx 默認使用 /run/nginx.pid . 我們可以創建一個文件夾,user有寫權限,然後把我們的PID文件放到那裡. 一個使用systemd-tmpfiles的例子:
/etc/tmpfiles.d/nginx.conf
d /run/nginx 0775 root group - -

運行配置:

# systemd-tmpfiles --create

基於最初的nginx.serviceEdit(編輯)PID的值:

/etc/systemd/system/nginx.service.d/user.conf
[Service]
...
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;'
/var/lib/nginx/*
一些/var/lib/nginx下面的目錄需要被以 root 運行的nginx的引導. 所以有必要啟動整個伺服器老這麼做, nginx會在一次簡單的 #配置驗證之後自己這麼做. 所以只要運行這些中的一個就好啦.
日誌文件 & 目錄權限
運行配置測試的步驟會創建一個懸空的root擁有的日誌文件. 移除/var/log/nginx下面的日誌文件開始刷新.
啟用nginx服務的用戶需要/var/log/nginx的寫權限. 這可能需要 改變權限 和/或 你系統這個目錄的所有權.

現在一切都好了。開始start(啟動) nginx, 然後就可以想用你的非root下的nginx了.

提示:同樣的配置可能還要針對你的 FastCGI server 再做一次.

針對systemd的可選腳本[編輯 | 編輯原始碼]

在純systemd的情況下,你可以享受chroot + systemd的好處. [3] 基於在下面的文件設置 用戶組一個 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=syslog.target network.target

[Service]
Type=forking
PIDFile=/srv/http/run/nginx.pid
RootDirectory=/srv/http
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/usr/sbin/nginx -c /etc/nginx/nginx.conf -s reload
ExecStop=/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop

[Install]
WantedBy=multi-user.target

沒必要設置默認路徑,nginx默認加載 -c /etc/nginx/nginx.conf,二這也是一個好主意.

作為可選項,你可以在chroot環境下僅僅運行 ExecStartRootDirectoryStartOnly參數要調成,查看 yes systemd服務手冊 或者在掛載點生效前啟用它,或者一個 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";
...

故障排除[編輯 | 編輯原始碼]

配置驗證[編輯 | 編輯原始碼]

# nginx -t
 nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
 nginx: configuration file /etc/nginx/nginx.conf test is successful

接入本地IP重定向到 localhost[編輯 | 編輯原始碼]

Arch Linux 論壇的解決方案.

/etc/nginx/nginx.conf有一行server_name localhost ,前面沒有 #, 把下面的加入到這一行之下:

server_name_in_redirect off;

默認行為事nginx將任何請求重定向到配置裡server_name給定的值裡.

Error: The page you are looking for is temporarily unavailable. Please try again later. (502 Bad Gateway)[編輯 | 編輯原始碼]

這是因為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代碼塊的下面的鍵的值 [4] [5]:

/etc/nginx/nginx.conf
http {
    types_hash_max_size 4096;
    server_names_hash_bucket_size 128;
    ...
}

不能指定請求地址[編輯 | 編輯原始碼]

來自systemctl status nginx.service的全部錯誤是

[emerg] 460#460: bind() to A.B.C.D:443 failed (99: Cannot assign requested address)

儘管,你的單元文件配置為用systemd運行在 network.target , nginx可能還是企圖監聽一個配置了但沒添加到任何接口的地址. 確保這種情況下手動start (啟動) nginx (從而確保IP位址配置正確). 配置 nginx監聽任何地址都會解決這個問題. 如果你的情況是需要監聽特定的地址, 一個可能的解決方案是重新配置systemd.

在所有網絡配置工作和指定IP位址都結束後開啟nginx, 在nginx.service裡附加 network-online.targetAfter= 然後 start/enable systemd-networkd-wait-online.service.

參見[編輯 | 編輯原始碼]