折腾
给站点上 HTTPS:一次 acme.sh 就够
站点用 HTTP 跑了几天,浏览器地址栏那个「不安全」的小标记实在碍眼。正好大陆服务器上的域名已经备案,可以名正言顺地申请证书了。
这次选的是 acme.sh + Let's Encrypt:免费、90 天有效期、能自动续期,比手动申请省心得多。
第一步:确保 80 端口能用
HTTP-01 验证要求 Let's Encrypt 能访问到 http://你的域名/.well-known/acme-challenge/xxx。所以:
- 云服务器的防火墙(安全组 / 轻量应用服务器的「防火墙」面板)要放行 TCP 80;
- Nginx 已经在监听 80,并且站点根目录可读;
- 域名解析已经指向这台机器。
三条缺一条,验证就会卡在 Pending 或者直接 Timeout。
第二步:安装 acme.sh 并签发
curl https://get.acme.sh | sh -s email=你的邮箱
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
~/.acme.sh/acme.sh --issue \
-d example.com -d www.example.com \
-w /var/www/example.com/html
参数里 -w 是站点根目录,acme.sh 会自己在里面建 .well-known/acme-challenge/ 放验证文件,验证完再删掉。签发成功后会落到 ~/.acme.sh/example.com/ 下。
第三步:把证书装到 Nginx 并让它自动重载
~/.acme.sh/acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.pem \
--reloadcmd "systemctl reload nginx"
注意 --reloadcmd 一定要写。证书续期后 acme.sh 会执行这条命令,不写的话 Nginx 会一直用旧证书,直到某天早上发现过期了。
Nginx 这边加一段 HTTPS 的 server,再把 80 的请求全部跳过来:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/example.com/html;
index index.html;
}
第四步:验证
curl -I https://example.com返回 200;curl -I http://example.com返回 301 并指向 https;openssl s_client -connect example.com:443 -servername example.com能看到完整证书链;- 手机流量(不是同一个 Wi-Fi)也能正常打开。
踩过的几个坑
证书申请被拒,提示域名未备案。 大陆服务器上,没备案的域名 80 端口会被云厂商拦截,验证请求根本到不了服务器。备案是前提,不是可选项。
续期任务没跑起来。 acme.sh 安装时会自动加一条 cron,可以用 crontab -l | grep acme 确认。容器环境里没有 cron 的话,要自己用 systemd timer 补上。
www 和裸域名只签了一个。 两个都要在 -d 里写上,DNS 也要都能解析到这台机器,否则签出来的证书只对一个名字有效。
弄完这些,地址栏终于变成了小锁。虽然只是个静态博客,但看着还是挺舒服的。