云服务器端部署
来源:
intranet-tunnel/deploy/cloud/README.md(整篇)(原文 5604 字符)
内网穿透系统 —— 云服务器部署包
本目录是一套可直接部署到云服务器的完整配置,与本机测试版(仓库根的 docker-compose.yml)相比做了 4 处针对云环境的调整。
在已运行宝塔面板的服务器上部署? 先读
BAOTA-DEPLOY.md(源码路径./BAOTA-DEPLOY.md)。 那篇记录了 2026-09-12 的实测:80/443 被宝塔占用时的共存方案、*泛解析与_acme-challenge被占用时的域名规划、以及本项目自带的 DNS-01 证书链路为何在阿里云上不可用(附根因与绕行方案)。
一、包内文件
| 文件 | 说明 |
|---|---|
docker-compose.yml | 云版编排:4 个服务(tunnel-server / postgres / nginx / db-backup) |
.env | 完整生产配置,192 项(由代码自动提取,含已生成的强随机凭据) |
.env.example | 脱敏模板,所有敏感项为 change_me_* |
nginx/nginx-compose.conf | nginx 主配置(含 upstream 定义) |
nginx/conf.d/00-http.conf | 80 端口:ACME 挑战透传 + 301 跳转 HTTPS |
nginx/conf.d/10-panel.conf | 443:管理面板入口(需替换域名) |
nginx/conf.d/20-tunnel.conf | 443:隧道域名入口(需替换域名) |
云版与本地版的差异:
- postgres 不再映射端口到宿主机 —— 服务端容器通过 compose 网络用服务名
postgres访问即可,减少暴露面 - tunnel-server 放开
nofile到 65535 —— 隧道服务持有大量并发连接,默认 1024 在高并发下会too many open files - 各服务加
no-new-privileges—— 容器内进程无法再提权 - **资源上限走
.env的*_LIMIT变量** —— 按服务器规格调整
二、部署前必须做的三件事
1. 确认服务器架构
现有镜像 tar 是 amd64 的,如果服务器是 arm64 则无法使用。在服务器上执行:
uname -m- 输出
x86_64→ 可直接用现有镜像 tar - 输出
aarch64或arm64→ 需要重新导出 arm64 镜像(告诉我,我在本地用 buildx 交叉构建)
2. 配置云安全组
只需放行这些端口(其余一律不要开):
| 端口 | 用途 | 是否必需 |
|---|---|---|
80 | ACME HTTP-01 验证 + 跳转 HTTPS | 必需(证书自动签发依赖它) |
443 | HTTPS 入口(面板 + 隧道) | 必需 |
47800 | 控制连接,客户端接入 | 必需 |
48081-48100 | TCP 隧道端口池 | 需要 TCP 隧道时 |
49000-49100 | TCP/UDP 端口转发 | 需要端口转发时 |
48443 | 反向代理 HTTPS | 用内置反代直出 HTTPS 时 |
47801 | 管理 API | 不要开放(只给 nginx 用,已在 compose 里绑 127.0.0.1) |
5432 | PostgreSQL | 绝对不要开放 |
3. 修改 .env 与 nginx 配置
.env 里只有 2 处需要填(其余已自动生成,含强随机密钥):
EXTERNAL_IP=<服务器公网IP> # NAT/云环境必填,影响隧道入口地址拼接
CERT_EMAIL=<你的邮箱> # 证书申请的联系邮箱nginx 配置里需要替换域名(两个文件):
# nginx/conf.d/10-panel.conf 把 <PANEL_DOMAIN> 全部替换为面板域名
# nginx/conf.d/20-tunnel.conf 把 <TUNNEL_DOMAIN> 全部替换为隧道域名例如:
sed -i 's/<PANEL_DOMAIN>/panel.example.com/g' nginx/conf.d/10-panel.conf
sed -i 's/<TUNNEL_DOMAIN>/example.com/g' nginx/conf.d/20-tunnel.conf提示:隧道域名建议用泛域名(如
*.example.com),这样以后新增隧道都不用再动 nginx。 但泛域名证书只能用 DNS-01 验证(HTTP-01 签不了通配符)。
三、部署步骤
1. 上传
# 本地执行
scp -r deploy/cloud/* user@<服务器IP>:/home/docker/intranet-tunnel/
scp release/intranet-tunnel-server-images-<版本>.tar user@<服务器IP>:/home/docker/intranet-tunnel/2. 导入镜像(不需要联网)
cd /home/docker/intranet-tunnel
docker load -i intranet-tunnel-server-images-<版本>.tar
docker images | grep -E 'intranet-tunnel|postgres|nginx'
# 应看到:intranet-tunnel/server:1.0.0、postgres:16-alpine、nginx:alpine3. 建运行时目录
mkdir -p logs/nginx cores certs backups/db4. 启动
docker compose up -d
docker compose ps # 三个容器应为 healthy
curl -s localhost:47801/healthz
# 期望:{"status":"ok","database":"ok",...}5. 首次登录
浏览器打开 https://<面板域名>/
- 用户名:
admin - 口令:见第四节(已自动生成的强随机口令)
首次登录需要输入图形验证码(默认开启)。
四、已自动生成的凭据
这些是随机生成的,请立即保存到密码管理器。 部署后可在 .env 里查看:
| 项目 | 变量 |
|---|---|
| 管理后台口令 | ADMIN_PASSWORD |
| 数据库口令 | DB_PASSWORD / POSTGRES_PASSWORD |
| JWT 签名密钥 | JWT_SECRET(64 hex) |
| 客户端令牌盐 | TOKEN_SALT(48 hex) |
| 配置加密密钥 | CONFIG_ENCRYPT_KEY(恰好 32 字节) |
⚠️
CONFIG_ENCRYPT_KEY一旦开始使用就不能再改。 它加密着数据库里的敏感设置项(SMTP 口令、DNS 服务商凭据等)。 改了密钥,这些已保存的值将无法解密,需要重新填写。 请把它和数据库备份一起妥善保管。
五、证书申请
部署完成后,在面板里为域名申请证书:
- 进入「SSL 证书」→「申请证书」
- 填域名(面板域名 + 隧道域名各申请一张,或申请一张泛域名)
- 验证方式选 HTTP-01(需 80 端口可从公网访问,安全组已放行)
- 邮箱填
CERT_EMAIL的值
证书签发后落在宿主机 ./certs/<域名>/,含 cert.pem 与 key.pem,nginx 已挂载该目录。
申请完成后执行一次
docker compose restart nginx让 nginx 加载新证书。已知限制:证书自动续期后 nginx 不会自动重载,需要手动执行上面的 restart。 如需自动化,可以给 nginx 容器挂载 docker socket 并加 inotify 脚本 —— 但那会扩大容器的权限面,本项目默认不做。
六、安全加固建议
按你的选择「nginx 转 HTTPS + 安全入口」,建议再做这几步:
- 设置安全入口:面板「系统设置」→「安全入口」填一段自定义路径(如
/tunnel-console)。
之后只有该路径能打开后台首页,其它路径返回 404,可挡掉绝大多数扫描器。
- 限制面板来源(可选):在
nginx/conf.d/10-panel.conf里取消allow/deny注释,只放行你的常用出口 IP。 - 面板不要直接暴露 47801:compose 里已绑定
127.0.0.1,确认安全组也没放行它。 - 开启告警邮件:填好 SMTP 后,登录爆破、服务异常会发邮件通知。
- 定期检查审计日志:面板「日志审计」可查所有管理操作。
七、日常运维
# 查看状态 / 日志
docker compose ps
docker compose logs -f tunnel-server
docker compose logs -f postgres # 时间戳应为 CST
# 重启 / 停止(保留数据卷)
docker compose restart tunnel-server
docker compose stop
docker compose down
# 更新服务端(导入新镜像后)
docker load -i intranet-tunnel-server-images-<新版本>.tar
docker compose up -d
# 数据库备份产物
ls -lh backups/db/ # db-backup 每 24 小时一次,保留 30 天恢复数据库:
docker compose exec -T postgres pg_restore -U tunnel_user -d tunnel --clean < backups/db/tunnel-<时间戳>.dump八、排障
| 现象 | 原因与处理 |
|---|---|
lookup postgres: no such host | DB_HOST 被改成了非 compose 服务名。容器内应为 postgres |
password authentication failed | DB_PASSWORD 与 POSTGRES_PASSWORD 不一致,或数据库卷是用旧口令初始化的 |
address already in use | 端口被占用,检查是否有其它 nginx/postgres 在跑 |
nginx 启动报 host not found in upstream | tunnel-server 未启动或未 healthy。depends_on 已配健康检查,查 docker compose logs tunnel-server |
| 面板打开是 502 | 后端没起来,或 tunnel_api upstream 指向不对(应为 tunnel-server:47801) |
| 证书申请失败 | 80 端口未从公网可达(安全组/防火墙),或域名未解析到本机 |
| HTTPS 打开证书报错 | 证书目录名与 server_name 不匹配。ls certs/ 看实际目录名 |
| 隧道 502 | 客户端离线,或隧道上游地址不通。面板「客户端」看在线状态 |
九、需要我提供什么
如果还有以下信息,我可以把配置改成最终版,你直接上传即可:
- 公网 IP
- 面板域名 与 隧道域名(隧道是否用泛域名?)
- 服务器规格(决定
*_LIMIT资源上限取值) uname -m的输出(确认架构,arm64 需要重新构建镜像)
来源:
intranet-tunnel/release/README.md→## 一、包内文件(原文 589 字符)
一、包内文件
| 文件 | 说明 |
|---|---|
intranet-tunnel-server-images-1.1.1.tar | 服务端镜像归档:server:1.1.1 + postgres:16-alpine + nginx:alpine,服务器无需联网拉取 |
intranet-tunnel-server-upgrade-1.1.1.tar | 仅 server:1.1.1 镜像(约 13 MB)。升级时导它就行,不必传 148 MB |
intranet-tunnel-server-deploy-1.1.1.zip | 服务端自包含部署包(上面两项 + compose + .env 模板 + 本说明) |
intranet-tunnel-client-images-1.2.1.tar | 客户端镜像归档:client:1.2.1(含 Web 配置界面与 SQLite 持久化) |
intranet-tunnel-client-deploy-1.2.1.zip | 客户端自包含部署包(客户端镜像 + compose + init.sh + 配置模板 + 说明) |
README.md | 本文件(服务端部署说明) |
