博文

Penpot Docker 部署笔记(TNAS)

约 3 分钟

1. 环境信息

项目值
主机TNAS-0976(Tnas 2018.04.9,内核 5.15.59)
SSH端口 9222,用户 ZcAuto_1234(uid=0,admin 组)
Docker20.10.17(DockerEngine 套件,data-root /Volume1/@DockerData)
docker-composev2.12.2(独立二进制,非 CLI 插件)
存储/Volume1 约 3.7T,btrfs

关键路径

docker CLI : /Volume1/@apps/DockerEngine/dockerd/bin/docker
compose    : /Volume1/@apps/DockerEngine/dockerd/bin/docker-compose
daemon 配置: /Volume1/@apps/DockerEngine/conf/daemon.json
服务脚本  : /Volume1/@apps/DockerEngine/init.d/service
部署目录  : /Volume1/User/penpot/docker-compose.yaml

PATH 中无 docker,需用完整路径或先 PATH=/Volume1/@apps/DockerEngine/dockerd/bin:$PATH。 无 docker compose 子命令,用独立 docker-compose。

2. 登录

# Windows(plink,首次缓存 hostkey)
echo Y

注意:最初给的用户名 ZC_Auto1234 认证失败,实际可用用户名为 ZcAuto_1234。

3. 镜像加速(必须)

直连 registry-1.docker.io 超时。修改 daemon.json 增加 mirrors:

{
  "registry-mirrors"
    "
    "
    "
    "
  ],
  "log-driver"
  "data-root"
  "pidfile"
  "live-restore"
  "bip"
}

重启 Docker(用官方脚本,避免手动起 dockerd 缺 PATH 找不到 containerd/iptables):

pkill
sh

4. Compose 部署

/Volume1/User/penpot/docker-compose.yaml(基于官方 2.17 compose 精简,去掉 mcp 服务):

  • 服务:frontend / backend / exporter / postgres:15 / valkey:8.1 / mailcatcher

  • PENPOT_PUBLIC_URI: http://192.168.1.196:9001

  • PENPOT_SECRET_KEY:本地随机生成的 512bit base64(勿用默认占位)

  • flags:disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies disable-telemetry

  • 邮件走内置 mailcatcher(Web 界面 :1080),生产可换真实 SMTP

cd
PATH
PATH

远程传文件技巧

plink/heredoc 会吞双引号导致 JSON 损坏;pscp/scp 不稳。可靠做法:本地 base64 → plink 回显解码写入。

$b64
# 远端: echo <b64> | base64 -d > /Volume1/User/penpot/docker-compose.yaml

5. 部署结果

docker-compose ps(全部 running):

容器状态端口
penpot-frontendrunning0.0.0.0:9001→8080
penpot-backendrunning—
penpot-exporterrunning—
penpot-postgresrunning (healthy)5432(内部)
penpot-valkeyrunning (healthy)6379(内部)
penpot-mailcatchrunning1080(邮件预览)

验证:

  • 本机浏览器 http://192.168.1.196:9001/ → HTTP 200(约 268KB)

  • backend 日志:DB migrations 正常执行至完成

6. 常用运维命令

# SSH 后
export
cd

docker-compose
docker-compose
docker-compose
docker-compose
docker-compose

数据卷:penpot_penpot_postgres_v15、penpot_penpot_assets(compose down 不会删,需 -v 才删)。

7. 踩坑记录

  1. 用户名:ZC_Auto1234 拒绝,ZcAuto_1234 成功。

  2. docker 不在 PATH:TNAS 套件路径在 /Volume1/@apps/DockerEngine/dockerd/bin/。

  3. Docker Hub 超时:必须配 registry-mirrors 并用官方 service 脚本重启。

  4. 手动起 dockerd 失败:containerd/iptables 不在 PATH → 用 init.d/service restart。

  5. heredoc 吞引号:plink 下写 JSON/YAML 用 base64 传输。

  6. postgres 首启 unhealthy:initdb 期间 healthcheck 失败属正常,init 完成后自动 healthy,再 up -d 拉起 backend/frontend。

  7. 无 curl/wget:NAS 上用 python -c urllib 或从宿主机 Invoke-WebRequest 验证。

  8. 异地经 Easytier 打开 10.126.126.x:9001 黑屏(2026-09-24):见第 9 节。

8. 后续建议

  • 注册首个管理员账号后,按需在 flags 加 disable-registration 关闭开放注册

  • 对外暴露时配 HTTPS(compose 内有 Traefik 注释模板)并启用 enable-secure-session-cookies

  • 密钥/密码入库 KeePass;本笔记不记录明文密码

  • 定期备份数据卷 penpot_penpot_postgres_v15

9. 异地(Easytier)访问与黑屏修复

现象

异地电脑加入 Easytier 网络后,打开 http://10.126.126.1:9001:页面能出(静态资源相对路径可加载),但黑屏。

原因

前端 js/config.js 由后端环境变量生成:

var
  • 静态 HTML/CSS/JS 用相对路径 → 挂在 10.126.126.x 上也能下到

  • 接口 / WebSocket / 重定向按 PENPOT_PUBLIC_URI 回连 192.168.1.196:9001

  • 异地客户端若没有 192.168.1.0/24 路由 → 回连失败 → 黑屏

  • 另:Easytier 虚拟 IP 是 DHCP,docker rm/重启后可能从 .1 变成 .3,不要把 10.126.126.1 当固定入口

修法(已实施:子网代理 + 固定 URL)

  1. NAS Easytier 容器加 -n 192.126... → 实际为 -n 192.168.1.0/24,重建容器(见 Easytier 笔记第 3 节)。

  2. 确认路由:docker exec easytier easytier-cli route 本节点 proxy_cidrs 含 192.168.1.0/24。

  3. 异地一律打开:http://192.168.1.196:9001(与 PENPOT_PUBLIC_URI 一致),不要用 10.126.126.x:9001。

# NAS 上重建 easytier(在原 run 命令基础上加 -n)
docker
docker
  --restart
  easytier/easytier:latest
  --network-name
  -p
  -n

异地仍黑屏时排查

检查命令/位置
客户端有无 192.168.1.0/24 路由Windows: route print;Easytier GUI 路由页
子网代理是否同步NAS: easytier-cli route 看 proxy_cidrs
是否还在用 10.126.126.x URL改开 http://192.168.1.196:9001
PUBLIC_URI 是否被改过http://192.168.1.196:9001/js/config.js
虚拟网卡防火墙Easytier 文档:子网代理需关闭 tun 网卡上的防火墙拦截

不推荐的改法

  • 把 PENPOT_PUBLIC_URI 改成 http://10.126.126.1:9001:虚拟 IP 会变,且局域网直连 192.168.1.196 的用户会反过来黑屏。

  • 双 URI:Penpot 只支持单个 PENPOT_PUBLIC_URI,无法同时完美匹配两个入口;子网代理后统一 LAN IP 即可。

相关阅读

← 返回博文列表