nginx
配置
内置变量
http://nginx.org/en/docs/varindex.html
$host
- 主机名(无端口号)
$http_<header>
:HTTP 头的值。名称使用全小写。$scheme
$https
- 如果正在使用 HTTPS 访问,为
on
,否则为空。 $request_uri
- 请求的 URL 路径
$uri
- 正规化之后的请求的 URL 路径,可以被后续操作修改。
虚拟主机
见官方的VirtualHostExample。
server_name_in_redirect
指示是否根据server_name
跳转到其第一个值,默认值为off
[1]。
使用listen 80 default_server
形式指定默认虚拟主机。
日志
记录 Cloudflare 这种反代 IP 的:
log_format cflog '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $realip_remote_addr';
加上请求处理时间:
log_format cflog '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent $request_time "$http_referer" "$http_user_agent" $realip_remote_addr';
HTTPS
要使用 HTTPS,在server
段中这样配置[2]。其中监听 80 端口是可选的。
listen 80;
listen 443 ssl;
server_name chat.vim-cn.com chat.edisonnotes.com;
ssl_certificate /etc/stunnel/stunnel.pem;
ssl_certificate_key /etc/stunnel/stunnel.pem;
关于证书相关信息,参见 openssl。
nginx 参数$https
在使用 HTTPS 时为on
,否则为空。但是位于 Cloudflare 这种反向代理后边时,需要依据其它 HTTP 头来生成。因为fastcgi_param
不能在if
块内使用,所以需要使用 map 模块,如下
http {
map $http_x_forwarded_proto $cf_https {
http off;
https on;
}
...
location ... {
...
fastcgi_param HTTPS $cf_https;
}
}
另见Nginx的访问控制/地址转向/HTTPS设置 [Lainme's Blog]
加密算法相关配置
使用 openssl 生成 DH 参数:
openssl dhparam -out dhparams.pem 2048
然后配置 nginx:[3]
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam dhparams.pem;
#ssl_ciphers ALL:!3DES:!MD5:!RC4:!aNULL:!eNULL:!MEDIUM:!LOW:!EXP;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
重定向到 HTTPS
server {
listen [::]:80;
return 301 https://$host$request_uri;
}
参见
PHP + FastCGI
PHP 公用配置:
index index.php index.html;
location ~ (.+\.php\d?)($|/) {
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
set $script $request_filename;
if ($request_filename ~ ^(.+\.php\d?)(/.*)$){
set $script $1;
set $pathinfo $2;
}
fastcgi_param PATH_INFO $pathinfo if_not_empty;
fastcgi_param SCRIPT_FILENAME $script;
include fastcgi_params;
}
PHP FastCGI 方案一:
安装 php-cgi 后,可使用以下命令启动PHP:
php-cgi -b 9000
PHP FastCGI 方案二:
安装 php-fpm 后修改配置文件并启动该服务即可。
PATH_INFO
通过在 location 中使用正则表达式可达成此设置
location ~ ^(.*\.py)(/.*)?$ {
root /home/lily;
include fastcgi_params;
fastcgi_pass unix:/tmp/sock;
fastcgi_index index.py;
fastcgi_param SCRIPT_FILENAME $document_root$1;
fastcgi_param PATH_INFO $2;
fastcgi_param SCRIPT_NAME $1;
}
owncloud 的有效配置
此配置经测试在 owncloud 5.0.2 上有效。参照了官方的(有问题的)配置[4]。
server {
server_name owncloud.localhost;
access_log /srv/http/localhost/logs/owncloud.access.log;
error_log /srv/http/localhost/logs/owncloud.error.log;
root /usr/share/webapps/owncloud;
index index.php;
# deny direct access
location ~ ^/(data|config|\.ht|db_structure\.xml|README) {
deny all;
}
# default try order
location / {
try_files $uri $uri/ @webdav;
}
# owncloud WebDAV
location @webdav {
fastcgi_split_path_info ^(.+\.php\d?)(/.*)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# enable php
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php\d?)(/.*)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Jappix 的有效配置
map $http_x_forwarded_proto $cf_https {
http off;
https on;
}
server {
server_name chat.example.com;
root /var/www/jappix;
error_log /var/log/nginx/chat.example.com_error_log;
access_log /var/log/nginx/chat.example.com_access_log combined;
index index.html index.htm index.php index.php4 index.php5;
include cloudflare;
location ~ (.+\.php\d?)($|/) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
set $script $request_filename;
if ($request_filename ~ ^(.+\.php\d?)(/.*)$){
set $script $1;
set $pathinfo $2;
}
include fastcgi_params;
fastcgi_param HTTPS $cf_https;
fastcgi_param PATH_INFO $pathinfo if_not_empty;
fastcgi_param SCRIPT_FILENAME $script;
}
}
server {
server_name bosh.example.com;
error_log /var/log/nginx/bosh.example.com_error_log;
access_log /var/log/nginx/bosh.example.com_access_log combined;
include cloudflare;
location / {
proxy_pass http://localhost:5280;
proxy_pass_header Server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
CGI
有如下方案
使用 nginx-fcgi。
使用 fcgiwrap 程序[5]
fcgiwrap
文件[6]:
fastcgi_pass unix:/run/fcgiwrap.sock;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param REMOTE_USER $remote_user;
配置:
location /cgi-bin {
root /srv/http;
include fcgiwrap;
}
alias 指示
给本地地址取别名,类似于Apache的Alias
指示。注意,有时结尾的/
很重要,因为 nginx 会删除结尾的一个字符(如此处第三例)。
location /test {
alias /home/lilydjwg/tmpfs/;
index index.php;
autoindex on;
}
也可以使用正则表达式,但要求使用捕获组
location ~ ^/test/(.*\.php)($|/) {
alias /home/lilydjwg/tmpfs/$1;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
location /path/ {
if ($request_uri ~ ^(.*/)index\.html$) {
rewrite ^(.*/)index\.html$ $1 permanent;
}
alias /some/path/;
autoindex on;
index index.html;
}
location 指示
参见官方文档。
搜索顺序
=
开头者。如匹配则停止- 字面地址,匹配最精确的优先。如果以
^~
开头则停止 - 正则表达式,按其在配置中出现的顺序
- If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
类型
=
- 精确匹配
(无)
- 字面字符串,开头匹配
^~
- 同上,但如匹配立即停止
~
- 正则匹配
代理
WebSocket
添加以下配置就可以了:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
Authentication with reverse proxy
Here's a sample config setting with basic authentication enabled:[7]
location /couchdb/ {
auth_basic "Restricted";
auth_basic_user_file htpasswd;
rewrite /couchdb/(.*) /$1 break;
proxy_pass http://localhost:5984;
# or should it be this in this case? --- proxy_redirect /couchdb/ /;
proxy_pass_header Server; # 将来自上游的 Server 头发送给客户端
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
DNS
注意:proxy_pass
会缓存 DNS 解析结果。要迫使 nginx 每次将重新解析,可将 URL 赋值到变量来绕过[8]
set $backend_upstream "http://dynamic.example.com:80";
proxy_pass $backend_upstream;
realip
set_real_ip_from 192.168.1.0/24;
real_ip_header X-Forwarded-For;
URL 重写
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
域名重定向:
# ...
server_name img.vim-cn.com elimage.edisonnotes.com;
location / {
if ($host != 'img.vim-cn.com' ) {
rewrite ^/(.*)$ $scheme://img.vim-cn.com/$1 permanent;
}
# ...
}
去掉结尾的index.html
,只能使用if
,否则会死循环:
location /path/ {
if ($request_uri ~ ^(.*/)index\.html$) {
rewrite ^(.*/)index\.html$ $1 permanent;
}
alias /some/path/;
autoindex on;
index index.html;
}
代理中的 URL 重写
在proxy_redirect off
时,应当proxy_set_header Host $http_host
。否则不应该设置。
proxy_redirect
第一个参数为前缀匹配。如果写proxy_redirect / /
将会给没有域名部分的重定向添加上(Nginx 这边的)域名。
注意:一个请求中proxy_redirect
不会被多次应用。
一个复杂的重写示例(同时进行普通 URL 重写和代理中的重写):
location /download/ {
rewrite ^/download/name/(.*)$ /download/$1 break;
proxy_pass http://127.0.0.1:7474;
proxy_redirect http://127.0.0.1:7474/download/ /download/name/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
给 Etherpad Lite 的重写
MediaWiki 的插件 EtherEditor 在 Google Chrome 浏览器下要求 wiki 和 Etherpad Lite 使用完全相同的域名(端口号也要相同;火狐不需要)。
location ~ ^/(pad/|static/|offlinemanifest\.appcache$|socket\.io/|locales\.json$|javascripts/|pluginfw/|offline\.html$) {
rewrite ^/pad/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:9001;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
目录列表的编码
syntax: charset encoding|off
default: charset off
context: http, server, location, if in location
功能
gzip
gzip on;
gzip_comp_level 5;
gzip_proxied any;
gzip_types text/plain application/javascript text/css application/xml text/javascript application/json;
注:默认未启用。启用后默认只 gzip text/html 类型。[10]
似乎没有办法针对不同的 IP 使用不同的 gzip 设置(支持在 location
的 if
块中使用,但是不生效)。
限速
if ($http_user_agent ~ "MSIE") {
limit_rate 2k;
}
[11]
指定的User-Agent
返回错误,如阻止据说是迅雷的UA:[12]
if ($http_user_agent ~ "Mozilla/4.0\ \(compatible;\ MSIE\ 6.0;\ Windows\ NT\ 5.1;\ SV1;\ .NET\ CLR\ 1.1.4322;\ .NET\ CLR\ 2.0.50727\)") {
return 404;
}
防盗链
授权
在location
里写[13]
auth_basic "Restricted";
auth_basic_user_file htpasswd;
即可,其中htpasswd
是授权文件,和 Apache 的相同,可使用 htpasswd 命令维护或者 openssl passwd -apr1
生成。
注意,据来源说这样会把授权信息传给代理。
IP 限制
allow 127.0.0.1;
allow ::1;
deny all;
缓存代理
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=one:10m use_temp_path=off max_size=10g inactive=100d;
resolver 127.0.0.1:53;
server {
listen 1110;
location / {
proxy_pass http://$http_host/$uri;
proxy_cache one;
proxy_cache_valid 200 302 100d;
proxy_cache_valid 404 1m;
}
}
添加跨站支持
比如用于重定向 Grafana 的代理请求至 Graphite 源站(需要浏览器扩展进行重定向和添加鉴权信息):
add_header Access-Control-Allow-Origin $http_origin;
if ( $request_method = "OPTIONS" ) {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
add_header Access-Control-Allow-Method "POST, OPTIONS";
return 204;
}
旧版本的问题
- 1.0.x 的 realip 模块不能正确处理多个
X-Forwarded-For
头,造成无法从 HAProxy 默认配置获取到正确的源 IP。[14] - 1.9.13 之前的版本,对于代理默认会重发非幂等的请求[15][16]
参见
外部链接
- linux下为nginx安装mod_wsgi扩展以支持python - Leven's Blog
- OpenResty - a powerful web app server by extending nginx
- Nginx的配置与部署研究,Upstream负载均衡模块 - Linux Today
- How nginx "location if" works
- Brilliant Place: Nginx alias try_files php-fpm 共存
- 如何正确配置Nginx+PHP | 火丁笔记
- 通过FastCGI Cache实现服务降级 | 火丁笔记
- Rule convertor, convert apache htaccess rewrite rules to nginx rewrite rules automatically
- Nginx的访问控制/地址转向/HTTPS设置 [Lainme's Blog] (SSL 相关)
- CloudFlare's Internet facing SSL cipher configuration
- 使用 GZip Bomb 对抗站点扫描工具 | Rocka's Blog
安全相关
参考资料
- ↑ http://wiki.nginx.org/NginxCoreModule#server_name_in_redirect
- ↑ HttpSslModule
- ↑ Cipherli.st - Strong Ciphers for Apache, nginx and Lighttpd
- ↑ Installation — ownCloud Administrators Manual 4.5 documentation
- ↑ Fcgiwrap - Nginx Community
- ↑ FcgiWrap – Nginx
- ↑ Nginx_As_a_Reverse_Proxy - Couchdb Wiki
- ↑ Nginx, reverse proxies and DNS resolution | Jethro Carr
- ↑ Module ngx_http_realip_module
- ↑ Module ngx_http_gzip_module
- ↑ 骨头:nginx 对某些 User_Agent 进行限速的方法
- ↑ 骨头:nginx 禁止某个 User_Agent 的方法
- ↑ Nginx_As_a_Reverse_Proxy - Couchdb Wiki
- ↑ #106 (Nginx realip module not working correctly with multiple x-forwarded-for headers) – nginx
- ↑ Module ngx_http_proxy_module
- ↑ reverse proxy - How can I stop nginx from retrying PUT or POST requests on upstream server timeout? - Server Fault