不論是新老用戶均可能掉進一樣的陷阱裏。下面咱們列舉了覺的問題同時也給出瞭解決辦法。在Freenode的IRC頻道#nginx裏,咱們常常遇到這類問題。javascript
這些常見問題,通常是因某人試圖從別人的配置裏直接拷貝後拿來用,並非全部拷貝的都有問題,惋惜的是,大部分都有問題。即便是Linode文檔庫裏也存在因社區成員不去維護致使質量差的信息。php
這個文檔由大量NGINX社區成員建立和審查,這個特殊文檔的存在也是由於這些太過來常見了並常常發生。css
你可能並無找你跟你直接有關的特殊問題,也許咱們確實是沒有指出你常常的特殊問題。但,不要覺得你來到這個頁面是沒有緣由的,你被帶到這個頁面至少表示你在下面的問題裏遇到過問題:)html
永遠不要使用777。不要覺得這只是一個漂亮的數字,即便在測試環境也代表你會沒有線索查你正在作的事。你能夠對整個路徑的權限進行檢查,能夠考慮你正在作的事實。前端
要檢查路徑的權限,你能夠:java
namei -om /path/to/check
劣:node
server { server_name www.example.com; location / { root /var/www/nginx-default/; # [...] } location /foo { root /var/www/nginx-default/; # [...] } location /bar { root /var/www/nginx-default/; # [...] } }
能夠工做。每一個location塊裏都加上root指令沒有錯,也能很好的工做。那會有什麼問題呢?若是某一個location塊你路徑寫錯了,將致使沒有根目錄。來看下什麼是優的配置。nginx
優:正則表達式
server { server_name www.example.com; root /var/www/nginx-default/; location / { # [...] } location /foo { # [...] } location /bar { # [...] } }
劣:後端
http { index index.php index.htm index.html; server { server_name www.example.com; location / { index index.php index.htm index.html; # [...] } } server { server_name example.com; location / { index index.php index.htm index.html; # [...] } location /foo { index index.php; # [...] } } }
爲什麼重複那麼多沒必要要的行?其實只要簡單的使用index指令一次,只要在http{}裏使用一次,下面的區塊將自動繼承。
優:
http { index index.php index.htm index.html; server { server_name www.example.com; location / { # [...] } } server { server_name example.com; location / { # [...] } location /foo { # [...] } } }
只有少數一些討論if的文章,有篇叫 if是魔鬼 的你必定要看,下面舉些列子說明爲什麼if如此壞。
劣:
server { server_name example.com *.example.com; if ($host ~* ^www\.(.+)) { set $raw_domain $1; rewrite ^/(.*)$ $raw_domain/$1 permanent; } # [...] } }
這裏實際上有三個問題。首先看看if,也是咱們如今要關注的,爲什麼是劣的?你讀過這篇文章 If是魔鬼 嗎?當nginx接收到一個請求無論子域名是什麼,即便是www.example.com或example.com,if指令也是每次都要調用,由於NGINX須要每次對請求頭Host作處理,這特別沒有效率,你要千萬注意避免它。能夠替換爲兩個server區塊,以下面的列子:
優:
server { server_name www.example.com; return 301 $scheme://example.com$request_uri; } server { server_name example.com; # [...] }
這種配置也可使配置更好閱讀,這種方法減小了NGINX的處理需求。咱們去除了謬誤的if,同時咱們使用了$schema避免了硬編碼URI,如http或https。
使用if來判斷一個文件是否存在太可怕了。也就是說若是你有最新版的NGINx,使用tryfiles指令將更加容易。
劣:
server { root /var/www/example.com; location / { if (!-f $request_filename) { break; } } }
優:
server { root /var/www/example.com; location / { try_files $uri $uri/ /index.html; } }
咱們只是修改了判斷文件是否存在但又不使用if指令,使用tryfiles表示能夠測試一系列文件,若是$uri不存在,再試$uri/,若是還不存在,就使用默認位置(index.html)。
在這個列子,若是$uri存在就使用它,若是不存在,再判斷$uri/目錄是否存在,若是不存在就使用index.html,必需要保證最後一個檢測的文件存在。很簡單吧!下面是另外一個例子去掉if指令。
"前端控制模式"-Front controller patterm在php開源界很是流行,但大都使用的比較複雜,如Drupal、jammla等,只要像這樣:
try_files $uri $uri/ /index.php?q=$uri&$args;
注意-參數根據你使用的開源軟件不一樣而不一樣。如:
有些軟件甚至不須要查詢參數而是用REQUEST_URI參數,如,Wordpress支持這個:
try_files $uri $uri/ /index.php;
若是你不關心檢查目錄,只要去掉$uri/。
固然,你可能遇到些特殊狀況,須要更復雜的配置,但對通常站點,這些就夠了。
不少NGINX+PHP的配置會傳遞全部以.php結尾的請求給php,但這裏會出現一個嚴重的安全問題,可能致使精心構造的代碼被執行。
這類問題看起來如:
location ~* \.php$ { fastcgi_pass backend; # [...] }
這裏,每一個以.php結尾的請求將傳遞給FastCGI後端。這會致使一個問題,PHP的默認配置對於找不到的文件,會對整個請求文件路徑猜想哪一個部分須要執行。
舉例,若是請求是/forum/avatar/1232.jpg/file.php,文件並不存在,但/forum/avatar/1232.jpg存在,則php也會執行1232.jpg,若是1232.jpg包含php代碼,也會被執行。
避免執行的選項有:
cgi.fixpathinfo=0.這會致使php不嘗試字面上的路徑,若是文件沒找到就中止處理。
保證NGINX只傳遞特定文件給PHP
location ~* (file_a|file_b|file_c)\.php$ { fastcgi_pass backend; # [...] }
指定用戶上傳的目錄不能夠執行php
location /uploaddir { location ~ \.php$ {return 403;} # [...] }
使用tryfles指令過濾有問題的條件
location ~* \.php$ { try_files $uri =404; fastcgi_pass backend; # [...] }
使用嵌套location過濾
location ~* \.php$ { location ~ \..*/.*\.php$ {return 404;} fastcgi_pass backend; # [...] }
腳本文件中的FastCGI路徑
太多例子說用絕對路徑來指定路徑的錯誤作法。一般見於php配置塊。當你從svn中安裝NGINX,一般會有include fastcgiparams;在你的配置中,目錄通常在/etc/nginx。
優:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
劣:
fastcgi_param SCRIPT_FILENAME /var/www/yoursite.com/$fastcgi_script_name;
$docmentroot在哪設的?一般是在你的server塊裏,不在?看看上面的第一個坑。
在這不要犯糊,很容易被正則表達式搞蒙,事實上,很簡單,只要努力作到足夠簡單就行。
劣:
rewrite ^/(.*)$ http://example.com/$1 permanent;
優:
rewrite ^ http://example.com$request_uri? permanent;
更優:
return 301 http://example.com$request_uri;
看看上面的例子,第一個規則是獲取所有url而後減fcfu最一個反斜杆,事實上使用內置變量$request_uri能夠更簡單。
很是簡單,rewrites規則都是相對路徑,除非你告訴NGINX不是,使用rewrite的絕對路徑也很簡單,添加一個schema。
劣:
rewrite ^ example.com permanent;
優:
rewrite ^ http://example.com permanent;
上面的例子中只是添加了http://,簡單而有效。
劣:
server { server_name _; root /var/www/site; location / { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/tmp/phpcgi.socket; } }
噁心。這個例子中,什麼內容都代理給了PHP,爲何?Apache也許用來替代,但不必。try_files指令神奇的地方是:它按必定的順序嘗試使用文件。NGINX能夠首先嚐試靜態文件,若是沒有,繼續嘗試。意思是PHP不必定要處理全部文件。速度將更快!例如你有個1M的圖片比較下經過用PHP來處理和用服務器直接處理的速度。看看優化後的方案:
server { server_name _; root /var/www/site; location / { try_files $uri $uri/ @proxy; } location @proxy { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/tmp/phpcgi.socket; } }
一樣也是好的方案
server { server_name _; root /var/www/site; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/tmp/phpcgi.socket; } }
很容易不是嗎?若是請求的URI存在,NGINX能夠直接處理,若是不存在,若是是個目錄也能夠處理,若是還不是,再傳遞給代理。僅當NGINX不能處理時才傳遞給代理。
考慮下你的多少內容是靜態的(圖片、css、javascript等),可能能節省下大量的消耗。
瀏覽器緩存的問題。你的配置也許很完善但也有撞牆的時候。出現問題的緣由就是瀏覽器緩存。當下載頁面時,瀏覽器會作緩存,同時也保存了文件怎麼更新,若是你在測試 types{}指令,你可能須要經過如下方法來清緩存
若是nginx工做不正常多是由於sendfile指令,只要註釋掉再試下。
若是你沒有設置underscores_in_headers on;指令,NGINX將把包括下劃線的頭信息丟掉(依據http標準),這也是爲了一種保護機制,防止異常的頭信息與CGI變量衝突。
全部系統都有些不能使用的目錄,如/和root,永遠不要設置成document root目錄。通常都是放在/var/www或/srv或/usr/share/www/。
不要使用系統安裝包默認的DocumentRoot目錄,由於軟件升級或從新安裝時,有可能修改該目錄,若是你的業務恰好在使用這個目錄,oops,目錄有可能被刪除並安裝它的默認文件。當心。
劣:
upstream { server http://someserver; }
優:
server { listen myhostname:80; # [...] }
永遠不要在listen指令中使用主機名。雖然能夠工做,但會帶來不少問題,一個是系統啓動或service啓動時hostname不必定能解析,這將致使nginx不能綁定到指令的tcp socket並啓動失敗。
安全的作法是指令ip地址來代替主機名。避免了域名解析的成本。同理,在upstream也同樣,儘可能避免使用主機名。
優:
upstream { server http://10.48.41.12; }
注:多虛擬主機名時仍是避免不了。
SSLv3由於有安全風險,建議不要使用,而用TLS代替。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
翻譯 朱淦<350050183@qq.com> 2016.7.20