{T}

搭建反向代理服务

使用 Nginx 搭建一个功能完整、安全、高性能的反向代理服务器

反向代理概述

反向代理(Reverse Proxy)是代理服务器的一种,它接收客户端的请求,然后将请求转发给后端服务器,并将后端服务器的响应返回给客户端。客户端不知道实际的后端服务器

反向代理的优势

  • 负载均衡:将请求分发到多个后端服务器
  • SSL 终止:在 Nginx 层处理 HTTPS,减轻后端服务器压力
  • 缓存:缓存后端响应,提高性能
  • 安全:隐藏后端服务器信息,提供额外的安全层
  • 高可用:后端服务器故障时可以自动切换

基本反向代理配置

最简单的反向代理

nginx
server {
    listen 80;
    server_name proxy.example.com;

    location / {
        proxy_pass http://backend_server;
    }
}

完整的反向代理配置

nginx
server {
    listen 80;
    server_name proxy.example.com;

    # 访问日志
    access_log /var/log/nginx/proxy.access.log;
    error_log /var/log/nginx/proxy.error.log;

    location / {
        # 后端服务器地址
        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;

        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # 缓冲设置
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
        proxy_busy_buffers_size 8k;
    }
}

负载均衡配置

定义上游服务器组

nginx
# 在 http 块中定义
upstream backend_servers {
    # 轮询(默认)
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;

    # 或者使用权重
    # server 127.0.0.1:8080 weight=3;
    # server 127.0.0.1:8081 weight=2;
    # server 127.0.0.1:8082 weight=1;

    # 或者使用 IP 哈希
    # ip_hash;

    # 或者使用最少连接
    # least_conn;

    # 健康检查
    # server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    server_name proxy.example.com;

    location / {
        proxy_pass http://backend_servers;
        # 其他代理设置...
    }
}

负载均衡算法

  1. 轮询(Round Robin):默认方式,按顺序分配请求
  2. 权重(Weight):根据权重分配请求
  3. IP 哈希(IP Hash):根据客户端 IP 分配,保证同一客户端访问同一服务器
  4. 最少连接(Least Connections):分配给连接数最少的服务器

创建反向代理服务器配置

创建配置文件

创建配置文件 /etc/nginx/sites-available/reverse-proxy.conf

nginx
# 反向代理服务器配置
upstream backend_servers {
    # 负载均衡配置
    server 127.0.0.1:8080 weight=3 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 weight=2 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8082 weight=1 max_fails=3 fail_timeout=30s backup;

    # 保持连接
    keepalive 32;
}

server {
    listen 80;
    listen [::]:80;
    server_name proxy.example.com www.proxy.example.com;

    # 访问日志
    access_log /var/log/nginx/reverse-proxy.access.log main;
    error_log /var/log/nginx/reverse-proxy.error.log warn;

    # 客户端限制
    client_max_body_size 100M;
    client_body_buffer_size 128k;

    # 主位置块
    location / {
        # 代理到后端服务器
        proxy_pass http://backend_servers;

        # 请求头设置
        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;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # 缓冲设置
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
        proxy_busy_buffers_size 8k;
        proxy_temp_file_write_size 8k;

        # 重试设置
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_next_upstream_tries 3;
        proxy_next_upstream_timeout 10s;

        # 禁用代理缓冲(用于流式响应)
        # proxy_buffering off;

        # 保持连接
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }

    # 健康检查端点
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }

    # 代理 WebSocket 连接
    location /ws {
        proxy_pass http://backend_servers;
        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;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 超时设置
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    # 静态文件直接服务(不代理)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        root /var/www/static;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}

高级配置选项

1. 缓存配置

nginx
# 在 http 块中定义缓存路径
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=backend_cache:10m max_size=1g
                 inactive=60m use_temp_path=off;

server {
    location / {
        proxy_pass http://backend_servers;

        # 启用缓存
        proxy_cache backend_cache;
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_valid any 5m;

        # 缓存键
        proxy_cache_key "$scheme$request_method$host$request_uri";

        # 缓存控制
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
        proxy_cache_background_update on;
        proxy_cache_lock on;

        # 添加缓存状态头
        add_header X-Cache-Status $upstream_cache_status;
    }
}

2. SSL 终止配置

nginx
server {
    listen 443 ssl http2;
    server_name proxy.example.com;

    # SSL 证书配置
    ssl_certificate /etc/nginx/ssl/proxy.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/proxy.example.com.key;

    # SSL 优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        proxy_pass http://backend_servers;
        # 通知后端使用 HTTPS
        proxy_set_header X-Forwarded-Proto https;
    }
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name proxy.example.com;
    return 301 https://$server_name$request_uri;
}

