1Panel OpenResty 为 Headscale 配置 Let's Encrypt 与 HTTPS 反代(命令行)
适用场景:服务器已用 1Panel 跑 OpenResty 占用 80/443,Headscale 监听本机
127.0.0.1:8080,需要为控制面域名签发证书并完成 HTTPS 反代。
背景
自建 Headscale 时,Tailscale 客户端必须能访问一个 HTTPS 控制面地址(server_url)。常见做法是:
- Headscale 容器内跑 明文 HTTP(例如
8080) - 由前置 反向代理 终止 TLS,对外提供
https://你的域名
本机 80/443 已被 1Panel 的 OpenResty 占用,无法在 Headscale 容器里再绑一份 Caddy/Nginx。因此采用:
客户端 ──HTTPS──▶ OpenResty (443) ──HTTP──▶ Headscale (127.0.0.1:8080)
架构要点
| 组件 | 说明 |
|---|---|
| Headscale | Docker 映射 127.0.0.1:8080,配置 server_url: https://hs.example.com |
| OpenResty | 1Panel 容器,站点配置挂载在宿主 /opt/1panel/www |
| 证书 | Let's Encrypt HTTP-01,证书需复制到 /opt/1panel/www/sites/域名/ssl/(容器内读 /www/...) |
| DERP | 443 做 HTTP 反代时,不要开嵌入 DERP;用公共 derp.urls 中继即可 |
日志里若出现 Listening without TLS but ServerURL does not start with http://,表示 TLS 在反代层终止,属于正常现象。
前置条件
- 域名 A/AAAA 已解析到本机公网 IP
- 公网能访问 80(Let's Encrypt 校验)
- 上游已就绪:
curl http://127.0.0.1:8080/health返回 200 - 存在名称匹配
1Panel-openresty*的 Docker 容器
一键脚本(推荐)
脚本已整理进个人 Skills 仓库:my-ide-skills / 1panel-openresty-letsencrypt-proxy
git clone https://github.com/zhaodongyang2016/my-ide-skills.git
cd my-ide-skills/1panel-openresty-letsencrypt-proxy
sudo chmod +x scripts/provision-https-reverse-proxy.sh
export DOMAIN="hs.example.com"
# 可选:反代目标,默认 http://127.0.0.1:8080
# export UPSTREAM="http://127.0.0.1:8080"
# 可选:Certbot 邮箱
# export EMAIL="you@example.com"
sudo -E bash scripts/provision-https-reverse-proxy.sh
脚本会自动完成:
- 写入 Nginx 站点与反代片段(含 WebSocket、长超时)
- 先以 仅 HTTP 配置 reload,便于 HTTP-01
certbot certonly --webroot申请证书- 证书复制到 1Panel 站点目录,启用 HTTPS 并 301 跳转
- 安装 续期 deploy hook(续签后同步证书并 reload OpenResty)
验证
# 证书与 TLS
curl -fsS "https://${DOMAIN}/health"
# 期望输出类似
# {"status":"pass"}
浏览器访问 https://你的域名/health 应无证书警告。
配置文件落盘位置
| 用途 | 宿主路径 |
|---|---|
站点 server 块 |
/opt/1panel/www/conf.d/${DOMAIN}.conf |
| 反代、日志、证书、ACME webroot | /opt/1panel/www/sites/${DOMAIN}/ |
| Let's Encrypt 源证书 | /etc/letsencrypt/live/${DOMAIN}/ |
| 续期钩子 | /etc/letsencrypt/renewal-hooks/deploy/01-copy-${DOMAIN}-to-1panel-www.sh |
手动 reload OpenResty:
CT=$(docker ps --filter "name=1Panel-openresty" --format '{{.Names}}' | head -1)
sudo docker exec "$CT" openresty -t && sudo docker exec "$CT" openresty -s reload
客户端接入(简要)
确认控制面可用后,在客户端指定自定义登录服务器:
export HS_URL="https://hs.example.com"
sudo tailscale up --login-server "$HS_URL" --accept-dns
或使用预授权密钥(在 Headscale 服务器生成):
sudo tailscale up --login-server "$HS_URL" --authkey <PREAUTH_KEY> --accept-dns
各平台图形界面入口一般为 Custom Login Server / Use alternate server,填入 https://你的域名。
故障排查
| 现象 | 可能原因与处理 |
|---|---|
| 证书申请失败 | 80 未指向本机;检查 /.well-known/acme-challenge/ 是否落到站点 index 目录 |
| HTTPS 仍是 localhost 证书 | 域名未匹配独立 server 块,走了 443 default_server;确认 server_name 与 reload |
/health 404 |
反代未指向上游;确认 proxy_pass http://127.0.0.1:8080 |
| 502 | 上游未启动;本机 curl http://127.0.0.1:8080/health |
与 1Panel 面板的关系
本方式直接写 /opt/1panel/www/conf.d,面板里未必显示为「已创建网站」。请避免对同一域名在面板再建一套冲突配置。若改由面板托管,迁移后删除 conf.d 里对应文件并 reload。
续期
系统 certbot.timer 负责自动续期;deploy hook 会把新证书同步到站点 ssl/ 并 reload。可手动模拟:
sudo certbot renew --dry-run
参考
评论区