Nginx 配置 HTTPS 与 WebSocket 实战指南:以 Let’s Encrypt 自动续期为例

摘要:在生产环境中,为多个子域名配置 HTTPS 并支持 WebSocket 长连接是常见需求。本文将基于真实案例,详细讲解如何在阿里云服务器上,使用 Certbot (Let’s Encrypt) 免费证书,为新增子域名 copaw.thoughtly.xyz 配置 Nginx 反向代理。文章将涵盖从域名解析、证书申请、Nginx 配置文件编写到 WebSocket 优化的全流程,特别解决了“先申请证书后写配置”的常见场景,并提供可直接复用的配置模板。


一、背景与需求

在之前的架构中,我们已经成功运行了 claw.thoughtly.xyz,它通过 Nginx 反向代理本地 18789 端口,并完美支持 WebSocket 长连接。现在,我们需要部署一个新的服务 copaw,其需求如下:

  1. 新域名copaw.thoughtly.xyz
  2. 后端端口:本地服务运行在 127.0.0.1:8088
  3. 协议要求:必须启用 HTTPS,且证书需自动续期(免费)。
  4. 功能依赖:应用强依赖 WebSocket,需确保长连接稳定,不被 Nginx 过早切断。
  5. 现有环境:服务器已安装 Nginx 和 Certbot,且其他子域名已有成功配置经验。

二、核心操作流程

步骤 1:阿里云域名解析 (DNS)

在配置服务器之前,必须确保域名已指向服务器公网 IP。

  1. 登录 阿里云控制台 -> 云解析 DNS
  2. 找到主域名 thoughtly.xyz,点击 解析设置
  3. 添加一条 A 记录
    • 主机记录copaw
    • 记录值<您的服务器公网 IP>
    • TTL:默认(通常 600 秒)
  4. 保存后,可在本地终端使用 ping copaw.thoughtly.xyz 验证解析是否生效。

步骤 2:使用 Certbot 申请证书(关键技巧)

很多教程建议“先写配置再运行 Certbot”,但在实际操作中,先运行 Certbot 申请证书,再手动写入配置往往更灵活,尤其是当你需要自定义复杂的 WebSocket 配置时。

2.1 执行申请命令

在服务器终端直接运行:

1
sudo certbot --nginx -d copaw.thoughtly.xyz

预期现象与解释
此时你可能会看到类似以下的提示:

Could not automatically find a matching server block for copaw.thoughtly.xyz.
The certificate was saved, but could not be installed.

不要惊慌!这是正常的。

  • 原因:Certbot 的 --nginx 插件试图自动修改 Nginx 配置,但它发现你的配置文件中还没有 server_name copaw.thoughtly.xyz; 这一行,所以它无法自动注入证书路径。
  • 结果:虽然自动安装失败,但证书已经成功申请并保存到了 /etc/letsencrypt/live/copaw.thoughtly.xyz/ 目录下。
  • 优势:Certbot 已经自动配置好了后台的定时任务(Systemd Timer 或 Cron),证书将在 90 天后自动续期,无需人工干预。

2.2 确认证书文件

检查证书是否生成成功:

1
ls -l /etc/letsencrypt/live/copaw.thoughtly.xyz/

你应该能看到 fullchain.pem (公钥) 和 privkey.pem (私钥) 两个文件。

步骤 3:编写 Nginx 配置文件

既然证书已就位,现在我们需要手动创建 Nginx 配置,引用这些证书,并配置反向代理规则。

3.1 创建配置文件

根据系统不同,选择以下任一方式:

  • Debian/Ubuntu: sudo nano /etc/nginx/sites-available/copaw.thoughtly.xyz
  • CentOS/通用: sudo nano /etc/nginx/conf.d/copaw.thoughtly.xyz.conf

3.2 填入完整配置代码