3. 限流配置

nginx
# 在 http 块中定义限流区域
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

server {
    location / {
        # 请求限流
        limit_req zone=api_limit burst=20 nodelay;

        # 连接限流
        limit_conn conn_limit 10;

        proxy_pass http://backend_servers;
    }
}

4. 安全头配置

nginx
server {
    location / {
        proxy_pass http://backend_servers;

        # 安全头
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    }
}

实际部署步骤

1. 创建配置文件

bash
# 创建配置文件目录(如果不存在)
mkdir -p /etc/nginx/sites-available
mkdir -p /etc/nginx/sites-enabled

# 创建反向代理配置文件
cat > /etc/nginx/sites-available/reverse-proxy.conf << 'EOF'
# 反向代理配置内容(见上文完整配置)
EOF

2. 创建日志目录

bash
mkdir -p /var/log/nginx

3. 启用站点

bash
# 创建符号链接启用站点
ln -sf /etc/nginx/sites-available/reverse-proxy.conf \
       /etc/nginx/sites-enabled/reverse-proxy.conf

# 验证符号链接
ls -la /etc/nginx/sites-enabled/

4. 测试配置

bash
# 测试配置文件语法
/usr/local/nginx/sbin/nginx -t

# 如果测试通过,重新加载配置
systemctl reload nginx
# 或
/usr/local/nginx/sbin/nginx -s reload

5. 验证部署

bash
# 检查服务状态
systemctl status nginx

# 测试健康检查(使用正确的 Host 头)
curl -H "Host: proxy.example.com" http://localhost/health

# 测试代理(需要后端服务运行)
curl -H "Host: proxy.example.com" http://localhost/

# 检查配置是否加载
/usr/local/nginx/sbin/nginx -T | grep -A 10 "reverse-proxy.conf"

实际部署记录

服务器信息

  • IP: 14.103.203.158
  • 操作系统: CentOS Linux 7 (Core)
  • Nginx 版本: 1.28.0

执行步骤

  1. ✅ 创建反向代理配置文件 /etc/nginx/sites-available/reverse-proxy.conf
  2. ✅ 创建日志目录 /var/log/nginx
  3. ✅ 启用站点(创建符号链接)
  4. ✅ 测试配置文件语法
  5. ✅ 重新加载 Nginx 配置
  6. ✅ 验证服务状态和健康检查端点

配置要点

  • Upstream 配置:backend_servers 指向 127.0.0.1:8080
  • 负载均衡:使用权重配置(weight=3)
  • 健康检查:配置了 max_fails=3fail_timeout=30s
  • WebSocket 支持:配置了 /ws 路径的 WebSocket 代理
  • 静态文件:配置了静态文件直接服务,不经过代理

验证结果

  • ✅ 健康检查端点 /health 正常响应
  • ✅ 配置文件语法正确
  • ✅ 服务正常运行
  • ✅ 配置已成功加载

注意事项

  • 由于 server_name 配置为 proxy.example.com,访问时需要使用 Host 头或修改本地 hosts 文件
  • 后端服务需要运行在配置的端口(默认 8080)才能正常代理
  • 如果后端服务未运行,代理请求会返回 502 Bad Gateway

常见配置场景

场景 1:代理到单个后端服务

nginx
server {
    listen 80;
    server_name api.example.com;

    location / {
        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;
    }
}

场景 2:代理到多个后端服务(负载均衡)

nginx
upstream app_servers {
    server 192.168.1.10:8080 weight=3;
    server 192.168.1.11:8080 weight=2;
    server 192.168.1.12:8080 weight=1;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

场景 3:路径路由

nginx
server {
    listen 80;
    server_name example.com;

    # API 请求代理到后端 API 服务器
    location /api/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
    }

    # 静态文件直接服务
    location /static/ {
        root /var/www;
        expires 1y;
    }

    # 其他请求代理到 Web 服务器
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
    }
}

场景 4:WebSocket 代理

