Pangolin 1.25.1 常用命令与运维操作详解
以实测命令与回显详解 Pangolin 1.25.1 日常运维操作——服务状态管理、日志诊断、健康核验、管理员会话、API Key 与 Integration API 调用、资源编排命令、数据备份恢复与错误速查。
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)
二、前置条件
- 已按部署指南完成三服务栈部署与管理员初始化,栈处于健康状态(本篇 3.1 有状态核验命令与回显)。
- 管理员可登录(本篇 6.1 提供登录命令与回显;后续章节大量操作依赖登录会话)。
- 操作均通过两条通道完成:服务器本机的
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 状态码速查
| 状态码 | 响应特征(实测原文) | 根因 | 处置 |
|---|---|---|---|
| 401 | Username or password is incorrect | 口令或邮箱错误 | 核对凭据;密码须满足大小写+数字+特殊字符策略 |
| 403 | {"error":"CSRF token missing or invalid"} | 写请求缺 x-csrf-token 头 | 所有 POST/PUT/DELETE 统一带该头(值任意非空,如 x-csrf-protection) |
| 403 | Key does not have permission perform this action | API Key 未授权对应动作 | 经 actions 接口提交 actionIds 授权(见 7.2) |
| 404 | 404 page not found(纯文本) | Traefik 无匹配路由:Host 头不对,或 badger 插件未加载 | 带 -H "Host: pangolin.example.com";查 traefik 日志确认 Plugins loaded.(见 4.3) |
| 429 | Rate limit exceeded. You can make 3 requests every 1 minute(s). | 触发 rate_limits.auth 限流 | 等滚动窗口滑过;按需调大 max_requests(改值实验见配置参数详解篇 5.7) |
| 400 | mode is required when deprecated fields are not provided | 创建资源缺 mode 字段 | 补 "mode":"http" 等(见 8.1) |
| 400 | Validation 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 串。
十一、参考链接
- 《Pangolin 1.24.0 介绍与选型指南》——组件定位、架构与选型对比
- 《Pangolin 1.25.1 Docker Compose 部署指南》——三服务栈从零部署、Newt 站点接入与持久化说明
- 《Pangolin 1.25.1 配置参数详解》——config.yml 全字段、默认值与三组改值实验
- Pangolin 官方文档:https://docs.pangolin.net/
- Pangolin 源码仓库:https://github.com/fosrl/pangolin