Pangolin 1.25.1 配置参数详解
逐段详解 Pangolin 1.25.1 控制面配置文件 config.yml 全部配置段与字段(含默认值),附 log_level、enable_integration_api、rate_limits 三组改值验证还原实录与生产配置模板。
Pangolin 1.25.1 配置参数详解
目标:逐段讲透 Pangolin 控制面主配置文件
/opt/pangolin/config/config.yml的全部配置段与字段——每个字段给出类型、默认值与实测说明,并附三组「改值 → 验证 → 还原」实验实录(日志级别、Integration API 开关、登录限流)、非法配置的启动失败实录与一份可直接落地的生产配置模板。文中全部命令与回显均在 Pangolin 1.25.1 实机环境(Ubuntu 24.04、Pangolin 1.25.1 / Gerbil 1.5.2 / Traefik v3.7,管理台域名pangolin.example.com)实测通过。部署过程见 《Pangolin 1.25.1 Docker Compose 部署指南》,组件定位与选型背景见 《Pangolin 1.24.0 介绍与选型指南》。
一、环境信息
本篇参数讲解与全部实验基于以下实测环境,读者操作时请将域名、密钥等换成自己环境对应值:
- 操作系统:Ubuntu 24.04(x86_64),root 权限
- Docker Compose:Docker Compose version v5.5.1(编排栈部署方式见部署指南)
- Pangolin:
fosrl/pangolin:1.25.1(2026-10-21 发布的最新稳定版) - 配套组件:
fosrl/gerbil:1.5.2(WireGuard 隧道服务端)、traefik:v3.7(边缘反代) - 配置文件:
/opt/pangolin/config/config.yml(编排文件所在目录/opt/pangolin/,./config子目录挂载到控制面服务内的/app/config) - 示例域名:管理台
pangolin.example.com,根域example.com - 示例管理员:邮箱
admin@example.com、密码Q1w2e3r4!
💡 说明:Pangolin 的配置分两层——
config.yml是控制面(pangolin 服务)的主配置,Traefik 的静态/动态配置是独立的两个 YAML(traefik_config.yml、dynamic_config.yml,详见部署指南第八章挂载对照)。本篇只覆盖config.yml;Traefik 两文件的参数含义在部署指南第四、八章已结合部署讲解。
二、前置条件
开始本篇操作前,需满足:
- 已按部署指南完成三服务栈部署并完成管理员初始化(本环境实测栈状态正常):
cd /opt/pangolin && docker compose ps --format "table {{.Service}}\t{{.Status}}"
实测回显:
SERVICE STATUS
gerbil Up About an hour
pangolin Up About an hour (healthy)
traefik Up About an hour
- 管理员可正常登录(配置实验会反复重启控制面,先确认基线状态可用):
curl -sk -X POST https://127.0.0.1/api/v1/auth/login \
-H "Host: pangolin.example.com" -H "Content-Type: application/json" \
-H "x-csrf-token: x-csrf-protection" \
-d '{"email":"admin@example.com","password":"Q1w2e3r4!"}'
实测回显:
{"data":null,"success":true,"error":false,"message":"Logged in successfully","status":200}
- 配置文件在位(实测 800 字节、31 行):
ls -lh /opt/pangolin/config/config.yml
实测回显:
-rw-r--r-- 1 root root 800 Oct 22 11:52 /opt/pangolin/config/config.yml
三、参数查看与修改方式
3.1 配置文件位置与服务内读取路径
宿主机侧编辑的文件是 /opt/pangolin/config/config.yml,经编排挂载 ./config:/app/config 映射为控制面服务内的 /app/config/config.yml。两处是同一份文件(bind mount),在宿主机改完即对服务可见,无需复制:
cd /opt/pangolin && docker compose exec pangolin grep -n "log_level" /app/config/config.yml
实测回显:
10: log_level: "info"
当前环境的完整配置内容如下(cat 实测,共 31 行),后文所有实验都在这份基线上做改值与还原:
cat /opt/pangolin/config/config.yml
实测回显:
# To see all available options, please visit the docs:
# https://docs.pangolin.net/
gerbil:
start_port: 51820
base_endpoint: "https://pangolin.example.com"
app:
dashboard_url: "https://pangolin.example.com"
log_level: "info"
telemetry:
anonymous_usage: false
domains:
domain1:
base_domain: "example.com"
server:
secret: "ckrLbFxQVDUV5lBC9cVGxWGGMR6tUxmiiDopESP1"
cors:
origins: ["https://pangolin.example.com"]
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
allowed_headers: ["X-CSRF-Token", "Content-Type"]
credentials: false
flags:
require_email_verification: false
disable_signup_without_invite: true
disable_user_create_org: false
allow_raw_resources: true
enable_integration_api: false
💡 说明:这份基线只写了约 1/3 的可用字段,其余字段全部按内置默认值运行(默认值清单见第四章参数总览)。
config.yml采用「没写就用默认」的策略,生产上建议只显式写出需要偏离默认值的字段。
3.2 修改与生效流程
config.yml 在控制面启动时一次性读入,修改后必须重启 pangolin 服务才会生效(gerbil、traefik 不读这份文件,无需重启)。标准流程为「编辑 → 重启 → 验证」三步:
cd /opt/pangolin && docker compose restart pangolin
实测回显:
Container pangolin Started
重启后用健康状态与登录接口双重验证(服务就绪约需 10 秒,健康检查由编排内置探针完成):
cd /opt/pangolin && sleep 10 && docker compose ps pangolin --format "{{.Service}} {{.Status}}"
实测回显(一次还原实验后的实测):
pangolin Up 11 seconds (healthy)
💡 技术拓展:服务配置的生效机制业界常见三种——① 启动时读入(改后需重启,如 Nginx 旧版、本文 Pangolin);② SIGHUP/管理通道热加载(改后发信号,如 Nginx
nginx -s reload);③ 定时或监听文件变化自动重载(如 Traefik 对动态配置文件的 watch)。Pangolin 1.25.1 对config.yml采用第 ① 种;但 Traefik 侧的dynamic_config.yml由 Traefik 文件提供器自动监听,改后无需重启——两套机制不要混淆。
3.3 非法配置的行为:启动失败并循环拉起
控制面对 config.yml 做严格校验(每个字段有类型与取值约束,未知字段直接报错)。本节实测一次非法值写入后的行为——把 app.log_level 改成合法枚举之外的 verbose:
app:
dashboard_url: "https://pangolin.example.com"
log_level: "verbose"
执行 docker compose restart pangolin 后服务无法起来,进入反复重启状态:
cd /opt/pangolin && sleep 8 && docker compose ps pangolin --format "{{.Service}} {{.Status}}"
实测回显:
pangolin Restarting (1) 1 second ago
日志中可见明确的校验报错(zod 校验原文,指明字段路径与合法取值):
cd /opt/pangolin && docker compose logs pangolin --since 3m 2>&1 | grep -m 1 "Invalid configuration file"
实测回显:
Error: Invalid configuration file: Validation error: Invalid option: expected one of "debug"|"info"|"warn"|"error" at "app.log_level"
处置方式:把该字段改回合法值(本实验还原为 info),再执行 docker compose up -d pangolin,服务恢复 Up (healthy),管理台入口返回 200:
cd /opt/pangolin && docker compose up -d pangolin && sleep 20 && \
docker compose ps pangolin --format "{{.Service}} {{.Status}}" && \
curl -sk -o /dev/null -w "管理台入口 HTTP_STATUS:%{http_code}\n" \
-H "Host: pangolin.example.com" https://127.0.0.1/auth/login
实测回显:
Container pangolin Started
pangolin Up 11 seconds (healthy)
管理台入口 HTTP_STATUS:200
⚠️ 注意:因为编排里配置了异常自动拉起策略,配置错误不会让服务「躺平」,而是陷入「起 → 崩 → 再起」的循环。判断配置错误的关键信号就是
docker compose ps中状态反复处于Restarting,以及日志中出现Invalid configuration file行。
3.4 环境变量覆盖(优先级高于 config.yml)
部分敏感字段支持用环境变量覆盖 config.yml 中的同名值,环境变量优先。1.25.1 支持的覆盖变量如下(均为控制面服务的环境变量,经编排文件 environment: 段注入):
| 环境变量 | 覆盖的 config.yml 字段 | 说明 |
|---|---|---|
SERVER_SECRET | server.secret | 服务间签名密钥;不设则读配置文件值 |
EMAIL_SMTP_USER | email.smtp_user | SMTP 用户名 |
EMAIL_SMTP_PASS | email.smtp_pass | SMTP 密码(避免明文进配置文件) |
POSTGRES_LOGS_CONNECTION_STRING | postgres_logs.connection_string | 日志库连接串 |
ENABLE_AI_GATEWAY_CLIENT_IP_HEADER | server.enable_ai_gateway_client_ip_header | 取值 true/false |
本环境实测未启用任何环境变量覆盖(所有值都落在 config.yml,见 3.1 回显),这是小规模部署的推荐做法;多实例或密钥托管场景再用环境变量注入。
四、参数总览
config.yml 共 14 个顶层配置段。下表给出总览,字段级明细见第五章各子节:
| 配置段 | 作用 | 是否必填 | 实测基线是否书写 |
|---|---|---|---|
app | 控制面应用行为:管理台地址、日志级别、遥测、通知 | 段内 dashboard_url 必填 | 是 |
domains | 业务域名与证书解析器映射(资源发布用) | 必填(至少 1 个) | 是 |
server | 控制面核心:端口、内部主机名、会话、CORS、签名密钥 | secret 必填 | 是 |
gerbil | WireGuard 隧道服务端:起始端口、公网端点、网段规划 | 建议书写 | 是 |
traefik | 边缘反代联动参数:入口名、证书解析器、动态配置路径 | 可选(有默认) | 否 |
orgs | 新建组织的网段自动规划 | 可选(有默认) | 否 |
rate_limits | API 限流:全局与认证接口两档 | 可选(有默认) | 实验时临时书写 |
email | SMTP 邮件(邀请、告警、验证码) | 可选 | 否 |
flags | 功能开关族(注册策略、原始资源、Integration API 等) | 建议书写 | 是 |
acme | 证书存储路径与同步周期 | 可选(有默认) | 否 |
ai | AI 模型目录拉取(AI 网关用) | 可选(有默认) | 否 |
offline_checker | 站点/客户端离线判定阈值 | 可选(有默认) | 否 |
postgres | 外部 PostgreSQL 连接(不配则用内置 SQLite) | 可选 | 否 |
postgres_logs | 审计日志独立库存放 | 可选 | 否 |
另有三条顶层硬约束(不满足直接启动失败):domains 至少定义 1 个域名;server.secret 必填且非空;app.dashboard_url 必填且非空。
💡 技术拓展:「配置里没写的外部存储用内置 SQLite,写了才用外部 PostgreSQL」是自托管软件常见的可插拔存储设计。同类的还有 Gitea(SQLite/MySQL/PostgreSQL 三选一)、Outline(强制外部 PostgreSQL)。Pangolin 的取舍得失:内置 SQLite 让单机部署零依赖(本环境实测库文件仅 1.1MB 起步),代价是横向扩展与高可用能力有限——多副本部署必须显式配置
postgres段。本文单机场景实际采用内置 SQLite。
五、核心参数分类详解
本章逐段展开。每个子节先给字段表(类型与默认值来自 1.25.1 校验逻辑与实测),再给实测要点;三组「改值 → 验证 → 还原」实验分别落在 5.1、5.7、5.9。
5.1 app 段:应用行为
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
app.dashboard_url | URL | 无(必填) | 管理台对外访问地址,也是 Newt 连接端点派生来源 |
app.log_level | 枚举 | info | 日志级别,可选 debug/info/warn/error |
app.save_logs | 布尔 | false | 是否把日志落盘到 config/logs/(不开则只输出到标准输出) |
app.log_failed_attempts | 布尔 | false | 是否记录失败登录尝试 |
app.telemetry.anonymous_usage | 布尔 | true | 匿名使用统计上报 |
app.notifications.product_updates | 布尔 | true | 产品更新通知 |
app.notifications.new_releases | 布尔 | true | 新版本发布通知 |
log_level 改值实验:默认 info 级别下,日志只有运行主线(服务启动、peer 变更、错误)。把级别调成 debug 并重启:
# 编辑 config.yml 将 app.log_level 改为 "debug" 后执行
cd /opt/pangolin && docker compose restart pangolin
实测回显:
Container pangolin Started
debug 级别下日志量显著增大(实测全量日志中 [debug] 行达 171 行,[info] 行 103 行)。新增的 debug 行主要是周期性内部动作与每个 API 请求的路径记录,抽样实测:
cd /opt/pangolin && docker compose logs pangolin --tail 40 2>&1 | grep "\[debug\]" | head -5
实测回显(输出节选):
2026-10-22T11:39:45+00:00 [debug]: Handling Newt get config message!
2026-10-22T11:39:45+00:00 [debug]: In newt get config: existing site 1 has no endpoint, skipping
2026-10-22T11:39:50+00:00 [debug]: acmeCertSync: no certificates found for resolver "letsencrypt"
2026-10-22T11:39:55+00:00 [debug]: POST /api/v1/auth/login
2026-10-22T11:40:07+00:00 [debug]: sendToClient: Message type pong sent to clientId bg30ja3zzszynk1
还原为 info 并重启后,用启动横幅行做分界统计,验证 debug 行不再产生:
cd /opt/pangolin && docker compose restart pangolin && sleep 10 && \
docker compose logs pangolin -t --since 3m 2>&1 | awk "/0.0.0 start/{found=1; next} found" | grep -c "\[debug\]" || true
实测回显:
0
实测要点:debug 适合排障期临时开启(能看到每个 API 请求、Newt 控制通道消息、证书同步动作),常态运行建议 info——debug 下 Newt 心跳消息每 2 秒刷一行,日志噪音大。
5.2 domains 段:业务域名
domains 是一个映射结构,键名自取(本环境用 domain1),每个键下三个字段:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
domains.<名>.base_domain | 字符串 | 无(段内必填) | 业务根域,资源发布时在其下划分子域(自动转小写) |
domains.<名>.cert_resolver | 字符串 | 缺省回落 traefik.cert_resolver | 该域名单独指定证书解析器 |
domains.<名>.prefer_wildcard_cert | 布尔 | false | 优先申请泛域名证书 |
实测基线 domains.domain1.base_domain: "example.com" 生效的直接证据:创建子域资源 app 时,控制面自动拼出 app.example.com 全域名(创建接口实测回显 "fullDomain":"app.example.com",创建过程见部署指南 4.8 节)。
⚠️ 注意:顶层校验要求
domains至少有 1 个条目,整个段删空会导致启动失败(报错At least one domain must be defined);除非同时开启flags.disable_config_managed_domains(此时域名全部改为管理台维护,不走配置文件)。
5.3 server 段:控制面核心
字段最多的段,分四组说明。
端口组(默认值即官方编排的端口规划):
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
server.external_port | 端口 | 3000 | 对外 API 端口(Traefik 反代到这里的业务 API) |
server.internal_port | 端口 | 3001 | 内部端口(gerbil 拉取配置、健康检查走这里,实测编排探针指向 3001) |
server.next_port | 端口 | 3002 | 管理台页面服务端口 |
server.integration_port | 端口 | 3003 | Integration API 端口(默认不启动,见 5.9 flags 实验) |
server.ai_gateway_port | 端口 | 3005 | AI 网关端口 |
身份与会话组:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
server.internal_hostname | 字符串 | pangolin | 服务内部主机名(编排内服务名即 pangolin,勿改) |
server.session_cookie_name | 字符串 | p_session_token | 管理台会话 Cookie 名 |
server.dashboard_session_length_hours | 数值 | 720 | 管理台会话时长(小时),30 天 |
server.resource_session_length_hours | 数值 | 720 | 资源访问会话时长(小时) |
server.resource_session_request_param | 字符串 | resource_session_request_param | 资源会话请求参数名 |
server.resource_access_token_param | 字符串 | p_token | 资源访问令牌 URL 参数名 |
server.resource_access_token_headers.id | 字符串 | P-Access-Token-Id | 访问令牌 ID 请求头名 |
server.resource_access_token_headers.token | 字符串 | P-Access-Token | 访问令牌请求头名 |
server.remote_headers.* | 字符串 | Remote-User 等 6 项 | 回源时向业务后端传递身份的请求头名(Remote-User-Id/Remote-User/Remote-Email/Remote-Name/Remote-Role/Remote-Virtual-Api-Key-Id) |
网络与代理组:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
server.trust_proxy | 整数 | 1 | 信任的代理层数(取客户端真实 IP 时跳过的头层数) |
server.trust_ips | 字符串数组 | [] | 额外信任的代理 IP/网段 |
server.custom_ip_header | 字符串 | 空 | 自定义客户端 IP 来源头(如 CF-Connecting-IP) |
server.cors.origins | 字符串数组 | 无 | 允许的跨域来源(实测基线只放管理台自身) |
server.cors.methods | 字符串数组 | 无 | 允许的 HTTP 方法 |
server.cors.allowed_headers | 字符串数组 | 无 | 允许的请求头(实测基线含 X-CSRF-Token,管理台 CSRF 校验依赖它) |
server.cors.credentials | 布尔 | 无 | 是否允许跨域携带凭据 |
密钥与可选路径组:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
server.secret | 字符串 | 无(必填,≥8 位) | 服务间签名密钥,可用环境变量 SERVER_SECRET 覆盖 |
server.badger_override | 字符串 | 无 | 覆盖 Forward Auth 插件(badger)的获取地址 |
server.ai_gateway_override | 字符串 | 无 | 覆盖 AI 网关地址 |
server.maxmind_db_path / maxmind_asn_path | 字符串 | 无 | GeoIP 库路径(地理访问策略用) |
实测要点:server.secret 是初始化部署时随机生成的(本环境 40 位随机串,见 3.1 回显)。CORS 段与管理台的 CSRF 机制联动——基线 allowed_headers 中的 X-CSRF-Token 正是管理台发起写请求时携带的防伪头(缺该头调用写接口会得到 403 CSRF token missing or invalid,实测见运维命令篇),生产环境保持基线写法即可。
5.4 gerbil 段:WireGuard 隧道服务端
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
gerbil.start_port | 端口 | 51820 | WireGuard 主隧道起始端口(UDP) |
gerbil.clients_start_port | 端口 | 21820 | Newt 客户端隧道起始端口(UDP) |
gerbil.base_endpoint | 字符串 | 无(建议书写) | 隧道公网端点,Newt 由此接入 |
gerbil.exit_node_name | 字符串 | 无 | 自定义出口节点名 |
gerbil.subnet_group | CIDR | 100.89.137.0/18 | 出口节点网段池 |
gerbil.block_size | 数值 | 22 | 出口节点网段块大小 |
gerbil.site_block_size | 数值 | 30 | 站点网段块大小 |
实测要点:本环境实测基线只写 start_port 与 base_endpoint,其余默认。站点接入后从网段池实际分配的地址可在站点详情接口看到(实测 exitNodeSubnet":"100.89.128.4/30",与默认 block_size: 22 的 /30 切分一致);组织侧网段则由 orgs 段规划(实测组织子网 100.90.128.0/20,与 5.6 默认值吻合)。改 start_port/clients_start_port 需同步修改编排文件的端口发布映射,否则隧道不通。
5.5 traefik 段:边缘反代联动
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
traefik.http_entrypoint | 字符串 | web | HTTP 入口名(与 traefik_config.yml 的 entryPoints 对应) |
traefik.https_entrypoint | 字符串 | websecure | HTTPS 入口名 |
traefik.cert_resolver | 字符串 | letsencrypt | 默认证书解析器 |
traefik.prefer_wildcard_cert | 布尔 | false | 优先泛域名证书 |
traefik.certificates_path | 字符串 | /var/certificates | 服务内证书目录 |
traefik.dynamic_cert_config_path | 字符串 | /var/dynamic/cert_config.yml | 动态证书配置生成路径 |
traefik.dynamic_router_config_path | 字符串 | /var/dynamic/router_config.yml | 动态路由配置生成路径 |
traefik.static_domains | 字符串数组 | [] | 额外静态域名 |
traefik.site_types | 字符串数组 | ["newt","wireguard","local"] | 允许的站点类型 |
traefik.allow_raw_resources | 布尔 | true | 允许原始 TCP/UDP 资源 |
traefik.file_mode | 布尔 | false | 文件模式(资源路由全走静态文件) |
traefik.monitor_interval | 数值 | 5000 | 配置监听间隔(毫秒) |
traefik.additional_middlewares | 字符串数组 | 无 | 全局追加中间件 |
traefik.pp_transport_prefix | 字符串 | pp-transport-v | Proxy Protocol 传输前缀 |
traefik.rate_limit.average | 数值 | 30 | 边缘限流平均值(每秒) |
traefik.rate_limit.burst | 数值 | 50 | 边缘限流突发容量 |
实测要点:本环境基线未写 traefik 段,全部走默认值——默认入口名 web/websecure 与官方 traefik_config.yml 的入口定义一一对应,所以零配置即可联动。这一段的典型改法是「换了证书解析器名」或「改了入口名」时,让 config.yml 与 Traefik 侧保持一致,两侧名字必须严格相同。
5.6 orgs 段:组织网段规划
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
orgs.block_size | 数值 | 24 | 组织子网块大小 |
orgs.subnet_group | CIDR | 100.90.128.0/20 | 组织子网池 |
orgs.utility_subnet_group | CIDR | 100.96.128.0/20 | 组织辅助子网池 |
实测要点:新建组织时从池中自动切分子网。本环境实测首个组织分配到 subnet":"100.90.128.0/20"、utilitySubnet":"100.96.128.0/20",与两个默认池的首块完全一致。多组织环境按需扩大池或调整 block_size;网段不得与业务内网冲突(默认用 CGNAT 保留段 100.64.0.0/10 内的地址)。
5.7 rate_limits 段:API 限流
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
rate_limits.global.window_minutes | 数值 | 1 | 全局限流时间窗(分钟) |
rate_limits.global.max_requests | 数值 | 500 | 窗口内允许的最大请求数 |
rate_limits.auth.window_minutes | 数值 | 1 | 认证类接口(登录等未认证路由)限流时间窗 |
rate_limits.auth.max_requests | 数值 | 500 | 认证类接口窗口内最大请求数 |
auth.max_requests 改值实验:把登录限流压到 3 次/分钟,验证限流生效边界:
rate_limits:
auth:
max_requests: 3
window_minutes: 1
重启后连续登录 4 次(同一命令执行 4 次,每次 1 个请求):
curl -sk -w "\nHTTP_STATUS:%{http_code}\n" -X POST https://127.0.0.1/api/v1/auth/login \
-H "Host: pangolin.example.com" -H "Content-Type: application/json" \
-H "x-csrf-token: x-csrf-protection" \
-d '{"email":"admin@example.com","password":"Q1w2e3r4!"}'
4 次登录的逐次实测结果:
| 次序 | HTTP 状态 | 响应 message |
|---|---|---|
| 第 1 次 | 200 | Logged in successfully |
| 第 2 次 | 200 | Logged in successfully |
| 第 3 次 | 200 | Logged in successfully |
| 第 4 次 | 429 | Rate limit exceeded. You can make 3 requests every 1 minute(s). |
第 4 次完整实测回显:
{"data":null,"success":false,"error":true,"message":"Rate limit exceeded. You can make 3 requests every 1 minute(s).","status":429,"stack":null}
HTTP_STATUS:429
还原(删除 rate_limits 段,回落默认 500 次/分钟)并重启 65 秒后再登录,实测恢复 200:
{"data":null,"success":true,"error":false,"message":"Logged in successfully","status":200}
实测要点:限流器按来源 IP 计数,window_minutes 是滚动窗口而非固定桶——第 4 次请求等到窗口滑出旧请求后即恢复。爆破防护实战建议:auth.max_requests 保持默认 500 即可(登录接口另有失败锁定逻辑);若要走更严格的防爆破,把它压到 10~20 并配合 fail2ban 类工具分析 401 日志。
5.8 email 段:SMTP 邮件
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
email.smtp_host | 字符串 | 无 | SMTP 服务器地址 |
email.smtp_port | 端口 | 无 | SMTP 端口(587/465 常用) |
email.smtp_user | 字符串 | 无 | SMTP 用户名(可用环境变量 EMAIL_SMTP_USER 覆盖) |
email.smtp_pass | 字符串 | 无 | SMTP 密码(可用环境变量 EMAIL_SMTP_PASS 覆盖) |
email.smtp_secure | 布尔 | 无 | 是否直连 TLS(465 端口置 true) |
email.smtp_tls_reject_unauthorized | 布尔 | 无 | 是否拒绝无效 TLS 证书 |
email.no_reply | 邮箱地址 | 无 | 发件人地址(需合法邮箱格式) |
实测要点:本环境未配置(flags.require_email_verification: false 时用户邮箱验证不走邮件)。配置后邮件用于用户邀请、密码重置、资源访问码等场景;smtp_pass 建议走环境变量注入而不落配置文件。
5.9 flags 段:功能开关
1.25.1 全部开关及实测基线值:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
flags.require_email_verification | 布尔 | 无 | 注册后需邮箱验证(基线 false) |
flags.disable_signup_without_invite | 布尔 | 无 | 禁止无邀请注册(基线 true,仅邀请制) |
flags.disable_user_create_org | 布尔 | 无 | 禁止普通用户自建组织(基线 false) |
flags.allow_raw_resources | 布尔 | 无 | 允许原始 TCP/UDP 资源(基线 true) |
flags.enable_integration_api | 布尔 | 无(不启用) | 启用 Integration API(机器对机器接口,端口 3003) |
flags.disable_local_sites | 布尔 | 无 | 禁用本地站点类型 |
flags.disable_basic_wireguard_sites | 布尔 | 无 | 禁用基础 WireGuard 站点(只留 Newt) |
flags.disable_config_managed_domains | 布尔 | 无 | 禁用配置文件管理的域名(改管理台维护) |
flags.disable_product_help_banners | 布尔 | 无 | 关闭产品帮助横幅 |
flags.disable_enterprise_features | 布尔 | 无 | 关闭企业版功能入口 |
flags.disable_virtual_api_keys_ui | 布尔 | 无 | 隐藏虚拟 API Key 界面 |
flags.enable_acme_cert_sync | 布尔 | true | 控制面与 Traefik 间同步 ACME 证书 |
flags.disable_private_http_placeholder | 布尔 | false | 关闭内网 HTTP 占位页 |
enable_integration_api 改值实验:Integration API 默认关闭。开启(设为 true)并重启后,日志出现独立 API 服务的启动行:
cd /opt/pangolin && docker compose logs pangolin --since 1m 2>&1 | grep -i "integration"
实测回显(开启态):
2026-10-22T11:51:40+00:00 [info]: Integration API server is running on http://localhost:3003
该 API 只在控制面服务内部监听(3003 端口不在编排端口发布列表里),从服务内实测调用链路:未授权的键被拒绝 403,经管理 API 授权 listOrgs 动作后再调返回组织列表 200:
cd /opt/pangolin && docker compose exec pangolin \
curl -s -w "\nHTTP_STATUS:%{http_code}\n" http://localhost:3003/v1/orgs \
-H "Authorization: Bearer bxxf3fxe6o36qko.wjpyj4ntacesigp57h5ikineypxcy2z2oidg3ixr"
实测回显(未授权时):
{"data":null,"success":false,"error":true,"message":"Key does not have permission perform this action","status":403,"stack":null}
HTTP_STATUS:403
经 POST /api/v1/api-key/bxxf3fxe6o36qko/actions(请求体 {"actionIds":["listOrgs"]})授权后再次调用,实测回显(输出节选):
{"data":{"orgs":[{"orgId":"demo-org","name":"Demo Organization","subnet":"100.90.128.0/20","utilitySubnet":"100.96.128.0/20",
HTTP_STATUS:200
还原为 false 并重启:日志中不再出现新的启动行(实测全量日志中该行时间戳止于开启窗口内的 11:51:40),服务内再调直接连接拒绝:
cd /opt/pangolin && docker compose exec pangolin curl -sS -m 3 http://localhost:3003/v1/orgs
实测回显(还原后):
curl: (7) Failed to connect to localhost port 3003 after 0 ms: Couldn't connect to server
实测要点:该开关是「机器对机器」自动化的总闸(CI/CD 调 Pangolin 建资源等场景),Bearer 凭据格式为 API Key ID.API Secret,密钥与授权的完整操作见 《Pangolin 1.25.1 常用命令与运维操作详解》第七章。安全上建议:不用时保持默认关闭;开启时密钥只授最小动作集(如上例仅 listOrgs)。
5.10 acme 段:证书存储与同步
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
acme.acme_json_path | 字符串 | config/letsencrypt/acme.json | ACME 证书存储文件(相对编排数据目录) |
acme.acme_http_endpoint | 字符串 | 无 | 自定义 ACME 目录地址(私有 ACME/PKI 场景) |
acme.sync_interval_ms | 数值 | 5000 | 控制面同步证书的间隔(毫秒) |
实测要点:本环境未写该段,走默认路径——实测 config/letsencrypt/acme.json 文件由 Traefik 维护,控制面按 5 秒周期同步证书元数据(开启 debug 日志时可见周期性 acmeCertSync 动作,见 5.1 实验回显)。
5.11 ai 段:AI 模型目录
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ai.model_catalog.upstream_url | URL | https://api.fossorial.io/api/v1/models | 模型目录上游地址 |
ai.model_catalog.file | 字符串 | 无 | 用本地文件替代上游目录 |
ai.model_catalog.merge_file | 字符串 | 无 | 本地模型与上游目录合并 |
ai.model_catalog.refresh_interval_min_hours | 数值 | 6 | 目录刷新最短间隔(小时) |
ai.model_catalog.refresh_interval_max_hours | 数值 | 12 | 目录刷新最长间隔(小时) |
实测要点:该段服务于 AI 网关(3005 端口)的模型目录拉取,本环境未配置走默认。完全离线环境可配 file 指向本地目录文件,避免启动后访问外网。
5.12 offline_checker 段:离线判定阈值
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
offline_checker.check_interval_ms | 毫秒 | 30000 | 离线检查器的巡检间隔 |
offline_checker.newt_threshold_ms | 毫秒 | 120000 | Newt 站点超时判离线阈值(2 分钟) |
offline_checker.newt_wireguard_threshold_ms | 毫秒 | 480000 | 基础 WireGuard 站点阈值(8 分钟,按流量更新时间判定) |
offline_checker.olm_threshold_ms | 毫秒 | 120000 | OLM 客户端阈值(2 分钟) |
offline_checker.remote_exit_node_threshold_ms | 毫秒 | 120000 | 远程出口节点阈值(2 分钟) |
实测要点:本环境站点为 Newt 类型,管理台显示的 online 状态即由该检查器维护——实测站点在线时 lastPing 持续刷新(站点详情接口回显 online:true);网络抖动导致短暂断连时,2 分钟内恢复则状态不变。弱网环境可适当调大 newt_threshold_ms 避免状态抖动。
5.13 postgres / postgres_logs 段:外部数据库
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
postgres.connection_string | 字符串 | 无 | 业务库连接串(不配则用内置 SQLite) |
postgres.replicas[].connection_string | 字符串数组 | 无 | 只读副本连接串 |
postgres.pool.max_connections | 数值 | 20 | 连接池上限 |
postgres.pool.max_replica_connections | 数值 | 10 | 副本池上限 |
postgres.pool.idle_timeout_ms | 数值 | 30000 | 空闲连接回收(毫秒) |
postgres.pool.connection_timeout_ms | 数值 | 5000 | 建连超时(毫秒) |
postgres.pool.jit_mode | 布尔 | true | PostgreSQL JIT 开关 |
postgres_logs.connection_string | 字符串 | 无 | 审计日志独立库连接串(可用环境变量 POSTGRES_LOGS_CONNECTION_STRING 覆盖) |
实测要点:单机部署不配置即用内置 SQLite(实测库文件 config/db/db.sqlite 仅 1.1MB,备份与恢复见运维命令篇第九章)。postgres 与 postgres_logs 分开设计是为了把高写入的审计日志流量隔离到独立库,大规模部署才需要拆分。
六、生产配置模板
综合全篇参数与实测数据,给出一份适合「单台 2GB 内存服务器、托管 3~5 个业务域名」场景的注释模板。资源占用实测基准(docker stats --no-stream):pangolin 约 270~340MiB(编排限制 2GiB)、gerbil 约 7MiB、traefik 约 24MiB——2GB 内存足以承载控制面本体,站点与流量增长后主要瓶颈在带宽与连接数而非内存:
# Pangolin 1.25.1 生产配置模板(单机 2GB 内存场景)
# 路径:/opt/pangolin/config/config.yml,修改后需重启 pangolin 服务生效
gerbil:
start_port: 51820 # WireGuard 主隧道端口,与编排端口映射一致
base_endpoint: "https://pangolin.example.com" # 换成你的管理台域名
app:
dashboard_url: "https://pangolin.example.com" # 换成你的管理台域名
log_level: "info" # 排障期临时改 debug,用完改回
save_logs: true # 生产建议落盘日志到 config/logs/
telemetry:
anonymous_usage: false # 按合规要求决定是否匿名上报
domains:
domain1:
base_domain: "example.com" # 换成你的业务根域
cert_resolver: "letsencrypt" # 与 Traefik 侧解析器名一致
server:
secret: "ckrLbFxQVDUV5lBC9cVGxWGGMR6tUxmiiDopESP1" # 首次部署随机生成,保留即可
cors:
origins: ["https://pangolin.example.com"] # 只放管理台自身来源
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
allowed_headers: ["X-CSRF-Token", "Content-Type"]
credentials: false
dashboard_session_length_hours: 168 # 管理台会话收敛到 7 天(默认 30 天)
resource_session_length_hours: 24 # 资源访问会话收敛到 1 天
orgs:
block_size: 24
subnet_group: "100.90.128.0/20" # 与业务内网冲突时整池换段
utility_subnet_group: "100.96.128.0/20"
rate_limits:
auth:
max_requests: 100 # 收紧登录接口限流(默认 500)
window_minutes: 1
flags:
require_email_verification: false # 配好 email 段后可改 true
disable_signup_without_invite: true # 仅邀请制注册,生产必开
disable_user_create_org: false
allow_raw_resources: true
enable_integration_api: false # 需要自动化时再开(见 5.9 实验)
💡 技术拓展:
dashboard_session_length_hours与resource_session_length_hours这类会话时长的取值是「安全性与运维成本」的权衡。业界常见档位——管理后台类 4~24 小时(金融级),1~7 天(通用 SaaS 后台),30 天(内部工具);终端用户访问类资源通常比管理台更宽松。本模板采用「管理台 7 天、资源 1 天」的组合,兼顾日常使用与暴露面收敛。
七、常见问题
Q1:改了 config.yml 为什么没生效?
排查顺序:① 确认改的是 /opt/pangolin/config/config.yml(编排挂载源),不是别的同名文件;② 确认执行了 cd /opt/pangolin && docker compose restart pangolin——该文件只在启动时读入;③ 服务内核对实际读到的内容,正确命令与实测回显:
cd /opt/pangolin && docker compose exec pangolin grep -n "log_level" /app/config/config.yml
实测回显:
10: log_level: "info"
服务内看到的值与宿主机一致即说明文件同步无问题,剩下的问题只会是「还没重启」。
Q2:重启后服务反复 Restarting 怎么办?
这是配置校验失败的典型表现(实测复现过程见 3.3 节)。定位命令与实测回显:
cd /opt/pangolin && docker compose logs pangolin --since 3m 2>&1 | grep -m 1 "Invalid configuration file"
Error: Invalid configuration file: Validation error: Invalid option: expected one of "debug"|"info"|"warn"|"error" at "app.log_level"
按报错里的字段路径(at "app.log_level")修正取值即可。常见踩坑点:枚举值拼写、domains 删空、server.secret 为空或短于 8 位。
Q3:Integration API 开了但调不通?
三步排查(全部实测过):① 确认 flags.enable_integration_api: true 且重启过,日志有 Integration API server is running on http://localhost:3003 行;② 确认从控制面服务内调用——3003 不在编排端口发布列表,宿主机直接 curl http://127.0.0.1:3003 永远是连接拒绝,正确姿势是 docker compose exec pangolin curl http://localhost:3003/v1/orgs;③ 确认 API Key 已授权对应动作,未授权时返回 403 Key does not have permission perform this action(实测见 5.9)。若从外部网络调用,需自行在编排里为 pangolin 服务追加 3003 端口映射并做好访问控制。
Q4:日志级别调 debug 后找不到 [debug] 行?
两处易错:① 改完没重启(见 Q1);② 检索方式——日志行里的级别名带终端着色控制符,grep "[debug]" 会被方括号正则语义吞掉(实测 grep -c "[debug]" 把几乎所有行都算进去、grep "\[debug\]" 一行都匹配不上)。可靠写法是固定字符串匹配:
cd /opt/pangolin && docker compose logs pangolin 2>&1 | grep -c "mdebug"
实测回显(debug 态全量统计):
171
mdebug 是级别字段着色序列里的固定片段,能精确命中 debug 行;同理 minfo/mwarn/merror 对应其他级别。
八、参考链接
- 《Pangolin 1.24.0 介绍与选型指南》——组件定位、架构与选型对比
- 《Pangolin 1.25.1 Docker Compose 部署指南》——三服务栈从零部署、Traefik 配置与 Newt 站点接入
- 《Pangolin 1.25.1 常用命令与运维操作详解》——服务管理、API Key 与 Integration API、日志诊断、备份恢复
- Pangolin 官方配置文档:https://docs.pangolin.net/self-host/advanced/config-file
- Pangolin 源码仓库:https://github.com/fosrl/pangolin