完整项目流程:宿主机Nginx + acme.sh(Cloudflare DNS) + Halo博客反向代理搭建全记录
目标:搭建 https://blog.myfamily2027.top ,子域名 stockapi.myfamily2027.top,后端Halo运行在8090端口,库管API预留8888端口,宿主机Nginx做HTTPS反向代理,acme.sh申请Let’s Encrypt证书
一、前期准备
- 域名:
myfamily2027.top,域名托管在Cloudflare,已申请Cloudflare DNS API令牌(仅DNS编辑权限) - 服务器:Racknerd VPS,宿主机安装Nginx(不是Docker Nginx)
- 后端服务:Halo博客部署在VPS本机,监听
127.0.0.1:8090;库管API预留127.0.0.1:8888 - 计划:使用acme.sh DNS验证方式申请SSL证书,Nginx反向代理,关闭裸端口8090对外暴露
二、证书申请阶段
执行acme.sh签发多域名证书命令,成功:
~/.acme.sh/acme.sh --issue --dns dns_cf -d blog.myfamily2027.top -d stockapi.myfamily2027.top
证书默认路径:~/.acme.sh/blog.myfamily2027.top/
证书安装(关键步骤)
- 创建证书存放目录
mkdir -p /etc/ssl/myfamily2027
- acme.sh执行install-cert,复制证书到固定目录,并配置证书续期后重载Nginx
~/.acme.sh/acme.sh --install-cert -d blog.myfamily2027.top \
--key-file /etc/ssl/myfamily2027/private.key \
--fullchain-file /etc/ssl/myfamily2027/fullchain.cer \
--reloadcmd "systemctl reload nginx"
作用:acme.sh自动检测证书到期,自动续证并执行reload加载新证书
三、Nginx站点配置文件创建
宿主机Nginx,配置文件存放路径:/etc/nginx/conf.d/blog.conf
宿主机Nginx两种方案:
方案1:/etc/nginx/sites-available/+ sites-enabled软链接
方案2(本次选用):直接放在/etc/nginx/conf.d/,nginx主配置自带include /etc/nginx/conf.d/*.conf;,自动加载所有conf
blog.conf完整配置:
server {
listen 80;
server_name blog.myfamily2027.top;
# http强制跳转https
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name blog.myfamily2027.top;
ssl_certificate /etc/ssl/myfamily2027/fullchain.cer;
ssl_certificate_key /etc/ssl/myfamily2027/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
location / {
proxy_pass http://127.0.0.1:8090; # Halo博客
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;
}
}
# stockapi子域名,库管API
server {
listen 80;
server_name stockapi.myfamily2027.top;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name stockapi.myfamily2027.top;
ssl_certificate /etc/ssl/myfamily2027/fullchain.cer;
ssl_certificate_key /etc/ssl/myfamily2027/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://127.0.0.1:8888; #库管API端口
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;
}
}
检查配置语法:
nginx -t
输出test is successful代表语法无错误。
四、遇到核心故障:浏览器访问 blog.myfamily2027.top 返回 ERR_CONNECTION_REFUSED
现象:
- ping域名可以正常解析到VPS公网IP;Cloudflare代理关闭(灰色云)
- Nginx只监听80端口,443端口没有监听
nginx -T查看配置,443 ssl的server块配置语法正常,nginx -t检测通过- 查看nginx error.log,只有notice日志,无error报错
故障根因
acme.sh生成的private.key私钥文件属主是root,Nginx运行用户
www-data没有读取私钥权限
重点坑:nginx -t仅校验语法,不会真实读取证书文件;systemctl reload nginx遇到证书读取失败时,不会直接崩溃,会静默丢弃443监听,仅保留80端口。
修复证书权限命令
chmod 755 /etc/ssl/myfamily2027
chmod 644 /etc/ssl/myfamily2027/fullchain.cer
chown www-data:www-data /etc/ssl/myfamily2027/private.key
chmod 600 /etc/ssl/myfamily2027/private.key
安全规范:私钥600权限,仅属主可读;证书链fullchain.cer允许全局可读
完整重启Nginx(不能只用reload)
systemctl stop nginx
systemctl start nginx
查看nginx启动日志确认无报错:
journalctl -u nginx --since "1 minute ago"
检查端口监听:
ss -tlnp | grep nginx
✅修复成功:输出同时包含0.0.0.0:80 和 0.0.0.0:443监听。
五、后续待验证步骤(当前Nginx侧全部就绪)
- Racknerd服务商后台防火墙放行TCP 443入站(独立于系统ufw,Racknerd默认拦截,是外部访问443拒绝连接最常见原因)
- VPS本机测试Halo后端连通性
curl -v http://127.0.0.1:8090
- 本地电脑测试VPS的443端口连通性:
telnet VPS公网IP 443 - 浏览器访问 https://blog.myfamily2027.top
- 成功进入网站:部署完成
- 出现502 Bad Gateway:Nginx HTTPS正常,无法连接后端Halo服务,排查Halo
- Cloudflare设置:SSL/TLS → 模式改为
Full,关闭Flexible - 证书自动续期:acme.sh自带crontab定时任务,每日自动检测证书到期,自动续证并重载Nginx
# 查看定时任务
crontab -l
# 手动测试续期
~/.acme.sh/acme.sh --cron
- 安全收尾:Racknerd安全组关闭8090端口对外暴露,外部访问全部走443反向代理
六、踩坑总结清单
- ❌坑:
nginx -t语法正常 ≠ 证书可以正常加载;reload遇到证书权限问题会静默丢弃443监听 - ❌坑:Racknerd防火墙分两层:系统ufw + 服务商后台防火墙,二者互相独立,80放行不代表443放行
- ❌坑:私钥权限root:root,www-data无法读取,不会直接在error.log抛错,隐蔽性极强
- ❌坑:
listen 443 ssl;必须带ssl关键字,漏写会导致443工作异常 - ✅好习惯:修改证书相关配置后,使用stop+start完整重启nginx,不要只用reload
需要我把这份文档导出为纯文本,方便你直接保存成txt下载吗?