华为云 Flexus L 公网 IP 配 HTTPS:Let's Encrypt 6 天短效证书 + nginx 自动续期踩坑记
最近在华为云 Flexus 应用服务器 L(2 核 2G)上跑了一个自己写的小应用,想让手机 App 通过 wss:// 连上来。问题是:我没给这台机器绑域名,浏览器和 App 对明文 ws 又不太友好。查了一圈发现,Let’s Encrypt 现在可以直接给公网 IP 签证书,只不过证书是"短效"的,只有 6 天左右。这篇记录我的配置和踩到的坑。
一、整体思路
- nginx 监听 80 和 443,80 端口只用来放 ACME 的 HTTP-01 验证文件,其余请求一律 404;
- 443 终止 TLS,把 /ws/mobile 这一个路径反代给后端;
- certbot 用 webroot 方式申请证书,选 shortlived 配置;
- systemd timer 每天跑两次 renew,续上之后 reload nginx。
安全组需要放行 80 和 443(华为云控制台里的安全组规则,默认没开,别忘了)。
二、nginx 配置(节选)
server {
listen 80;
server_name <你的公网IP>;
location ^~ /.well-known/acme-challenge/ {
root /var/lib/myapp/acme;
default_type text/plain;
}
location / { return 404; }
}
server {
listen 443 ssl;
server_name <你的公网IP>;
ssl_certificate /etc/letsencrypt/live/myapp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location = /ws/mobile {
proxy_pass http://127.0.0.1:3080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_buffering off;
}
location / { return 404; }
}
三、申请证书
我用 pip 在独立 venv 里装了 certbot(这台机器 PyPI 官方源很慢,换成了华为云的 PyPI 镜像),当前版本 5.8.0。关键参数是 webroot 验证、ECDSA 密钥和 shortlived 配置,对应 renewal 文件里能看到:
preferred_profile = shortlived
authenticator = webroot
key_type = ecdsa
IP 证书只能走 HTTP-01 / TLS-ALPN 这类验证,不能用 DNS 验证,所以 80 端口必须能从外网访问。
四、自动续期
证书有效期只有 6 天多一点,我这张是 11 月 3 日签发、11 月 9 日到期,手动续肯定不现实。写了一对 systemd 单元:
# renew.timer
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=20m
Persistent=true
# renew.service
[Service]
Type=oneshot
ExecStart=/opt/myapp/certbot/bin/certbot renew --quiet --deploy-hook "/bin/systemctl reload nginx"
Persistent=true 的作用是:如果服务器恰好关机错过了触发点,开机后补跑一次。短效证书对这个很重要。
五、踩坑
坑 1:deploy-hook 必须是一个整体参数。如果写成 --deploy-hook /bin/systemctl reload nginx,certbot 只会把 /bin/systemctl 当 hook,后面的 reload nginx 成了多余参数,续期命令会报错。要用双引号把整条命令包起来。我是用 systemd 的 drop-in 覆盖的:先写一行空的 ExecStart= 清掉原来的,再写新的,不改原文件,升级也不会被覆盖。
坑 2:后端只监听内网网卡。我的应用绑定的是 Flexus 的内网网卡地址,而 nginx 里习惯写 127.0.0.1,对不上。不想改应用的话,可以用 systemd 自带的 systemd-socket-proxyd 做本地转发:
# loopback.socket
[Socket]
ListenStream=127.0.0.1:3080
# loopback.service
[Service]
ExecStart=/usr/lib/systemd/systemd-socket-proxyd <内网网卡地址>:3080
不用额外装 socat,有连接才拉起,对 2G 内存的小机器很友好。
六、验证
systemctl list-timers 能看到下次触发时间;journalctl -u renew.service 看到 “Deactivated successfully” 就说明跑通了。我这边 11 月 4 日凌晨那次检查是正常结束的,nginx 和转发的 socket 都是 active。想自己确认证书日期可以用:
openssl x509 -in /etc/letsencrypt/live/myapp/fullchain.pem -noout -dates
七、小结
给裸 IP 配 HTTPS 比我想象的简单,难点不在签发,而在"6 天一续"带来的自动化细节:timer 要有 Persistent、hook 引号要对、80 端口要一直通。手头没有域名时,这是个挺实用的办法。nginx 只暴露必要路径、其余全部 404,也别把后端直接裸露在公网上。
- 点赞
- 收藏
- 关注作者
评论(0)