跳到主要内容
方的代码随记
返回

Nginx 实用配置片段

更新于:

按场景组织的即用型配置片段,复制后改域名和路径即可。

二级目录映射到后端服务

前后端分离后常见「前端一个端口、后端一个端口」。要在同一个域名同一个端口下同时提供两者,用反向代理把 /api/ 转发到后端:

location ^~ /api/ {
    proxy_pass  https://example.com:4433/;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

反向代理完整参数

location / {
    proxy_pass  http://example.com;
    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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_max_temp_file_size 0;
    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;
    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
}

HTTP 强制跳转 HTTPS

server {
    listen 80 default_server;
    server_name example.com;
    rewrite ^(.*) https://$server_name$1 permanent;
    # 也可以写成
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name example.com;
}

HSTS 保持 HTTPS

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

非标准 HTTPS 端口重定向

让 2083 这类非标准端口也支持 HTTP 跳 HTTPS:

error_page 497 https://$host:2083$request_uri;

否则用户用 HTTP 访问 HTTPS 端口会报 The plain HTTP request was sent to HTTPS port。

端口转发(暴露内网服务)

把内网 192.168.1.2:3306 通过本机的 33062 端口暴露出去:

upstream TCP3306 {
    hash $remote_addr consistent;
    server 192.168.1.2:3306;
}

server {
    listen 33062;
    proxy_connect_timeout 5s;
    proxy_timeout 300s;
    proxy_pass TCP3306;
}

跨域

if ($request_method = OPTIONS ) {
    add_header "Access-Control-Allow-Origin"  *;
    add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD";
    add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept";
    add_header 'Access-Control-Max-Age' 600;
    return 200;
}

带 cookie 的跨域,需要指定具体源并开启 credentials:

server {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;
        proxy_cookie_domain www.domain2.com www.domain1.com;   # 修改 cookie 里的域名
        index  index.html index.htm;

        # 前端只跨域不带 cookie 时,Allow-Origin 可为 *
        add_header Access-Control-Allow-Origin http://www.domain1.com;
        add_header Access-Control-Allow-Credentials true;
    }
}

用 webpack-dev-server 等中间件代理接口时没有浏览器参与,不受同源限制,上面这段可不加。

Chrome 80+ 默认禁止第三方 Cookie,除非服务端显式设置 SameSite:

取值行为
Strict完全禁止第三方 Cookie,跨站任何情况都不发送
Lax大多数情况不发送,但导航到目标网址的 GET 请求除外
None允许跨站发送,但必须同时设置 Secure(仅 HTTPS)
Set-Cookie: widget_session=abc123; SameSite=None; Secure

另一种思路是 proxy_pass 反向代理:仅转换 Host 和端口时 Cookie 不会丢失;路径变化时需要额外做 Cookie 路径转换。

Gzip 压缩

http {
    gzip on;
    gzip_types text/plain application/javascript text/css application/xml text/javascript image/jpeg image/gif image/png;
    gzip_comp_level 5;
    gzip_vary on;
    gzip_buffers 16 8k;
    gzip_disable "MSIE [1-6]\.";   # 低版本 IE 不支持压缩
    gzip_http_version 1.1;
    gzip_min_length 2k;
    gzip_proxied off;
}
参数释义
gzip开关
gzip_types按文件类型选择性压缩
gzip_comp_level压缩级别,越高越耗时、压缩率越好
gzip_vary是否在响应头加 Vary: Accept-Encoding
gzip_buffers压缩请求缓冲区数量与大小
gzip_disable针对特定 UA 关闭压缩
gzip_http_version触发压缩的最低 HTTP 版本
gzip_min_length触发压缩的最小文件大小
gzip_proxied是否压缩后端响应结果

动静分离

location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {
    root /data/www/static;
    expires 30d;
}

静态资源直接由 Nginx 返回,动态请求才转发给后端,可显著降低后端压力。

代理缓存

http {
    # 缓存目录:内存缓存区 hot_cache 128m,3 天未访问自动清除,磁盘上限 2GB
    proxy_cache_path /log/nginx/cache levels=1:2 keys_zone=hot_cache:128m inactive=3d max_size=2g;

    server {
        location / {
            proxy_cache hot_cache;
            proxy_cache_valid 200 206 304 301 302 1d;
            proxy_cache_valid any 30m;
            proxy_cache_key $host$uri$is_args$args;
            proxy_cache_min_uses 3;              # 至少访问 3 次才加入缓存
            proxy_cache_lock on;                 # 回源时只放行一个请求
            proxy_cache_lock_timeout 3s;
            proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
            add_header Cache-status $upstream_cache_status;   # 便于调试命中情况
        }
    }
}

proxy_cache_path 关键参数:

参数含义
path缓存路径
levels目录层次结构,最多三层
keys_zone共享内存空间(1M 约存 8000 个 Key)
inactive多久未被访问后删除,默认十分钟
max_size最大存储空间,超出后按 LRU 移除
use_temp_path是否使用临时目录

IP 黑白名单

单个 IP 直接写在 location 里:

server {
    location ^~ /my_api/ {
        deny 192.177.12.222;      # 屏蔽单个 IP
        deny 127.0.0.0/8;         # 屏蔽网段
        allow 192.177.44.201;     # 允许单个 IP
        allow 127.45.0.0/16;      # 允许网段
        deny all;                 # 其余全部禁止
    }
}

只允许内网访问管理后台:

location /admin {
    allow 192.168.1.0/24;
    allow 10.0.0.0/24;
    deny all;
}

规则自上而下匹配,命中即停止。批量 IP 建议抽成 .conf 文件后用 include 引入。

防盗链

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    valid_referers none blocked *.example.com example.com;
    if ($invalid_referer) {
        return 403;
    }
}

大文件传输优化

client_max_body_size 100m;
client_body_buffer_size 1m;
proxy_request_buffering off;    # 大文件上传时边收边转发
proxy_read_timeout 300s;

过滤请求方法

明确只用 GET / POST / HEAD 时,其他方法直接屏蔽:

if ($request_method !~ ^(GET|HEAD|POST)$) {
    return 404;
}

超时设置

http {
    client_body_timeout 10;
    client_header_timeout 30;
    keepalive_timeout 30 30;
    send_timeout 10;
}

隐藏版本号

避免版本漏洞被猜解:

server_tokens off;

分享这篇文章:

下一篇
Nginx 性能优化