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)。

FroxlorFroxlor面板虚拟主机PHP自托管2026/11/03

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 / Compose29.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、unzipcron 承载面板每 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 唯一与官方安装文档保持路径一致性的容器路线。

三、前置条件

  1. 服务器已安装 Docker Engine 与 Compose v2+ 插件:
docker --version && docker compose version

回显(实测):

Docker version 29.9.2, build a82e528
Docker Compose version v5.6.1
  1. 宿主 8141 端口空闲(ss -ltn | grep ':8141 ' 无输出);
  2. 服务器可直连 Docker Hub 与 GitHub Releases(构建期拉基底镜像、下载官方包);
  3. 磁盘余量 ≥ 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:

字段解读:

字段取值作用
namefroxlor-2.3.16-stack显式项目名,down 只影响本组件资源
db.healthcheck + depends_on.conditionservice_healthy面板安装连库前确保 MariaDB 就绪(首启建库慢,直接 started 会撞"连接被拒")
./init-db.sql:rodocker-entrypoint-initdb.d仅数据库首次初始化时执行,卷已有数据则跳过
hostnamepanel.froxlor.test安装参数 servername 与面板 system.hostname 的取值
ports8141:80宿主 8141 → 服务内 80
froxlor-data 卷/var/www/html/froxlor持久化面板代码目录 + 安装凭据 lib/userdata.inc.php(见第五章)
ipv4_address10.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_PASSWORDdb 服务q1w2e3r4MariaDB 官方镜像首启 root 口令
MARIADB_DATABASE / MARIADB_USERdb 服务未设置故意留空——froxlor 库与业务账号由面板安装器自建(mysql_force_create: 1),避免双重建库

💡 技术拓展:容器化应用的配置注入两条主流路线——

路线代表特点
环境变量驱动imgproxy、多数 Go 服务十二要素,compose environment: 即可改
配置文件/数据库存储Froxlor、Ajenti 等传统面板配置在文件+数据库里,需挂载持久化(本方案的卷设计即为此)

Froxlor 属于后者,所以本方案用"卷持久化 + 无人值守安装 JSON"的组合,而不是 env 覆盖。

七、配置参数说明(速览)

安装写入 panel_settings 表的关键参数速览(全量 276 行、分组分布与逐项详解见《Froxlor 2.3.16 配置参数详解》):

settinggroup / varname本方案取值一句话含义
system.hostnamepanel.froxlor.test面板域名,进 vhost ServerName
system.ipaddress10.89.68.10面板监听 IP(与固定 IP 一致)
system.webserverapache2接管的 Web 服务器
system.apacheconf_vhost/etc/apache2/sites-enabled/vhost 生成目录
system.documentroot_prefix/var/customers/webs/客户站点根前缀
system.distributionbookworm服务配置模板线
system.update_channelstable更新通道
system.use_ssl0面板自身 HTTP(生产建议上 TLS/Let's Encrypt)
system.mysql_access_hostdb,10.89.68.10允许连 MySQL 的主机白名单
panel.version / panel.db_version2.3.16 / 202608210本体与数据库结构版本
panel.paging20列表每页行数(演示改值见配置篇)
login.maxloginattempts / deactivatetime3 / 900登录失败锁定策略

八、配置文件挂载方式

本栈的"配置即文件"部分只有三个宿主文件,均已在 compose 中体现或可即时替换:

  1. init-db.sql:只读 bind 进 /docker-entrypoint-initdb.d/,仅数据库首启执行;改完口令类参数后需 docker compose down -v 重建库才会重放。
  2. install.json:不挂载,安装期 docker compose cp 进服务执行一次即可;重装/改参时改文件重推。
  3. 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/任意后重跑任务作业。

十二、参考链接

Froxlor 2.3.16 Docker Compose 部署指南 - Quzuo