Nginx

Nginx

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

  1. Directives with the "=" prefix that match the query exactly. If found, searching stops.
  2. All remaining directives with conventional strings. If this match used the "^~" prefix, searching stops.
  3. Regular expressions, in the order they are defined in the configuration file.
  4. 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.45.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 反向代理

jwilder/nginx-proxy

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 速度果然慢的离谱,不可能在上面跑任何应用。


Last update: 2022-04-14 01:06:32 UTC
';\nsub_filter_once on;\n```\n\n## Docker 反向代理\n\n[jwilder/nginx-proxy](https://hub.docker.com/r/jwilder/nginx-proxy/dockerfile)\n\nhttps://github.com/jwilder/nginx-proxy\n\n\n```\ndocker run --name nginx -p 80:80 -p 443:443 -d \\\n# -v /root/data/nginx-config/proxy.conf:/etc/nginx/proxy.conf \\\n# -v /root/data/nginx-config/vhost.d:/etc/nginx/vhost.d \\\n# -v /root/data/certs:/etc/nginx/certs \\\n -v /var/run/docker.sock:/tmp/docker.sock:ro \\\n jwilder/nginx-proxy\n```\n\n## Direct set http response body\n\n```\nlocation = /test_url {\n types { } default_type \"application/json; charset=utf-8\";\n add_header Set-Cookie \"token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT\" always;\n return 200 '{}';\n}\n```\n\n# Examples\n\n## nginx 架设本机运行的 app 的入口代理\n\nWSL1 环境。配置文件保存在 /mnt/c/files/appdata/system/nginx/。使用腾讯云的[免费 ssl 证书](https://console.cloud.tencent.com/ssl)(优点是一年有效期;缺点是不能自己上传 CSR,生成的证书的安全性严重值得怀疑,另外也不支持泛域名证书)。\n\n/mnt/c/files/appdata/system/nginx/nginx.conf :\n\n\n```\n\n# include /mnt/c/files/appdata/system/nginx/nginx.conf;\n\nserver {\n server_name example.com;\n listen 0.0.0.0:80;\n return 301 https://$host$request_uri;\n}\n\n\nserver {\n server_name example.com;\n\n listen 0.0.0.0:443 ssl spdy;\n\n client_max_body_size 100m;\n\n ssl on;\n ssl_certificate /mnt/c/files/appdata/system/nginx/1_example.com_bundle.crt;\n ssl_certificate_key /mnt/c/files/appdata/system/nginx/2_example.com.key;\n #ssl_dhparam /root/example.com/dhparam.pem;\n #ssl_ciphers 'AES256+EECDH:AES256+EDH:!aNULL';\n #ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n #ssl_session_cache shared:SSL:10m;\n #ssl_stapling on;\n #ssl_stapling_verify on;\n #ssl_prefer_server_ciphers on;\n\n location / {\n proxy_pass http://127.0.0.1:8765;\n proxy_buffering off;\n #proxy_set_header Upgrade $http_upgrade;\n #proxy_set_header Connection 'upgrade';\n proxy_set_header Host $host;\n proxy_set_header X-Forwarded-For $remote_addr;\n }\n}\n```\n\n/etc/nginx/nginx.conf : 咋默认配置的 http 区块里加一行 include 即可。\n\n```\nhttp {\n # ...\n include /mnt/c/files/appdata/system/nginx/nginx.conf;\n # ...\n}\n```\n\n以上配置:本机应用监听 http://127.0.0.1:8765 . 通过 nginx 的反向代理对外提供 https://example.com 的访问入口。\n\nPS. WSL1 的 IO 速度果然慢的离谱,不可能在上面跑任何应用。\n\n\n\n","note":null,"ctime":"2019-04-29T07:01:21.971Z","mtime":"2022-04-14T13:06:32.184Z","meta":[]},"status":200,"parentMetas":[]},"serverParams":{"csrf":"j9jE3q7M-4YPhVJqevAWvSBnXeefdG5VFzdQ","old":false}}; //-->