Go服务必须绑定127.0.0.1,否则Nginx反向代理失效;正确写法为http.ListenAndServe("127.0.0.1:8080", handler),Docker跨容器需改用服务名或host.docker.internal;proxy_pass末尾斜杠决定路径拼接逻辑,WebSocket需透传Upgrade和Connection头,真实IP依赖X-Forwarded-For等头透传。

Go服务必须绑定 127.0.0.1,否则 Nginx 反向代理形同虚设——这不是优化项,是生产环境的准入红线。
Go 服务监听地址必须显式写成 127.0.0.1:端口
默认用 r.Run(":8080") 或 http.ListenAndServe(":8080", r),等于让 Go 直接监听所有网卡(*:8080),绕过 Nginx 的 TLS 终止、限流、日志审计等能力。Nginx 健康检查也可能因路径/协议不一致而失败。
- 正确写法:
r.Run("127.0.0.1:8080")或http.ListenAndServe("127.0.0.1:8080", r) - Docker 场景下注意:
127.0.0.1在容器内只指向自己,Nginx 若在另一容器中,应改用服务名(如go-app:8080)或host.docker.internal - 验证方式:运行
ss -tln | grep :8080,输出里必须含127.0.0.1:8080,不能出现*:8080
proxy_pass 末尾斜杠决定路径拼接逻辑
Nginx 转发路径是否带前缀,完全取决于 proxy_pass URL 是否以 / 结尾。漏掉这个斜杠,前端路由或静态资源请求大概率 404。
- 若 Nginx 配置
location /api/ { proxy_pass http://127.0.0.1:8080; }(无尾部/),请求/api/v1/users会被转发为http://127.0.0.1:8080/api/v1/users—— 后端需自行处理/api前缀 - 推荐写法:
location /api/ { proxy_pass http://127.0.0.1:8080/; }(带尾部/),此时请求/api/v1/users被转发为http://127.0.0.1:8080/v1/users,后端无需感知/api - SPA 应用常用:
location / { proxy_pass http://127.0.0.1:8080/; },由 Go 处理所有路由
WebSocket 连接必须透传 Upgrade 和 Connection 头
Gin 默认不拦截 WebSocket 升级请求,但 Nginx 默认不转发 Upgrade 和 Connection 头,导致连接约 60 秒后静默断开。
立即学习“go语言免费学习笔记(深入)”;
- 必须在
location块中显式添加:proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade"; - 若使用
upstream,这些头需放在location内,不能只写在server级 - 配合 Gin 的
gin.WebSocket或第三方库(如gorilla/websocket)时,确保后端未主动关闭空闲连接
真实客户端 IP 获取依赖 X-Forwarded-For 和 X-Real-IP
Gin 的 c.ClientIP() 默认返回的是 Nginx 的连接 IP(即 127.0.0.1),不是用户真实 IP。必须靠 Nginx 设置头 + Gin 显式信任才能还原。
- Nginx 配置中加:
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; - Gin 中启用信任:
r.SetTrustedProxies([]string{"127.0.0.1"})(若 Nginx 与 Go 同机)或对应内网段 - 之后调用
c.ClientIP()才能拿到真实 IP;否则直接读c.GetHeader("X-Real-IP")也行,但需自行校验防伪造
最容易被忽略的是 Docker 环境下的网络地址映射和 upstream 健康检查的响应语义——Nginx 不会自动重试超时,必须显式配置 proxy_next_upstream 并列出所有要重试的状态码,否则一次 GC STW 就会让请求卡死。


















