Pangolin 1.25.1 配置参数详解

逐段详解 Pangolin 1.25.1 控制面配置文件 config.yml 全部配置段与字段(含默认值),附 log_level、enable_integration_api、rate_limits 三组改值验证还原实录与生产配置模板。

Pangolin零信任VPN安全2026/10/22

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 两文件的参数含义在部署指南第四、八章已结合部署讲解。

二、前置条件

开始本篇操作前,需满足:

  1. 已按部署指南完成三服务栈部署并完成管理员初始化(本环境实测栈状态正常):
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
  1. 管理员可正常登录(配置实验会反复重启控制面,先确认基线状态可用):
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}
  1. 配置文件在位(实测 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_SECRETserver.secret服务间签名密钥;不设则读配置文件值
EMAIL_SMTP_USERemail.smtp_userSMTP 用户名
EMAIL_SMTP_PASSemail.smtp_passSMTP 密码(避免明文进配置文件)
POSTGRES_LOGS_CONNECTION_STRINGpostgres_logs.connection_string日志库连接串
ENABLE_AI_GATEWAY_CLIENT_IP_HEADERserver.enable_ai_gateway_client_ip_header取值 true/false

本环境实测未启用任何环境变量覆盖(所有值都落在 config.yml,见 3.1 回显),这是小规模部署的推荐做法;多实例或密钥托管场景再用环境变量注入。

四、参数总览

config.yml 共 14 个顶层配置段。下表给出总览,字段级明细见第五章各子节:

配置段作用是否必填实测基线是否书写
app控制面应用行为:管理台地址、日志级别、遥测、通知段内 dashboard_url 必填是
domains业务域名与证书解析器映射(资源发布用)必填(至少 1 个)是
server控制面核心:端口、内部主机名、会话、CORS、签名密钥secret 必填是
gerbilWireGuard 隧道服务端:起始端口、公网端点、网段规划建议书写是
traefik边缘反代联动参数:入口名、证书解析器、动态配置路径可选(有默认)否
orgs新建组织的网段自动规划可选(有默认)否
rate_limitsAPI 限流:全局与认证接口两档可选(有默认)实验时临时书写
emailSMTP 邮件(邀请、告警、验证码)可选否
flags功能开关族(注册策略、原始资源、Integration API 等)建议书写是
acme证书存储路径与同步周期可选(有默认)否
aiAI 模型目录拉取(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_urlURL无(必填)管理台对外访问地址,也是 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端口3003Integration API 端口(默认不启动,见 5.9 flags 实验)
server.ai_gateway_port端口3005AI 网关端口

身份与会话组:

字段类型默认值说明
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端口51820WireGuard 主隧道起始端口(UDP)
gerbil.clients_start_port端口21820Newt 客户端隧道起始端口(UDP)
gerbil.base_endpoint字符串无(建议书写)隧道公网端点,Newt 由此接入
gerbil.exit_node_name字符串无自定义出口节点名
gerbil.subnet_groupCIDR100.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字符串webHTTP 入口名(与 traefik_config.yml 的 entryPoints 对应)
traefik.https_entrypoint字符串websecureHTTPS 入口名
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-vProxy 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_groupCIDR100.90.128.0/20组织子网池
orgs.utility_subnet_groupCIDR100.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 次200Logged in successfully
第 2 次200Logged in successfully
第 3 次200Logged in successfully
第 4 次429Rate 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.jsonACME 证书存储文件(相对编排数据目录)
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_urlURLhttps://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毫秒120000Newt 站点超时判离线阈值(2 分钟)
offline_checker.newt_wireguard_threshold_ms毫秒480000基础 WireGuard 站点阈值(8 分钟,按流量更新时间判定)
offline_checker.olm_threshold_ms毫秒120000OLM 客户端阈值(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布尔truePostgreSQL 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 对应其他级别。

八、参考链接