跳到主要内容

Nginx 实战配置速查:静态服务、反向代理与 HTTPS 一次搞清楚

详解 Nginx 最高频的配置场景:静态文件、反向代理尾斜杠陷阱、HTTPS 跳转、gzip 压缩、语法验证,每个场景附可直接复制的配置片段。

发布于
#nginx #devops #web服务器 #反向代理 #https

Nginx 实战配置速查:静态服务、反向代理与 HTTPS 一次搞清楚

Nginx 是当前部署最广的 Web 服务器。据 W3Techs 2024 年 4 月数据,它在全球前 100 万站点中占约 34% 的市场份额,超过 Apache(28%)和 IIS(7%)。但即便是有多年经验的工程师,也常在 server 块嵌套、location 匹配顺序、proxy_pass 尾斜杠这几个地方反复踩坑。

本文整理了我在实际项目中最频繁遇到的配置场景,每个场景都附上能直接复制使用的片段,以及背后值得记住的原因。

静态文件服务:SPA 路由必须会的 try_files

部署 Vite、Create React App 或任何纯前端产物时,try_files 是让客户端路由正常工作的核心:

server {
    listen 80;
    server_name example.com;
    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

try_files $uri $uri/ /index.html 的逻辑是:先找实体文件,再找目录下的 index,都找不到就回退到 index.html,由前端路由接管。漏掉最后这个回退参数,用户刷新任何子页面都会得到 404。

对静态资源加缓存头也是常见需求:

location ~* \.(js|css|png|jpg|svg|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

immutable 告诉浏览器文件内容不会改变(适合带 hash 文件名的构建产物),在重复访问时跳过 304 协商,加载更快。

反向代理:尾斜杠决定后端收到什么路径

把流量转发到 Node.js、Django 或 Spring Boot 时,proxy_pass 的尾斜杠是最隐蔽的陷阱:

# 情形 A:location 和 proxy_pass 都不带斜杠
location /api {
    proxy_pass http://127.0.0.1:8080;
}
# 请求 /api/users → 后端收到 /api/users

# 情形 B:location 和 proxy_pass 都带斜杠
location /api/ {
    proxy_pass http://127.0.0.1:8080/;
}
# 请求 /api/users → 后端收到 /users(前缀被剥除)

我在一个项目里因为 location 用了情形 A,proxy_pass 却带了斜杠,后端一直收到路径变成 / 的请求,花了近两小时才定位到这一个字符的差异。规则很简单:要么两边都带斜杠,要么都不带。

加上必要的请求头,让后端能拿到真实客户端 IP 和协议:

location /api/ {
    proxy_pass         http://127.0.0.1:8080/;
    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 $scheme;
}

HTTPS 强制跳转与 TLS 配置

Let's Encrypt 证书签好之后,最简洁的 HTTP 转 HTTPS 写法:

# 第一个 server 块:HTTP 全部跳转
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

# 第二个 server 块:HTTPS 主配置
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    # 其他配置放这里
}

return 301rewrite 更推荐:它在 Nginx 内部直接处理,不走正则引擎,性能更高,配置也更直白。www 到顶级域的跳转同理,用 return 301 https://example.com$request_uri 即可。

Gzip 压缩:开启后文本资源普遍缩小 60% 以上

Nginx 内置 gzip 模块,对 HTML/CSS/JS/JSON 这类文本资源的压缩效果显著。我实测一个 React 生产包(未压缩约 280 KB),开启 gzip 后降至 74 KB,压缩率约 74%。配置放在 http {} 块里全局生效:

gzip            on;
gzip_types      text/plain text/css application/json application/javascript
                text/xml application/xml text/javascript;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_vary       on;

几个参数的选择理由:gzip_min_length 1024 避免对小文件压缩(小文件压后可能反而变大);gzip_comp_level 6 是速度与压缩率的均衡点,测试表明从 6 升到 9 平均只多压 2%,但 CPU 开销明显更高,通常不划算;gzip_vary on 确保 CDN 能区分压缩与非压缩版本,不会把 gzip 响应缓存后发给不支持的客户端。

语法验证与线上调试

修改配置后一定先验证语法,不然 reload 可能让服务中断:

nginx -t
# 正常输出:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 语法通过后热重载(不中断现有连接)
nginx -s reload

想知道某个请求匹配了哪条 location,临时把错误日志级别改为 debug:

error_log /var/log/nginx/debug.log debug;

然后用一个 HTTP 请求触发,在日志里搜索 "using configuration" 就能看到实际匹配的路径和文件。调试完记得改回 warn 级别,debug 日志量极大,磁盘会很快写满。

测试接口时,我一般在终端里配合 curl 速查表 来快速拼接参数,特别是需要带自定义 header、跟踪 301 重定向链或测试 HTTPS 证书时,不用每次翻 man 手册。

另外,Nginx 的 root 目录和日志目录的文件权限也常常成为问题根源。worker 进程需要对 root 指向的目录有读权限,对 /var/log/nginx/ 有写权限。配置权限时用 Linux 权限计算器 换算 755644 等八进制数值,比心算或翻文档省事很多。

如果你需要快速查某条指令的含义或搜索不记得全称的参数名,Nginx 配置速查表 按类别整理了常用指令,支持实时搜索,直接在浏览器里用,不用开新标签页查官方文档。


Made by Toolora · Updated 2026-06-16