目录
[一. 充当web服务器](#一. 充当web服务器)
[二. 反向代理](#二. 反向代理)
[1. proxy_pass](#1. proxy_pass)
[2. 为什么必须处理请求头](#2. 为什么必须处理请求头)
[3. 协议升级](#3. 协议升级)
[HTTPS 安全加固:SSL 卸载](#HTTPS 安全加固:SSL 卸载)
[WebSocket 升级:实时通信的关键](#WebSocket 升级:实时通信的关键)
[三. 负载均衡](#三. 负载均衡)
[1. 基础配置](#1. 基础配置)
[2. Nginx不同的分配策略:](#2. Nginx不同的分配策略:)
[3. ip_hash](#3. ip_hash)
聊起高性能 Web 服务器,Nginx 几乎是绕不开的骨干。最近我们帮学院部署开发项目学习到了Nginx的使用, 既然要实战部署,那咱们就以最经典的 Vue 3 + Golang (Gin) 架构为例。这种架构下,Nginx 不再单单只是一个工具,而是连接前后端的核心管家。
Nginx的主要作用有三个: 1. 充当web服务器 2. 反向代理 3. 负载均衡
一. 充当web服务器
动静分离
当用户访问你的网站时,请求的本质流程是这样的:
浏览器 → Nginx
├── 返回前端静态资源(HTML / JS / CSS)
└── 转发 API 请求 → Gin 后端
而浏览器从头到尾只知道 Nginx,不知道你的后端服务。当Vue项目build打包后,本质上就是一堆静态文件:
index.html
app.js
chunk-vendors.js
style.css
当浏览器请求这些资源时:
GET /index.html
GET /assets/app.js
Nginx 直接:
-
根据 URL 匹配 location
-
找到磁盘文件路径利用Sendfile机制从磁盘推送到网卡
-
把文件返回给浏览器
这些步骤完全不经过后端, 但是如果让 Gin 来做这件事,会多一层:
浏览器 → Nginx → Gin → 文件 → 返回
而现在直接:
浏览器 → Nginx → 文件 → 返回
即使是少一次网络跳转,性能差距在高并发下会被无限放大。
前端项目部署注意点:
Vue 使用 history 路由时:
假如访问 /user/profile → 404
原因:
浏览器请求 /user/profile
→ Nginx 当成文件路径
→ 文件不存在
→ 返回 404
解决方式:
location / {
try_files $uri /index.html;
}
这段配置意思就是把前端路由交给前端管理
二. 反向代理
1. proxy_pass
既然静态资源可以直接有Nginx管理, 那么动态请求怎么被管理呢?
也就是说请求是怎么被转发给后端的?
当浏览器发起 API 请求:
GET /api/user/info
Nginx 不再返回文件,而是把请求转发给后端服务:
比如:
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
这样就是变成:
浏览器 → Nginx → Gin(8080) → 返回数据 → Nginx → 浏览器
当然很多人第一次部署就踩这里, 比如我:
location /api/ {
proxy_pass http://127.0.0.1:8080/;
}
请求:
/api/user
实际转发:
/user
但如果写成:
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
请求:
/api/user
转发变成:
/api/user
选择哪种配置方式,完全取决于后端服务期望接收的路径格式
-
使用不带 / 的配置 :如果后端接口本身就设计为包含/api前缀,
(例如http://127.0.0.1:8080/api/...),那么我们应该使用这种配置,将完整的路径透传给后端
-
使用带 / 的配置 :如果后端服务直接监听在根路径,
(例如http://127.0.0.1:8080/user/...),而我希望通过 Nginx 对外暴露 /api 前缀来区分或组织接口,那么应该使用这种配置来剥离前缀
Nginx这种反向代理也是同时解决了http的跨域问题
2. 为什么必须处理请求头
默认情况下,后端拿到的信息是有误的:
客户端 IP:127.0.0.1(本机状态下)
Host: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;
正确状态:
IP = 用户真实IP(比如 8.x.x.x)
Host = www.yoursite.com
这样后端就能看到用户真实的代理请求
一个基础的静态服务配置:
XML
server {
listen 80;
server_name yourdomain.com;
# 1. 前端静态资源
location / {
root /var/www/dist; # Vue build后的目录
index index.html;
try_files $uri $uri/ /index.html; # 解决 Vue Router 的 history 模式 404 问题
}
# 2. 后端 API 代理
location /api/ {
proxy_pass http://127.0.0.1:8080;
# 代理头设置
# 1. 传递域名
proxy_set_header Host $host;
# 2. 传递真实 IP (单跳)
proxy_set_header X-Real-IP $remote_addr;
# 3. 传递代理链 IP (多跳)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 4. 传递原始协议 (http/https)
proxy_set_header X-Forwarded-Proto $scheme;
}
}
3. 协议升级
HTTPS 安全加固:SSL 卸载
在 2026 年,没有 HTTPS 的网站基本没法看了。通过 Nginx 处理 SSL,你的 Golang 代码只需要关注 HTTP 逻辑,不需要处理证书加载。
值得注意的细节:
-
强制跳转:把所有的 80 端口(HTTP)请求重定向到 443(HTTPS)。
-
HSTS:告诉浏览器,以后直接用 HTTPS 访问我。
XML
# 1. HTTP Server 块:负责重定向到 HTTPS
server {
listen 80;
server_name yourdomain.com;
# 强制跳转
return 301 https://$server_name$request_uri;
}
# 2. HTTPS Server 块:负责处理业务逻辑(Vue + Gin)
server {
listen 443 ssl;
server_name yourdomain.com;
# SSL 证书路径
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# 推荐的安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# --- 1. 前端静态资源 ---
location / {
root /var/www/dist; # Vue build后的目录
index index.html;
# 解决 Vue Router 的 history 模式 404 问题
try_files $uri $uri/ /index.html;
}
# --- 2. 后端 API 代理 ---
location /api/ {
proxy_pass http://127.0.0.1:8080;
# 代理头设置
# 1. 传递域名
proxy_set_header Host $host;
# 2. 传递真实 IP (单跳)
proxy_set_header X-Real-IP $remote_addr;
# 3. 传递代理链 IP (多跳)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 4. 传递原始协议 (http/https)
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 升级配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 其他可选配置:开启 Gzip 提高 Vue 静态资源加载速度
gzip on;
gzip_types text/plain text/css application/javascript application/json;
}
WebSocket 升级:实时通信的关键
如果你的项目里有即时通讯(比如聊天、监控大屏),Golang 通常会起一个 WebSocket 服务。Nginx 默认不支持长连接转发,必须显式修改 Header。
XML
# 1. HTTP Server 块:负责重定向到 HTTPS
server {
listen 80;
server_name yourdomain.com;
# 强制跳转
return 301 https://$server_name$request_uri;
}
# 2. HTTPS Server 块:负责处理业务逻辑(Vue + Gin)
server {
listen 443 ssl;
server_name yourdomain.com;
# SSL 证书路径
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# 推荐的安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# --- 1. 前端静态资源 ---
location / {
root /var/www/dist; # Vue build后的目录
index index.html;
# 解决 Vue Router 的 history 模式 404 问题
try_files $uri $uri/ /index.html;
}
# --- 2. 后端 API 代理 (包含基础 WebSocket 支持) ---
location /api {
proxy_pass http://127.0.0.1:8080;
# 代理头设置
# 1. 传递域名
proxy_set_header Host $host;
# 2. 传递真实 IP (单跳)
proxy_set_header X-Real-IP $remote_addr;
# 3. 传递代理链 IP (多跳)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 4. 传递原始协议 (http/https)
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 升级配置 (让普通的 /api 也能支持升级握手)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# --- 3. 专门的 WebSocket 路径优化 ---
# 如果你的 WS 地址是 /api/ws,则该块会优先匹配,并增加超时保护
location /api/ws/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 传递真实 IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 调大超时时间,防止 WebSocket 莫名其妙断开
# 默认 60s 没数据就会断开,这里改为 1 小时
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# 其他可选配置:开启 Gzip 提高 Vue 静态资源加载速度
gzip on;
gzip_types text/plain text/css application/javascript application/json;
}
三. 负载均衡
1. 基础配置
负载均衡的核心逻辑是:Nginx 站在最前面,收到请求后,根据预设的"策略",把请求转发给后端最合适的服务器。
当后端服务(或者服务器)不止一个时:
8080
8081
8082
Nginx 可以这样配置(分配权重):
XML
# 定义后端集群
upstream backend {
# 策略 1:轮询 (默认) - 每个请求按时间顺序逐一分配
# 策略 2:权重 (weight) - 性能好的机器多扛点
server 127.0.0.1:8080 weight=3;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 backup; # 备用机,平时休息,其他都挂了它再上
}
server {
listen 443 ssl;
server_name yourdomain.com;
# ... 其他 SSL 和静态资源配置保持不变 ...
location /api {
proxy_pass http://backend;
# 代理头设置
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;
# WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
然后:
location /api/ {
proxy_pass http://backend;
}
效果:
请求1 → 8080
请求2 → 8081
从而避免服务器单点崩溃, 分摊并发压力
2. Nginx不同的分配策略:
A. 轮询 (Round Robin) ------ 最公平
-
做法:每个请求按顺序轮流发给后端
-
场景:后端服务器硬件配置完全一样,且业务没啥特殊要求
B. 权重 (Weight) ------ 能者多劳
-
做法:在server后面加weight=x
-
场景:比如 8080 是你的主力服务器(16核),8081 是你的旧笔记本(2核),那就给 8080 分更高的权重
C. IP Hash ------ 解决认人问题
-
做法:在upstream块里写上ip_hash
-
场景:如果后端涉及到 Session(比如用户登录状态存存在服务器内存里,而不是 Redis 中),必须开启这个。它能保证同一个用户的请求始终发往同一台服务器,防止用户刷一下页面就掉线了
3. ip_hash
使用ip_hash就无法与backup连用: 正如代码注释里提到的,一旦开启了ip_hash,你就不能在这一组服务器里设置backup (备用机)了。因为ip_hash算法要求所有的服务器都在线参与计算。如果你非要搞一台备用机,可能得考虑其他的负载均衡方式或者使用更高级的第三方模块。
例如:
XML
# 定义后端集群
upstream backend {
# 关键指令:开启 IP Hash 策略
ip_hash;
server 127.0.0.1:8080 weight=3;
server 127.0.0.1:8081 weight=1;
# 注意:在使用 ip_hash 时,不能直接使用 backup 标志,
# 因为 ip_hash 的算法需要确定的服务器列表。
}
server {
listen 443 ssl;
server_name yourdomain.com;
# ... 其他 SSL 和静态资源配置保持不变 ...
location /api {
proxy_pass http://backend;
# 代理头设置
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;
# WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
为什么负载均衡很重要?
-
高可用性: 如果你只跑一个 Gin 实例,它万一崩了,全校同学就都打不开网页了。有了负载均衡,Nginx 会自动检测后端健康状况,如果 8080 挂了,它会立刻把流量转给 8081
-
无缝升级: 当需要更新后端代码时,可以先停掉 8080 升级,此时 8081 顶上;等 8080 升好了,再换 8081。整个过程用户完全感知不到
-
横向扩展: 明天校赛突然有几万人访问,我们只需要多开几个 Gin 端口,在 Nginx 配置里加一行server,并发能力能提高很多
总结: Nginx 是一个异步框架的Web 服务器,也可以用作反向代理 ,负载均衡和HTTPS缓存等核心功能。
下面是一个完整参考的nginx.conf配置文件:
XML
# 运行 nginx 的用户(通常不用改)
user nginx;
# 根据你的 CPU 核心数调整,一般设为 auto
worker_processes auto;
# 错误日志路径和级别
error_log /var/log/nginx/error.log warn;
# 进程 ID 文件
pid /var/run/nginx.pid;
# 事件模块配置
events {
worker_connections 1024; # 单个进程最大连接数
use epoll; # Linux 下高性能网络 IO 模型
multi_accept on; # 尽可能多地接受新连接
}
# HTTP 核心模块
http {
# 基础配置
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on; # 高效传输文件
tcp_nopush on; # 合并数据包
tcp_nodelay on; # 禁用 Nagle 算法
keepalive_timeout 65; # 保持连接超时时间
client_max_body_size 50M; # 允许上传的最大文件大小
# Gzip 压缩(提升前端加载速度)
gzip on;
gzip_vary on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/x-javascript image/svg+xml;
gzip_disable "MSIE [1-6]\.";
# ---------- 以下是你需要修改的核心 Server 块 ----------
# 1. HTTP 服务(监听 80 端口,负责跳转到 HTTPS)
server {
listen 80;
listen [::]:80; # 支持 IPv6
server_name your-domain.com www.your-domain.com; # 【改成你的域名】
# 将所有 HTTP 请求永久重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
# 2. HTTPS 服务(监听 443 端口,真正的业务入口)
server {
listen 443 ssl http2; # 启用 HTTP/2 提升性能
listen [::]:443 ssl http2;
server_name your-domain.com www.your-domain.com; # 【改成你的域名】
# ---------- SSL 证书配置(请修改为你的实际路径)----------
ssl_certificate /etc/nginx/ssl/your-domain.com.pem; # 证书文件
ssl_certificate_key /etc/nginx/ssl/your-domain.com.key; # 私钥文件
# SSL 安全增强配置(推荐)
ssl_protocols TLSv1.2 TLSv1.3; # 只启用安全的 TLS 版本
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# ---------- 前端静态文件代理(以 Vue 打包后的 dist 为例)----------
root /var/www/dist;
index index.html;
# 处理前端路由(History 模式)
location / {
try_files $uri $uri/ /index.html;
}
# 缓存静态资源(CSS/JS/图片等)
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# ---------- 后端 API & WebSocket 统一代理 ----------
# 整合了普通接口和 WebSocket 协议升级,统一指向 8080 端口
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;
# WebSocket 核心配置:允许协议升级
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时设置:同时兼顾普通 API 和 WebSocket 长连接
proxy_connect_timeout 60s;
# 调大发送和读取超时,防止 WebSocket 莫名其妙断开(设为 1 小时)
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
}
# 可选:健康检查路径(不记录日志)
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
}