ERPNext 基于 Frappe Framework,集成了财务、采购、库存、销售、制造、人力资源和项目管理等模块。对希望掌握数据、避免 SaaS 按用户收费的团队来说,VPS 自托管是一个可控的方案。本文以 Ubuntu 24.04 LTS、Docker Compose 和官方 frappe_docker 为例,说明如何部署一个可维护的 ERPNext 生产环境。
ERPNext 同时运行 MariaDB、Redis、Web、WebSocket、多个后台队列和定时任务,内存比普通 WordPress 更敏感。可以按下面的起点规划:
| 场景 | CPU | 内存 | 磁盘 | 建议 |
|---|---|---|---|---|
| 个人测试、演示 | 2 vCPU | 4 GB | 60 GB SSD | 关闭不需要的 worker,限制并发 |
| 小团队生产 | 4 vCPU | 8 GB | 120 GB NVMe | 独立备份空间,启用 SMTP |
| 多公司或制造模块 | 8 vCPU+ | 16 GB+ | 200 GB NVMe+ | 将数据库、文件和队列拆分 |
2 GB VPS 通常只能用于短时体验。上线前至少预留 30% 内存和 25% 磁盘空间,并用 free -h、df -h、docker stats 持续观察资源。部署前可以先参考 VPS 配置与规格选择指南。
先准备域名,例如 erp.example.com,将 A/AAAA 记录指向 VPS。服务器只开放 SSH、HTTP 和 HTTPS,MariaDB 与 Redis 不要暴露到公网。
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/erpnext
sudo chown -R "$USER":"$USER" /opt/erpnext
cd /opt/erpnext
git clone https://github.com/frappe/frappe_docker.git
cd frappe_docker
不要直接跟随 main 分支。部署前查看稳定 tag 或记录当前 commit,升级时再由测试环境验证:
git fetch --tags
git tag --sort=-version:refname | head -n 10
git rev-parse HEAD
这样可以在升级出现问题时准确回退到原镜像和配置版本。
官方仓库会持续调整 compose 文件,建议以对应版本的 .env.example 为准,不要盲目复制旧教程。常见变量包括 ERPNext/Frappe 镜像版本、MariaDB 密码、管理员密码、站点名和对外端口:
cp .env.example .env
openssl rand -hex 32
nano .env
chmod 600 .env
示例值如下,生产环境必须替换所有密码:
ERPNEXT_VERSION=v15
DB_PASSWORD=change-a-long-database-password
MYSQL_ROOT_PASSWORD=change-a-long-root-password
ADMIN_PASSWORD=change-a-long-admin-password
SITE_NAME=erp.example.com
HTTP_PUBLISH_PORT=8080
在启动前检查最终配置,避免变量为空或端口冲突:
docker compose config
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=200 backend
典型服务包括 MariaDB、redis-cache、redis-queue、backend、frontend、websocket、queue-short、queue-default、queue-long 和 scheduler。数据库、Redis、backend 任一服务不健康,前台都可能表现为 502 或登录失败。
如果使用官方 create-site profile,优先按仓库当前文档执行:
docker compose --profile create-site run --rm create-site
需要手动创建时,可以在 backend 容器中执行 bench new-site。站点名必须与域名一致,否则 Host 路由和证书配置容易出错:
docker compose exec backend bench new-site erp.example.com \
--mariadb-root-password "$MYSQL_ROOT_PASSWORD" \
--admin-password "$ADMIN_PASSWORD"
docker compose exec backend bench --site all list-apps
docker compose exec backend bench --site erp.example.com migrate
完成后登录后台,确认 ERPNext 应用已经安装,再创建公司、会计科目、仓库和用户角色。管理员账号只用于初始化,日常操作应使用最小权限的用户。
如果前端容器发布在 127.0.0.1:8080,可以在宿主机使用 Caddy 终止 TLS:
sudo apt install -y caddy
sudo nano /etc/caddy/Caddyfile
erp.example.com {
encode gzip zstd
reverse_proxy 127.0.0.1:8080
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
}
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://erp.example.com
Caddy 会自动申请和续期证书。反向代理必须保留 Upgrade 请求,Caddy 的 reverse_proxy 默认支持 WebSocket;如果使用其他代理,实时通知失效时要优先检查 WebSocket、Host 和 X-Forwarded-Proto。
ERPNext 的密码重置、通知、工作流和报表依赖 SMTP 与队列。配置 SMTP 时同时设置 SPF、DKIM、DMARC 和正确的反向 DNS,先向内部邮箱发送测试邮件,再启用批量通知。
- 为财务、销售、库存和只读审计分别创建角色,避免所有人使用 Administrator。
- 为 API 集成创建独立用户和 API Key,限制访问范围并设置轮换日期。
- 为管理员启用 MFA,并限制后台登录来源或接入 VPN。
- 检查
queue-short、queue-default、queue-long和 scheduler 是否持续运行。
docker compose logs --tail=200 queue-short
docker compose logs --tail=200 queue-default
docker compose logs --tail=200 scheduler
docker compose exec backend bench --site erp.example.com show-pending-jobs
队列长期堆积通常与 Redis 连接、worker 内存不足、第三方 API 超时或某个失败任务反复重试有关。不要简单地删除 Redis 数据,先保存日志和任务上下文。
ERPNext 备份不能只保存数据库。sites 目录中的私有文件、附件、配置和站点密钥同样重要。先执行内置备份:
docker compose exec backend bench --site erp.example.com backup --with-files
docker compose exec backend find sites/erp.example.com/private/backups -maxdepth 1 -type f
将备份复制到宿主机,再同步到另一台 VPS 或对象存储。备份目录、.env、compose 文件和仓库 commit 都应纳入加密存储,但不要把 .env 提交到 Git:
mkdir -p /opt/erpnext/backups
docker cp "$(docker compose ps -q backend):/home/frappe/frappe-bench/sites/erp.example.com/private/backups" /opt/erpnext/backups/
cp .env /opt/erpnext/backups/
docker compose config > /opt/erpnext/backups/compose-$(date +%F).yaml
git rev-parse HEAD > /opt/erpnext/backups/frappe-docker-commit.txt
至少每月在临时 VPS 上做一次完整恢复演练,验证数据库、附件、登录、后台任务和邮件是否都能工作。备份策略也可以结合 Restic、Rclone 与 Docker 数据库的恢复演练。
升级前先记录当前 tag、镜像 digest、docker compose config、数据库备份和站点文件备份。建议在维护窗口执行:
git fetch --tags
git checkout <tested-tag-or-commit>
docker compose pull
docker compose up -d
docker compose exec backend bench --site all migrate
docker compose logs --tail=200 backend
迁移完成后检查登录、列表、打印格式、文件下载、邮件和队列。若新版本启动失败,先停止继续迁移,恢复上一个已验证的 commit 和镜像;数据库已经迁移时,不要直接把旧代码接回生产库,应使用备份恢复到隔离环境确认兼容性。
先看 docker compose ps,再检查 frontend、backend 日志和 Caddy 日志。确认 8080 端口确实监听,DNS 没有指向旧 IP,防火墙没有拦截 80/443。
检查 websocket 容器、代理的 Upgrade 头、HTTPS 协议和浏览器控制台。如果只在 HTTP 下测试,Mixed Content 也会让 WebSocket 失败。
用 docker stats --no-stream 判断是 MariaDB、backend 还是 worker 占用内存。先降低并发、清理无用镜像和日志,再考虑增加内存或把数据库拆到独立 VPS。慢查询应在 MariaDB 层面分析,不要盲目重启所有容器。
检查 SMTP 凭据、DNS 记录、scheduler 和对应队列日志,再查看待处理任务。若第三方 SMTP 拒绝连接,先确认出站 25 端口策略和服务商限制。
- 域名、HTTPS、WebSocket 和自动续期均已验证。
- MariaDB、Redis、backend、frontend、worker、scheduler 均为 healthy。
- Administrator 已启用 MFA,普通用户遵循最小权限。
- SMTP、SPF、DKIM、DMARC 测试通过。
- 数据库、附件、
sites、.env和版本信息已异地备份。 - 已在隔离环境完成一次恢复演练,并记录耗时和缺失项。
ERPNext 自托管的难点不在于执行一次 docker compose up,而在于版本固定、队列监控、权限控制和可验证的恢复流程。把这些运维环节做好,VPS 才能从一次性演示环境变成稳定的业务系统。
延伸阅读:
