Mafl 0.15.4 Docker Compose 部署指南
Mafl v0.15.4 Docker Compose 部署全流程实测:config.yml 挂载与生效机制、健康检查与 /api/settings/TCP 状态探测验证链、PORT 与 NITRO_SSL 环境变量及 HTTPS 直连实测,含无配置 500、tags 类型崩溃、热更新需页面在线三段排障实录。
Mafl 0.15.4 Docker Compose 部署指南
目标:在单台 Ubuntu 22.04 服务器上以 Docker Compose 部署 Mafl v0.15.4 首页面板,完成
config.yml持久化挂载、分组/标签/状态检查配置、健康检查与/api/settings验证、HTTPS 直连形态与端口自定义,并沉淀「无配置 500」「配置改动不生效」「tags 类型错误崩溃」三段排障实录。本文全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64)
- Docker Engine:29.9.2,Docker Compose 插件 v5.6.1
- Mafl 版本:v0.15.4(2024-07-13 发布,官方最新 Release)
- 官方镜像:
hywax/mafl:v0.15.4(Docker Hub,另有 GHCR 渠道ghcr.io/hywax/mafl),镜像内容层约 48.2MB,底座 Alpine Linux 3.20.1 + Node.js v20.15.1 - 应用监听端口:实例内
3000(Nitro 默认);本教程宿主映射8132,生产可改 3000 或由反代接管 - 编排目录:
/opt/mafl/(示例路径,含docker-compose.yml与配置子目录mafl/) - 独立网络:
mafl-net(bridge,网段10.89.59.0/24,显式子网避免与同机其他编排栈冲突) - Compose 项目名:
mafl-v0154-stack(显式name:,防止与其他组件栈互相误删) - 演示访问账号:Mafl 无内置认证;如需公网暴露,请在反向代理层配置账号
root/ 密码q1w2e3r4的 Basic Auth(见第十一章常见问题 6)
二、镜像选型说明
Mafl 官方在 Docker Hub 与 GHCR 双渠道发布同一构建,选型要点集中在仓库地址与标签策略:
| 渠道/标签 | 含义 | 适用场景 |
|---|---|---|
hywax/mafl:v0.15.4 | 精确版本标签(Docker Hub) | 生产推荐,升级可控、回显可复现 |
hywax/mafl:latest | 滚动最新 | 仅测试尝鲜,面板类「latest 即最新 Release」,风险低于数据库类 |
ghcr.io/hywax/mafl | GitHub 容器仓库同构建 | Docker Hub 受限时的备用渠道 |
实测拉取(2026-11-02):
docker pull hywax/mafl:v0.15.4
10c28d5fbad7: Pull complete
f2f35e6867e8: Pull complete
Digest: sha256:2c89020be334b341da41a6b95830b1b52b1b9f43c9f16d09c0ab4e9dad3ea4ad
Status: Downloaded newer image for hywax/mafl:v0.15.4
docker.io/hywax/mafl:v0.15.4
输出节选(实测首尾)。锁定 digest 便于供应链核对:sha256:2c89020be334b341da41a6b95830b1b52b1b9f43c9f16d09c0ab4e9dad3ea4ad。
docker images hywax/mafl
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hywax/mafl:v0.15.4 2c89020be334 196MB 48.2MB
💡 说明:镜像内置健康检查(
node /app/extra/healthcheck.mjs,每 10 秒 GETlocalhost:3000/api/health,状态码 200 记健康),docker compose ps可见健康状态,无需另配。
三、前置条件
- Docker Engine ≥ 24 与 Compose v2 插件(本文实测 29.9.2 / v5.6.1);
- 宿主端口
8132空闲:
ss -ltn | grep -E ':(8132)\b'
(无输出即空闲)
- 编排目录与配置子目录:
mkdir -p /opt/mafl/mafl
⚠️ 网络说明:
docker pull经宿主 Docker 守护进程代理渠道完成(官方源直连当时不可用,现象为连接超时;守护进程已配置代理192.168.1.62:7897,实测可用)。服务器上若 Docker Hub 直连正常则无需任何额外配置;GHCR 渠道ghcr.io/hywax/mafl可作降级备选。
四、部署步骤
4.1 编写 compose 编排文件
cat > /opt/mafl/docker-compose.yml <<'EOF'
name: mafl-v0154-stack
services:
mafl:
image: hywax/mafl:v0.15.4
container_name: mafl-v0154-web
restart: unless-stopped
ports:
- '8132:3000'
volumes:
- ./mafl/:/app/data/
networks:
- mafl-net
networks:
mafl-net:
driver: bridge
ipam:
config:
- subnet: 10.89.59.0/24
EOF
逐项说明:
name:显式项目名,多组件同机共存时docker compose down只影响本栈;ports: '8132:3000'宿主 8132 → 实例 3000(应用端口固定 3000,除非注入PORT环境变量,见第六章);volumes: ./mafl/:/app/data/把配置目录持久化到宿主,config.yml就放在这里;ipam显式网段,避免自动分配与既有栈撞段。
4.2 首次启动(空配置,观察真实行为)
先不写 config.yml 直接启动,这是官方文档未明说但必须掌握的行为基线:
cd /opt/mafl && docker compose up -d
Network mafl-v0154-stack_mafl-net Creating
Network mafl-v0154-stack_mafl-net Created
Container mafl-v0154-web Creating
Container mafl-v0154-web Created
Container mafl-v0154-web Starting
Container mafl-v0154-web Started
docker compose logs --tail=30
mafl-v0154-web | Listening on http://[::]:3000
mafl-v0154-web | Error: Config not found
mafl-v0154-web | at loadConfig (file:///app/server/chunks/_/config.mjs:96:13)
mafl-v0154-web | at async Object.run (file:///app/server/chunks/tasks/update.mjs:32:20)
mafl-v0154-web | at async runTask (file:///app/server/chunks/runtime.mjs:10319:17)
mafl-v0154-web | Set "main" config
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:8132/
HTTP 500
⚠️ 排障实录 ①:
config.yml缺失时进程不会退出、健康检查照常通过(docker compose ps显示Up (healthy)),但所有页面请求返回 500。日志里的Error: Config not found就是根因——「healthy 但 500」不要往网络方向查,先查配置文件是否挂载到位。
4.3 编写 config.yml 并重启
cat > /opt/mafl/mafl/config.yml <<'EOF'
title: Quzuo Home Page
lang: zh
theme: dark
checkUpdates: false
behaviour:
target: _self
tags:
- name: Infra
color: green
- name: Demo
color: blue
layout:
grid:
small: 1
medium: 2
large: 3
xlarge: 4
services:
Infrastructure:
- title: Mafl Panel
description: 面板实例自身(状态应为在线)
link: http://127.0.0.1:3000/
icon:
name: mdi:view-dashboard
wrap: true
color: '#3dbcf3'
status:
enabled: true
tags:
- Infra
Tools:
- title: Dead Service
description: 指向未监听端口(状态应为离线)
link: http://127.0.0.1:3999/
icon:
name: mdi:power-plug-off
wrap: true
status:
enabled: true
interval: 30
tags:
- Demo
- title: Docs Site
description: 官方文档(无状态检查)
link: https://mafl.hywax.space/
icon:
name: simple-icons:mdbook
wrap: true
EOF
配置结构要点(逐参数详解见 《Mafl 0.15.4 配置参数详解》篇):
- 全局层:
title页面标题、lang: zh中文界面、theme: dark深色主题、checkUpdates关闭版本提示、behaviour.target链接跳转方式、tags全局标签定义、layout.grid各断点列数; - 服务层:
services用「组名: [卡片列表]」的分组形态;每张卡片title/link必填语义位,icon.name支持 Iconify 图标名,status.enabled开启 TCP 状态灯,tags引用全局标签名。
docker compose restart
Container mafl-v0154-web Restarting
Container mafl-v0154-web Started
docker compose logs --since 30s
mafl-v0154-web | Listening on http://[::]:3000
mafl-v0154-web | Set "main" config
Set "main" config 即配置加载成功标记,且不再出现 Error: Config not found。
4.4 验证部署
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:8132/
HTTP 200
curl -s http://127.0.0.1:8132/ | grep -oE "<title>[^<]*</title>"
<title>Quzuo Home Page</title>
curl -s http://127.0.0.1:8132/api/health -o /dev/null -w "health HTTP %{http_code}\n"
health HTTP 200
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
mafl-v0154-web hywax/mafl:v0.15.4 "docker-entrypoint.s…" mafl 4 minutes ago Up 3 seconds (healthy) 0.0.0.0:8132->3000/tcp, [::]:8132->3000/tcp
浏览器访问 http://<服务器IP>:8132/ 可见中文界面、双分组卡片与状态灯(Mafl 状态灯由服务端 TCP 探测驱动,实测响应见 4.5)。
4.5 状态检查链路实测(服务端 API)
面板的状态灯数据可通过内部 API 独立核对。先从 /api/settings 取服务 UUID,再调 base 服务探测端点:
ID=$(curl -s http://127.0.0.1:8132/api/settings | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['services'][0]['items'][0]['id'])")
curl -s "http://127.0.0.1:8132/api/services/base?id=$ID"
{"ping":{"status":true,"time":0},"data":{}}
在线服务(127.0.0.1:3000)返回 status: true。对离线目标:
ID2=$(curl -s http://127.0.0.1:8132/api/settings | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['services'][1]['items'][0]['id'])")
curl -s "http://127.0.0.1:8132/api/services/base?id=$ID2"
{"ping":{"status":false,"time":null},"data":{}}
未开启 status.enabled 的卡片则响应中根本没有 ping 字段(实测 {"data":{}})——状态灯只反映显式开启检查的服务。
五、数据持久化说明
| 宿主路径 | 实例路径 | 类型 | 说明 |
|---|---|---|---|
/opt/mafl/mafl/config.yml | /app/data/config.yml | 文件 | 唯一必需配置文件 |
/opt/mafl/icons/ | /app/public/icons/ | 目录 | 本地图标(可选,卡片 icon.url 按文件名引用) |
/opt/mafl/favicons/ | /app/public/favicons/ | 目录 | 站点图标(可选) |
Mafl 没有任何数据库:全部状态即 config.yml 一个文件,备份 = 拷贝该文件;重建 = 换一台服务器挂载同文件。实测重建验证:
cd /opt/mafl && docker compose down && docker compose up -d
Container mafl-v0154-web Stopping
Container mafl-v0154-web Stopped
Container mafl-v0154-web Removing
Container mafl-v0154-web Removed
Network mafl-v0154-stack_mafl-net Removing
Network mafl-v0154-stack_mafl-net Removed
Network mafl-v0154-stack_mafl-net Creating
Network mafl-v0154-stack_mafl-net Created
Container mafl-v0154-web Creating
Container mafl-v0154-web Created
Container mafl-v0154-web Starting
Container mafl-v0154-web Started
curl -s http://127.0.0.1:8132/ | grep -oE "<title>[^<]*</title>"
<title>Quzuo Home Page</title>
六、环境变量表
Mafl 本体不读业务环境变量(一切走 config.yml),可注入的是 Nitro 运行时层参数(实测有效项):
| 变量 | 默认 | 实测行为 |
|---|---|---|
PORT | 3000 | 设 3005 后日志变 Listening on http://[::]:3005,端口映射需同步改 |
HOST | :: | 监听地址 |
NITRO_SSL_CERT | 无 | 传入证书 PEM 内容(非路径)即启用 HTTPS |
NITRO_SSL_KEY | 无 | 传入私钥 PEM 内容,与上项配对 |
NITRO_UNIX_SOCKET | 无 | 改 Unix socket 监听(对接反代) |
NITRO_SHUTDOWN_TIMEOUT | — | 优雅停机超时 |
PORT 实测(独立验证实例,宿主映射 8134):
docker run -d --name mafl-v0154-envtest --network mafl-slot60-probe -e PORT=3005 -p 8134:3005 -v /opt/mafl/mafl:/app/data hywax/mafl:v0.15.4
docker logs mafl-v0154-envtest
Listening on http://[::]:3005
Set "main" config
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:8134/
HTTP 200
HTTPS 直连实测(不挂反代、证书以内容注入):
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -subj "/CN=mafl-test"
docker run -d --name mafl-v0154-tlstest -e NITRO_SSL_CERT="$(cat server.crt)" -e NITRO_SSL_KEY="$(cat server.key)" -p 8134:3000 -v /opt/mafl/mafl:/app/data hywax/mafl:v0.15.4
docker logs mafl-v0154-tlstest
Listening on https://[::]:3000
Set "main" config
curl -sk -o /dev/null -w "HTTPS %{http_code}\n" https://127.0.0.1:8134/
HTTPS 200
⚠️ 注意:证书以环境变量内容注入会进入
docker inspect可见范围,生产建议优先走 Nginx/Caddy 反代终结 TLS;NITRO_SSL_*适合内网快速验证。
七、配置参数说明(速览)
config.yml 全局参数与默认值(默认值取自实例内置出厂配置,经 /api/settings 合并结果实测核对):
| 参数 | 默认值 | 一句话说明 |
|---|---|---|
title | Mafl Home Page | 页面标题 |
lang | en | 界面语言,支持 zh |
theme | system | system/light/dark/deep/sepia/bluer |
checkUpdates | true | 新版本横幅提示(不自动更新) |
behaviour.target | _blank | 卡片跳转方式,可被单卡片 target 覆盖 |
layout.grid | small 2 / medium 2 / large 3 / xlarge 4 | 各断点网格列数(1-12) |
tags | [] | 全局标签(name+color) |
services | [](缺失则首页报错) | 卡片列表或分组映射 |
逐参数语义、服务卡片字段、type/options/secrets 与服务类型的完整实测见 《Mafl 0.15.4 配置参数详解》篇。
八、配置文件挂载
官方文档明确「必须显式提供 config.yml,其余路径可默认」。挂载形态二选一:
# 形态 A(本文采用):目录挂载,便于同时放图标目录与备份
volumes:
- ./mafl/:/app/data/
# 形态 B(官方 docker run 示例采用):单文件挂载
volumes:
- ./config.yml:/app/data/config.yml
⚠️ 排障实录 ②:改了
config.yml页面不更新。Mafl 的配置热更新由 WebSocket 通道驱动——只有当浏览器页面处于打开状态(/api/websocket有活跃 peer)时,服务端才监听配置文件变化并自动重载。实测无浏览器在线时修改title后 10 秒内页面不变、日志无Set "main" config;两种生效路径:① 保持页面打开,保存文件即秒级生效(页面标题实测变为新值);② 无人在线时执行docker compose restart。完整链路验证见 《Mafl 0.15.4 日常运维手册》篇第二章。
九、等价 docker run
compose 编排等价的一次性运行(官方 README 形态 + 本文端口):
docker run -d --name mafl-v0154-web -p 8132:3000 -v /opt/mafl/mafl:/app/data --restart unless-stopped hywax/mafl:v0.15.4
官方 README 给出的最小形态(单文件挂载、默认 3000 端口):
docker run --name mafl -p 3000:3000 -v ./config.yml:/app/data/config.yml hywax/mafl
十、常用运维命令
# 查看运行与健康状态
docker compose ps
# 跟踪日志(配置加载标记为 Set "main" config)
docker compose logs -f
# 重载配置(无浏览器在线时的必选路径)
docker compose restart
# 升级到新版本:改 compose 中 image 标签后
docker compose pull && docker compose up -d
# 回滚:把 image 标签改回 v0.15.4 再执行上两条命令
升级实测(v0.15.3→v0.15.4 同理,标签替换即可):
docker pull hywax/mafl:v0.15.4
docker compose up -d
Container mafl-v0154-web Recreate
Container mafl-v0154-web Recreated
Container mafl-v0154-web Starting
Container mafl-v0154-web Started
十一、常见问题(FAQ)
Q1: 页面 500,日志 Error: Config not found?
A: config.yml 未挂载或路径错。docker compose exec 进实例 ls /app/data 核对(实测空目录时即此现象,见 4.2)。
Q2: 启动日志 TypeError: tags.reduce is not a function,页面 500?
A: tags 写成了字符串而非数组。实测 tags: work 触发该崩溃(tags 解析发生在 schema 校验之前,报错先于任何字段校验)。正确形态:
tags:
- name: Infra
color: green
Q3: 卡片拼错字段名(如 titel)为什么不报错?
A: Mafl 的配置 schema 对未知键静默透传(实测 titel: typo 原样进入 /api/settings 响应,页面渲染为无标题空卡片)。配置自检唯一可靠手段是回读 /api/settings 比对(见 《Mafl 0.15.4 配置参数详解》篇参数查看章节)。
Q4: HTTPS 服务卡片状态灯总是「离线」?
A: 状态检查是 TCP 探测且端口缺省取 80:https://example.com/ 这类不带显式端口的链接探测的是 80 端口。给 link 写明端口(如 https://example.com:8443/)即可修正(探测逻辑实测见配置篇)。
Q5: 能否多用户/登录访问?
A: 不能,Mafl 无内置认证。公网部署务必置于反代之后并启用认证,例如 Nginx 层:auth_basic "Mafl"; auth_basic_user_file /etc/nginx/mafl-passwd;,用账号 root / 密码 q1w2e3r4 生成口令文件:printf 'root:%s\n' "$(openssl passwd -apr1 q1w2e3r4)" > /etc/nginx/mafl-passwd。
Q6: 更新横幅出现是否意味着已自动升级?
A: 否。checkUpdates: true 只提示新版本,升级需手动换标签(第十章);官方建议自动化场景使用 watchtower。
十二、参考链接
- 官方仓库:https://github.com/hywax/mafl
- 官方文档 Getting Started:https://mafl.hywax.space/guide/getting-started.html
- 官方文档 Configuration:https://mafl.hywax.space/reference/configuration.html
- Docker Hub:https://hub.docker.com/r/hywax/mafl
- 本专栏延伸阅读:《Mafl 介绍与选型指南》、《Mafl 0.15.4 配置参数详解》、《Mafl 0.15.4 日常运维手册》