Pangolin 1.25.1 常用命令与运维操作详解

以实测命令与回显详解 Pangolin 1.25.1 日常运维操作——服务状态管理、日志诊断、健康核验、管理员会话、API Key 与 Integration API 调用、资源编排命令、数据备份恢复与错误速查。

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

Pangolin 1.25.1 常用命令与运维操作详解

目标:把 Pangolin 1.25.1 日常运维的高频操作整理成可独立执行的手册——服务运行状态管理、日志查看与诊断(含一次真实的插件下载超时故障实录)、健康核验、管理员会话与 API 调用基础、API Key 管理与 Integration API 调用、资源与目标编排命令、数据备份与恢复,以及一张按 HTTP 状态码组织的错误速查表。文中全部命令与回显均在 Pangolin 1.25.1 实机环境(Ubuntu 24.04、Docker Compose v5.5.1、Pangolin 1.25.1 / Gerbil 1.5.2 / Traefik v3.7,管理台域名 pangolin.example.com)实测通过。部署过程见 《Pangolin 1.25.1 Docker Compose 部署指南》,config.yml 参数级说明见 《Pangolin 1.25.1 配置参数详解》。

一、环境信息

本篇所有操作基于以下实测环境,读者执行时请替换为自己的域名、密钥与账号:

  • 操作系统: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、traefik:v3.7、fosrl/newt:1.19.0(远端内网侧站点连接器)
  • 部署目录:/opt/pangolin/(编排文件),数据目录 /opt/pangolin/config/
  • 示例域名:管理台 pangolin.example.com,根域 example.com,示例资源 app.example.com
  • 示例管理员:邮箱 admin@example.com、密码 Q1w2e3r4!
  • 实测数据基线:组织 demo-org(子网 100.90.128.0/20)、Newt 站点 Lab Site(siteId=1,online)、HTTP 资源 Docs App(resourceId=2,app.example.com)

二、前置条件

  1. 已按部署指南完成三服务栈部署与管理员初始化,栈处于健康状态(本篇 3.1 有状态核验命令与回显)。
  2. 管理员可登录(本篇 6.1 提供登录命令与回显;后续章节大量操作依赖登录会话)。
  3. 操作均通过两条通道完成:服务器本机的 docker compose 命令族(服务编排管理)与 控制面 REST API(https://127.0.0.1/api/v1/,经 Traefik 入口访问,需带 Host 头与 CSRF 头)。API 的参数级行为与配置开关详见 《Pangolin 1.25.1 配置参数详解》 5.9 节,本篇给出全部可直接执行的命令。

三、服务运行状态管理

3.1 查看服务运行状态

三个服务(控制面 pangolin、隧道网关 gerbil、边缘反代 traefik)的状态一条命令看全:

cd /opt/pangolin && docker compose ps

实测回显:

NAME       IMAGE                             COMMAND                  SERVICE    CREATED          STATUS                        PORTS
gerbil     docker.io/fosrl/gerbil:1.5.2      "/entrypoint.sh --re…"   gerbil     17 minutes ago   Up 17 minutes                 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/udp, [::]:443->443/udp, 0.0.0.0:21820->21820/udp, [::]:21820->21820/udp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 0.0.0.0:51820->51820/udp, [::]:51820->51820/udp
pangolin   docker.io/fosrl/pangolin:1.25.1   "docker-entrypoint.s…"   pangolin   18 minutes ago   Up About a minute (healthy)
traefik    docker.io/traefik:v3.7            "/entrypoint.sh --co…"   traefik    17 minutes ago   Up 9 minutes

判读要点:pangolin 带 (healthy) 表示编排内置健康检查(探测内部 3001 端口)通过;gerbil 的 PORTS 列出现全部四个对外端口(80/tcp、443/tcp+udp、51820/udp、21820/udp)说明边缘入口就绪。单看某服务可用精简格式:

cd /opt/pangolin && docker compose ps pangolin --format "{{.Service}} {{.Status}}"

实测回显:

pangolin Up About an hour (healthy)

3.2 查看资源占用

docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}"

实测回显:

