十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Penpot私有化部署实战:基于Docker Compose从零搭建UI设计协作平台

Penpot私有化部署实战:基于Docker Compose从零搭建UI设计协作平台 Penpot 这个项目关注开源设计工具的人应该不陌生。简单说它就是一套开源免费的 UI/UX 设计协作平台主要用来做界面原型、矢量设计和团队协作很多人直接拿它当 Figma 的替代方案来用。不过相比直接用官方云服务自托管 Penpot 意味着你把整个设计资产、用户数据和协作环境都掌握在自己手里对于有数据安全要求、需要内网部署或者想省下订阅费用的团队来说这条路的吸引力很大。这篇文章我打算完整走一遍 Penpot 私有化部署过程重点放在 Docker 配置上。为什么要用 Docker因为它能帮你把数据库、后端服务、前端页面、对象存储这些组件一次性编排起来不用手动装一堆依赖也不会把宿主机环境搞得一团糟。整个部署流程走顺之后确实可以在几分钟内把服务拉起来但前提是前置准备做得够仔细。我会把我自己实操中踩过的坑、排查过的报错一并写出来打算部署的朋友可以直接照着做。1. 自托管 Penpot 的整体思路与选型考量1.1 为什么选择自托管而不是直接用官方服务先聊清楚一个核心问题既然 Penpot 官方提供了在线服务注册账号就能用为什么还要费劲自托管我个人的判断标准有三条。第一是数据资产的控制权。设计文件是团队的核心资产如果放在第三方云服务上虽然方便但数据出境、服务商政策变动、账号被封禁等风险始终存在。自托管之后PostgreSQL 数据库、上传的图片资源和团队资产全部落在你自己的服务器上备份、迁移、审计都自己说了算。第二是团队协作的封闭性。很多企业内部项目对访问范围有严格要求内网部署可以让整个设计系统只在公司网络内访问避免和外部用户混在一起。对于需要跟研发部门共用一个 GitLab、内部 Wiki 等基础设施的团队来说把设计工具也纳入统一的内部系统管理起来更顺手。第三是成本。Penpot 虽然是开源软件但如果你不想自己维护服务器用官方云服务是按成员数付费的。对于一个小团队来说这可能不是大钱但拉长到一年、三年自托管只需要一台配置还行的服务器边际成本几乎为零。当然自托管不是没有代价你得付出维护精力比如升级版本、处理故障、做备份这些软性成本要在决策之前想清楚。1.2 为什么用 Docker Compose 来部署Penpot 官方实际上提供了多种部署方式包括直接跑二进制、用 Docker 单容器、用 Docker Compose 编排全家桶。我最初也想图省事用单容器结果发现它把 PostgreSQL 也塞在同一个容器里数据卷管理和升级都别扭生产环境根本不敢这么用。真正推荐的是 Docker Compose 方式。原因很直接Penpot 的服务是由多个组件构成的包括负责前端页面的 penpot-frontend、处理业务逻辑的 penpot-backend、导出图片用的 penpot-exporter、执行数据库迁移的 penpot-migrations以及作为核心存储的 PostgreSQL可选组件还有用于存放上传资源的对象存储。如果手动一个个装光是版本对齐就能耗掉半天。Compose 文件把这些组件之间的网络、依赖关系、数据卷都定义好了一条命令就能把整个环境拉起来。对于有 K8s 经验的朋友可能会问为什么不直接上 Helm Chart。说实话如果团队已经有标准的 Kubernetes 平台用 Helm 部署是合理的但如果只是为了自托管一个设计工具专门维护一套 K8s 集群有点杀鸡用牛刀。Docker Compose 的运维心智负担最低单机部署足够支撑几十人团队的设计协作场景了。1.3 适合谁来参考这份部署方案如果你属于下面几类人这份方案应该对你有直接帮助小团队的技术负责人想在公司内网搭一套设计协作平台又不想花太多精力维护自由职业者或独立开发者想拥有一个完全属于自己的设计工具同时练手 Docker 部署之前用过 Docker 部署其他开源系统比如 GitLab、Nextcloud对容器编排有一定概念但还没碰过 Penpot 的被 Figma 的订阅费用或网络环境搞得头疼想试试开源方案的 UI 设计师我默认你对 Linux 命令和 Docker 有最基础的认识比如知道docker ps是查看容器列表就够了。如果你连 Docker 都还没装好也没关系下一节我会专门讲环境准备。2. 部署前的准备工作与环境规划2.1 服务器配置怎么选资源要多少Penpot 对服务器硬件的要求并不算高但也不能太寒酸。我实际测试下来2 核 4G 内存的云主机跑一个三四人的小团队日常使用是够用的如果团队人数超过十人或者需要频繁并行导出大文件建议直接上 4 核 8G。磁盘方面系统盘 40G 勉强够但考虑到设计文件和 PostgreSQL 数据会持续增长建议至少预留 100G。操作系统方面Ubuntu 22.04 LTS 或者 Debian 12 是我用起来最顺手的组合。CentOS 7 之类的老系统也能跑但 Docker 新版对内核版本有要求旧系统会遇到各种兼容性问题不推荐给自己找麻烦。网络环境上如果你是云服务器记得在安全组里放行 80 和 443 端口如果要用 HTTPS以及你自定义的 SSH 端口。我遇到过不少人部署完发现页面打不开排查了半天最后发现是云平台安全组没放行端口这种低级错误最耽误时间。2.2 Docker 与 Compose 环境检查这一步非常关键很多部署失败都源于 Docker 环境本身有问题。在开始之前先依次执行下面几个命令确认环境状态。# 查看 Docker 版本 docker --version # 查看 Docker Compose 插件版本 docker compose version # 查看 Docker 服务运行状态systemd 系统 systemctl status docker --no-pager如果你是从零开始安装 DockerUbuntu 和 Debian 上我建议直接用官方脚本然后配置好镜像加速再启动服务。# 安装 Docker官方脚本方式 curl -fsSL https://get.docker.com | bash # 将当前用户加入 docker 组避免每次都要 sudo sudo usermod -aG docker $USER # 重新登录终端使组权限生效然后启动并设置开机自启 sudo systemctl enable --now docker这里要特别提醒一件事国内网络环境下从 Docker Hub 拉取镜像可能会很慢甚至超时。解决办法是在/etc/docker/daemon.json中配置镜像加速器然后重启 Docker 让配置生效。{ registry-mirrors: [https://docker.m.daocloud.io] }sudo systemctl restart docker配置完成后用docker info查看 Registry Mirrors 是否生效。这一步省下来的时间比后面任何优化都值。2.3 域名、端口与目录规划Penpot 部署前最好先确定一个访问域名。如果你打算用 IP 直连技术上可行但后续如果要开 HTTPS、配置邮件服务、接入 SSO没有域名会处处碰壁。我自己习惯用一个子域名比如design.example.com专门指给 Penpot 用。端口规划上也有一点讲究。Penpot 默认通过 80 端口对外提供 HTTP 服务如果你服务器上已经跑了 Nginx 或其他 Web 服务就要提前想好是让 Penpot 直接占用 80还是通过反向代理转发。我的建议是如果服务器上已经有一套 Nginx 统一管理入口就不要让 Penpot 直接绑 80而是保留给 Nginx再由 Nginx 通过内部网络转发到 Penpot 的容器端口。目录规划方面我会在/opt/penpot下放部署文件数据卷由 Docker 自动管理备份时再把数据卷导出来。也可以直接在 Compose 文件里把 PostgreSQL 和资产目录挂载到宿主机的/data/penpot下这样备份更直观。两种方式各有优劣后面讲备份的时候我会细说。3. Docker Compose 部署实操从拉取到启动3.1 获取部署文件并调整配置结构Penpot 官方维护了一个部署仓库里面带了一份可以直接用的docker-compose.yaml和.env模板。获取方式很简单直接克隆或者下载压缩包都行。# 创建工作目录 mkdir -p /opt/penpot cd /opt/penpot # 克隆官方部署仓库 git clone https://github.com/penpot/penpot-deploy .如果你的服务器访问 GitHub 有困难也可以直接下载压缩包然后手动上传解压效果一样。拿到文件之后不要急着启动先把目录结构看清楚。建议只保留docker-compose.yaml、.env和docker目录里面是 Caddy 等组件的配置其余文档可以留着当参考。3.2 核心环境变量逐项解读.env文件是整个部署的关键里面几乎每个变量都会影响服务的实际行为。我挑几个最核心的逐个讲清楚。PENPOT_PUBLIC_URI是 Penpot 对外访问的基础地址必须填成你实际访问用的地址比如https://design.example.com。这个变量会写入前端页面和后端生成链接的逻辑里如果填的是localhost即使你用域名打开页面页面里生成的邀请链接、资源地址也会指向localhost导致功能异常。这是我见过的最常见的配置错误之一。# 必改项你的访问域名 PENPOT_PUBLIC_URIhttps://design.example.comPENPOT_FLAGS是功能开关用英文逗号分隔。官方默认会启用一些遥测和统计功能如果你在意隐私可以显式关掉。PENPOT_FLAGSdisable-telemetry,disable-registration这里我解释一下disable-registration如果你只想让团队成员通过邀请链接加入就加上这个开关关闭公开注册防止陌生人来你的实例上乱注册账号。如果是个人自用加上它也没问题管理员可以手动创建用户并发送邀请。PostgreSQL 相关变量也需要改尤其是密码。默认密码太简单放在公网上很容易被扫描爆破。POSTGRES_DBpenpot POSTGRES_USERpenpot POSTGRES_PASSWORD这里换成一个强密码PENPOT_HTTP_SERVER_PORT是容器内部的服务端口一般不需要改。但如果你对外映射端口时想避开 80可以在docker-compose.yaml的ports部分调整宿主机端口映射比如改成8080:80。3.3 启动服务并验证运行状态配置文件改好之后就可以启动了。cd /opt/penpot docker compose up -d第一次启动时Docker 会拉取所有镜像这个过程取决于你的网络速度和镜像加速是否生效。镜像下载完成后容器会依次启动Penpot 会自动执行数据库初始化脚本创建表结构和初始数据。查看容器状态docker compose ps正常情况下你会看到以下几个容器都在运行或者处于 healthy 状态penpot-frontend前端静态页面penpot-backend后端 API 服务penpot-exporter用于导出图片的辅助服务penpot-migrations数据库迁移任务跑完就可能退出penpot-postgres存储业务数据的数据库penpot-caddy默认自带的 Web 服务器和自动 HTTPS如果所有容器都起来了打开浏览器访问你的域名应该能看到 Penpot 的登录界面。首次部署时系统会自动创建一个管理员账号登录凭据可以在容器日志里找到。docker compose logs backend | grep -i admin看到管理员密码之后立刻登录后台修改默认密码这是非常重要的安全步骤。3.4 为什么我说 5 分钟能搞定很多第一次接触的人看到这么多个容器会觉得复杂但实际操作下来在镜像已经拉取成功的前提下从执行docker compose up -d到页面能打开真的只需要大约三到五分钟。因为 Compose 已经帮我们把容器间的网络依赖、数据卷挂载、启动顺序都定义好了你要做的只是填几个环境变量。当然这 5 分钟的前提是前置准备做得充分Docker 环境正常、镜像加速配置好、域名解析生效、安全组放行端口。这些准备花的时间不在 5 分钟之内但它们是部署能否顺利的关键。4. 生产环境的核心配置从“能跑”到“好用”4.1 反向代理与 HTTPS 配置Penpot 的官方 Compose 文件默认带了一个 Caddy 容器它的好处是能自动申请和续期 HTTPS 证书配置极简。如果PENPOT_PUBLIC_URI填的是https://design.example.comCaddy 会自动去申请证书完全不用手动干预。但我遇到过一个特殊情况服务器在公网 IP 后面还有一层负载均衡器比如云厂商的 SLB证书申请会失败因为 ACME 验证请求到达不了容器。这种情况下建议关掉 Caddy 的自动 TLS改用外部 Nginx 做 HTTPS 终止。如果你希望用自己已有的 Nginx 反代Compofile 里ports部分把 Caddy 端口改掉然后再加一个 Nginx 配置片段。下面是一个最小可用的反代配置server { listen 80; server_name design.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name design.example.com; ssl_certificate /etc/letsencrypt/live/design.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/design.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }这里我把 Penpot 的宿主机映射端口定为 8080Nginx 再把请求转发过去。用 Nginx 的好处是证书管理可以集成到现有的 ACME 脚本体系里统一运维。4.2 邮件服务配置与用户邀请机制Penpot 的团队协作依赖邮件邀请。如果不配置 SMTP系统默认不会真正发送邮件你只能绕道去数据库里手动创建用户这在多人协作场景下是完全不可接受的。邮件配置也是放在.env里核心参数如下PENPOT_SMTP_ENABLEDtrue PENPOT_SMTP_DEFAULT_FROMPenpot penpotexample.com PENPOT_SMTP_HOSTsmtp.example.com PENPOT_SMTP_PORT465 PENPOT_SMTP_USERNAMEpenpotexample.com PENPOT_SMTP_PASSWORD邮箱的SMTP授权码 PENPOT_SMTP_SSLtrue我建议用 465 或 587 端口对应 SSL 和 STARTTLS具体看邮件服务商的说明。比如你用企业邮箱一般是在邮箱设置里开启 SMTP 服务然后生成专用授权码而不是直接用登录密码。配置完成后重启后端容器让配置生效。然后到后台团队管理页面添加成员时输入对方邮箱系统就会发送一封邀请邮件。如果你在日志里看到邮件发送失败的报错先去检查 SMTP 端口是否被服务器防火墙封了这是很常见的问题。4.3 数据卷、备份与灾难恢复方案自托管服务最怕的就是数据丢失Penpot 的数据主要是两块PostgreSQL 里存业务数据用户、项目、设计文件的结构信息等对象存储里存上传的图片和资源文件。备份必须同时覆盖这两部分。我常用的备份方式是用pg_dump在容器内执行逻辑备份# 备份数据库到宿主机 docker compose exec -T postgres pg_dump -U penpot penpot /backup/penpot_$(date %F).sql恢复时则把备份文件导入一个新启动的数据库容器cat /backup/penpot_2025-01-01.sql | docker compose exec -T postgres psql -U penpot -d penpot如果你用的是 Compose 里的默认数据卷方式对象存储的内容都在 Docker 管理的 volume 里。备份时可以用下面这种方式打包docker run --rm -v penpot-assets:/data -v /backup:/backup alpine tar czf /backup/penpot_assets_$(date %F).tar.gz -C /data .恢复时反过来解压到对应 volume 即可。这里我想额外说一句数据库逻辑备份只能覆盖表结构里的数据文件资源必须单独备份。我踩过一次坑只备了数据库结果服务器磁盘故障导致上传的图片资源全没了恢复出来的设计文件全是裂图教训很深刻。建议至少每天做一次全量备份并把备份文件同步到异地存储。4.4 外部对象存储接入默认的 Compose 方案里Penpot 会把上传的图片资源存放在一个本地 volume 挂载的目录里由后端服务直接读写。这种方式在单机部署时没什么问题但如果你后续要扩容到多台服务器或者希望资源跟应用分离应该接入 S3 兼容的对象存储。Penpot 支持 S3 协议配置方式如下PENPOT_STORAGE_BACKENDs3 PENPOT_STORAGE_S3_BUCKETpenpot-assets PENPOT_STORAGE_S3_REGIONus-east-1 PENPOT_STORAGE_S3_ENDPOINThttps://s3.example.com PENPOT_STORAGE_S3_ACCESS_KEY_ID你的AccessKey PENPOT_STORAGE_S3_SECRET_ACCESS_KEY你的SecretKey如果你没有专门的对象存储服务也可以用 MinIO 在自家服务器上搭一个兼容 S3 的存储服务。反正都是 Docker 起一个容器的事跟 Penpot 部署在同一台机器上数据卷仍然受你控制。不过这里有一个需要注意的兼容性点如果你原来是用本地文件存储跑的后来改成 S3历史已经上传的图片不会自动迁移需要你手动把 volume 里的文件拷到新存储里或者干脆在切换之前做好全量备份然后重新上传一遍。这个设计上略微有点坑提前知道就好。4.5 版本升级的正确姿势Penpot 的迭代速度不算慢官方基本每月都会有新版本。升级其实不复杂但要讲究顺序不能直接在跑着的环境上乱来。我的升级流程是这样的cd /opt/penpot # 1. 先备份数据库和资源文件前面讲过方法 # 2. 拉取最新的镜像 docker compose pull # 3. 重新创建容器 docker compose up -d # 4. 查看迁移任务是否成功 docker compose logs migrations --tail 50升级过程中migrations 容器会执行数据库结构变更这个过程不要中断。如果迁移失败日志里会明确报错。遇到这种情况我的第一反应是检查是不是跳了多个大版本升级如果是老版本直接升到最新可能要把迁移脚本分步执行而不是硬跳。5. 常见问题排查与避坑经验5.1 容器反复重启或直接退出部署完后第一件事是看一眼docker compose ps如果某个容器状态是 Restarting多半是配置问题。我遇到过的几种典型情况penpot-backend起不来日志里报数据库连接失败。先确认POSTGRES_*环境变量跟 Compose 文件里的数据库服务配置是否一致还要确认 PostgreSQL 容器是否已经初始化完成。有时数据库容器正在初始化后端比它先启动就连不上等数据库 ready 后后端会自动重连。端口冲突导致容器起不来。执行docker compose logs查看具体报错如果是bind: address already in use说明宿主机上 80 端口已经被其他进程占了需要改端口映射或者停掉原先的服务。migrations 容器一直退出导致其他服务无法初始化。这种情况直接把迁移容器单独跑一遍看详细日志docker compose run --rm migrations如果迁移脚本报错了提 issue 之前先把完整日志存下来里面通常有精确到行号的错误信息。5.2 页面能打开但登录不了或接口报错页面能打开说明前端容器和 Caddy 这一链路是正常的接口报错问题通常出在后端或者数据库。一个很常见的坑是PENPOT_PUBLIC_URI配错了协议或端口。比如你配置的是http://design.example.com:8080但实际访问时用的是https://design.example.com后端生成的重定向地址就会对不上导致回调失败。解决办法就是让这个地址和用户实际访问的地址完全一致。另外检查后端日志里有没有明显的异常堆栈docker compose logs backend --tail 100最常见的其实是数据库连接数或存储空间问题。PostgreSQL 默认连接数目对一个小团队来说足够但如果你改过配置或者同一台服务器还跑了其他业务连接数被占满也会导致登录失败。5.3 上传文件失败或图片加载不出来如果后端配置了外部对象存储但桶权限没配对上传文件时就会 500。可以先用 AWS CLI 或 MinIO 客户端测一下能不能向桶里正常写入文件确认存储端没问题再查 Penpot 配置。如果用的是默认本地存储文件上传失败大概率是数据卷权限问题。容器里的进程是以某个固定 UID 运行的宿主机挂载目录的所有者如果不对就写不进去。解决办法是给目录设置正确的属主# 比如容器内进程 UID 是 1000宿主机目录改成同样属主 sudo chown -R 1000:1000 /data/penpot这里如果不想手动配权限可以让 Docker 帮你在容器内创建卷避免宿主机目录所有权的问题。5.4 大团队使用时的性能优化建议如果你的团队规模比较大几十人同时在线部署完基础版本之后有几件事值得做。给 Penpot 单独配一台服务器不要跟 GitLab、数据库等业务混在一起避免资源抢占。PostgreSQL 的shared_buffers和work_mem适当调大。修改方式是在 Compose 文件里给 postgres 容器加command参数或者挂载自定义的postgresql.conf。前端静态资源可以交给 CDN 缓存减少源站压力。Penpot 前端是纯静态资源缓存策略调整一下收益很明显。定时清理没用的旧项目和过期邀请控制数据库膨胀。5.5 Docker Desktop 环境下的坑如果你是在本地 Windows/macOS 环境用 Docker Desktop 做测试部署有几件事要注意。Docker Desktop 在 Windows 上依赖 WSL2 后端。如果启动时报虚拟化未开启或 WSL 内核版本过旧先去 BIOS 开启虚拟化再执行wsl --update更新内核。这个问题在热搜词里出现次数很多确实是新手最容易卡住的一关。本地测试时.env里的PENPOT_PUBLIC_URI直接填http://localhost即可不需要域名。但如果要在局域网里让其他同事访问要填宿主机 IP并且注意防火墙要放行端口。另外Docker Desktop 默认资源限制比较保守如果本地测试时 Penpot 很卡可以去 Docker Desktop 的 Settings 里把内存调到 4G 以上否则多个容器同时跑容易内存不足。写在最后的一点个人体会Penpot 这套自托管方案我在自己服务器上跑了有小半年了。刚开始部署时确实有些波折但真的把流程理顺之后日常维护几乎不费什么心。团队里几个设计师用下来的反馈是基本的矢量编辑、组件复用、多人实时协作都够用跟商业工具相比短板主要在一些生态插件和精细交互上但对于绝大多数轻量设计场景完全能胜任。如果你以前只用过商业化设计工具的云服务第一次接触自托管可能会觉得有点不适应特别是要亲手配置环境变量、处理反向代理、管理数据库这些“运维杂活”。但换个角度想一旦你把部署流程吃透了以后不管是在公司服务器上搭内网服务还是给其他开源系统做私有化部署这套思路和排错方法都是通用的也算是一举多得。最后再分享一个小技巧部署完之后建议把.env文件里所有改过的配置项都记录到一个本地文档里特别是数据库密码、SMTP 授权码这些变数。等三个月后你要升级版本或者迁移服务器这份记录能帮你省下大量回忆时间。补一句题外话如果你想在团队里推这套方案先自己把“从空白服务器到能正常登录”的完整流程跑两遍再拿给同事用效果会好很多真的。
返回列表