Nginx 容器化部署实战:SPA 路由、Cookie 透传与 WebSocket 全配置详解

场景:容器内同时跑 Nginx 和 Go 后端。Nginx 负责:前端 Vue SPA 静态资源(7777 端口)、/api 反向代理到 Go(8888)、/static 静态资源代理(上传的图片/文件)并带 30 天强缓存。同时解决四个经典问题:SPA 路由 404、Cookie 丢失、WebSocket 握手失败、非 root 用户运行权限。

1. 完整配置 nginx.conf

nginx 复制代码
# Nginx 配置文件
# 容器以非 root 用户 (1000) 运行,不切换用户

worker_processes auto;              # 自动匹配 CPU 核数
pid /run/nginx/nginx.pid;           # PID 文件位置(非 root 可写)
error_log /var/log/nginx/error.log warn;

events {
    worker_connections 1024;        # 单 worker 最大连接数
}

http {
    # 非 root 用户临时目录(覆盖 Alpine 默认的 /var/lib/nginx/tmp,否则 403 权限错误)
    client_body_temp_path /tmp/nginx_client_body;
    proxy_temp_path /tmp/nginx_proxy;
    fastcgi_temp_path /tmp/nginx_fastcgi;
    uwsgi_temp_path /tmp/nginx_uwsgi;
    scgi_temp_path /tmp/nginx_scgi;

    # MIME 类型
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;

    server {
        listen 7777;                # 前端入口端口
        server_name _;

        client_max_body_size 30M;   # 上传文件大小限制(壁纸/图片/头像)

        # ─────────────────────────────
        # 前端静态文件 + SPA 路由
        # ─────────────────────────────
        location / {
            root /usr/share/nginx/html;
            index index.html;
            # SPA 路由核心:所有未匹配的路径都返回 index.html
            # 由前端 vue-router 接管路由(history 模式)
            try_files $uri $uri/ /index.html;
        }

        # ─────────────────────────────
        # 后端 API 反向代理
        # ─────────────────────────────
        location /api/ {
            proxy_pass http://127.0.0.1:8888;   # 注意:无尾斜杠 = 保留原始 URI
            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;

            # 确保 cookie 透传(解决 session/JWT 丢失问题)
            proxy_set_header Cookie $http_cookie;
            proxy_pass_header Set-Cookie;

            # 禁止 nginx 修改重定向(解决 307 二次请求问题)
            proxy_redirect off;

            # WebSocket 支持
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";

            # 代理超时(聊天/SSE 流式接口需要)
            proxy_connect_timeout 90;
            proxy_read_timeout 90;
        }

        # ─────────────────────────────
        # 静态文件代理(壁纸、聊天文件、头像等)
        # ─────────────────────────────
        location /static/ {
            proxy_pass http://127.0.0.1:8888;   # Go 后端 r.Static("/static", "./static")
            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;

            # 静态资源强缓存 30 天
            expires 30d;
            add_header Cache-Control "public, immutable";
        }
    }
}

2. 逐段讲解:每个配置解决什么问题

2.1 SPA 路由 ------ try_files

nginx 复制代码
location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
}

问题 :Vue Router 用 history 模式时,URL 是 /blog/article/123 而不是 /#/blog/article/123。用户刷新页面时,Nginx 找不到对应的真实文件,返回 404。

