farmOS 4.0.9 Docker Compose 部署指南
Docker Compose 部署 farmOS 4.0.9 官方镜像与 PostgreSQL 17 数据库栈:部署步骤、持久化与销毁重建恢复闭环实测、环境变量与文件挂载、drush 运维命令与常见问题。
farmOS 4.0.9 Docker Compose 部署指南
目标:用 Docker Compose 在 Linux 服务器上部署 farmOS 4.0.9 官方镜像与 PostgreSQL 17 数据库栈,完成 Web 安装向导、数据持久化验证与「销毁重建数据不丢」的恢复闭环,并整理日常运维命令。全部命令与回显均在 Docker 29.8.0 + Compose v5.5.1 环境实测采集(实测日期:2026-10-23)。
一、环境信息
- 操作系统:Linux 服务器(Ubuntu 22.04 系实测)
- Docker:29.8.0(
docker --version),Compose 插件:v5.5.1(docker compose version) - farmOS 镜像:
farmos/farmos:4.0.9(1.58GB,官方 Docker Hub 镜像,内含 Apache + PHP 8.4.27 + 完整代码库) - 数据库镜像:
postgres:17(640MB,官方 compose 示例同款) - 部署目录:
/opt/farmos-stack/(compose 项目名farmos-409-stack) - 端口:宿主机 80 → farmOS Web(生产建议前置反向代理做 TLS,见官方 Requirements)
- 镜像内置验证(容器内实测):
php -v回显PHP 8.4.27 (cli) (built: Oct 21 2026 15:53:29) (NTS),与 4.0.9 更新日志"官方镜像升级 PHP 8.4.27 修复 CVE-2026-109618/109619"一致
💡 说明:官方镜像已封装 farmOS 全部 Web 依赖(PHP 8.4 + BCMath/EXIF/GEOS/SimpleXML + Apache),这是官方推荐的托管方式——不需要像裸机部署那样自己编译 GEOS 扩展(对比见《Ubuntu 22.04 安装 farmOS 4.0.9 指南》3.2.3 节)。
二、镜像选型说明
官方镜像发布在 Docker Hub:hub.docker.com/r/farmos/farmos,官方部署文档明确两点:
- 必须锁版本:镜像标签用具体版本号(本文
4.0.9),官方明示"不建议使用 latest 标签,因为更新需要手动步骤"(数据库更新不会自动执行); - 镜像与预打包 tarball 同源:官方 tarball 就是从镜像内
/opt/drupal打包而来,两条路线代码一致。
镜像内关键路径:代码库 /opt/drupal,文档根 /opt/drupal/web,站点数据 /opt/drupal/web/sites(Web 安装向导与上传文件都落在这里),OAuth2 密钥目录 /opt/drupal/keys。进程用户 www-data(UID/GID 33),bind mount 的宿主目录需要归属 33:33。
数据库选型:官方 docker-compose.production.yml 示例配 PostgreSQL 17(farmOS 官方推荐的数据库)。也可换成外部 MySQL/MariaDB(farmOS 支持 MySQL 8.0+/MariaDB 10.6+),或在示例栈外自备数据库并删除 db 服务。
三、前置条件
- 服务器已安装 Docker 29+ 与 Compose 插件(
docker compose version可用); - 服务器 80 端口空闲(或改映射端口);
- 能访问 Docker Hub 拉取镜像(内网环境可走代理或私有镜像仓库);
- 磁盘余量 ≥ 5GB(镜像 2.2GB + 数据库与站点数据)。
四、部署步骤
4.1 准备目录与 compose 文件
mkdir -p /opt/farmos-stack/{sites,keys,db}
cd /opt/farmos-stack
# 官方要求:sites 目录属主必须是容器内 www-data(UID 33),否则安装器写不进 settings.php
sudo chown 33:33 sites keys
创建 docker-compose.yml(源自官方 docker/docker-compose.production.yml,把版本号改为 4.0.9 并加显式项目名与 php.ini 挂载):
name: farmos-409-stack
services:
db:
image: postgres:17
volumes:
- './db:/var/lib/postgresql/data'
environment:
# 生产环境请改成强密码,并按需更换用户/库名
POSTGRES_USER: farm
POSTGRES_PASSWORD: farm
POSTGRES_DB: farm
restart: always
www:
depends_on:
- db
image: farmos/farmos:4.0.9
volumes:
- './sites:/opt/drupal/web/sites'
- './keys:/opt/drupal/keys'
- './php.ini:/usr/local/etc/php/conf.d/farmos.ini'
ports:
- '80:80'
restart: always
同目录创建 php.ini(上传上限按需调整,官方 Customizing PHP 一节的做法):
upload_max_filesize = 50M
post_max_size = 50M
逐项说明:db 服务用 bind mount ./db 持久化 PGDATA;www 服务把 sites(设置+上传文件)与 keys(OAuth2 密钥)持久化到宿主,php.ini 以只读方式挂进 PHP 的 conf.d;depends_on 保证数据库先起;restart: always 让两服务开机自启并崩溃自愈。
4.2 启动栈
docker compose up -d
实测回显:
Container farmos-409-stack-db-1 Started
Container farmos-409-stack-www-1 Starting
Container farmos-409-stack-www-1 Started
确认状态(实测回显):
docker compose ps
NAME STATUS
farmos-409-stack-db-1 Up 12 seconds
farmos-409-stack-www-1 Up 12 seconds
镜像体积核对(docker compose images 实测回显节选):
farmos-409-stack-db-1 postgres 17 linux/amd64 640MB
farmos-409-stack-www-1 farmos/farmos 4.0.9 linux/amd64 1.58GB
4.3 Web 安装向导
浏览器访问 http://<服务器IP>/,自动 302 到安装器(实测:curl -s -o /dev/null -w "%{http_code} %{redirect_url}" http://localhost/ 回显 302 /core/install.php)。farmOS 只有英文界面与 farm Profile,语言/Profile 步自动跳过,直达 Database configuration 页。按 compose 里的环境变量填:
| 字段 | 取值 | 对应 compose 配置 |
|---|---|---|
| 驱动 | PostgreSQL | — |
| Database name | farm | POSTGRES_DB: farm |
| Database username | farm | POSTGRES_USER: farm |
| Database password | farm | POSTGRES_PASSWORD: farm |
| Host | db | compose 服务名(容器 DNS) |
| Port | 5432 | PG 默认端口 |
⚠️ 注意:Host 一定要填
db(compose 服务名),不能填 127.0.0.1——farmOS 在自己的容器里,127.0.0.1 指向它自己。填错会报数据库连接失败。
点击 Save and continue 后进入 Installing farmOS 批量安装(数分钟),随后是 Configure site 页:站点名(实测 farmOS Compose)、站点邮箱 admin@example.com、管理员账号 admin / 密码 q1w2e3r4、时区 UTC,提交后 302 回首页。
4.4 部署结果验证
验证 1:Web 可用。 登录后首页标题(实测):
curl -s http://localhost/ | grep -o "<title>[^<]*"
<title>Dashboard | farmOS Compose
验证 2:站点数据已落宿主目录。 站点关键文件出现在宿主 sites/ 下(实测 ls sites/default/):
default.services.yml
default.settings.php
files
settings.php
settings.php 内含安装向导写入的数据库连接(host 为 db),这是后续恢复与升级的命根子。
验证 3:容器内 drush 可用。
docker compose exec www drush status --root=/opt/drupal | grep -E "Drupal version|DB driver|Database "
实测回显:
Drupal version : 11.3.19
DB driver : pgsql
Database : Connected
五、数据持久化说明
farmOS 容器分两类数据,持久化策略完全不同:
| 数据 | 容器内路径 | 持久化方式 | 丢失后果 |
|---|---|---|---|
| 站点设置与上传文件 | /opt/drupal/web/sites | bind mount → 宿主 ./sites | settings.php 丢失=重新安装向导 |
| OAuth2 密钥 | /opt/drupal/keys | bind mount → 宿主 ./keys | 需重新生成密钥对 |
| 数据库 | /var/lib/postgresql/data | bind mount → 宿主 ./db | 全部业务数据丢失 |
| 代码库 | /opt/drupal(sites/keys 除外) | 不持久化(跟随镜像版本) | 无需持久化,升级即换镜像 |
官方文档强调:容器里 /opt/drupal/web/sites 之外的一切在容器销毁后都会被镜像内容替换——这正是「代码跟随镜像、数据跟随宿主」的设计。
恢复闭环实测:把整个栈销毁再重建(模拟服务器重启/容器升级):
docker compose down
docker compose up -d
sleep 15
docker compose exec www drush status --root=/opt/drupal | grep -E "DB driver|Database "
实测回显:
Container farmos-409-stack_default Removed
Container farmos-409-stack-www-1 Started
DB driver : pgsql
Database : Connected
再从宿主访问登录页(实测回显):
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8147/user/login
200
站点直接可用、无需重跑安装向导——sites 与 db 两个 bind mount 在容器销毁后完整保留了设置与数据,恢复闭环通过。
六、环境变量表
| 变量 | 位置 | 示例值 | 说明 |
|---|---|---|---|
| POSTGRES_USER | db 服务 | farm | 数据库超级用户名,与向导 Database username 一致 |
| POSTGRES_PASSWORD | db 服务 | farm | 数据库密码,生产必改强口令 |
| POSTGRES_DB | db 服务 | farm | 初始化创建的库名,与向导 Database name 一致 |
| depends_on | www 服务 | db | 启动顺序:先库后站 |
💡 说明:farmOS 官方镜像本身没有业务环境变量——数据库连接、站点配置全部由 Web 安装向导写入
sites/default/settings.php(随 bind mount 持久化)。镜像的可定制点只有 PHP 运行参数(挂 php.ini)与站点/密钥目录(挂 sites/keys)。
七、配置参数说明与文件挂载
./sites:/opt/drupal/web/sites:必挂。含default/settings.php(数据库连接、hash_salt、config 同步目录)、default/files/(公开上传文件)、private/(私有文件,需按官方文档在 settings.php 加file_private_path后创建);./keys:/opt/drupal/keys:启用 farmOS API OAuth2 时需要。在后台 Configuration > Web Services > Consumers 的 Settings 页把公私钥路径设为../keys/public.key与../keys/private.key并生成,宿主目录属主需为 33:33;./php.ini:/usr/local/etc/php/conf.d/farmos.ini:PHP 运行参数覆盖。本文挂载的 50M 上传限制实测生效(容器内php -i | grep upload_max_filesize回显upload_max_filesize => 50M => 50M,post_max_size => 50M => 50M);./db:/var/lib/postgresql/data:PGDATA。注意 PG 17 的 data 目录挂载后由 postgres 用户管理,不要手工改属主。
八、等价 docker run 命令
不使用 Compose 时的官方等价单容器命令(仅 Web,不含数据库):
mkdir sites && sudo chown 33:33 sites
docker run --rm -p 80:80 -v "${PWD}/sites:/opt/drupal/web/sites" farmos/farmos:4.0.9
与 Compose 栈的差异:docker run 单容器没有数据库、没有 restart 策略、没有 keys/php.ini 挂载,只适合临时体验。生产一律用 Compose 栈或自备外部数据库。
九、常用运维命令
# 状态查看
docker compose ps
# 日志跟踪(数据库与 Web 分开看)
docker compose logs -f www
docker compose logs -f db
# 重启(数据不受影响)
docker compose restart
# 停止并移除容器与网络(bind mount 数据保留)
docker compose down
# 修改 compose 文件或镜像版本后应用
docker compose up -d
farmOS 侧命令统一用 docker compose exec www drush ...(实测可用):
# 例行维护(建议宿主 crontab 每周触发一次)
docker compose exec www drush cron
# 清缓存
docker compose exec www drush cr
# 数据库更新(升级后必跑)
docker compose exec www drush updatedb -y
# 生成管理员一次性登录链接(实测输出示例)
docker compose exec www drush uli --uid=1
drush uli 实测回显:
http://default/user/reset/1/1792731154/mtdX6t1NZHFQTRw2pJFgHcUchY-ZeXsy-WDTZu0tBII/login
⚠️ 注意:链接里的主机名是
default(drush 在容器内感知不到对外域名),把域名部分替换成你的站点地址即可使用;一次性链接有时效。
备份与升级:
# 备份:数据库导出 + 站点目录打包
docker compose exec db pg_dump -U farm farm > farm-$(date +%F).sql
tar czf farm-sites-$(date +%F).tar.gz sites keys
# 升级:改镜像版本号(如 farmos/farmos:4.0.10)后
docker compose down
docker compose up -d
docker compose exec www drush updatedb -y
docker compose exec www drush cr
升级要点(官方 Updating 一节):down 彻底移除旧容器,up -d 用新镜像重建;sites 挂载目录里的 settings.php 与文件全部保留;升级后必须跑 drush updatedb 与 drush cr。
十、常见问题(FAQ)
Q1:ghcr.io 能不能拉 farmOS?
本文实测 docker pull ghcr.io/farmos/farmos:4.0.9 返回 denied——farmOS 官方镜像发布在 Docker Hub(farmos/farmos),官方文档引用的也是 Docker Hub 地址,请勿从 ghcr 拉取。
Q2:启动后 sites 目录写入失败 / 向导无法写 settings.php?
bind mount 的宿主目录属主不对。官方要求 sites 目录属主为 UID 33(容器内 www-data):sudo chown 33:33 sites 后重启容器再试。
Q3:向导数据库步骤报连接失败?
按顺序排查:Host 是否填的 db(服务名);compose 里 POSTGRES_PASSWORD 与向导密码是否一致;db 容器是否真的 Ready(docker compose logs db 看到 database system is ready to accept connections 再刷新向导)。
Q4:容器重建后又回到了安装向导?
sites 挂载丢失或被清空(settings.php 没了)。检查 compose 文件 volumes 段与宿主目录内容;只要 ./sites/default/settings.php 还在,重建容器就不会触发重装。
Q5:down 之后数据会丢吗?
不会。down 只删容器与网络,三个 bind mount(sites/keys/db)都在宿主目录里;实测 down → up 后站点直接可用(见第五节恢复闭环)。会丢数据的操作只有 rm -rf ./sites ./db 这类删目录行为。
Q6:cron 邮件报错 "Unable to send email"?
与裸机部署同理:栈内没有 MTA。drush cron 的维护任务本身已执行,邮件发送失败仅写入日志。需要通知能力时接入 SMTP 模块或外置邮件服务。
十一、参考链接
- 官方 Docker 部署文档:https://farmos.org/hosting/docker
- 官方 compose 示例:https://github.com/farmOS/farmOS/blob/4.x/docker/docker-compose.production.yml
- Docker Hub 镜像页:https://hub.docker.com/r/farmos/farmos
- 服务器要求:https://farmos.org/hosting/requirements
- 安装步骤(向导部分):https://farmos.org/hosting/install
- 更新指南:https://farmos.org/hosting/update
- GitHub Releases:https://github.com/farmOS/farmOS/releases