Skip to content

Nginx 反向代理、重写与 WebSocket

nginx 反向代理可灵活地转发请求并修改 URL 路径,常用于隐藏后端服务真实路径、统一入口域名或适配不同服务的路径规则

基础反向代理(代理单个目标服务)

http://your-domain.com 的请求代理到本地或远程的目标服务(如 http://127.0.0.1:3000)

shell
server {
    listen 80;
    server_name your-domain.com;  # 你的域名

    # 反向代理配置
    location / {
        proxy_pass http://127.0.0.1:3000;  # 目标服务地址(必填)
        
        # 可选但推荐的代理参数(传递客户端信息给目标服务)
        proxy_set_header Host $host;                # 传递客户端请求的 Host 头
        proxy_set_header X-Real-IP $remote_addr;    # 传递客户端真实 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 传递代理链 IP
        proxy_set_header X-Forwarded-Proto $scheme; # 传递协议(http/https)
    }
}

代理到不同路径(按 URL 路径区分服务)

将不同路径的请求代理到不同服务(例如 /api 代理到后端 API,/ 代理到前端页面)。

shell
server {
    listen 80;
    server_name your-domain.com;

    # API 接口:代理到 3000 端口的后端服务
    location /api {
        proxy_pass http://127.0.0.1:3000;  # 注意:目标地址后是否加 / 会影响路径拼接
        # 若 proxy_pass 目标地址以 / 结尾,(如 http://127.0.0.1:3000/),则请求 /api/user 会被代理为 http://127.0.0.1:3000/user
        # 若 proxy_pass 目标地址不以 / 结尾,则代理为 http://127.0.0.1:3000/api/user。
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # 前端页面:代理到 8080 端口的前端服务
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

HTTPS 反向代理(带 SSL 证书)

https://your-domain.com 代理到目标服务,并配置 SSL 证书(需提前准备证书文件)

shell
server {
    listen 443 ssl;
    server_name your-domain.com;

    # SSL 证书配置
    ssl_certificate /path/to/your/cert.pem;    # 证书公钥
    ssl_certificate_key /path/to/your/key.pem; # 证书私钥

    # 可选:SSL 优化参数
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 反向代理配置
    location / {
        proxy_pass http://127.0.0.1:3000;  # 目标服务(可以是 http 或 https)
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;  # 传递 https 协议
    }
}

# 可选:将 http 强制跳转至 https
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$host$request_uri;
}

说明: 与「反向代理」重复的 upstream 轮询示例已移除;多后端调度、权重与健康检查等完整内容见本目录 《05、负载均衡详解》(对应原「负载均衡详解」一章)。

代理 WebSocket 服务

WebSocket 需要特殊配置以支持长连接(如代理聊天、实时通知服务)。

shell
server {
    listen 80;
    server_name your-domain.com;

    location /ws {
        proxy_pass http://127.0.0.1:8080;  # WebSocket 服务地址
        
        # WebSocket 必需参数
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 其他常规参数
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

路径重写

shell
# 语法
rewrite 正则表达式 目标路径 [flag];

# flag 值
last:完成重写后,不再匹配后续规则,重新查找 location
break:完成重写后,停止后续规则,使用当前 location
redirect:临时重定向(302)
permanent:永久重定向(301)

# 场景一:将 /api/ 前缀转发到后端的 /
# 比如:把 example.com/api/user 转发到 backend:8080/user
location /api/ {
    # 去掉路径中的 /api 前缀(注意正则后的 /)
    rewrite ^/api/(.*)$ /$1 break;
    proxy_pass http://backend:8080;
    # 其他 proxy 头配置...
}

# 场景二:将 / 前缀转发到后端的 /api/
# 比如:把 example.com/user 转发到 backend:8080/api/user
location / {
    # 将根路径重写为 /api/
    rewrite ^/$ /api/ last;
    proxy_pass http://backend:8080;
}

# 场景三:将多路径映射到不同后端服务
# 比如:将不同的路径前缀重写成 / ,然后匹配不同服务(场景一的灵活使用)
# /user 路径转发到用户服务
location /user/ {
    rewrite ^/user/(.*)$ /$1 break;
    proxy_pass http://user_service:8081;
}
# /order 路径转发到订单服务
location /order/ {
    rewrite ^/order/(.*)$ /v2/$1 break;  # 同时添加后端的 /v2 前缀
    proxy_pass http://order_service:8082;
}

# 场景四:带参数的路径重写
# 比如:将 /search?key=xxx 重写为 /query?keyword=xxx
location /search {
    rewrite ^/search$ /query?keyword=$arg_key last;
    proxy_pass http://search_service:8083;
}

注意

  1. server 块儿配置通常在 /etc/nginx/conf.d/ 目录下的 域名.conf 文件中定义,也就是分散定义在子配置文件中,便于区分管理
  2. 任何配置变更后,需执行nginx -t测试配置语法是否正确,无误后再用systemctl reload nginx重启服务。
  3. proxy_pass 末尾的 / 影响
shell
# 带 / (相当于把 /api/ 重写为 /)
location /api/ {
    proxy_pass http://backend:8080/;  # /api/user → http://backend:8080/user
}

# 不加 /(正常匹配,不重写)
location /api/ {
    proxy_pass http://backend:8080;  # /api/user → http://backend:8080/api/user
}