解决try_files 依次尝试:

  1. $uri --- 命中真实文件(如 /assets/index-xxx.js
  2. $uri/ --- 命中目录(自动找 index.html)
  3. /index.html --- 兜底,交给前端路由处理

注意:后端要有对应的 API 接口或返回 404 页面,避免 SEO 无效页面被索引。

nginx 复制代码
proxy_set_header Cookie $http_cookie;
proxy_pass_header Set-Cookie;

问题:默认 Nginx 会透传 Cookie,但某些场景(跨域、代理到不同端口)会导致 Session 丢失。显式声明后:

  • Cookie:把客户端 Cookie 原样传给后端
  • Set-Cookie:后端设置的 Cookie 原样返回给客户端

2.3 307 重定向问题 ------ proxy_redirect off

问题:Go 后端某些接口返回 307(如 HTTP→HTTPS 跳转),Nginx 默认会改写 Location 头,导致客户端跳转到错误地址,出现"二次请求"或死循环。

解决proxy_redirect off; 让 Location 头原样透传。

2.4 WebSocket ------ 协议升级

nginx 复制代码
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

问题 :WebSocket 握手时客户端发 Upgrade: websocket 头,HTTP/1.0 不支持长连接,Nginx 必须用 HTTP/1.1 转发并带上 Upgrade/Connection 头,否则握手失败。

2.5 非 root 用户运行 ------ 临时目录

nginx 复制代码
client_body_temp_path /tmp/nginx_client_body;
proxy_temp_path /tmp/nginx_proxy;

问题 :容器以 USER 1000:1000 运行时,Nginx 默认的 /var/lib/nginx/tmp 没有写权限,上传文件或代理大响应时直接 403/500。

解决 :把临时目录全部指到 /tmp 下,并在 Dockerfile 里 chown 给用户 1000。

2.6 上传大小限制

nginx 复制代码
client_max_body_size 30M;

不设置默认只有 1M,上传壁纸/图片会报 413 Request Entity Too Large

3. 验证与排查命令

bash 复制代码
# 检查配置语法
nginx -t -c /etc/nginx/nginx.conf

# 容器内实时日志
docker logs -f ledger-service

# 手动验证各路由
curl -I http://localhost:7777/                      # 前端页面
curl -I http://localhost:7777/api/v1/user/info      # API 代理
curl -I http://localhost:7777/static/wallpapers/xxx.jpg  # 静态资源(看 Cache-Control)

4. 常见问题排查表

现象 原因 解决
刷新页面 404 没配 try_files try_files $uri $uri/ /index.html;
登录后刷新掉登录态 Cookie 没透传 proxy_set_header Cookie + proxy_pass_header Set-Cookie
WebSocket 连不上 缺 Upgrade 头 proxy_http_version 1.1 + Upgrade/Connection 头
上传 413 体积超限 client_max_body_size 30M;
上传 403 非 root 无写权限 临时目录指到 /tmp + chown
图片不更新 强缓存 30 天 文件名带 hash 或改用 no-cache
接口 502 后端没启动/端口不对 检查 proxy_pass 地址与后端监听端口

5. 与 Dockerfile 的配合

dockerfile 复制代码
# 非 root 运行所需:创建目录并授权
RUN mkdir -p /var/log/nginx /run/nginx /var/lib/nginx/logs /tmp/nginx_client_body /tmp/nginx_proxy && \
    chown -R 1000:1000 /app /usr/share/nginx/html /var/log/nginx /run/nginx /var/lib/nginx /tmp/nginx_client_body /tmp/nginx_proxy

USER 1000:1000

总结

这份配置的核心价值:

  1. 一个 7777 端口搞定前后端:静态资源 + API + WebSocket + 静态文件,外部只暴露一个入口
  2. 四个经典坑全部规避:SPA 404、Cookie 丢失、WS 握手失败、非 root 权限
  3. 性能:静态资源 30 天强缓存,后端只处理动态请求
相关推荐
Csxyzj2 小时前
Nginx:企业高性能web服务器(一)
运维·服务器·nginx
Linux运维技术栈3 小时前
云平台服务器遭遇黑客攻击?用 Nginx 批量封锁敏感接口,自动返回 444 关闭连接
运维·服务器·nginx·安全·防御
life码农16 小时前
Linux截取Nginx指定时间段日志的三种方法(grep/awk/sed)
linux·nginx
小飞侠在吗21 小时前
Windows 下 Nginx 访问 127.0.0.1 报 50x 错误:根因是路径里 \t 被当成 Tab
运维·windows·nginx
宠友信息1 天前
IM系统开发技术路线分析,即时通讯源码助力快速搭建聊天应用
java·spring boot·redis·websocket·mysql·uni-app·vue
liuyicenysabel1 天前
Flask 个人站 iProfile 上线笔记(k3s + Nginx + Let‘s Encrypt)
笔记·nginx·flask
oooo_z1 天前
WebSocket实时行情推送API实战:用iTick搭一个盯盘小工具
网络·websocket·网络协议
Jimmy_jimi2 天前
利用nginx代理完成url重定位
运维·nginx
【赫兹威客】浩哥2 天前
基于SpringBoot+Vue3的健身运动管理系统|WebSocket实时消息 健身房毕设项目
spring boot·websocket·课程设计