site logo

Marico's space

如何设置 Nginx 反向代理与 SSL(Let's Encrypt)

服务器技术 2026-04-25 22:58:25 5
## 你需要准备什么 你需要准备以下内容: - n8n Cloud 或自托管 n8n(可选,用于 API 监控) - 服务器:Hetzner VPS 或 Contabo VPS - 域名注册:Namecheap - 备选托管方案:DigitalOcean - SSH 访问 Linux 服务器(推荐 Ubuntu 20.04 或更高版本) - 指向服务器 IP 地址的域名 - 基本的命令行知识 --- ## 目录 1. [Understanding Nginx Reverse Proxy Architecture](#understanding-nginx-reverse-proxy-architecture) 2. [Installing Nginx and Certbot](#installing-nginx-and-certbot) 3. [Configuring Your First Reverse Proxy](#configuring-your-first-reverse-proxy) 4. [Setting Up SSL with Let's Encrypt](#setting-up-ssl-with-lets-encrypt) 5. [Securing Your Configuration](#securing-your-configuration) 6. [Getting Started](#getting-started) --- ## Understanding Nginx Reverse Proxy Architecture 我管理生产服务器多年,很早就明白了一个道理:反向代理是基础设施的最佳拍档。与保护客户端的正向代理不同,反向代理位于面向互联网的流量和内部应用程序之间。这种架构为你提供负载均衡、SSL 终止、安全加固,以及在单个域名下运行多个服务的能力。 这为什么重要:如果你运行多个后端服务——比如 Node.js API 运行在端口 3000,Python Flask 应用运行在端口 5000——反向代理让客户端可以通过 `api.example.com` 和 `app.example.com` 访问这两个服务,而无需暴露内部端口。配合 Let's Encrypt SSL,你就拥有了企业级的免费加密。 如果你正在构建自动化工作流,这尤其有用。例如,如果你运行自托管的 n8n Cloud 实例或管理替代昂贵 SaaS 工具的自动化工作流,你需要端到端加密的流量。 --- ## Installing Nginx and Certbot 首先,SSH 登录到你的服务器。假设你已经准备好 Hetzner VPS 或 Contabo VPS(Ubuntu 20.04 或更高版本)。你的域名应该已经指向服务器的 IP 地址(如果没有,请在 Namecheap 更新 DNS 记录)。 更新包管理器并安装 Nginx: ```shell sudo apt update sudo apt upgrade -y sudo apt install -y nginx ``` 启动 Nginx 并设置开机自启: ```shell sudo systemctl start nginx sudo systemctl enable nginx ``` 检查 Nginx 是否正在运行: ```shell sudo systemctl status nginx ``` 你应该看到输出中显示 `active (running)`。现在安装 Certbot(Let's Encrypt 客户端)和 Nginx 插件: ```shell sudo apt install -y certbot python3-certbot-nginx ``` 验证安装: ```shell certbot --version ``` 很好。现在我们准备开始配置。 --- ## Configuring Your First Reverse Proxy 假设你有一个后端服务运行在 `localhost:3000`(可能是 Node.js 应用、Python 服务或任何 HTTP 服务)。你想通过 `api.example.com` 安全地暴露它。 打开 Nginx 配置目录: ```shell sudo nano /etc/nginx/sites-available/default ``` 用以下配置替换整个文件: ```nginx 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; } } ``` 让我详细解释: - **upstream backend_service**:定义流量去向。指向你实际的后端端口。 - **listen 80**:监听 HTTP(Certbot 会将其升级为 HTTPS)。 - **server_name api.example.com**:你的域名。将其改为你实际的域名。 - **proxy_pass**:将请求路由到后端服务。 - **proxy_set_header 指令**:保留客户端信息(IP、协议、域名),让你的后端应用看到真实的客户端。 测试配置语法: ```shell sudo nginx -t ``` 如果看到 `syntax is ok`,重新加载 Nginx: ```shell sudo systemctl reload nginx ``` 如果你现在在浏览器中访问 `http://api.example.com`,它应该会代理到端口 3000 上的后端服务。不过连接是未加密的——下一步就来解决这个问题。 > 💡 **快速推进你的项目:** 不想自己配置?我可以构建自定义 n8n 流程和机器人。发消息给我,注明代码 SYS3-DEVTO。 --- ## Setting Up SSL with Let's Encrypt 这就是见证奇迹的时刻。Certbot 自动化了整个 SSL 设置过程,包括续订。运行 Certbot 并使用 Nginx 插件: ```shell sudo certbot --nginx -d api.example.com ``` Certbot 会问几个问题: 1. 输入你的电子邮件地址(用于续订提醒)。 2. 接受 Let's Encrypt 服务条款。 3. 可选:与 EFF 分享你的电子邮件(他们的选择)。 当被问到将 HTTP 流量重定向到 HTTPS 时,选择 **"2"**: ```plaintext 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 流量。你的配置现在应该是这样的: ```shell sudo cat /etc/nginx/sites-available/default ``` 你会看到类似这样的内容(Certbot 添加了 HTTPS server 块并修改了 HTTP 块): ```nginx 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; } } ``` 测试语法: ```shell sudo nginx -t ``` 重新加载 Nginx: ```shell sudo systemctl reload nginx ``` 现在访问 `https://api.example.com`。你的连接已使用有效 SSL 证书加密——而且完全免费。你的证书有效期为 90 天。Certbot 通过系统定时器在到期前自动续订。 验证续订定时器是否处于活动状态: ```shell sudo systemctl status certbot.timer ``` 你应该看到输出中显示 `active`。 --- ## Securing Your Configuration 没有适当安全防护的反向代理就像没锁前门。让我们加固这个设置。 **1. 添加安全响应头** 编辑 Nginx 配置: ```shell sudo nano /etc/nginx/sites-available/default ``` 在 HTTPS server 块内(在 `ssl_dhparam` 之后)添加以下指令: ```nginx 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 块之外(文件顶部附近): ```nginx 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 块内添加: ```nginx limit_req zone=general burst=20 nodelay; ``` **3. 限制文件访问** 在 HTTPS server 块内添加以下内容以阻止敏感文件: ```nginx location ~ /\. { deny all; access_log off; log_not_found off; } location ~ ~$ { deny all; access_log off; log_not_found off; } ``` **4. 启用 Gzip 压缩** 在任何 server 块之外添加: ```nginx 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]\."; ``` 测试并重新加载: ```shell sudo nginx -t sudo systemctl reload nginx ``` --- ## Advanced: Multiple Backend Services 如果你运行多个服务(比如一个 API 和一个 Web 仪表板),创建单独的 upstream 块和 location 指令。例如: ```shell sudo nano /etc/nginx/sites-available/default ``` ```nginx 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。*