NAME       MEM USAGE / LIMIT    CPU %
newt-lab   17.84MiB / 31.3GiB   0.02%
traefik    23.64MiB / 31.3GiB   0.04%
gerbil     7.016MiB / 31.3GiB   0.01%
pangolin   339.5MiB / 2GiB      2.35%

判读要点:控制面常驻约 270~340MiB(编排限制 2GiB),gerbil 与 traefik 均在 25MiB 以内;CPU 空闲时低于 3%。容量规划时按「控制面 512MiB 起步 + 每千站点/资源约 50~100MiB」估算即可,2GB 内存的单机足以支撑中小规模。

3.3 重启与重建

改配置后的标准动作是重启控制面(gerbil、traefik 不读 config.yml,无需陪跑):

cd /opt/pangolin && docker compose restart pangolin

实测回显:

 Container pangolin Started

全栈重建(down 拆掉全部服务再 up 拉起)用于版本升级或编排文件变更。实测验证数据持久性——重建后业务数据完好:

cd /opt/pangolin && docker compose down

实测回显(输出节选):

 Container pangolin Stopping
 Container pangolin Removed
 Network pangolin_frontend Removing
cd /opt/pangolin && docker compose up -d

实测回显(输出节选):

 Container pangolin Waiting
 Container pangolin Healthy
 Container traefik Starting
 Container traefik Started

重建后先看状态,再验证业务数据(登录成功即代表 SQLite 库中的账号、组织、站点、资源全部完好):

cd /opt/pangolin && sleep 20 && docker compose ps --format "table {{.Service}}\t{{.Status}}"

实测回显:

SERVICE    STATUS
gerbil     Up 20 seconds
pangolin   Up 31 seconds (healthy)
traefik    Up 20 seconds
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}

⚠️ 注意:全栈重建后 Traefik 侧的 badger 中间件插件需要重新下载(无持久化缓存卷),网络不佳时会出现「全站 404」的窗口期,属已知行为——故障特征与处置见第四章实录。

四、日志查看与诊断

4.1 日志查看的基本姿势

控制面日志(docker compose logs pangolin)是排障第一入口。常用形态与实测:

cd /opt/pangolin && docker compose logs pangolin --tail 5

实测回显(输出节选,newt 心跳应答期):

pangolin  | 2026-10-22T11:40:07+00:00 [info]: Adding peer with public key hH2I3YMHKdWtr8uKVn67dcDg4DTCqdWTj5ApTsK7WQ4= to exit node 1
pangolin  | 2026-10-22T11:40:07+00:00 [info]: Exit node request successful: {"method":"POST","url":"http://gerbil:3004/peer","status":"Peer added successfully"}

按时间窗过滤(--since 接受 10m/1h 等相对时长):

cd /opt/pangolin && docker compose logs pangolin --since 10m 2>&1 | wc -l

实测回显:

134

按内容检索错误行:

cd /opt/pangolin && docker compose logs pangolin 2>&1 | grep -i error | head -3

实测回显(输出节选——重启期 npm 的退出噪音,属正常现象):

pangolin  | npm error path /app
pangolin  | npm error command failed
pangolin  | npm error signal SIGTERM

Traefik 侧日志单独查看:

cd /opt/pangolin && docker compose logs traefik --tail 3

实测回显:

traefik  | 2026-10-22T11:55:31Z INF Loading plugins... plugins=["badger"]
traefik  | 2026-10-22T11:55:35Z INF Plugins loaded. plugins=["badger"]

4.2 日志级别统计技巧

日志行的级别名([info]/[debug] 等)带终端着色控制符,方括号并不连续,直接 grep "[debug]" 会因正则语义失真(方括号被解释为字符组)。实测三种写法的差异:

cd /opt/pangolin && docker compose logs pangolin 2>&1 | grep -cF "mdebug"

实测回显(debug 级别全开时期):

171

mdebug 是着色序列中的固定片段,可精确命中 debug 行;同理 minfo/mwarn/merror。统计某时间窗内错误量(排障时判断故障密度):

cd /opt/pangolin && docker compose logs pangolin --since 10m 2>&1 | grep -cF "merror"

实测回显(健康期):