nginx
upstream websocket_backend {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name ws.example.com;

    location / {
        proxy_pass http://websocket_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 86400s;
    }
}

监控和维护

查看代理状态

bash
# 查看访问日志
tail -f /var/log/nginx/reverse-proxy.access.log

# 查看错误日志
tail -f /var/log/nginx/reverse-proxy.error.log

# 查看后端服务器状态
curl http://localhost/health

性能调优

nginx
# 在 http 块中优化
http {
    # 增加缓冲大小
    proxy_buffer_size 8k;
    proxy_buffers 16 8k;
    proxy_busy_buffers_size 16k;

    # 启用 keepalive
    upstream backend_servers {
        keepalive 32;
    }
}

测试后端服务

创建简单的测试后端服务

为了测试反向代理功能,可以创建一个简单的测试后端服务:

方法 1:使用 Python 创建简单 HTTP 服务器

bash
# 创建测试目录和文件
mkdir -p /tmp/backend_test
echo "<h1>Backend Server Response</h1><p>This is a test backend server running on port 8080</p>" > /tmp/backend_test/index.html

# 启动 Python HTTP 服务器(在后台运行)
cd /tmp/backend_test
nohup python3 -m http.server 8080 > /tmp/backend_server.log 2>&1 &

# 检查服务是否运行
curl http://127.0.0.1:8080

方法 2:使用 Nginx 作为测试后端

bash
# 创建一个简单的 Nginx 配置作为后端
cat > /etc/nginx/sites-available/backend-test.conf << 'EOF'
server {
    listen 8080;
    server_name localhost;
    root /tmp/backend_test;
    index index.html;
}
EOF

ln -sf /etc/nginx/sites-available/backend-test.conf /etc/nginx/sites-enabled/
systemctl reload nginx

测试反向代理

bash
# 1. 测试健康检查
curl -H "Host: proxy.example.com" http://localhost/health

# 2. 测试代理到后端(需要后端服务运行)
curl -H "Host: proxy.example.com" http://localhost/

# 3. 查看代理日志
tail -f /var/log/nginx/reverse-proxy.access.log

# 4. 测试 WebSocket 代理(如果有 WebSocket 服务)
curl -H "Host: proxy.example.com" -H "Upgrade: websocket" http://localhost/ws

故障排查

常见问题

  1. 502 Bad Gateway

    • 检查后端服务是否运行:curl http://127.0.0.1:8080
    • 检查后端服务地址和端口是否正确
    • 检查防火墙设置:firewall-cmd --list-ports
    • 查看错误日志:tail -50 /var/log/nginx/reverse-proxy.error.log
  2. 504 Gateway Timeout

    • 增加 proxy_read_timeout
    • 检查后端服务响应时间
    • 检查网络连接:ping backend_server_ip
  3. 连接被拒绝

    • 检查后端服务是否监听正确端口:netstat -tlnp | grep 8080
    • 检查 SELinux 设置(如果启用):getenforce
    • 检查后端服务日志
  4. 请求被错误的路由

    • 检查 server_name 配置是否正确
    • 使用正确的 Host 头访问:curl -H "Host: proxy.example.com" http://localhost/
    • 检查是否有其他 server 块匹配了请求

调试命令

bash
# 测试后端服务连接
curl -v http://127.0.0.1:8080

# 检查端口监听
netstat -tlnp | grep 8080
# 或
ss -tlnp | grep 8080

# 查看 Nginx 错误日志
tail -50 /var/log/nginx/reverse-proxy.error.log

# 查看访问日志
tail -50 /var/log/nginx/reverse-proxy.access.log

# 测试配置
/usr/local/nginx/sbin/nginx -t

# 查看完整配置
/usr/local/nginx/sbin/nginx -T | grep -A 20 "upstream backend_servers"

# 检查进程
ps aux | grep nginx

# 检查服务状态
systemctl status nginx

性能调优建议

nginx
# 1. 增加缓冲区大小(处理大响应)
proxy_buffer_size 8k;
proxy_buffers 16 8k;
proxy_busy_buffers_size 16k;

# 2. 启用 keepalive 连接
upstream backend_servers {
    keepalive 32;
    # ...
}

# 3. 调整超时时间(根据实际需求)
proxy_connect_timeout 30s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;

# 4. 启用缓存(对于静态内容)
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=backend_cache:10m;
proxy_cache backend_cache;