
译者按:最近看到一篇关于 Nginx 反向代理和 SSL 设置的教程,写得非常详细。作者从架构讲起,一步步演示如何配置、如何加 SSL、如何加固安全。特别适合那些想自己搭建服务但被反向代理搞晕的人。我试着整理了一下,分享给大家。
在开始之前,你需要:
如果你没有服务器,可以考虑 Hetzner、Contabo 或 DigitalOcean 这样的 VPS 提供商。域名可以在 Namecheap 注册。
我管理生产服务器多年,很早就明白了一个道理:反向代理是基础设施的最佳拍档。与保护客户端的正向代理不同,反向代理位于面向互联网的流量和内部应用程序之间。这种架构为你提供负载均衡、SSL 终止、安全加固,以及在单个域名下运行多个服务的能力。
这为什么重要:如果你运行多个后端服务——比如 Node.js API 运行在端口 3000,Python Flask 应用运行在端口 5000——反向代理让客户端可以通过 api.example.com 和 app.example.com 访问这两个服务,而无需暴露内部端口。配合 Let's Encrypt SSL,你就拥有了企业级的免费加密。
如果你正在构建自动化工作流,这尤其有用。比如你运行自托管的 n8n 实例或管理替代昂贵 SaaS 工具的自动化工作流,你需要端到端加密的流量。
首先,SSH 登录到你的服务器。假设你已经准备好 VPS(Ubuntu 20.04 或更高版本)。你的域名应该已经指向服务器的 IP 地址(如果没有,请在域名注册商处更新 DNS 记录)。
更新包管理器并安装 Nginx:
sudo apt update
sudo apt upgrade -y
sudo apt install -y nginx
启动 Nginx 并设置开机自启:
sudo systemctl start nginx
sudo systemctl enable nginx
检查 Nginx 是否正在运行:
sudo systemctl status nginx
你应该看到输出中显示 active (running)。现在安装 Certbot(Let's Encrypt 客户端)和 Nginx 插件:
sudo apt install -y certbot python3-certbot-nginx
验证安装:
certbot --version
很好。现在我们准备开始配置。
假设你有一个后端服务运行在 localhost:3000(可能是 Node.js 应用、Python 服务或任何 HTTP 服务)。你想通过 api.example.com 安全地暴露它。
打开 Nginx 配置目录:
sudo nano /etc/nginx/sites-available/default
用以下配置替换整个文件:
upstream backend_service {
server localhost:3000;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name api.example.com;
location / {
proxy_pass http://backend_service;
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;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
}
让我详细解释:
测试配置语法:
sudo nginx -t
如果看到 syntax is ok,重新加载 Nginx:
sudo systemctl reload nginx
如果你现在在浏览器中访问 http://api.example.com,它应该会代理到端口 3000 上的后端服务。不过连接是未加密的——下一步就来解决这个问题。
这就是见证奇迹的时刻。Certbot 自动化了整个 SSL 设置过程,包括续订。运行 Certbot 并使用 Nginx 插件:
sudo certbot --nginx -d api.example.com
Certbot 会问几个问题:
当被问到将 HTTP 流量重定向到 HTTPS 时,选择 "2":
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, unless you have a specific reason otherwise.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certbot 自动修改你的 Nginx 配置以启用 HTTPS 并重定向 HTTP 流量。你的配置现在应该是这样的:
sudo cat /etc/nginx/sites-available/default
你会看到类似这样的内容(Certbot 添加了 HTTPS server 块并修改了 HTTP 块):
upstream backend_service {
server localhost:3000;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://backend_service;
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;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
}
测试语法:
sudo nginx -t
重新加载 Nginx:
sudo systemctl reload nginx
现在访问 https://api.example.com。你的连接已使用有效 SSL 证书加密——而且完全免费。你的证书有效期为 90 天。Certbot 通过系统定时器在到期前自动续订。
验证续订定时器是否处于活动状态:
sudo systemctl status certbot.timer
你应该看到输出中显示 active。
没有适当安全防护的反向代理就像没锁前门。让我们加固这个设置。
1. 添加安全响应头
编辑 Nginx 配置:
sudo nano /etc/nginx/sites-available/default
在 HTTPS server 块内(在 ssl_dhparam 之后)添加以下指令:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
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;
这些响应头可以防止点击劫持、MIME 类型嗅探,并强制全程使用 HTTPS。
2. 限制请求速率
如果你担心 DDoS 或暴力攻击,添加速率限制。将以下内容放在任何 server 块之外(文件顶部附近):
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
然后在 HTTPS server 块内添加:
limit_req zone=general burst=20 nodelay;
3. 限制文件访问
在 HTTPS server 块内添加以下内容以阻止敏感文件:
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ ~$ {
deny all;
access_log off;
log_not_found off;
}
4. 启用 Gzip 压缩
在任何 server 块之外添加:
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
gzip_disable "MSIE [1-6]\.";
测试并重新加载:
sudo nginx -t
sudo systemctl reload nginx
如果你运行多个服务(比如一个 API 和一个 Web 仪表板),创建单独的 upstream 块和 location 指令。比如:
sudo nano /etc/nginx/sites-available/default
upstream api_backend {
server localhost:3000;
keepalive 32;
}
upstream app_backend {
server localhost:5000;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name api.example.com app.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live
...
}
最初发表于 Automation Insider。