0

💡 说明:debug 级别的开启方法与前后对比实测见配置参数详解篇 5.1 节;该级别下每个 API 请求、Newt 控制通道消息、证书同步动作都会落日志,排障期临时开启后记得改回 info。

4.3 故障实录:Traefik 插件下载超时导致全站 404

第三章的全栈重建实验中实际触发过一次真实故障:up -d 后服务全部 Up,但访问任何域名(管理台、资源)一律返回纯文本 404 page not found。定位过程与处置如下,供读者遇到同类现象时对照。

第一步:确认现象——服务状态正常但路由全失:

curl -sk -o /dev/null -w "%{http_code}\n" -H "Host: pangolin.example.com" https://127.0.0.1/auth/login

实测回显:

404

第二步:查 Traefik 日志,发现 badger 插件下载超时、引用该中间件的路由全部失效:

cd /opt/pangolin && docker compose logs traefik 2>&1 | grep -E "unable to download plugin|invalid middleware" | head -3

实测回显(输出节选):

traefik  | 2026-10-22T11:54:07Z ERR Plugins are disabled because an error has occurred. error="unable to set up plugins environment: unable to install plugin badger: unable to download plugin github.com/fosrl/badger: failed to call service: Get \"https://plugins.traefik.io/public/download/github.com/fosrl/badger/v1.7.0\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)" plugins=["badger"]
traefik  | 2026-10-22T11:54:07Z ERR error="invalid middleware \"badger@file\" configuration: invalid middleware type or middleware does not exist" entryPointName=websecure routerName=api-router@file

第三步:重启 traefik 触发插件重新下载,直到日志出现 Plugins loaded.:

cd /opt/pangolin && docker compose restart traefik

实测回显:

 Container traefik Started

约 25 秒后验证插件加载与路由恢复:

cd /opt/pangolin && docker compose logs traefik --since 90s 2>&1 | grep -F "Plugins loaded."

实测回显:

2026-10-22T11:55:35Z INF Plugins loaded. plugins=["badger"]
curl -sk -o /dev/null -w "%{http_code}\n" -H "Host: pangolin.example.com" https://127.0.0.1/auth/login

实测回显:

200

复盘:badger 是 Pangolin 的 Forward Auth 中间件,Traefik 每次重建都会从 plugins.traefik.io 拉取;下载失败时 Traefik 不阻塞启动,而是禁用插件继续跑——于是引用 badger@file 中间件的全部路由静默失效,表现为 404 而非 5xx。生产环境若外网受限,应在部署期确认 Plugins loaded. 出现过一次,或在编排里为 traefik 持久化插件缓存目录后再重建。

五、健康检查与状态核验

5.1 控制面健康端点

未认证的根端点返回固定健康标记,适合做监控探针:

curl -sk -H "Host: pangolin.example.com" https://127.0.0.1/api/v1/

实测回显:

{"message":"Healthy"}

5.2 站点在线状态核验

远端站点(Newt 连接器)是否在线,用站点详情接口核验(会话登录后调用,登录见 6.1):

curl -sk -b /tmp/pg-cookies.txt -H "Host: pangolin.example.com" https://127.0.0.1/api/v1/site/1

实测回显(输出节选):