以下是经过优化的最终配置,包含了 HTTPS 强制跳转WebSocket 支持长连接超时优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
server {
server_name copaw.thoughtly.xyz;

listen 443 ssl;

# 【核心】引用 Certbot 生成的证书路径
ssl_certificate /etc/letsencrypt/live/copaw.thoughtly.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/copaw.thoughtly.xyz/privkey.pem;

# 引入 Certbot 推荐的 SSL 安全参数
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

location / {
# 转发到本地 8088 端口
proxy_pass http://127.0.0.1:8088;

# --- 必要的 Header 设置 ---
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 关键配置 (必选) ---
# 1. 必须使用 HTTP/1.1
proxy_http_version 1.1;
# 2. 传递 Upgrade 和 Connection 头,实现协议升级
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# --- 长连接超时优化 ---
# 默认 Nginx 超时为 60s,会导致 WS 连接频繁断开
# 设置为 24 小时 (86400 秒),适应长连接场景
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
}

# --- HTTP 强制跳转 HTTPS ---
server {
if ($host = copaw.thoughtly.xyz) {
return 301 https://$host$request_uri;
}

listen 80;
server_name copaw.thoughtly.xyz;

# 兜底策略:如果未匹配到跳转,返回 404
return 404;
}

3.3 启用配置 (仅限 Debian/Ubuntu)

如果你使用的是 sites-available 模式,需要建立软链接:

1
sudo ln -s /etc/nginx/sites-available/copaw.thoughtly.xyz /etc/nginx/sites-enabled/

步骤 4:测试与重载

在重启服务前,务必检查语法,防止配置错误导致 Nginx 无法启动。

1
2
3
4
5
6
7
8
9
# 1. 语法测试
sudo nginx -t

# 输出应显示:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 2. 平滑重载配置
sudo systemctl reload nginx

三、关键技术点解析

1. 为什么 WebSocket 需要特殊配置?

标准的 HTTP 请求是“短连接”,请求结束连接即断开。而 WebSocket 是“长连接”,需要保持 TCP 通道一直打开。

  • proxy_http_version 1.1:WebSocket 协议升级依赖于 HTTP/1.1,默认的 1.0 不支持。
  • UpgradeConnection:这是客户端告诉 Nginx“我要升级协议”的关键信号。如果 Nginx 不透传这两个头给后端,握手就会失败,报错 Error during WebSocket handshake: Unexpected response code: 400

2. 超时时间的重要性

Nginx 默认的 proxy_read_timeout60 秒。如果一个 WebSocket 连接在 60 秒内没有数据传输(例如用户挂机),Nginx 会主动切断连接。

  • 解决方案:将 proxy_read_timeoutproxy_send_timeout 设置为更大的值(如 86400 秒),确保长连接不会被误杀。

3. “先证书后配置”的优势

传统的 certbot --nginx 流程会让 Certbot 自动修改配置文件。但这有两个缺点:

  1. Certbot 生成的配置比较基础,可能不包含 WebSocket 所需的复杂 Header 和超时设置。
  2. 如果配置文件结构复杂,Certbot 可能会修改出错。
    本方案的优势:利用 Certbot 强大的证书申请和自动续期能力,同时保留手动编写配置的灵活性,确保生产环境的绝对可控。

四、验证与运维

1. 验证 HTTPS

浏览器访问 https://copaw.thoughtly.xyz,点击地址栏锁图标,确认:

  • 证书有效,颁发者为 Let’s Encrypt
  • 有效期约为 3 个月(Certbot 会自动续期)。

2. 验证 WebSocket

打开浏览器的开发者工具 (F12) -> Network (网络) -> WS
刷新页面,观察是否有 WebSocket 连接建立:

  • Status 应为 101 Switching Protocols
  • 连接应保持稳定,不会在 60 秒后自动断开。

3. 自动续期测试

虽然 Certbot 会自动运行,但我们可以手动测试续期逻辑是否正常:

1
sudo certbot renew --dry-run

如果输出 Congratulations, all renewals succeeded,说明自动续期机制工作正常,未来无需人工干预。


五、常见问题排查 (FAQ)

问题现象 可能原因 解决方案
502 Bad Gateway 后端服务未启动或端口错误 检查 127.0.0.1:8088 是否有进程监听 (netstat -tlnp | grep 8088)
WebSocket 握手失败 (400/426) 缺少 Upgrade 头配置 检查 proxy_set_header Upgrade $http_upgrade; 是否遗漏
连接每 60 秒断开一次 超时时间过短 检查 proxy_read_timeout 是否已调大
证书过期警告 自动续期失败 检查服务器 80 端口是否开放(验证需要),手动运行 sudo certbot renew
域名无法解析 DNS 未生效 等待几分钟,或检查阿里云解析记录是否正确

结语

通过上述步骤,我们成功为 copaw.thoughtly.xyz 部署了安全的 HTTPS 环境,并完美支持了 WebSocket 长连接。这种 “Certbot 管证书,人工管配置” 的模式,既享受了自动化续期的便利,又保证了复杂业务场景下的配置灵活性,是生产环境中推荐的最佳实践。

现在,你的 clawcopaw 双服务都已安全上线,可以安心开展业务了!