Config
include
include mime.types;
include vhosts/*.conf;
ACL
# first match win
allow 192.168.0.0/16;
deny all;
server syntax
- 位于顶级的 http block 里。
- server_name 可以写空格分隔的多个域名。
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /root/files/appdata/nginx/example.com.crt;
ssl_certificate_key /root/files/appdata/nginx/example.com.key;
location / {
# ...
}
}
如果某个 http(s) 请求没有找到任何匹配 server_name 的 server, nginx 会使用配置文件里第 1 个监听端口符合的 server 记录项来处理该请求(即使该 server 没有配置 server_name 或 server_name 不匹配)。可以在 listen 参数里指定 "default_server" flag 显式设置其为默认 server。
location syntax
- Directives with the "=" prefix that match the query exactly. If found, searching stops.
- All remaining directives with conventional strings. If this match used the "^~" prefix, searching stops.
- Regular expressions, in the order they are defined in the configuration file.
- If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
location = / {
# matches the query / only.
[ configuration A ]
}
location / {
# matches any query, since all queries begin with /, but regular
# expressions and any longer conventional blocks will be
# matched first.
[ configuration B ]
}
location /documents/ {
# matches any query beginning with /documents/ and continues searching,
# so regular expressions will be checked. This will be matched only if
# regular expressions don't find a match.
[ configuration C ]
}
location ^~ /images/ {
# matches any query beginning with /images/ and halts searching,
# so regular expressions will not be checked.
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
# matches any request ending in gif, jpg, or jpeg. However, all
# requests to the /images/ directory will be handled by
# Configuration D.
[ configuration E ]
}
Can nginx location blocks match a URL query string?
Short answer: No.
Long answer: There is a workaround if we have only a handful of such location blocks.
Here's a sample workaround for 3 location blocks that need to match specific query strings:
server {
#... common definitions such as server, root
location / {
error_page 418 = @queryone;
error_page 419 = @querytwo;
error_page 420 = @querythree;
if ( $query_string = "service=git-receive-pack" ) { return 418; }
if ( $args ~ "service=git-upload-pack" ) { return 419; }
if ( $arg_somerandomfield = "somerandomvaluetomatch" ) { return 420; }
# do the remaining stuff
# ex: try_files $uri =404;
}
location @queryone {
# do stuff when queryone matches
}
location @querytwo {
# do stuff when querytwo matches
}
location @querythree {
# do stuff when querythree matches
}
}
You may use $query_string, $args or $arg_fieldname. All will do the job. You may know more about error_page in the official docs.
Warning: Please be sure not to use the standard HTTP codes.
静态网站
location / {
root /var/www/webroot;
try_files $uri /index.html;
}
说明:
- root 指定的目录(包括父级目录的相应权限)必须 nginx 用户有访问权限。
- 以上重定向所有文件不存在的 url 访问到 index.html 文件。
反向代理
假设源站 IP 1.2.3.4,同样监听 80 / 443 端口。
server {
server_name example.com;
charset utf-8;
listen 0.0.0.0:80;
location / {
proxy_pass http://1.2.3.4;
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;
proxy_set_header X-Forwarded-Proto https;
}
}
server {
server_name example.com;
listen 0.0.0.0:443 ssl spdy;
client_max_body_size 100m;
ssl on;
ssl_certificate /root/example.com/fullchain.pem;
ssl_certificate_key /root/example.com/privkey.pem;
ssl_dhparam /root/example.com/dhparam.pem;
ssl_ciphers 'AES256+EECDH:AES256+EDH:!aNULL';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
ssl_prefer_server_ciphers on;
location / {
proxy_pass https://1.2.3.4;
proxy_ssl_server_name on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
# proxy_cache_bypass $http_upgrade;
}
}
upstream app {
server 127.0.0.1:3000;
}
location /app {
proxy_pass http://app/main/;
proxy_redirect off;
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
注:
- proxy_cache_bypass 可能造成问题。参考。
- 如果 proxy_pass 后面的 url 带有 path 部分。则 nginx 会把 url 匹配到的 path 重写,例如对于上面例子,用户访问 http://example.com/app/test 则后端实际收到请求的 path 是 "/main/test"。
保护源站
可以在源站主机上设置 iptables 规则,禁止非反向代理访问。
# 假设 1.2.3.4 和 5.6.7.8 分别是源站和反向代理主机 IP
iptables -I INPUT 1 -p tcp --dport 80 -d 1.2.3.4 ! -s 5.6.7.8 -j DROP
iptables -I INPUT 1 -p tcp --dport 443 -d 1.2.3.4 ! -s 5.6.7.8 -j DROP
https 反向代理
(http block)
upstream originServer {
server 1.2.3.4:443;
}
server {
listen 443;
# server_name example.com
ssl_certificate /root/files/appdata/nginx/example.com.crt;
ssl_certificate_key /root/files/appdata/nginx/example.com.key;
ssl on;
location / {
proxy_pass https://originServer;
proxy_redirect off;
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
Redirect http to https
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
字符串替换 sub_filter
http://nginx.org/en/docs/http/ngx_http_sub_module.html
默认仅替换 text/html
# 配合反向代理使用时,禁止后端 App gzip压缩,否则无法替换字符串。
#proxy_set_header Accept-Encoding "";
sub_filter '</head>' '<script src="https://example.com/test.js"></script></head>';
sub_filter_once on;
Docker 反向代理
https://github.com/jwilder/nginx-proxy
docker run --name nginx -p 80:80 -p 443:443 -d \
# -v /root/data/nginx-config/proxy.conf:/etc/nginx/proxy.conf \
# -v /root/data/nginx-config/vhost.d:/etc/nginx/vhost.d \
# -v /root/data/certs:/etc/nginx/certs \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
jwilder/nginx-proxy
Direct set http response body
location = /test_url {
types { } default_type "application/json; charset=utf-8";
add_header Set-Cookie "token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT" always;
return 200 '{}';
}
Examples
nginx 架设本机运行的 app 的入口代理
WSL1 环境。配置文件保存在 /mnt/c/files/appdata/system/nginx/。使用腾讯云的免费 ssl 证书(优点是一年有效期;缺点是不能自己上传 CSR,生成的证书的安全性严重值得怀疑,另外也不支持泛域名证书)。
/mnt/c/files/appdata/system/nginx/nginx.conf :
# include /mnt/c/files/appdata/system/nginx/nginx.conf;
server {
server_name example.com;
listen 0.0.0.0:80;
return 301 https://$host$request_uri;
}
server {
server_name example.com;
listen 0.0.0.0:443 ssl spdy;
client_max_body_size 100m;
ssl on;
ssl_certificate /mnt/c/files/appdata/system/nginx/1_example.com_bundle.crt;
ssl_certificate_key /mnt/c/files/appdata/system/nginx/2_example.com.key;
#ssl_dhparam /root/example.com/dhparam.pem;
#ssl_ciphers 'AES256+EECDH:AES256+EDH:!aNULL';
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#ssl_session_cache shared:SSL:10m;
#ssl_stapling on;
#ssl_stapling_verify on;
#ssl_prefer_server_ciphers on;
location / {
proxy_pass http://127.0.0.1:8765;
proxy_buffering off;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
/etc/nginx/nginx.conf : 咋默认配置的 http 区块里加一行 include 即可。
http {
# ...
include /mnt/c/files/appdata/system/nginx/nginx.conf;
# ...
}
以上配置:本机应用监听 http://127.0.0.1:8765 . 通过 nginx 的反向代理对外提供 https://example.com 的访问入口。
PS. WSL1 的 IO 速度果然慢的离谱,不可能在上面跑任何应用。