{"data":{"siteId":1,"orgId":"demo-org","niceId":"lab-site","exitNodeId":1,"networkId":null,"name":"Lab Site","pubKey":"hH2I3YMHKdWtr8uKVn67dcDg4DTCqdWTj5ApTsK7WQ4=","exitNodeSubnet":"100.89.128.4/30","megabytesIn":0,"megabytesOut":0,"lastBandwidthUpdate":null,"type":"newt","online":true,"lastPing":1

判读要点:online:true 表示 WebSocket 控制通道存活;lastPing 持续刷新。站点离线判定阈值由 offline_checker 配置段控制(Newt 默认 2 分钟无心跳判离线,见 《Pangolin 1.25.1 配置参数详解》 5.12 节)。

六、管理员会话与 API 调用基础

6.1 登录获取会话

管理 API 的写操作依赖会话 Cookie(p_session_token)与 CSRF 防伪头,两者都来自登录响应:

curl -sk -c /tmp/pg-cookies.txt -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}

会话写入本地 Cookie 文件后,后续 API 调用统一带 -b /tmp/pg-cookies.txt。会话有效期由 server.dashboard_session_length_hours 控制(默认 720 小时)。

6.2 两个必踩的坑:缺 CSRF 头与口令错误

写请求(POST/PUT/DELETE)缺 x-csrf-token 头会被拦截,实测:

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" \
  -d '{"email":"admin@example.com","password":"Q1w2e3r4!"}'

实测回显:

{"error":"CSRF token missing or invalid"}
HTTP_STATUS:403

口令错误时的响应(区分于 CSRF 403):

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":"WrongPass9!"}'

实测回显:

{"data":null,"success":false,"error":true,"message":"Username or password is incorrect","status":401,"stack":null}
HTTP_STATUS:401

💡 技术拓展:Web 应用的写请求防伪常见三种机制——① 同步器令牌模式(表单隐藏字段 + 会话比对,传统服务端渲染);② 双提交 Cookie(Cookie 存随机值 + 请求头再带一份,服务端比对两者一致,本文 Pangolin 采用的变体:固定头名 x-csrf-token);③ SameSite Cookie 属性(浏览器侧缓解)。API 自动化场景注意:脚本必须显式带 CSRF 头,否则全部写操作 403。

七、API Key 管理与 Integration API 调用

7.1 创建根 API Key

机器对机器调用先建根级 API Key(管理员会话下创建,密钥明文只在创建响应里出现一次):

curl -sk -b /tmp/pg-cookies.txt -X PUT https://127.0.0.1/api/v1/api-key \
  -H "Host: pangolin.example.com" -H "Content-Type: application/json" \
  -H "x-csrf-token: x-csrf-protection" \
  -d '{"name":"d1-demo-key"}'

实测回显:

{"data":{"apiKeyId":"0h2hmx9bozbnkeu","name":"d1-demo-key","apiKey":"dqxzepctil4t2fxa6pjyljko5kdbsdjxgg7nfhf7","lastChars":"fhf7","createdAt":"2026-10-22T11:38:05.279Z"},"success":true,"error":false,"message":"API key created","status":201}

凭据格式为 <apiKeyId>.<apiKey>,下文 Bearer 串即 0h2hmx9bozbnkeu.dqxzepctil4t2fxa6pjyljko5kdbsdjxgg7nfhf7。

7.2 查看 Key 列表与授权动作

新建的 Key 默认无任何权限,先看列表再授权:

curl -sk -b /tmp/pg-cookies.txt -H "Host: pangolin.example.com" https://127.0.0.1/api/v1/api-keys

实测回显(输出节选):

{"data":{"apiKeys":[{"apiKeyId":"wqmavio4pqphwoy","lastChars":"4mbt","createdAt":"2026-10-22T11:21:13.522Z","name":"ops-key"},{"apiKeyId":"0h2hmx9bozbnkeu","lastChars":"fhf7","createdAt":"2026-10-22T11:38:05.279Z","name":"d1-demo-key"},{"apiKeyId":"bxxf3fxe6o36qko","lastChars":"3ixr","createdAt":"2026-10-22T11:51:46.343Z","name":"c1-d1-key"}],"pagination":{"total":3,"limit":1000,"offset":0}},"success":true,"error":false,"message":"API keys retrieved successfully","status":200}

授权用「动作 ID 元组」提交。注意请求体字段名是 actionIds 且必须是数组(实测传错字段名会被严格校验拒绝):

curl -sk -b /tmp/pg-cookies.txt -X POST https://127.0.0.1/api/v1/api-key/0h2hmx9bozbnkeu/actions \
  -H "Host: pangolin.example.com" -H "Content-Type: application/json" \
  -H "x-csrf-token: x-csrf-protection" \
  -d '{"actionIds":["listOrgs"]}'

实测回显:

{"data":{},"success":true,"error":false,"message":"API key actions updated successfully","status":200}

错误字段名的对照实测(请求体写成 {"actions":["listOrgs"]}):

{"data":null,"success":false,"error":true,"message":"Validation error: Invalid input: expected tuple, received undefined at \"actionIds\"; Unrecognized key: \"actions\"","status":400,"stack":null}

7.3 组织级 API Key

限定在单个组织内使用的 Key(最小权限首选):

curl -sk -b /tmp/pg-cookies.txt -X PUT https://127.0.0.1/api/v1/org/demo-org/api-key \
  -H "Host: pangolin.example.com" -H "Content-Type: application/json" \
  -H "x-csrf-token: x-csrf-protection" \
  -d '{"name":"d1-org-key"}'

实测回显:

{"data":{"apiKeyId":"eum3ow5r17e9usd","apiKey":"jnmddhk3y3ureim7pgxg44xps3td3m6wgpvrn6uf","name":"d1-org-key","lastChars":"n6uf","createdAt":"2026-10-22T11:53:28.069Z"},"success":true,"error":false,"message":"API key created","status":201}

组织级 Key 不能调根级端点(如 /api/v1/orgs 列表),只能在授权动作范围内调组织域端点。

7.4 调用 Integration API

Integration API 是给自动化程序用的独立 HTTP 服务(默认关闭,开启方法与开关验证见 《Pangolin 1.25.1 配置参数详解》 5.9 节),Bearer 认证、端口 3003、路径前缀 /v1。它只在控制面服务内监听,从服务内调用:未授权的 Key 返回 403——

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

按 7.2 的方法给该 Key 授权 listOrgs 后再次调用,返回组织列表:

cd /opt/pangolin && docker compose exec pangolin \
  curl -s http://localhost:3003/v1/orgs \
  -H "Authorization: Bearer bxxf3fxe6o36qko.wjpyj4ntacesigp57h5ikineypxcy2z2oidg3ixr"

实测回显(输出节选):

{"data":{"orgs":[{"orgId":"demo-org","name":"Demo Organization","subnet":"100.90.128.0/20","utilitySubnet":"100.96.128.0/20","createdAt":"2026-10-22T11:15:45.925Z","requireTwoFactor":null,"maxSessionLengthHours":null,"passwordExpiryDays":null,"settingsLogRetentionDaysRequest":7,"settingsLogRetentionDaysAccess":0,

八、资源与目标编排命令

资源(对外发布的域名/端口)与目标(真实后端服务)是 Pangolin 的核心对象。以下链路展示「建资源 → 挂目标 → 查资源」的完整命令。

8.1 创建 HTTP 资源

在 demo-org 下创建子域资源 app(domainId 取配置里 domains 段的键名,mode 必填):

curl -sk -b /tmp/pg-cookies.txt -X PUT https://127.0.0.1/api/v1/org/demo-org/resource \
  -H "Host: pangolin.example.com" -H "Content-Type: application/json" \
  -H "x-csrf-token: x-csrf-protection" \
  -d '{"name":"Docs App","subdomain":"app","domainId":"domain1","mode":"http"}'

实测回显(输出节选):

{"data":{"resourceId":2,"resourcePolicyId":null,"defaultResourcePolicyId":2,"resourceGuid":"c039e14b-1be3-4e34-9107-7eb7f8f5f3c4","orgId":"demo-org","niceId":"blue-scaphiopus-holbrookii","name":"Docs App","subdomain":"app","fullDomain":"app.example.com","domainId":"domain1","ssl":true,"blockAccess":false,"proxyPort":null,"sso":null,"emailWhitelistEnabled":null,"applyRules":null,"enabled":true,"stickySession":false,"loadBalancingStrategy":"wrr",

缺 mode 字段时的对照实测(1.25.1 强制要求显式模式):

{"data":null,"success":false,"error":true,"message":"mode is required when deprecated fields are not provided","status":400,"stack":null}

fullDomain":"app.example.com" 即控制面按 domains.domain1.base_domain 自动拼接的结果,Traefik 侧路由由控制面自动下发(无需手改 Traefik 配置)。

8.2 给资源挂目标

目标指向站点内网可达的真实服务(本实验以 192.168.1.10:80 演示,siteId 即 5.2 节在线站点的 ID):

curl -sk -b /tmp/pg-cookies.txt -X PUT https://127.0.0.1/api/v1/resource/2/target \
  -H "Host: pangolin.example.com" -H "Content-Type: application/json" \
  -H "x-csrf-token: x-csrf-protection" \
  -d '{"siteId":1,"ip":"192.168.1.10","port":80,"mode":"http"}'

实测回显(输出节选):

{"data":{"targetHealthCheckId":2,"targetId":2,"orgId":"demo-org","siteId":1,"name":"Resource Docs App - 192.168.1.10:80","hcEnabled":false,"hcPath":null,"hcScheme":null,"hcMode":null,"hcHostname":null,"hcPort":null,"hcInterval":null,"hcUnhealthyInterval":null,"hcTimeout":null,"hcHeaders":null,"hcFollowRedirects":null,"hcMethod":null,"hcStatus":null,"hcHealth":"unknown","hcTlsServerName":null,"hcHealthyThreshold":null,"hcUnhealthyThreshold":null,"resourceId":2,"providerId":null,"ip":"192.168.1.10","method":null,"port":80,"internalPort":53219,"enabled":true,

8.3 查询资源详情

curl -sk -b /tmp/pg-cookies.txt -H "Host: pangolin.example.com" https://127.0.0.1/api/v1/resource/2

实测回显(输出节选):

{"data":{"resourceId":2,"resourcePolicyId":null,"defaultResourcePolicyId":2,"resourceGuid":"c039e14b-1be3-4e34-9107-7eb7f8f5f3c4","orgId":"demo-org","niceId":"blue-scaphiopus-holbrookii","name":"Docs App","subdomain":"app","fullDomain":"app.example.com","domainId":"domain1","ssl":true,"blockAccess":false,

资源创建后默认策略为「需要认证」(未登录访问会被 Forward Auth 拦截,实测见部署指南 4.7 节)。匿名放行、白名单、访问规则等策略经 resourcePolicies 相关接口另行配置。

九、数据备份与恢复

9.1 备份对象与基线

Pangolin 的全部状态集中在单一目录树 /opt/pangolin/config/:核心是 SQLite 业务库 db/db.sqlite(账号、组织、站点、资源、目标、API Key、会话全在里面),其余为 config.yml、Traefik 配置与证书、gerbil 服务端私钥 key。实测基线:

ls -lh /opt/pangolin/config/db/db.sqlite

实测回显:

-rw-r--r-- 1 root root 1.1M Oct 22 11:52 /opt/pangolin/config/db/db.sqlite

9.2 备份操作

数据库文件级备份(建议先 docker compose stop pangolin 再拷贝,避免拷到写一半的库文件):

cp /opt/pangolin/config/db/db.sqlite /opt/pangolin/config/db/db.sqlite.bak-20261022
ls -lh /opt/pangolin/config/db/

实测回显:

total 2.1M
-rw-r--r-- 1 root root 1.1M Oct 22 11:52 db.sqlite
-rw-r--r-- 1 root root 1.1M Oct 22 11:52 db.sqlite.bak-20261022

整目录树打包(覆盖配置、证书、密钥,整机迁移用):

tar -czf /opt/pangolin/config-backup-20261022.tar.gz -C /opt/pangolin config
ls -lh /opt/pangolin/config-backup-20261022.tar.gz

实测回显:

-rw-r--r-- 1 root root 115K Oct 22 11:52 /opt/pangolin/config-backup-20261022.tar.gz

备份文件用校验和固化基线,恢复时核对:

md5sum /opt/pangolin/config/db/db.sqlite /opt/pangolin/config/db/db.sqlite.bak-20261022

实测回显:

464c223c28aecd7515ef1a9f15c4ccac  config/db/db.sqlite
55190e42b6c7058b19a6dd0607502100  config/db/db.sqlite.bak-20261022

两个校验和不同是正常的:备份点之后系统仍在写入(本实验备份后又创建过一把组织级 API Key)。

9.3 恢复实测(全流程)

把库文件回滚到备份点并验证业务可用。第一步停控制面:

cd /opt/pangolin && docker compose stop pangolin

实测回显:

 Container pangolin Stopped

第二步用备份覆盖(现库先挪走留存):

cd /opt/pangolin && mv config/db/db.sqlite config/db/db.sqlite.before-restore && \
  cp config/db/db.sqlite.bak-20261022 config/db/db.sqlite && \
  md5sum config/db/db.sqlite

实测回显:

55190e42b6c7058b19a6dd0607502100  config/db/db.sqlite

校验和与备份文件完全一致,覆盖到位。第三步重启并验证:

cd /opt/pangolin && docker compose start pangolin && sleep 20 && \
  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!"}'

实测回显:

 Container pangolin Started
{"data":null,"success":true,"error":false,"message":"Logged in successfully","status":200}
HTTP_STATUS:200

第四步验证数据完整性与还原点语义。备份点之前存在的资源完好:

curl -sk -b /tmp/pg-cookies.txt -H "Host: pangolin.example.com" https://127.0.0.1/api/v1/resource/2 | head -c 200

实测回显:

{"data":{"resourceId":2,"resourcePolicyId":null,"defaultResourcePolicyId":2,"resourceGuid":"c039e14b-1be3-4e34-9107-7eb7f8f5f3c4","orgId":"demo-org","niceId":"blue-scaphiopus-holbrookii","name":"Docs App",

而备份点之后才创建的组织 Key 已随回滚消失(Key 列表只剩备份时刻的 3 把):

keys: ['ops-key', 'd1-demo-key', 'c1-d1-key']

要点:恢复语义是「回到备份时刻」,之后的一切写入(含会话、Key、审计记录)都会消失;重建场景(down 后 up,见 3.3)数据不丢,因为 SQLite 库落在挂载目录里,重建不触碰它。

十、常见问题与错误速查

10.1 按 HTTP 状态码速查

状态码响应特征(实测原文)根因处置
401Username or password is incorrect口令或邮箱错误核对凭据;密码须满足大小写+数字+特殊字符策略
403{"error":"CSRF token missing or invalid"}写请求缺 x-csrf-token 头所有 POST/PUT/DELETE 统一带该头(值任意非空,如 x-csrf-protection)
403Key does not have permission perform this actionAPI Key 未授权对应动作经 actions 接口提交 actionIds 授权(见 7.2)
404404 page not found(纯文本)Traefik 无匹配路由:Host 头不对,或 badger 插件未加载带 -H "Host: pangolin.example.com";查 traefik 日志确认 Plugins loaded.(见 4.3)
429Rate limit exceeded. You can make 3 requests every 1 minute(s).触发 rate_limits.auth 限流等滚动窗口滑过;按需调大 max_requests(改值实验见配置参数详解篇 5.7)
400mode is required when deprecated fields are not provided创建资源缺 mode 字段补 "mode":"http" 等(见 8.1)
400Validation error: Invalid input: expected tuple, received undefined at "actionIds"; Unrecognized key: "actions"授权请求体字段名/类型错改用 {"actionIds":["<动作ID>"]}(见 7.2)

10.2 高频问题问答

Q:docker compose exec 进控制面执行 curl 报 No such container? A:服务名写错了。编排里服务名是 pangolin,写成其他名字会得到 No such container 报错;例如 docker compose exec pangolin grep -n log_level /app/config/config.yml,用 docker compose ps 核对 NAME 列。

Q:日志里搜不到 [debug] 行? A:级别名带终端着色控制符,方括号正则会失真,用固定串 grep -cF "mdebug" 统计(见 4.2);另外确认 app.log_level 改过且重启过。

Q:管理台改完配置立即验证没变化? A:config.yml 启动时读入,改后必须 docker compose restart pangolin;配置非法会导致循环重启,从日志 Invalid configuration file 行定位(实测过程见 《Pangolin 1.25.1 配置参数详解》 3.3 节)。

Q:Integration API 想从其他机器调用怎么办? A:3003 端口默认只在控制面服务内监听。确需远程调用时,在编排里为 pangolin 服务追加 3003 端口映射,并配合防火墙限制来源;凭据仍用 apiKeyId.apiSecret Bearer 串。

十一、参考链接