Froxlor 2.3.16 Docker Compose 部署指南
Froxlor 2.3.16 官方稳定版 Docker Compose 自建部署全记录:php:8.2-apache 基底+官方 tarball 自建面板镜像、MariaDB 10.11 双服务栈、install.json 无人值守安装、config-services 服务接管、命名卷持久化与 down/up 后 Apache 配置丢失排障实录(Ubuntu 22.04 + Docker 29.9.2 实测,2026-11-02)。
Froxlor 2.3.16 Docker Compose 部署指南
目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 从零构建并部署 Froxlor 2.3.16 虚拟主机管理面板(官方稳定版无生产容器镜像,本篇给出完整自建方案),完成无人值守安装、服务接管配置、HTTP 访问登录、数据持久化与 down/up 重建后的配置恢复全链路实测。已在 Ubuntu 22.04(x86_64)+ Docker Engine 29.9.2 + Compose v5.6.1 实测通过。
Froxlor 是开源的服务器管理/虚拟主机托管面板(定位与选型见《Froxlor 介绍与选型指南》)。它的官方安装形态是"Debian/Ubuntu apt 包 + Web 安装向导",不提供生产可用的容器镜像(官方 froxlor/container 仓库 README 明确标注尚未推荐生产使用,且内容是 froxlor 3 开发线),因此容器化部署的全部工作量在于:把官方 tarball 安装路径翻译成一个可复现的 Dockerfile + Compose 栈。本篇即完成这件事,并把它固化为一条 docker compose up 命令。
一、环境信息
| 项目 | 取值 |
|---|---|
| 服务器操作系统 | Ubuntu 22.04(x86_64) |
| Docker Engine / Compose | 29.9.2 / v5.6.1(docker compose 子命令) |
| Froxlor 版本 | 2.3.16(GitHub Release 资产 froxlor-2.3.16.tar.gz,2026-10-20 发布,4.3 MB,GPL-2.0) |
| 面板镜像 | froxlor/panel:2.3.16(自建,基底 php:8.2-apache,Debian 13 trixie 底,PHP 8.2.35 + Apache 2.4.69) |
| 数据库镜像 | mariadb:10.11(实测运行版本 10.11.19-MariaDB-ubu2204) |
| 项目目录 | /opt/froxlor-2.3.16/(compose.yml、init-db.sql、install.json、docker/Dockerfile、docker/entrypoint.sh、docker/froxlor-2.3.16.tar.gz) |
| Compose 项目名 | froxlor-2.3.16-stack |
| 服务名 / 主机名 | db + froxlor / panel.froxlor.test |
| 监听 | 面板 HTTP 80(服务内)→ 宿主发布 8141 |
| 内部网络 | user-defined bridge froxlor-2316-stack_froxlor-net(compose 把项目名 froxlor-2.3.16-stack 归一化为资源前缀 froxlor-2316-stack_),网段 10.89.68.0/24,面板固定地址 10.89.68.10 |
| 数据库持久化 | 命名卷 froxlor-2316-stack_db-data → /var/lib/mysql |
| 面板目录持久化 | 命名卷 froxlor-2316-stack_froxlor-data → /var/www/html/froxlor |
| 演示账号 | 面板 admin / q1w2e3r4;数据库 root / q1w2e3r4,安装专用全权限账号 froxroot / q1w2e3r4 |
💡 说明:Froxlor 面板自身把全部业务数据(设置、客户、域名、邮箱、任务队列)存在 MySQL/MariaDB 里,安装目录只保存代码与数据库连接凭据(
lib/userdata.inc.php),所以持久化的主角是数据库卷;服务内端口保持 80(Apache 默认),宿主端口显式规划为 8141 避开冲突。
二、镜像选型说明
Froxlor 官方稳定版 2.3.x 不发容器镜像(实查 2026-11-02:GitHub Releases 仅有源码 tarball,官方容器仓库 froxlor/container 为 froxlor 3 开发线且标注 not yet recommended for production use)。因此镜像只能自建。自建方案里真正要选的是"基底 + 软件来源":
| 选型项 | 本方案取值 | 理由 |
|---|---|---|
| 基底镜像 | php:8.2-apache | 官方要求 PHP 7.4–8.5 + Apache/Nginx;该基底自带 Apache 2.4 与官方 PHP 扩展安装工具链(docker-php-ext-install),Debian 底与面板的 apt 服务接管逻辑同源 |
| Froxlor 本体 | 官方 Release tarball froxlor-2.3.16.tar.gz 解包到 /var/www/html/froxlor | 与官方 tarball 手工安装路径(docs.froxlor.org Installation)完全一致,版本可控、可校验 sha256 |
| PHP 扩展 | gd intl mbstring gmp bcmath pdo_mysql | 官方需求清单 session/ctype/xml/filter/posix/mbstring/curl/gmp/json 中,基底已内置大部分,pdo_mysql 连 MariaDB、gd/intl 为面板推荐项,一并补齐 |
| 系统工具 | apt 安装 cron、mariadb-client、unzip | cron 承载面板每 5 分钟的任务作业(Froxlor 的核心执行层);mariadb-client 提供 mysql/mysqldump 供运维与面板 MySQL 功能使用 |
⚠️ 注意:
php:8.2-apache标签当前指向 Debian 13(trixie) 基底,而安装向导的发行版模板线最新只到 bookworm(Debian 12),这会让面板记下distro_mismatch=1(详见 11.4 节与froxlor:config-diff对比实录);面板本体功能不受影响,若追求完全一致可把基底固定到 Debian 12 对应的镜像标签/digest 重建。
💡 技术拓展:面板类软件容器化的三条常见路线——
路线 做法 取舍 官方镜像直用 docker run官方发布镜像最省事,但 Froxlor 稳定版没有;官方容器仓库是 froxlor 3 开发线 自建 tarball 镜像 官方 Release 包 + PHP 官方基底(本方案) 与官方手工安装文档同源、可复现、版本可控 apt 包 + 系统内跑 官方推荐的裸机路线 不属于容器化,见 B1 类安装文档 本方案采用"自建 tarball 镜像",因为它是稳定版 2.3.x 唯一与官方安装文档保持路径一致性的容器路线。
三、前置条件
- 服务器已安装 Docker Engine 与 Compose v2+ 插件:
docker --version && docker compose version
回显(实测):
Docker version 29.9.2, build a82e528
Docker Compose version v5.6.1
- 宿主 8141 端口空闲(
ss -ltn | grep ':8141 '无输出); - 服务器可直连 Docker Hub 与 GitHub Releases(构建期拉基底镜像、下载官方包);
- 磁盘余量 ≥ 2GB(构建后面板镜像实测 1.02GB,见 4.7 节回显,另有 mariadb:10.11 基底约 100MB 级)。
四、部署步骤
4.1 建立项目目录
所有部署文件集中在一个目录,compose 的相对路径构建上下文与文件挂载都以它为根:
mkdir -p /opt/froxlor-2.3.16/docker
cd /opt/froxlor-2.3.16
目录规划:
/opt/froxlor-2.3.16/
├── compose.yml # 编排:构建、端口、网络、持久化
├── init-db.sql # 数据库首启脚本(建全权限安装账号)
├── install.json # 无人值守安装参数
└── docker/
├── Dockerfile # 自建面板镜像定义
├── entrypoint.sh # 首启拉起 cron 守护进程
└── froxlor-2.3.16.tar.gz # 官方 Release 包(构建上下文)
4.2 下载官方包并校验
wget -P docker/ https://github.com/Froxlor/Froxlor/releases/download/2.3.16/froxlor-2.3.16.tar.gz
sha256sum docker/froxlor-2.3.16.tar.gz
回显(实测,与官方 Release 页公布值一致):
316a68957778861bfb7b15cac7d2828f57ea1fac71c2d9091839a2b7b698177d froxlor-2.3.16.tar.gz
包体 4510029 字节(约 4.3 MB)。
4.3 编写 Dockerfile
/opt/froxlor-2.3.16/docker/Dockerfile 全文如下(对应官方 tarball 安装文档的三步:装依赖 → 解包 → 属主):
FROM php:8.2-apache
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng-dev libjpeg62-turbo-dev libfreetype6-dev \
libonig-dev libgmp-dev libicu-dev \
cron mariadb-client unzip less vim-tiny \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j"$(nproc)" gd intl mbstring gmp bcmath pdo_mysql \
&& rm -rf /var/lib/apt/lists/*
COPY froxlor-2.3.16.tar.gz /tmp/
RUN tar xzf /tmp/froxlor-2.3.16.tar.gz -C /var/www/html/ \
&& rm /tmp/froxlor-2.3.16.tar.gz \
&& chown -R www-data:www-data /var/www/html/froxlor
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["apache2-foreground"]
逐段说明:
- apt 依赖层:
libpng/libjpeg/libfreetype/libonig/libgmp/libicu是 gd/mbstring/gmp/intl 扩展的编译期依赖;cron供面板写/etc/cron.d/froxlor后由系统调度执行任务作业;mariadb-client供面板与运维连数据库。 docker-php-ext-install:pdo_mysql是面板连数据库的硬需求(Froxlor\Database走 PDO),gd intl mbstring gmp bcmath覆盖官方需求与推荐清单。- 解包路径
/var/www/html/froxlor:与官方 tarball 文档一致(文档站示例即tar xzf ... -C /var/www/html/),面板 URL 因此是http://<服务器>/froxlor/形态;基底php:8.2-apache的 Apache DocumentRoot 为/var/www/html,安装完成后由面板自己生成 vhost 把 DocumentRoot 改指到/var/www/html/froxlor(见 4.10)。 CMD ["apache2-foreground"]:Apache 以 1 号进程前台运行,docker stop能正确传 SIGTERM。
4.4 编写 entrypoint.sh
面板的任务体系依赖系统 cron 守护进程,入口脚本负责把它拉起来:
#!/bin/bash
# start system cron daemon (froxlor writes /etc/cron.d/froxlor during installation)
service cron start >/dev/null 2>&1 || cron
exec "$@"
exec "$@" 把后续命令(apache2-foreground)升级为 1 号进程,cron 作为后台守护随之常驻。
4.5 编写 init-db.sql
Froxlor 安装向导需要一个能对 froxlor 库建库建表、下发权限的账号。官方镜像的 root 口令只存在于环境变量,面板配置里又不建议直接用 root,所以首启脚本额外建一个全权限账号 froxroot:
CREATE USER IF NOT EXISTS 'froxroot'@'%' IDENTIFIED BY 'q1w2e3r4';
GRANT ALL PRIVILEGES ON *.* TO 'froxroot'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
💡 说明:
GRANT ... WITH GRANT OPTION是必需的——面板安装时要为业务账号froxlor授权froxlor库全部权限,还要为每个客户建 MySQL 数据库/账号,没有转授权限装不下去。生产环境可按最小权限原则收敛为具体库的GRANT ALL ON froxlor.*+ 客户库模板权限。
4.6 编写 compose.yml
/opt/froxlor-2.3.16/compose.yml 全文:
name: froxlor-2.3.16-stack
services:
db:
image: mariadb:10.11
container_name: froxlor-2.3.16-db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: q1w2e3r4
volumes:
- db-data:/var/lib/mysql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
networks:
- froxlor-net
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 30s
interval: 10s
timeout: 5s
retries: 5
froxlor:
build: ./docker
image: froxlor/panel:2.3.16
container_name: froxlor-2.3.16-panel
hostname: panel.froxlor.test
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "8141:80"
volumes:
- froxlor-data:/var/www/html/froxlor
networks:
froxlor-net:
ipv4_address: 10.89.68.10
networks:
froxlor-net:
driver: bridge
ipam:
config:
- subnet: 10.89.68.0/24
gateway: 10.89.68.1
volumes:
db-data:
froxlor-data:
字段解读:
| 字段 | 取值 | 作用 |
|---|---|---|
name | froxlor-2.3.16-stack | 显式项目名,down 只影响本组件资源 |
db.healthcheck + depends_on.condition | service_healthy | 面板安装连库前确保 MariaDB 就绪(首启建库慢,直接 started 会撞"连接被拒") |
./init-db.sql:ro | docker-entrypoint-initdb.d | 仅数据库首次初始化时执行,卷已有数据则跳过 |
hostname | panel.froxlor.test | 安装参数 servername 与面板 system.hostname 的取值 |
ports | 8141:80 | 宿主 8141 → 服务内 80 |
froxlor-data 卷 | /var/www/html/froxlor | 持久化面板代码目录 + 安装凭据 lib/userdata.inc.php(见第五章) |
ipv4_address | 10.89.68.10 | 必须固定——面板把 IP 写进 vhost 文件名与 system.ipaddress,IP 漂移会导致站点配置全失效 |
⚠️ 注意:面板生成的 Apache vhost 只监听 10.89.68.10:80(安装参数
serveripv4的值),不监听 0.0.0.0。宿主 8141 经 Docker DNAT 转址后能命中;但在服务内部直接curl 127.0.0.1会落到默认站点返回 403,属预期(见 11.6 节)。
4.7 构建镜像
cd /opt/froxlor-2.3.16
docker compose build
构建输出节选(实测首尾):
Image froxlor/panel:2.3.16 Building
#1 [internal] load local bake definitions
#1 reading from stdin 540B done
#1 DONE 0.0s
#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 813B done
#2 DONE 0.0s
#3 [internal] load metadata for docker.io/library/php:8.2-apache
#3 DONE 0.3s
...
#9 [2/6] RUN apt-get update && apt-get install -y --no-install-recommends ... CACHED
#10 [5/6] COPY entrypoint.sh /usr/local/bin/entrypoint.sh CACHED
#11 [6/6] RUN chmod +x /usr/local/bin/entrypoint.sh CACHED
#12 exporting to image
(上面为二次构建全层命中缓存的回显;首次构建 #9 扩展编译层约 2–3 分钟。)核对产物:
docker images froxlor/panel
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
froxlor/panel:2.3.16 0592cfb2a308 1.02GB 249MB U
(Docker 29 的 docker images 以 DISK USAGE/CONTENT SIZE 两列展示共享与独占占用;基底 php:8.2-apache 共享层占大头,本镜像独占内容 249MB。)
4.8 启动服务栈
docker compose up -d
回显(实测):
Network froxlor-2316-stack_froxlor-net Creating
Network froxlor-2316-stack_froxlor-net Created
Container froxlor-2.3.16-db Creating
Container froxlor-2.3.16-db Created
Container froxlor-2.3.16-panel Creating
Container froxlor-2.3.16-panel Created
Container froxlor-2.3.16-db Starting
Container froxlor-2.3.16-db Started
Container froxlor-2.3.16-db Waiting
Container froxlor-2.3.16-db Healthy
Container froxlor-2.3.16-panel Starting
Container froxlor-2.3.16-panel Started
查看运行状态与端口发布:
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
froxlor-2.3.16-db mariadb:10.11 "docker-entrypoint.s…" db 11 seconds ago Up 11 seconds (healthy) 3306/tcp
froxlor-2.3.16-panel froxlor/panel:2.3.16 "/usr/local/bin/entr…" froxlor 11 seconds ago Up 6 seconds 0.0.0.0:8141->80/tcp, [::]:8141->80/tcp
db 达到 (healthy) 后 froxlor 才启动,depends_on 条件生效。
4.9 无人值守安装(install.json)
此时面板尚未安装:访问 http://<服务器>:8141/ 会跳向 /froxlor/install/ Web 向导。本方案改走官方 CLI 的无人值守通道——froxlor:install 接受一个 JSON 参数文件(字段与 Web 向导一一对应,可先用 froxlor:install -p 打印官方示例模板)。
/opt/froxlor-2.3.16/install.json 全文:
{
"mysql_host": "db",
"mysql_ssl_ca_file": "",
"mysql_ssl_verify_server_certificate": "0",
"mysql_root_user": "froxroot",
"mysql_root_pass": "q1w2e3r4",
"mysql_unprivileged_user": "froxlor",
"mysql_unprivileged_pass": "q1w2e3r4",
"mysql_database": "froxlor",
"mysql_force_create": "1",
"admin_name": "Administrator",
"admin_user": "admin",
"admin_pass": "q1w2e3r4",
"admin_pass_confirm": "q1w2e3r4",
"admin_email": "admin@froxlor.test",
"use_admin_email_as_sender": "1",
"sender_email": "admin@froxlor.test",
"distribution": "bookworm",
"serveripv4": "10.89.68.10",
"serveripv6": "",
"servername": "panel.froxlor.test",
"use_ssl": "0",
"webserver": "apache24",
"webserver_backend": "mod_php",
"httpuser": "www-data",
"httpgroup": "www-data",
"activate_newsfeed": "0",
"manual_config": "0"
}
关键项:mysql_host: db(compose 服务名即 DNS 名)、distribution: bookworm(发行版模板线,基底实为 trixie 会记 mismatch,见 11.4)、serveripv4: 10.89.68.10(与固定 IP 一致)、webserver_backend: mod_php(面板自身用 mod_php 跑,客户站点后续可切 PHP-FPM)、manual_config: 0(允许安装器生成 config-services 命令)。
执行安装(先把文件复制进服务):
docker compose cp install.json froxlor:/tmp/install.json
docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli froxlor:install /tmp/install.json
输出节选(实测首尾):
Froxlor installation
====================
[INFO] Running unattended installation
System check
------------
[INFO] Your system is running with PHP 8.2.35
[WARNING] The following php extensions could not be found but are recommended
zip
gnupg
Create database and user
------------------------
Setting field 'mysql_host' to value 'db'
Setting field 'mysql_root_user' to value 'froxroot'
...
Setting field 'mysql_database' to value 'froxlor'
Setting field 'mysql_force_create' to value '1'
Let's create the main administrator user.
-----------------------------------------
Setting field 'admin_user' to value 'admin'
...
Details about your server
-------------------------
Setting field 'distribution' to value 'bookworm'
Setting field 'serveripv4' to value '10.89.68.10'
Setting field 'servername' to value 'panel.froxlor.test'
Setting field 'webserver' to value 'apache24'
Setting field 'webserver_backend' to value 'mod_php'
[OK] Run the following command to finish the installation:
/var/www/html/froxlor/bin/froxlor-cli froxlor:config-services -a
'{"distro":"bookworm","dns":"x","http":"apache24","smtp":"postfix_dovecot"
,"mail":"dovecot_postfix2","antispam":"rspamd","ftp":"proftpd","system":["
cron","libnssextrausers","logrotate","goaccess"]}' --yes-to-all
Creating missing certificate /etc/ssl/froxlor_selfsigned.pem
安装器建好 froxlor 库(276 行初始设置、40+ 张表)、面板管理员 admin,并把数据库连接凭据写入 /var/www/html/froxlor/lib/userdata.inc.php(实测权限 -rw------- www-data www-data 303)。zip/gnupg 两条 WARNING 属推荐扩展缺失,不阻塞安装(影响见 11.5 节)。
4.10 服务接管配置(config-services)
上一步末尾打印的命令就是 Froxlor"安装即接管"的入口:按所选发行版模板安装并配置下游服务(Apache、邮件、反垃圾、FTP、系统项),会覆盖既有配置(自动备份)。执行:
docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli \
froxlor:config-services -a '{"distro":"bookworm","dns":"x","http":"apache24","smtp":"postfix_dovecot","mail":"dovecot_postfix2","antispam":"rspamd","ftp":"proftpd","system":["cron","libnssextrausers","logrotate","goaccess"]}' --yes-to-all
输出节选(实测首尾):
Creating missing certificate /etc/ssl/froxlor_selfsigned.pem
--- Configuring: HTTP ---
Configuring 'apache24'
Installing required packages
apache2 is already the newest version (2.4.69-1~deb13u1).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
--- Configuring: DNS ---
Skipping DNS configuration as desired
--- Configuring: SMTP ---
Configuring 'postfix_dovecot'
Installing required packages
E: Unable to locate package postfix
E: Unable to locate package postfix-mysql
...
--- Configuring: MAIL ---
Configuring 'dovecot_postfix2'
E: Unable to locate package dovecot-imapd
...
--- Configuring: ANTISPAM ---
Configuring 'rspamd'
W: OpenPGP signature verification failed: https://rspamd.com/apt-stable bookworm InRelease: Sub-process /usr/bin/sqv returned an error code (1), error message is: Missing key 3FA347D5E599BE4595CA2576FFA232EDBF21E25E, which is needed to verify signature.
Installing required packages
The following NEW packages will be installed:
... rspamd ...
0 upgraded, 14 newly installed, 0 to remove and 1 not up
...
Setting up rspamd (3.12.1-1) ...
--- Configuring: FTP ---
Configuring 'proftpd'
...
Setting up proftpd-core (1.3.8.c+dfsg-4+deb13u3) ...
Creating file "/etc/proftpd/proftpd.conf"
...
sh: 1: /usr/bin/php: not found
All services have been configured
逐项解读与排障:
- HTTP:apache2 已在基底内,直接生成配置接管。
- SMTP/MAIL 报
Unable to locate package postfix/dovecot-*:本镜像未预装邮件栈、apt 索引已清理,包解析失败后配置写入报一串file_put_contents ... No such file or directory。仅做 Web 托管可安全忽略(邮件功能保持关闭);需要邮件的宿主上这些包本来就存在,不会触发(见 11.1)。 - ANTISPAM 源签名失败:rspamd.com 的 apt 源 key 校验不过,但 Debian 主源里有 rspamd,安装器回退主源装上 rspamd 3.12.1(见 11.2)。
- 结尾
sh: 1: /usr/bin/php: not found:模板里的重载/校验命令硬编码/usr/bin/php,而php官方镜像把 PHP 装在/usr/local/bin/php。修复一条命令:
docker compose exec froxlor ln -sf /usr/local/bin/php /usr/bin/php
(本实验已建符号链接,后续 cron 任务与面板重载命令全部正常,见 11.3。)
4.11 验证 Apache 站点与登录
config-services 只是把 vhost 模板装好,站点文件要等一次 froxlor:cron 'tasks' 任务作业才生成(面板的声明式管线:改库 → 记任务 → cron 渲染配置)。手动触发:
docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'tasks' -f -d
回显(实测节选):
Checking froxlor file permissions...OK
Running "tasks" job (forced) (debug)
[information] TasksCron: Searching for tasks to do
[notice] Creating passwd file
[notice] Writing 0 entries to passwd file
[notice] Succesfully wrote passwd file
[information] apache::createIpPort: creating ip/port settings for 10.89.68.10:80
[debug] 10.89.68.10:80 :: inserted vhostcontainer
[information] apache::writeConfigs: rebuilding /etc/apache2/sites-enabled/
[information] Froxlor\Cron\Http\Apache::reload: reloading Froxlor\Cron\Http\Apache
[notice] Checking system's last guid
生成的 vhost DocumentRoot 已指向 /var/www/html/froxlor、ServerName panel.froxlor.test、仅绑 10.89.68.10:80。宿主侧登录闭环实测:
curl -s -o /dev/null -w "GET / -> %{http_code} redirect=%{redirect_url}\n" http://127.0.0.1:8141/
curl -s -o /dev/null -c /tmp/fxj -w "POST index.php -> %{http_code} redirect=%{redirect_url}\n" \
-X POST http://127.0.0.1:8141/index.php --data "loginname=admin&password=q1w2e3r4&redirect="
curl -s -b /tmp/fxj -o /tmp/fxdash -w "GET admin_index.php -> %{http_code}\n" http://127.0.0.1:8141/admin_index.php
GET / -> 200 redirect=
POST index.php -> 302 redirect=http://127.0.0.1:8141/admin_index.php
GET admin_index.php -> 200
<title>froxlor</title>
登录页 200、admin / q1w2e3r4 提交后 302 进后台 admin_index.php 并 200 返回仪表盘。浏览器访问 http://<服务器IP>:8141/ 同样可登录。
4.12 验证安装信息
docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli froxlor:install -s
回显(实测):
┌────────────────┬───────────────────────────┐
│ Key │ Value │
├────────────────┼───────────────────────────┤
│ Froxlor │ 2.3.16 (202608210) │
│ Update-channel │ stable │
│ Hostname │ panel.froxlor.test │
│ Install-dir │ /var/www/html/froxlor/ │
│ PHP CLI │ 8.2.35 │
│ PHP SAPI │ mod_php │
│ Webserver │ apache2 │
│ Kernel │ 7.0.0-38-generic (x86_64) │
│ Database │ 10.11.19-MariaDB-ubu2204 │
│ Distro config │ bookworm │
│ IP addresses │ 10.89.68.10 (80) │
└────────────────┴───────────────────────────┘
任务调度同样已就位——安装时生成的 /etc/cron.d/froxlor(实测全文):
# automatically generated cron-configuration by froxlor
# do not manually edit this file as it will be re-generated periodically.
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#
*/5 * * * * root /usr/bin/nice -n 5 /usr/bin/php -q /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'tasks' -q 1> /dev/null
0 0 * * * root /usr/bin/nice -n 5 /usr/bin/php -q /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'traffic' -q 1> /dev/null
5 0 * * * root /usr/bin/nice -n 5 /usr/bin/php -q /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'usage_report' -q 1> /dev/null
0 */6 * * * root /usr/bin/nice -n 5 /usr/bin/php -q /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'mailboxsize' -q 1> /dev/null
五、数据持久化说明
| 服务内路径 | 内容 | 持久化方式 | 位置 |
|---|---|---|---|
/var/lib/mysql | 面板全部业务数据(froxlor 库:设置/客户/域名/邮箱/任务/流量) | 命名卷 froxlor-2316-stack_db-data | 卷内 |
/var/www/html/froxlor/lib/userdata.inc.php | 数据库连接凭据(安装产物,权限 0600) | 命名卷 froxlor-2316-stack_froxlor-data | 卷内 |
/var/www/html/froxlor(代码) | 面板 PHP 代码 | 同上(首启用镜像内容填充空卷) | 卷内 |
/etc/apache2/sites-enabled/10_froxlor_*.conf 等 | 面板生成的下游服务配置 | 未持久化(容器层) | 重建即丢,见下方实录 |
实测 userdata.inc.php(卷内,节选):
$sql = [
'debug' => false,
'host' => 'db',
'user' => 'froxlor',
'password' => 'q1w2e3r4',
'db' => 'froxlor',
];
$sql_root = [
'0' => [
'caption' => 'Default',
'host' => 'db',
'user' => 'froxroot',
'password' => 'q1w2e3r4',
],
];
down/up 坑实录(本方案最大的坑):docker compose down(不带 -v,保留卷)再 up -d 后,数据库与 userdata.inc.php 完好、口令仍可校验,但 Apache 的 vhost/模块配置在容器层丢失,面板直接不可用。实测现象:
GET / -> 403
POST /index.php -> 404
froxlor-2.3.16-panel | [autoindex:error] AH01276: Cannot serve directory /var/www/html/: No matching DirectoryIndex (index.php,index.html) found, and server-generated directory index forbidden by Options directive
(AH01276 即"还在用基底默认站点、DocumentRoot 仍是 /var/www/html"的铁证。)恢复序列(实测有效):
docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli \
froxlor:config-services -a '{"distro":"bookworm","dns":"x","http":"apache24","smtp":"postfix_dovecot","mail":"dovecot_postfix2","antispam":"rspamd","ftp":"proftpd","system":["cron","libnssextrausers","logrotate","goaccess"]}' --yes-to-all
docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'tasks' -f
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8141/
Reloading Apache httpd web server: apache2.
200
根因:Froxlor 是"接管整台主机服务配置"的面板,其设计假设是主机持久;容器化后 /etc/apache2 属于容器可写层,重建即回滚。两种长期解法任选:把 /etc/apache2、/etc/proftpd 等被接管目录也做成命名卷/宿主 bind;或接受现状,把上面"config-services + cron tasks -f"两条命令写进编排的启动钩子(entrypoint 里判断 vhost 文件不存在则自动重放)。
💡 说明:备份口径——Froxlor 的全部状态 =
db-data卷(mysqldump 可导出)+froxlor-data卷里的lib/userdata.inc.php。两者齐备即可在任何新栈上恢复面板。
六、环境变量表
面板进程不读取环境变量,配置来源是 userdata.inc.php(数据库连接)+ panel_settings 表(业务设置,见配置篇)。本栈涉及的环境变量只有数据库侧:
| 名称 | 位置 | 本方案取值 | 说明 |
|---|---|---|---|
MARIADB_ROOT_PASSWORD | db 服务 | q1w2e3r4 | MariaDB 官方镜像首启 root 口令 |
MARIADB_DATABASE / MARIADB_USER | db 服务 | 未设置 | 故意留空——froxlor 库与业务账号由面板安装器自建(mysql_force_create: 1),避免双重建库 |
💡 技术拓展:容器化应用的配置注入两条主流路线——
路线 代表 特点 环境变量驱动 imgproxy、多数 Go 服务 十二要素,compose environment:即可改配置文件/数据库存储 Froxlor、Ajenti 等传统面板 配置在文件+数据库里,需挂载持久化(本方案的卷设计即为此) Froxlor 属于后者,所以本方案用"卷持久化 + 无人值守安装 JSON"的组合,而不是 env 覆盖。
七、配置参数说明(速览)
安装写入 panel_settings 表的关键参数速览(全量 276 行、分组分布与逐项详解见《Froxlor 2.3.16 配置参数详解》):
| settinggroup / varname | 本方案取值 | 一句话含义 |
|---|---|---|
system.hostname | panel.froxlor.test | 面板域名,进 vhost ServerName |
system.ipaddress | 10.89.68.10 | 面板监听 IP(与固定 IP 一致) |
system.webserver | apache2 | 接管的 Web 服务器 |
system.apacheconf_vhost | /etc/apache2/sites-enabled/ | vhost 生成目录 |
system.documentroot_prefix | /var/customers/webs/ | 客户站点根前缀 |
system.distribution | bookworm | 服务配置模板线 |
system.update_channel | stable | 更新通道 |
system.use_ssl | 0 | 面板自身 HTTP(生产建议上 TLS/Let's Encrypt) |
system.mysql_access_host | db,10.89.68.10 | 允许连 MySQL 的主机白名单 |
panel.version / panel.db_version | 2.3.16 / 202608210 | 本体与数据库结构版本 |
panel.paging | 20 | 列表每页行数(演示改值见配置篇) |
login.maxloginattempts / deactivatetime | 3 / 900 | 登录失败锁定策略 |
八、配置文件挂载方式
本栈的"配置即文件"部分只有三个宿主文件,均已在 compose 中体现或可即时替换:
init-db.sql:只读 bind 进/docker-entrypoint-initdb.d/,仅数据库首启执行;改完口令类参数后需docker compose down -v重建库才会重放。install.json:不挂载,安装期docker compose cp进服务执行一次即可;重装/改参时改文件重推。userdata.inc.php:安装产物,在froxlor-data卷内(4.9 节实测 0600)。若要"配置即代码",可把宿主文件 bind 覆盖:
# compose.yml froxlor 服务 volumes 段的替代写法(二选一)
volumes:
- ./userdata.inc.php:/var/www/html/froxlor/lib/userdata.inc.php:ro
⚠️ 注意:单文件 bind 后该文件只读,面板后台"系统设置 → 数据库"页保存会失败(写入方是进程本身);需要面板内改数据库连接时回到命名卷方案。
被接管的下游服务配置(/etc/apache2、/etc/proftpd、/etc/rspamd 等)默认留在容器层——这正是第五章 down/up 坑的根源;生产形态建议为每个被接管目录追加命名卷(如 apache-config:/etc/apache2),或在 entrypoint 加"vhost 缺失则重放 config-services + cron tasks -f"的自愈钩子(命令见第五章实测序列)。
九、等价 docker run
compose 的运行时等价命令(同镜像、同持久化语义,演示网络用栈内既有网络):
docker run -d --name froxlor-run-demo \
-v froxlor-run-demo-data:/var/www/html/froxlor \
--network froxlor-2316-stack_froxlor-net -p 8142:80 \
froxlor/panel:2.3.16
7fcb1fee02e7cb049f028378042f21c8d2d6fc08974430548c93abcf7d922dc3
run-demo 8142 GET / -> 403 redirect=
(403 是预期结果:该演示实例是全新未安装的解包目录形态,基底默认站点 DocumentRoot /var/www/html 无 DirectoryIndex——等价于 compose 方案里 4.8 刚 up、尚未跑 4.9/4.10 安装步骤的状态;安装链路与第五章恢复序列相同。)
镜像独立自检(不依赖任何卷/数据库):
docker run --rm froxlor/panel:2.3.16 php /var/www/html/froxlor/bin/froxlor-cli --version
froxlor-cli 2.3.16
验证完毕销毁演示实例:
docker rm -f froxlor-run-demo && docker volume rm froxlor-run-demo-data
froxlor-run-demo
froxlor-run-demo-data
十、常用运维命令
| 操作 | 命令 |
|---|---|
| 状态 | docker compose ps |
| 跟踪面板日志 | docker compose logs -f froxlor |
| 重启面板 | docker compose restart froxlor |
| 进入面板服务 | docker compose exec froxlor bash |
| 手动跑一次任务作业 | docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli froxlor:cron 'tasks' -f |
| 查安装信息 | docker compose exec froxlor php /var/www/html/froxlor/bin/froxlor-cli froxlor:install -s |
| 停止并删除栈(保留数据卷) | docker compose down |
| 连数据一起销毁 | docker compose down -v |
| 改 Dockerfile 后重建并拉起 | docker compose up -d --build |
| 数据库备份 | docker compose exec db mariadb-dump -uroot -pq1w2e3r4 froxlor > froxlor-backup.sql |
(ps/down/up/exec 类回显见 4.8、第五章实测节;froxlor:cron/froxlor:install -s 全量回显见 4.11/4.12;CLI 十一个子命令的逐条详解见《Froxlor 2.3.16 常用 CLI 命令与工具详解》。)
十一、常见问题
11.1 config-services 报 E: Unable to locate package postfix / dovecot 一连串 file_put_contents 警告
现象:SMTP/MAIL 段刷 Unable to locate package,随后 /etc/postfix/main.cf、/etc/dovecot/*.conf 等写入报 Failed to open stream: No such file or directory。定位:本镜像未预装邮件栈且构建时清掉了 apt 索引,目录不存在导致写入失败。解决:仅 Web 托管可直接忽略(邮件功能保持关闭即可);要邮件功能的宿主上 postfix/dovecot 包存在则整段正常通过。也可在 -a 的 JSON 里把 smtp/mail/antispam 改为不带邮件的取值跳过该段。
11.2 rspamd 官方 apt 源签名校验失败
现象:W: OpenPGP signature verification failed: https://rspamd.com/apt-stable bookworm InRelease: ... Missing key 3FA347D5E599BE4595CA2576FFA232EDBF21E25E。定位:安装器添加的 rspamd.com 源 key 未被 sqv 接受。解决:无需干预——Debian 主源自带 rspamd,安装器回退主源成功装上 3.12.1(实测 Setting up rspamd (3.12.1-1))。若主源也没有,需手工导入 rspamd 签名 key 后重试。
11.3 config-services 结尾 sh: 1: /usr/bin/php: not found
现象:整体走到最后一步报此错。定位:模板硬编码 /usr/bin/php,php 官方镜像的 PHP 在 /usr/local/bin/php。解决:ln -sf /usr/local/bin/php /usr/bin/php(4.10 节命令);更彻底的做法是在 Dockerfile 里加这层链接并重建。面板生成的 cron.d 命令行同样用 /usr/bin/php(4.12 节实测回显),链接不建则任务作业全部静默失败——这是容器化 Froxlor 最容易漏的一条。
11.4 面板记录 distro_mismatch=1
现象:panel_settings 里 system.distro_mismatch = 1。定位:安装选了 bookworm 模板线,而 php:8.2-apache 基底实为 Debian 13(trixie)。影响:服务配置按 bookworm 模板渲染;用 froxlor:config-diff bookworm trixie 可量化两者差异(实测集中在 proftpd 模块加载表与排版,见 CLI 篇),面板本体功能不受影响。解决:二选一——基底固定到 Debian 12 对应的镜像标签/digest 重建;或安装参数 distribution 直接填 trixie(该模板线在 config-diff -l 清单内)。
11.5 froxlor:update 报 PHP zip extension not found
现象:想用面板自更新时报此错。定位:安装期 WARNING 已提示缺 zip 扩展,Dockerfile 未编它。解决:镜像内 docker-php-ext-install zip(需 libzip-dev)后重跑;容器化部署更推荐"改 Dockerfile 版本号 + docker compose up -d --build"的升级路线替代面板内自更新。
11.6 服务内 curl 127.0.0.1 返回 403,宿主 8141 却正常
定位:面板生成的 vhost 只监听 10.89.68.10:80(Listen/<VirtualHost> 均按安装 IP 写死),127.0.0.1 命中的是基底默认站点。解决:服务内自检请用 curl http://10.89.68.10/;宿主侧经 8141 DNAT 访问不受影响。若需监听所有地址,在面板"IP 与端口"里把 IP 改为 0.0.0.0/任意后重跑任务作业。
十二、参考链接
- 官方主页:https://froxlor.org/
- 官方文档站(v2.3 latest):https://docs.froxlor.org/latest/
- tarball 安装文档(本方案 Dockerfile 的翻译对象):https://docs.froxlor.org/latest/general/installation/tarball.html
- 无人值守安装/CLI 文档:https://docs.froxlor.org/latest/admin-guide/cli-scripts/
- GitHub 仓库与 Releases(2.3.16 资产出处):https://github.com/Froxlor/Froxlor
- 官方容器仓库(开发线,非本方案采用):https://github.com/froxlor/container
- 同系列:《Froxlor 介绍与选型指南》、《Froxlor 2.3.16 配置参数详解》、《Froxlor 2.3.16 常用 CLI 命令与工具详解》