OpenProject 是一套开源项目管理平台,提供项目、工作包、看板、甘特图、时间跟踪、Wiki、会议和文档等功能。对需要自主管理项目数据、客户交付记录或研发流程的团队来说,VPS 自托管可以控制数据位置、插件版本和访问权限。
本文以 Ubuntu 24.04 LTS、Docker Compose、PostgreSQL 和 OpenProject 官方容器为例,说明如何部署 OpenProject,并配置域名 HTTPS、邮件、用户权限、后台任务、备份和升级。不同版本的环境变量可能有差异,生产部署应以对应版本的官方示例文件为准。
OpenProject 的 Web、后台任务、数据库和附件会共同消耗内存。搜索服务启用后,内存需求还会增加:
| 场景 | CPU | 内存 | 磁盘 | 建议 |
|---|---|---|---|---|
| 测试和演示 | 2 vCPU | 4 GB | 50 GB SSD | 少量用户,限制后台任务 |
| 小团队生产 | 4 vCPU | 8 GB | 100 GB NVMe | 独立备份,启用 SMTP |
| 多项目团队 | 8 vCPU | 16 GB+ | 200 GB NVMe+ | 数据库、附件和搜索分层 |
准备 pm.example.com,将 DNS A/AAAA 记录指向 VPS,只开放 SSH、HTTP 和 HTTPS。PostgreSQL、Redis、搜索服务和管理端口不要直接暴露公网。磁盘预算需要包含项目附件、导出文件、日志、数据库 WAL 和备份副本。部署前可先参考 VPS 配置怎么选。
sudo apt update
sudo apt install -y ca-certificates curl git openssl
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
newgrp docker
sudo mkdir -p /opt/openproject
sudo chown -R "$USER":"$USER" /opt/openproject
cd /opt/openproject
OpenProject 官方提供 Docker 镜像和 Compose 部署方式。生产环境不要使用 latest,应明确记录 OpenProject、PostgreSQL、Redis 和搜索服务的版本。把 compose 文件放入 Git 时,只提交不含密码的模板,实际 .env 放在服务器并设置 chmod 600。
git clone https://github.com/opf/openproject-docker-compose.git compose
cd compose
cp .env.example .env
chmod 600 .env
如果仓库结构随版本变化,以当前分支的 README 和示例环境文件为准,不要把旧版本变量直接套到新镜像上。
OpenProject 的业务数据保存在 PostgreSQL,附件保存在持久化卷或对象存储。常见环境变量包括数据库连接、站点 URL、缓存连接和应用密钥:
OPENPROJECT_HOST__NAME=pm.example.com
OPENPROJECT_HTTPS=true
OPENPROJECT_SECRET_KEY_BASE=replace-with-a-long-random-secret
DATABASE_URL=postgres://openproject:change-a-long-password@postgres/openproject
OPENPROJECT_RAILS__CACHE__STORE=memcache
使用随机值生成密钥和密码,不要把示例值用于生产:
openssl rand -hex 64
openssl rand -base64 48
启动前先检查 Compose 渲染结果和卷配置:
docker compose config
docker compose pull
docker compose up -d
docker compose ps
等待数据库迁移和初始化完成后,再查看 Web、后台 worker、cron 和 PostgreSQL 日志:
docker compose logs --tail=200 web
docker compose logs --tail=200 worker
docker compose logs --tail=200 cron
docker compose logs --tail=200 postgres
若容器持续重启,优先检查数据库 URL、密钥、主机名和 volume 权限,不要在没有备份的情况下删除数据库卷。
首次访问时完成管理员账号和组织信息设置。确认站点 URL 使用 HTTPS 域名后,再创建项目和角色。建议先建立一套模板项目,统一工作包类型、状态、优先级、版本、模块和通知规则。
一个实用的初始化顺序是:
- 创建组织、团队和项目,明确项目负责人。
- 配置工作包类型,例如任务、缺陷、里程碑、风险和变更。
- 创建状态流转和角色权限,限制谁可以关闭、删除或修改工时。
- 启用 Wiki、看板、甘特图、时间跟踪和文档模块。
- 建立项目模板,避免每个项目重复配置字段和权限。
不要让所有成员都拥有系统管理员权限。外部客户可以使用受限账号或只读角色,自动化脚本使用独立 API Token。
可以在宿主机使用 Nginx 终止 TLS,将请求转发到 OpenProject 容器的本地端口:
sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/openproject
server {
listen 80;
server_name pm.example.com;
client_max_body_size 100m;
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;
proxy_read_timeout 300s;
}
}
sudo ln -s /etc/nginx/sites-available/openproject /etc/nginx/sites-enabled/openproject
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d pm.example.com
HTTPS 配置、自动续期和 Docker 反向代理也可以使用 Caddy 自动 HTTPS 指南。如果出现重定向循环、CSRF 或链接生成 HTTP 地址,检查站点主机名、HTTPS 开关和 X-Forwarded-Proto。
OpenProject 的项目通知、评论提醒、密码重置和会议邀请依赖 SMTP。先在后台填写 SMTP 主机、端口、用户名、密码和发件人,再向管理员邮箱发送测试邮件。
同时配置 SPF、DKIM、DMARC 和反向 DNS,避免通知进入垃圾箱。邮件发送失败时检查容器时间、TLS 模式、出站 25 端口和 SMTP 服务商限制。
后台 worker 和 cron 负责异步通知、附件处理、报表和清理任务:
docker compose ps
docker compose logs --tail=200 worker
docker compose logs --tail=200 cron
如果工时汇总、邮件或导入任务长时间 pending,先确认 worker 没有 OOM,数据库没有锁等待,缓存服务连接正常。不要直接清空队列或 Redis,先保存日志和失败任务信息。
OpenProject 的权限以项目角色为核心。建议按“项目管理员、成员、报告者、只读访客”拆分,不要把全局权限授予所有项目成员。外部客户、供应商和审计人员应放在单独的角色中。
API 集成可以连接 Git、CI、工单系统或自建脚本:
- 为集成创建独立用户和 Token,限制到指定项目。
- Token 放在 CI 密钥管理中,不写进仓库和构建日志。
- 为自动化请求设置超时、重试和幂等规则。
- 定期轮换 Token,删除离职人员和旧集成账号。
如果通过 API 批量导入工作包,先在测试项目验证字段、状态和关联关系,再分批导入生产项目。
项目附件、会议录音和导出文件会持续增长。小团队可以先使用 Docker volume,附件较多时再迁移到兼容 S3 的对象存储。迁移前验证当前 OpenProject 版本的支持方式,并保留原始文件备份。
性能排查顺序建议是:
- 查看 Web、worker、PostgreSQL 的 CPU 和内存。
- 检查附件目录、数据库 WAL 和 Docker 日志是否占满磁盘。
- 分析慢查询和锁等待,再调整数据库参数。
- 最后再增加缓存、worker 并发或引入搜索服务。
不要只通过增加 worker 数量解决慢请求;内存不足时,更多 worker 反而会触发 OOM。
完整备份至少包括 PostgreSQL、项目附件、插件、.env、Compose 文件、密钥和当前镜像版本。示例数据库备份:
mkdir -p /opt/openproject/backups
docker compose exec -T postgres pg_dump -U openproject openproject | gzip > /opt/openproject/backups/openproject-$(date +%F).sql.gz
docker compose cp web:/var/openproject/assets /opt/openproject/backups/assets-$(date +%F)
cp .env docker-compose.yml /opt/openproject/backups/
docker compose config > /opt/openproject/backups/compose-$(date +%F).yaml
实际容器名和附件路径可能因官方模板版本不同而变化,先使用 docker compose ps 和 docker compose config 确认。备份完成后同步到另一台 VPS 或对象存储,对 .env 和密钥文件加密。
至少每月做一次隔离环境恢复演练,验证登录、项目、工作包、附件、邮件、API 和报表。可以参考 Restic、Rclone 与 Docker 数据库恢复演练。
OpenProject 升级可能包含数据库迁移和插件兼容性变化。正式升级前完成以下步骤:
- 记录 OpenProject、PostgreSQL、缓存服务和插件版本。
- 备份数据库、附件、配置和当前镜像 digest。
- 在测试环境升级,运行登录、工作包、看板、甘特图、附件和邮件回归测试。
- 生产环境开启维护窗口,拉取目标镜像并运行迁移。
- 验证后台任务和 API 后再恢复用户访问。
docker compose exec web bundle exec rake db:migrate
docker compose pull
docker compose up -d
docker compose logs --tail=200 web
具体迁移命令以当前官方镜像文档为准。若新版本已修改数据库结构,不要直接把旧镜像连回新数据库;应从备份恢复到隔离环境,确认可回滚后再处理生产切换。
检查 Nginx、Web 容器和 PostgreSQL 日志,确认 8080 端口监听、容器健康检查通过,域名没有指向旧 IP。长时间导出报表时适当增加 proxy_read_timeout。
检查站点主机名、HTTPS 开关、反向代理协议头和浏览器缓存。HTTP 与 HTTPS 混用时,Cookie 和重定向最容易出问题。
检查 Nginx client_max_body_size、应用上传限制、磁盘剩余空间和 volume 权限。对象存储配置错误时,先回退到本地目录验证应用本身。
检查 SMTP 日志、worker、cron、缓存服务和数据库连接。不要只重启 Web 容器,异步任务通常由独立 worker 处理。
- Web、worker、cron、PostgreSQL 和缓存服务均正常运行。
- HTTPS、站点 URL、反向代理头和大文件上传限制配置正确。
- 项目角色、外部用户、管理员 MFA 和 API Token 策略已验证。
- SMTP、密码重置、项目通知和定时任务测试成功。
- 数据库、附件、配置、插件和镜像版本已异地备份。
- 已完成隔离环境恢复演练,并记录恢复时间和缺失项。
- 升级前固定版本,升级后验证工作包、看板、甘特图、附件和 API。
OpenProject 自托管的核心不是启动几个容器,而是持续维护项目数据、附件、邮件、权限和升级回滚路径。先用一个项目模板建立稳定流程,再逐步接入 CI、API、对象存储和监控,VPS 才能成为团队可靠的项目协作平台。
延伸阅读:
