> Nginx反向代理配置详解:多站点共用一台服务器

什么是反向代理

反向代理就是Nginx接收用户请求后,转发给后端的应用服务器。用户只看到Nginx,不知道后面是谁在处理。

一台VPS上跑3个应用?没问题。Node.js用3000端口,Python用5000端口,Go用8080端口,Nginx在前面接80/443端口,根据域名分发请求。

1
2
3
4
用户请求 → Nginx (80/443)
                 ├── blog.example.com → Node.js (:3000)
                 ├── api.example.com  → Python  (:5000)
                 └── app.example.com  → Go      (:8080)

基本反向代理配置

最简配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;
    }
}
1
2
3
4
5
$ sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx

proxy_set_header解释

Header作用为什么需要
Host传递原始域名后端知道请求的是哪个域名
X-Real-IP传递真实客户端IP后端获取用户真实IP
X-Forwarded-ForIP转发链经过多级代理时保留所有IP
X-Forwarded-Proto原始协议后端知道用户用的是HTTP还是HTTPS

多站点配置实战

Node.js应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
server {
    listen 80;
    server_name blog.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;
    }
}

Python Flask/Django应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://127.0.0.1:5000;
        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;

        # 超时设置(API可能耗时较长)
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 静态文件直接由Nginx处理
    location /static/ {
        alias /var/www/api/static/;
        expires 30d;
    }
}

静态站点 + API代理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
server {
    listen 80;
    server_name www.example.com;

    # 前端静态文件
    root /var/www/frontend/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # API请求转发到后端
    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;
    }
}

WebSocket代理

如果应用使用WebSocket(聊天、实时推送等),需要额外配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
server {
    listen 80;
    server_name ws.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;

        # WebSocket超时(默认60秒会断开)
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

负载均衡

当一个应用跑多个实例时,用Nginx做负载均衡:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 定义上游服务器组
upstream myapp {
    # 默认轮询策略
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003;
}

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

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

负载均衡策略

策略配置说明
轮询默认依次分配请求
权重server ... weight=3按权重比例分配
IP Haship_hash;同一IP固定到同一后端
最少连接least_conn;分配给连接数最少的
1
2
3
4
5
6
upstream myapp {
    least_conn;  # 最少连接策略
    server 127.0.0.1:3001 weight=3;  # 权重3
    server 127.0.0.1:3002 weight=1;  # 权重1
    server 127.0.0.1:3003 backup;     # 备用,其他都挂了才用
}

代理缓存

对于不经常变化的内容,Nginx可以缓存后端响应:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 在http块中定义缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;

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

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_cache my_cache;
        proxy_cache_valid 200 10m;    # 200响应缓存10分钟
        proxy_cache_valid 404 1m;     # 404缓存1分钟
        add_header X-Cache-Status $upstream_cache_status;
    }
}
1
2
3
4
# 测试缓存是否生效
$ curl -I http://app.example.com
HTTP/1.1 200 OK
X-Cache-Status: HIT   # HIT表示命中缓存,MISS表示没命中

常见问题

502 Bad Gateway

1
2
3
4
5
6
7
# 后端服务没启动或崩了
$ curl http://127.0.0.1:3000
curl: (7) Failed to connect to 127.0.0.1 port 3000

# 检查后端服务状态
$ systemctl status myapp
$ docker ps  # 如果是Docker部署的话

真实IP获取不到

后端应用要从Header里读取真实IP:

1
2
3
4
5
# Python Flask
real_ip = request.headers.get('X-Real-IP', request.remote_addr)

# Node.js Express
const realIP = req.headers['x-real-ip'] || req.connection.remoteAddress;

上传文件大小限制

1
2
3
4
5
# Nginx默认限制1MB,修改为50MB
server {
    client_max_body_size 50m;
    # ...
}

测试配置

1
2
3
4
5
6
7
8
9
# 永远先测试再重载
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

$ sudo systemctl reload nginx

# 检查反向代理是否生效
$ curl -H "Host: app.example.com" http://127.0.0.1

总结

反向代理是Nginx最强大的功能之一。掌握了它,一台服务器就能跑无数个应用和网站。核心就是记住proxy_pass加上几个proxy_set_header

配置完反向代理后,别忘了配SSL证书,参考免费SSL证书申请与配置。Nginx的基础安装和配置可以回顾Nginx安装与配置入门

Nginx 反向代理 负载均衡
cd ..