环境与账号速查(脱敏)
来源:
intranet-tunnel/docs/configuration.md(整篇)(原文 15099 字符)
环境变量配置说明
两份模板怎么选
仓库里有两份环境变量模板,用途不同,不要混用:
| 精简版 | 完整版 | |
|---|---|---|
| 路径 | .env.example(仓库根) | deploy/cloud/.env.example |
| 配置项数 | 69 项 | 202 项 |
| 适用场景 | 本机开发、单机试用 | 云服务器生产部署 |
| 覆盖范围 | 启动服务端所必需的基础项 | 全部可配置能力 + compose 层变量 |
| 能否直接用 | 可以(未列出的走代码默认值) | 需要填 EXTERNAL_IP、CERT_EMAIL 等占位 |
怎么选
- 只想把服务跑起来看看 → 用精简版:
cp .env.example .env - 要部署到服务器、且需要证书自动化 / DDNS / 反向代理 / 端口转发 / 备份 / 告警等 → 用完整版:
cp deploy/cloud/.env.example deploy/cloud/.env
# 然后按 deploy/cloud/README.md 的第二节修改 EXTERNAL_IP、CERT_EMAIL 与 nginx 域名- 两份都需要(本机调试 + 云上部署)→ 各自独立,互不影响:根目录的
.env给本机 compose 用,deploy/cloud/.env给云版 compose 用,名字与位置都不同,不会被覆盖。
完整版比精简版多出什么
多出的 137 项覆盖这些能力域(按前缀):
AUTH 登录策略、2FA、第三方登录、验证码参数
PANEL 管理面板(安全入口、监听地址、面板 HTTPS)
CERT SSL 证书自动化(签发方式、ACME 目录、密钥算法、各云厂商 DNS 凭据)
DDNS 动态域名解析(服务商、检测间隔、IP 查询接口)
PROXY 内置反向代理(端口、超时、SSRF 防护)
FORWARD TCP/UDP 端口转发(端口范围、连接上限、UDP 空闲超时)
BACKUP 配置备份(路径、定时策略、保留天数、是否含密钥)
LOG 日志审计(文件轮转、入库、异步缓冲、异常捕获)
SMS 短信验证码(服务商、签名、模板、频控)
ALERT 安全告警(邮件通知、冷却时间、触发条件)
DB 数据库连接池(最大连接、空闲连接、连接寿命)
PERFORMANCE / WEBUI / TRUSTED_UPSTREAM_CIDRS 等注意:完整版里包含 compose 层变量(
SERVER_CPU_LIMIT、DB_MEM_LIMIT、DB_BACKUP_INTERVAL_HOURS等)。这些不在服务端代码里,只被docker-compose.yml使用,放在精简版里没有意义。
敏感项处理
两份模板中的敏感项(*_PASSWORD、*_SECRET、*_SALT、CONFIG_ENCRYPT_KEY) 都只写占位符 change_me_*,可以安全提交。
真实的 .env 由 .gitignore 的 /.env 规则排除,绝不会进仓库**。
本文档由实际勘察代码与 .env 生成(代码中定义 192 个环境变量, 根 .env 列出 145 个),用于快速查阅与部署前核对。
一、配置文件的三个位置
| 文件 | 用途 | 谁在读 |
|---|---|---|
根 .env | compose 栈部署用;既供 docker-compose.yml 做变量替换,也通过 env_file 注入 tunnel-server 容器 | docker compose + 容器 |
server/.env | 本地直接运行服务端(go run)时使用 | 服务端进程 |
server/.env.docker | 容器内的默认值模板(镜像构建时参考) | 仅作参考 |
优先级:环境变量 > .env 文件 > 代码默认值。
另一条配置通道:约 60 项配置可在 Web 设置页修改并热生效(存数据库、 敏感项 AES-GCM 加密),无需改 .env 或重启。本文档中标注 [可热改] 的即是此类。
二、配置项清单
1. 运行环境
| 变量 | 默认 | 说明 |
|---|---|---|
APP_ENV | development | 运行环境标识 |
LOG_LEVEL | info | 八级:trace/debug/info/notice/warning/error/fatal/panic [可热改] |
LOG_FORMAT | text | text 或 json(.env 中设为 json) |
2. 数据库
| 变量 | 默认 | 说明 |
|---|---|---|
DB_DRIVER | postgres | postgres / mysql / sqlite / sqlserver |
DB_HOST / DB_PORT | 127.0.0.1 / 5432 | |
DB_NAME / DB_USER / DB_PASSWORD | tunnel / tunnel_user / 空 | |
DB_SSLMODE | disable | PostgreSQL 专用 |
DB_DSN | 空 | 完整连接串,优先级高于上面各分项 |
DB_FILE | ./data/tunnel.db | SQLite 文件路径 |
DB_CHARSET | utf8mb4 | MySQL 专用 |
DB_AUTO_MIGRATE | true | 启动时自动建表 |
DB_LOG_LEVEL | warn | GORM 日志级别 |
DB_MAX_OPEN_CONNS / DB_MAX_IDLE_CONNS | 50 / 10 | 连接池 |
DB_CONN_MAX_LIFETIME | 1h | 连接最长存活 |
3. 端口规划(全部高位端口)
| 变量 | 默认 | 说明 |
|---|---|---|
BIND_ADDR | 0.0.0.0 | |
CONTROL_PORT | 47800 | 控制连接(TLS) |
API_PORT | 47801 | 管理 API / Web 面板 |
DATA_PORT | 48080 | 穿透数据面;与 PROXY_HTTP_PORT 相同时由反代接管 |
PORT_POOL_START / PORT_POOL_END | 48081 / 48100 | 隧道占用的端口池 |
EXTERNAL_IP | 空 | 对外通告的 IP(NAT 环境用) |
4. 鉴权与安全
| 变量 | 默认 | 说明 |
|---|---|---|
JWT_SECRET | 空 | 必填,openssl rand -hex 32 |
JWT_ISSUER | intranet-tunnel | |
JWT_EXPIRE | 1h | 访问令牌有效期 |
JWT_REFRESH_EXPIRE | 168h | 刷新令牌有效期 |
TOKEN_SALT | 空 | 客户端令牌的盐 |
BCRYPT_COST | 12 | 口令哈希成本 |
ADMIN_USERNAME / ADMIN_PASSWORD | admin / 空 | 初始管理员(仅首次建库时生效) |
API_ALLOWED_CIDRS | 空 | 管理 API IP 白名单,留空不限制 |
API_RATE_LIMIT | 300 | 管理 API 每分钟请求上限 |
CORS_ALLOWED_ORIGINS | 空 | 跨域来源白名单 |
AUTH_CAPTCHA_ENABLED | true | 登录图形验证码 [可热改] |
AUTH_CAPTCHA_LENGTH | 4 | 验证码位数 [可热改] |
AUTH_CAPTCHA_WIDTH / HEIGHT | 120 / 40 | 验证码尺寸 |
AUTH_CAPTCHA_TTL | 5m | 验证码有效期 |
AUTH_CAPTCHA_SMS_REQUIRED | true | 发短信/邮件前是否也要图形验证码 [可热改] |
AUTH_MAX_LOGIN_ATTEMPTS | 10 | 登录失败上限 [可热改] |
AUTH_TOKEN_TTL_HOURS | 24 | |
AUTH_DEFAULT_USERNAME / PASSWORD | 继承管理员 / 空 | 设置页的登录策略项 |
AUTH_2FA_ENABLED | false | 两步验证 |
AUTH_THIRD_PARTY_ENABLED | false | 第三方登录 |
5. 控制连接 TLS
| 变量 | 默认 | 说明 |
|---|---|---|
TLS_ENABLE | true | 控制连接是否走 TLS |
TLS_AUTO_SELF_SIGNED | true | 无证书时自动生成自签 |
TLS_CERT_DIR | ./data/certs | |
TLS_CERT_HOSTS | localhost,127.0.0.1 | 自签证书的 SAN |
TLS_MIN_VERSION | 1.2 | |
TLS_CERT_FILE / TLS_KEY_FILE | 空 | 使用自有证书时填写 |
6. 运行期行为
| 变量 | 默认 | 说明 |
|---|---|---|
HEARTBEAT_INTERVAL | 30s | |
HEARTBEAT_TIMEOUT | 90s | |
WORK_CONN_IDLE_TIMEOUT | 60s | 工作连接空闲超时 |
WORK_CONN_DIAL_TIMEOUT | 10s | |
WORK_CONN_POOL_SIZE | 64 | 工作连接池大小 |
MUX_ENABLE | true | yamux 多路复用 |
MUX_KEEPALIVE_INTERVAL | 30s | |
SHUTDOWN_TIMEOUT | 15s | 优雅退出宽限期 |
MAX_TUNNELS_PER_CLIENT | 20 | |
MAX_BANDWIDTH_KBPS | 0 | 0 表示不限速 |
7. DDoS 防护
分层设计:全局上限兜底 → 单 IP 限制单源 → 令牌桶抑速 → 失败达阈值自动封禁。
| 变量 | 默认 | 说明 |
|---|---|---|
GUARD_ENABLE | true | 总开关 |
GUARD_MAX_CONTROL_CONNS | 4096 | 控制面全局并发 |
GUARD_MAX_CONTROL_CONNS_PER_IP | 32 | |
GUARD_CONTROL_CONN_RATE | 120 | 单 IP 每分钟建连数 |
GUARD_LOGIN_RATE | 20 | 单 IP 每分钟登录尝试 |
GUARD_HANDSHAKE_TIMEOUT | 5s | 对抗慢速握手 |
GUARD_BAN_THRESHOLD | 10 | 失败多少次后封禁 |
GUARD_FAILURE_WINDOW | 5m | 失败统计窗口 |
GUARD_BAN_DURATION | 30m | 封禁时长 |
GUARD_MAX_DATA_CONNS | 8192 | 数据面全局并发 |
GUARD_MAX_DATA_CONNS_PER_IP | 128 | |
GUARD_MAX_CONNS_PER_TUNNEL | 256 | |
GUARD_MAX_CLIENTS | 1000 | |
GUARD_WORK_CONN_RATE | 600 | |
GUARD_WHITELIST | 127.0.0.1/32,::1/128 | 放行来源(本机默认在白名单内,因此无法用本机触发封禁) |
GUARD_TRUSTED_PROXIES | — | 可信代理网段,来自这些网段的 X-Forwarded-For 才被采信 |
GUARD_MAX_TRACKED_IPS | 100000 | IP 跟踪表容量 |
GUARD_IP_IDLE_TTL | 10m | 空闲回收 |
8. DDNS 动态域名解析
| 变量 | 默认 | 说明 |
|---|---|---|
DDNS_ENABLED | false | 只控制定时同步,不影响 DNS-01 [可热改] |
DDNS_PROVIDER | cloudflare | cloudflare / aliyun / dnspod / huawei / webhook [可热改] |
DDNS_INTERVAL | 5m | 检测周期(最低 60 秒) |
DDNS_TTL | 600 | |
DDNS_IP_PROTOCOL | ipv4 | |
DDNS_IP_APIS | ipify/ifconfig/ipinfo | 公网 IP 探测源,按序容错 |
DNS 服务商凭据(各家格式不同,均 [可热改],设置页加密存储):
| 服务商 | 变量 |
|---|---|
| Cloudflare | CF_API_TOKEN(API Token,非 Global API Key)、CF_ZONE_ID |
| 阿里云云解析 | ALIYUN_ACCESS_KEY_ID、ALIYUN_ACCESS_KEY_SECRET |
| 腾讯云 DNSPod | TENCENT_SECRET_ID、TENCENT_SECRET_KEY |
| 华为云 DNS | HUAWEI_ACCESS_KEY_ID、HUAWEI_ACCESS_KEY_SECRET |
| Webhook | DDNS_WEBHOOK_URL、DDNS_WEBHOOK_METHOD、DDNS_WEBHOOK_HEADERS、DDNS_WEBHOOK_BODY |
9. 内置反向代理
| 变量 | 默认 | 说明 |
|---|---|---|
PROXY_ENABLED | true | |
PROXY_HTTP_PORT | 48080 | 与 DATA_PORT 相同时由反代接管公网入口 |
PROXY_HTTPS_PORT | 48443 | |
PROXY_DIAL_TIMEOUT | 10s | |
PROXY_RESPONSE_HEADER_TIMEOUT | 30s | |
PROXY_IDLE_CONN_TIMEOUT | 90s | |
ALLOW_PRIVATE_UPSTREAM | false | 防 SSRF:默认禁止上游指向内网 |
TRUSTED_UPSTREAM_CIDRS | 空 | 允许的私有上游网段 |
10. SSL/TLS 证书
| 变量 | 默认 | 说明 |
|---|---|---|
CERT_ENABLED | false | |
CERT_ISSUER | letsencrypt | letsencrypt / letsencrypt_staging / zerossl / self_signed,或 cloudflare→aliyun/tencent/baidu(云厂商) |
CERT_EMAIL | 空 | ACME 账户邮箱(启用时必填) |
CERT_AGREE_TOS | false | 同意 ACME 条款(启用时须为 true) |
CERT_CHALLENGE_TYPE | http-01 | http-01 / dns-01 / self |
CERT_KEY_TYPE | ecdsa256 | ecdsa256/384、rsa2048/4096 |
CERT_STORAGE_PATH | ./certs | |
CERT_AUTO_RENEW_DAYS | 30 | 提前多少天续期 |
CERT_CHECK_INTERVAL | 12h | 续期巡检周期 |
CERT_DNS_PROVIDER | 空 | DNS-01 用哪家(默认复用 DDNS 配置) |
CERT_ACME_DIRECTORY | 空 | 自定义 ACME 目录(指向 staging 可联调) |
CERT_HTTP01_PORT | 继承 PROXY_HTTP_PORT |
云厂商证书签发来源(与上面的 DNS 凭据是两套不同的东西):
| 变量 | 说明 |
|---|---|
CERT_ALIYUN_ACCESS_KEY_ID / _SECRET | 阿里云数字证书管理服务 |
CERT_TENCENT_SECRET_ID / _KEY | 腾讯云 SSL 证书 |
CERT_BAIDU_ACCESS_KEY / _SECRET | 百度智能云 SSL 证书(接口细节未验证) |
CERT_CLOUD_ENDPOINT | 覆盖云厂商接入点(私有化/联调用) |
CERT_CLOUD_REGION | 云厂商地域 |
⚠️ 易混淆点:
ALIYUN_ACCESS_KEY_ID是云解析 DNS 的凭据(用于 DNS-01 验证域名),CERT_ALIYUN_ACCESS_KEY_ID是证书服务的凭据(用于直接申请证书)。 二者可以在同一账号下,但通常是两套独立的授权。
11. TCP/UDP 端口转发
| 变量 | 默认 | 说明 |
|---|---|---|
FORWARD_ENABLED | true | |
FORWARD_PORT_RANGE | 49000-49100 | 可申请范围 |
FORWARD_DEFAULT_MAX_CONNS | 100 | |
FORWARD_UDP_IDLE_TIMEOUT | 60s | |
FORWARD_BIND_ADDR | 0.0.0.0 | |
FORWARD_DEFAULT_RATE_LIMIT | 0 | 0 不限速 |
FORWARD_PORT_START / _END | 49000 / 49100 | 仅供 compose 生成端口映射,须与 FORWARD_PORT_RANGE 一致 |
12. 日志审计
| 变量 | 默认 | 说明 |
|---|---|---|
LOG_MAX_ENTRIES | 1024 | 每类日志保留条数 [可热改] |
LOG_CAPTURE_EXCEPTION | true | 异常日志捕获 [可热改] |
LOG_FILE_ENABLED | true | 写文件 |
LOG_DB_ENABLED | true | 写数据库 |
LOG_FILE_PATH | ./logs | |
LOG_FILE_MAX_SIZE | 100 | MB |
LOG_FILE_MAX_BACKUPS | 30 | |
LOG_FILE_MAX_AGE | 30 | 天 |
LOG_ASYNC_BUFFER | 10000 | 异步写缓冲 |
LOG_ADD_SOURCE | false | 是否带源码位置 |
13. 系统设置与面板
| 变量 | 默认 | 说明 |
|---|---|---|
CONFIG_ENCRYPT_KEY | 空 | 32 字节,敏感设置项的加密密钥;留空则明文存储(不推荐) |
PANEL_HTTP_PORT / PANEL_TLS_PORT | 0 | 留空沿用 API_PORT;0 表示未单独配置 [可热改] |
PANEL_LISTEN_ADDR | 空 | 留空沿用 BIND_ADDR |
PANEL_SECURITY_ENTRY | 空 | 安全入口:设置后后台首页只在该路径可访问(如 /tunnel) [可热改] |
PANEL_SECURITY_ENTRY_CHECK_DISABLED | false | |
PANEL_OUTSIDE_ACCESS | false | 允许外网访问面板 |
PANEL_FIREWALL_AUTO | false | 自动配置防火墙 |
PANEL_FORCE_HTTPS | false | 强制 HTTPS 跳转 |
PANEL_SSL_ENABLED | false | 面板自身启用 HTTPS |
PANEL_SSL_CERT_ID | 0 | 面板使用的证书 ID |
PERFORMANCE_GC_PERCENT | -1 | Go GC 百分比,-1 用默认 [可热改] |
WEBUI_DIR | 空 | 前端静态资源目录(一般无需设置) |
14. 配置备份
| 变量 | 默认 | 说明 |
|---|---|---|
BACKUP_ENABLED | true | |
BACKUP_PATH | ./backups | |
BACKUP_AUTO_ENABLED | false | 定时备份 |
BACKUP_AUTO_CRON | 0 3 * * * | |
BACKUP_KEEP_DAYS | 30 | |
BACKUP_INCLUDE_SECRETS | false | 备份是否含密钥(默认不含,避免泄露) |
15. 短信验证码(可选)
| 变量 | 默认 | 说明 |
|---|---|---|
SMS_ENABLED | false | [可热改] |
SMS_PROVIDER | mock | aliyun / tencent / huawei / webhook / mock [可热改] |
SMS_SIGN_NAME | 内网穿透系统 | |
SMS_TEMPLATE_CODE | 空 | |
SMS_CODE_LENGTH | 6 | |
SMS_CODE_TTL | 5m | |
SMS_SEND_INTERVAL | 1m | |
SMS_MAX_PER_HOUR / _DAY / _PER_IP_HOUR | 5 / 10 / 20 | 频控 |
SMS_MAX_VERIFY_ATTEMPTS | 5 | |
SMS_MOCK_MODE | false | 联调用:验证码直接返回 |
ALIYUN_SMS_ACCESS_KEY_ID / _SECRET / _ENDPOINT | 空 / dysmsapi | |
TENCENT_SMS_SECRET_ID / _KEY / _APP_ID / _SIGN_NAME / _TEMPLATE_ID | 空 | |
HUAWEI_SMS_ACCESS_KEY_ID / _SECRET / _ENDPOINT / _SENDER | 空 | |
SMS_WEBHOOK_URL / _METHOD / _HEADERS / _BODY | 空 / POST |
16. 邮件 SMTP 与邮箱登录(设置页配置,不读 .env)
SMTP 与安全告警的配置全部在 Web 设置页(因为是用户自己的邮箱,需频繁调整):
| 设置键 | 说明 |
|---|---|
smtp.enabled / host / port / username / password / from / from_name / use_tls / skip_verify | SMTP 服务 |
email.code_length / code_ttl / send_interval / max_per_hour / max_per_day / max_per_ip_hour / max_verify_attempts | 邮箱验证码 |
alert.enabled / recipients / min_level / cooldown / max_batch / notify_ban / notify_auth_brute / notify_exception / notify_rate_limit | 安全告警 |
system.timezone | 服务端时区(IANA 名称) |
ddns.provider / cf_api_token / aliyun_* / tencent_* / huawei_* / webhook_url | DNS 服务商凭据 |
这些项也支持
.env提供初始值(变量名见对应 config 文件),但设置页保存后以数据库为准。
三、目录结构与职责
intranet-tunnel/
├── .env compose 部署配置(本机实际使用)
├── docker-compose.yml 服务端 + PostgreSQL 编排
├── go.work Go 多模块工作区(根目录本身不是 Go module)
├── Makefile 构建/测试/打包命令
├── README.md 部署与使用说明
│
├── shared/ 【客户端与服务端共享】
│ ├── protocol/ 自定义二进制协议:4 字节大端长度 + JSON
│ │ (conn.go / message.go,含单元测试)
│ └── mux/ yamux 多路复用会话封装
│
├── server/ 【服务端主体,112 个 Go 文件】
│ ├── cmd/server/ 程序入口
│ │ ├── main.go 装配全部组件、启动顺序、优雅退出
│ │ ├── apiserver.go HTTP 服务装配
│ │ └── settings.go 设置变更 → 热生效的映射(各组件 Reload)
│ ├── internal/ ← 见下方模块表
│ ├── data/ 运行数据(SQLite、控制连接证书)
│ ├── logs/ 日志文件落盘目录
│ ├── backups/ 配置备份输出
│ └── Dockerfile 两阶段构建,产出静态二进制
│
├── client/ 【内网侧客户端,7 个 Go 文件】
│ └── cmd/client/main.go 连接服务端、注册隧道、转发流量
│
├── web/ 【Vue 3 管理面板,23 个 .vue】
│ └── src/
│ ├── api/ axios 实例与全部接口封装(client.js)
│ ├── components/ 通用组件(DataCard / ProTable / CaptchaImage 等 9 个)
│ ├── composables/ 组合式函数(主题等)
│ ├── router/ 路由与守卫
│ ├── store/ 登录态(reactive,非 Pinia)
│ ├── styles/ 设计令牌与 Element Plus 覆盖(7 个 scss)
│ ├── utils/ 格式化、剪贴板等工具
│ └── views/ 13 个页面
│
├── deploy/ 【生产部署资产】
│ ├── nginx/ 反向代理配置(HTTP 与 TCP stream)
│ ├── security/ DDoS 加固:sysctl 参数、fail2ban 规则、封禁名单示例
│ └── systemd/ 客户端 systemd 服务单元
│
├── docs/ 【项目文档,4 份】
│ ├── deployment-checklist.md 上线前检查清单
│ ├── docker-build.md Docker 构建与 compose 部署记录
│ ├── security-audit.md 安全审计报告
│ └── ui-refactor.md Web 界面改造记录(含红线合规表)
│
└── tools/pentest/ 【渗透测试工具,6 个 Go 文件】
27 个测试用例,覆盖认证、DoS、注入、信息泄露server/internal/ 模块职责(20 个)
| 模块 | 职责 |
|---|---|
config | 读取并校验全部环境变量(192 个),分文件组织:基础 / 短信 / 扩展 |
model | GORM 数据模型(用户、隧道、客户端、证书、日志、设置等) |
store | 数据访问层,按实体分文件;屏蔽各数据库方言差异 |
api | HTTP 接口、中间件(鉴权、访问日志、限流)、路由注册 |
auth | JWT 签发校验、令牌管理、登录失败计数 |
guard | DDoS 防护:分层限流、令牌桶、自动封禁、IP 跟踪表 |
control | 控制连接处理:客户端注册、心跳、隧道下发 |
data | 数据连接与流量代理(穿透数据面) |
proxy | 内置反向代理:域名路由、SSRF 防护、HTTP/HTTPS 入口 |
forward | TCP/UDP 端口转发 |
cert | 证书管理:ACME、云厂商签发来源、导入、存储与续期 |
ddns | DDNS 与 DNS 服务商适配(Cloudflare/阿里云/DNSPod/华为云/Webhook) |
sms | 短信验证码:服务商适配、频控、验证码存储 |
email | 邮件发送(SMTP,支持 HTML)与邮箱验证码 |
captcha | 图形验证码生成(点阵字体 + 干扰线) |
alert | 安全告警:事件聚合抑制、HTML 邮件通知 |
logger | 八级日志、审计日志、异常捕获、SSE 实时推送 |
settings | 系统设置:持久化、AES-GCM 加密、热生效分发 |
stats | 流量统计采集与聚合 |
backup | 配置备份与恢复(定时任务) |
四、部署前必须检查的项
JWT_SECRET—— 必须改成随机值(openssl rand -hex 32)TOKEN_SALT—— 同上CONFIG_ENCRYPT_KEY—— 必须为 32 字节,且妥善保管(丢失后已加密的设置项无法解密)ADMIN_PASSWORD—— 改掉默认值;注意它只在首次建库时生效DB_PASSWORD/POSTGRES_PASSWORD—— 改掉默认值,两者须一致GUARD_WHITELIST—— 确认只放行可信来源API_ALLOWED_CIDRS—— 如面板不对外,建议限制来源网段ALLOW_PRIVATE_UPSTREAM—— 保持false,除非确有必要PANEL_SECURITY_ENTRY—— 建议设置,隐藏后台入口BACKUP_INCLUDE_SECRETS—— 保持false
来源:
halo-kb/实例现状基线.md→## A) Halo 版本与运行形态(原文 4821 字符)
A) Halo 版本与运行形态
A.1 确切版本:Halo Pro 2.26.1
三处独立来源互证,结论确定:
证据 1 —— 容器启动日志第一行(最权威):
head -1 /vol1/1000/docker/halo/halo2/logs/halo.log2026-09-13T18:41:58.626+08:00 INFO 1 --- [main] run.halo.app.Application
: Starting Application v2.26.1 using Java 21.0.12 with PID 1
(/application/application.jar started by root in /application)证据 2 —— 首页 HTML 的 generator meta:
curl.exe -s --noproxy '*' http://<内网IP>:28090/ | Select-String 'generator'<meta name="generator" content="Halo 2.26.1"/>证据 3 —— 镜像 tag 与 digest:
docker inspect Halo --format 'Image={{.Config.Image}} ImageID={{.Image}} Created={{.Created}}'Image=registry.fit2cloud.com/halo/halo-pro:2.26
ImageID=sha256:a6291a728a3033f0a24bde32ef641d5987180859de57514fde25d06838c84042
Created=2026-09-13T11:02:00.654239422Z
RepoDigest: registry.fit2cloud.com/halo/halo-pro@sha256:982c894493238bc778b9629c7c672c287805c671ddd85702c1aeae20edde85a7⚠️ 镜像 tag 是
2.26,但实际运行版本是2.26.1—— tag 是滚动 tag,不能当精确版本用。 后续若要做版本锁定/回滚,必须按 digest(sha256:982c8944…)而不是 tag。
镜像来源(存疑点,如实记录):镜像 label org.opencontainers.image.source 指向 https://github.com/lxware-dev/halo-pro,而仓库域名是 registry.fit2cloud.com/halo/halo-pro(官方仓库)。 org.opencontainers.image.version label 值是无意义的 "2"。 本报告不对该镜像的官方性下结论,仅记录事实。
A.2 部署形态
部署目录(NAS 绝对路径):/vol1/1000/docker/halo/
/vol1/1000/docker/halo/
├── docker-compose.yaml (1526 B, 权限 rwx------ ZYJ:Users, mtime 2026-09-13 18:50)
└── halo2/ (Halo 工作目录, root:root, 绑定到容器 /root/.halo2)
├── backups/ (空)
├── indices/ (搜索索引, 含 halo/ 子目录)
├── keys/ (halo2.jks, pat_id_rsa, pat_id_rsa.pub)
├── logs/ (halo.log 671 KB)
├── plugins/ (20 个 jar + disabled.txt + configs/)
└── themes/ (Ethereal/, theme-earth/)该目录不在 git 管理下(无
.git),也没有.env文件 —— 配置全部内联在docker-compose.yaml里。
compose 文件内容摘要(已脱敏):
services:
halo:
image: registry.fit2cloud.com/halo/halo-pro:2.26
container_name: Halo
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks: [halo_network]
volumes:
- ./halo2:/root/.halo2
ports:
- "28090:8090"
healthcheck:
test: ["CMD","curl","-f","http://<内网IP>:28090/actuator/health/readiness"]
interval: 30s / timeout: 5s / retries: 5 / start_period: 30s
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=[redacted] # 原值存在
- --spring.sql.init.platform=postgresql
- --halo.external-url=http://<内网IP>:28090/
halodb:
image: postgres:15.4
container_name: PostgreSQL
restart: on-failure:3
volumes:
- /vol1/1000/docker/PostgreSQL:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=[redacted] # 原值存在
- POSTGRES_USER=halo
- POSTGRES_DB=halo
- PGUSER=halo
networks:
halo_network:| 配置项 | 值 |
|---|---|
Compose 服务名(halo / halodb) | halo、halodb |
| 容器名 | Halo、PostgreSQL |
| 镜像 | registry.fit2cloud.com/halo/halo-pro:2.26、postgres:15.4 |
| 端口映射 | 0.0.0.0:28090 -> 8090/tcp(宿主机全网卡暴露);PG 5432/tcp 仅容器网络内 |
| Volume | ./halo2 -> /root/.halo2(bind);/vol1/1000/docker/PostgreSQL -> /var/lib/postgresql/data(bind) |
| 网络 | 自定义 bridge halo_network |
| 重启策略 | on-failure:3 |
| 时区 | 容器 TZ=Asia/Shanghai(来自镜像环境) |
| JVM | JDK 21.0.12,-Xmx256m -Xms256m |
| 工作目录 | HALO_WORK_DIR=/root/.halo2 |
容器实况:
docker ps -a --format '{{.Names}}|{{.Image}}|{{.Status}}|{{.Ports}}'Halo|registry.fit2cloud.com/halo/halo-pro:2.26|Up About an hour (healthy)|0.0.0.0:28090->8090/tcp
PostgreSQL|postgres:15.4|Up About an hour (healthy)|5432/tcpPostgreSQL 版本(实测):
docker exec PostgreSQL psql -U halo -d halo -tAc "select version();"PostgreSQL 15.4 (Debian 15.4-2.pgdg120+1) on x86_64-pc-linux-gnu,
compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit✅ 用户所述 "PostgreSQL 15.x" 已核实为 15.4。
可达性(实测):
curl.exe -s -o NUL -w "HTTP %{http_code} in %{time_total}s" --noproxy '*' http://<内网IP>:28090/actuator/health
curl.exe -s -o NUL -w "HTTP %{http_code} in %{time_total}s" https://<服务名>.tunnel.sushike.cloud/actuator/health内网直连 HTTP 200 in 0.010253s
公网隧道 HTTP 200 in 0.079831s/actuator/health 响应体:{"groups":["liveness","readiness"],"status":"UP"} /actuator/health/liveness:{"status":"UP"}
版本探测中不可用的端点(如实记录): /actuator/info、/actuator、/actuator/env、/apis/api.halo.run/v1alpha1/ 均返回 HTTP 302 → /login?authentication_required,不暴露版本。版本只能靠日志 / HTML meta / 镜像三处拿到。
