Mafl 0.15.4 配置参数详解

Mafl v0.15.4 唯一配置文件 config.yml 逐参数实测:全局参数出厂默认值回读、卡片字段与 base/ip-api/openweathermap 三类型 options/secrets 结构、TCP 状态探测机制与端口缺省陷阱、WebSocket 热更新双路径生效链路,含未知键透传、tags 崩溃、本地图标 404 三项实测发现。

MaflMafl面板自托管Node.js2026/11/03

Mafl 0.15.4 配置参数详解

目标:逐参数讲清 Mafl v0.15.4 的唯一配置文件 config.yml——全局参数出厂默认值、服务卡片字段、三种服务类型(base/ip-api/openweathermap)的 options/secrets 结构、状态检查机制与配置生效链路;每个参数均给出实测配置与 /api/settings、服务端 API 的核对回显,并沉淀「未知键静默透传」「tags 类型崩溃」「本地图标挂载 404」三项实测发现。本文接续 《Mafl 0.15.4 Docker Compose 部署指南》的部署成果,全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)环境实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64),Docker Engine 29.9.2(Compose v5.6.1)
  • Mafl 版本:v0.15.4(镜像 hywax/mafl:v0.15.4,底座 Alpine 3.20.1 + Node.js v20.15.1,Nuxt 3.12.3 / Nitro 2.9.7)
  • 配置文件:宿主 /opt/mafl/mafl/config.yml ↔ 实例 /app/data/config.yml(挂载映射)
  • 访问形态:http://127.0.0.1:8132/(宿主端口 8132 → 实例端口 3000)
  • 核对端点:GET /api/settings(返回合并默认值后的生效配置,secrets 字段被服务端剔除)
  • 编排目录:/opt/mafl/(示例路径)

二、前置条件

  1. 已按 《Mafl 0.15.4 Docker Compose 部署指南》完成部署,curl http://127.0.0.1:8132/api/health 返回 200;
  2. 具备 config.yml 的编辑权限(配置即数据,改文件即改参数,无 GUI 设置后台);
  3. 本文实测基线配置(含两个分组、四张卡片、全局标签):
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
    - title: My Exit IP
      description: 服务端查询出口 IP(ip-api 类型)
      type: ip-api
      icon:
        url: test.svg
        background: '#eee'
      tags:
        - Demo

三、参数查看与修改方式

3.1 编辑 config.yml

Mafl 没有 --help、没有管理 CLI、没有设置页面——唯一的修改方式就是编辑 config.yml:

vi /opt/mafl/mafl/config.yml

3.2 回读生效配置(/api/settings)

改完文件后,最可靠的「参数现在到底是什么值」核对手段是回读服务端合并后的配置。出厂默认值会补齐你没写的字段:

curl -s http://127.0.0.1:8132/api/settings | python3 -m json.tool | head -20
{
    "title": "Quzuo Home Page",
    "lang": "zh",
    "theme": "dark",
    "checkUpdates": false,
    "layout": {
        "grid": {
            "small": 1,
            "medium": 2,
            "large": 3,
            "xlarge": 4
        }
    },
    "behaviour": {
        "target": "_self"
    },

输出节选(实测首尾)。把文件临时改成缺省形态(只留 title 与 services)重启后回读,可看到全部出厂默认值:

{"title":"Mafl Home Page","lang":"en","theme":"system","checkUpdates":true,"layout":{"grid":{"small":2,"medium":2,"large":3,"xlarge":4}},"behaviour":{"target":"_blank"},"tags":[],"services":[]}

⚠️ 注意:该响应里 services: [] 且带 "error" 字段时说明配置加载失败(见第九章排障),空数组不代表你写了空服务。

3.3 配置生效链路(两条路径,实测)

路径 A:浏览器页面打开时热更新。 Mafl 的配置文件监听器注册在 WebSocket 会话建立之后——有活跃页面(peer)在线时,保存 config.yml 秒级生效,无需重启。实测用 Node 内置 WebSocket 模拟一个在线页面:

docker exec mafl-v0154-web node --experimental-websocket -e '
const ws=new WebSocket("ws://localhost:3000/api/websocket");
ws.onopen=()=>console.log("WS OPEN");
ws.onmessage=e=>console.log("RECV",e.data);
setTimeout(()=>process.exit(0),12000);' &
sed -i 's/title: Quzuo Home Page WS/title: Quzuo Home Page WS2/' /opt/mafl/mafl/config.yml
WS OPEN
RECV {"event":"config:update"}

服务端日志同步出现:

mafl-v0154-web  | Peer connected #1 ([::1]:50412)
mafl-v0154-web  | Set "main" config

页面标题随即变为新值(实测回显):

curl -s http://127.0.0.1:8132/ | grep -oE "<title>[^<]*</title>"
<title>Quzuo Home Page WS2</title>

路径 B:无页面在线时必须重启。 实测:没有任何浏览器连接时修改 title,等待 10 秒以上页面不变、日志无 Set "main" config;执行 docker compose restart 后新值生效。生产上以路径 B 为准,路径 A 视为「开着配置页编辑时的便利特性」。

四、参数总览

全局参数(默认值经缺省配置回读实测核对):

参数类型默认值说明
titlestringMafl Home Page页面标题(浏览器标签页与顶栏)
langstringen界面语言:en/ru/zh/hi/es/ar/pl/fr/de/gr/nl
themestringsystem主题:system/light/dark/deep/sepia/bluer
checkUpdatesbooleantrue页面底部新版本提示横幅(不自动升级)
behaviour.targetstring_blank卡片全局跳转方式,可被卡片级 target 覆盖
layout.gridobjectsmall 2 / medium 2 / large 3 / xlarge 4四档屏幕断点的网格列数,取值 1-12,可只写一档
tagsarray[]全局标签定义(name+color),v0.10.0 引入
servicesarray 或 map[](缺失则报错)卡片扁平列表或「组名: 列表」分组映射

服务卡片参数(三种类型通用):

字段类型默认值说明
titlestring无卡片标题
descriptionstring无标题下方副标题
linkstring无点击跳转地址,同时是状态探测目标
targetstring继承 behaviour.target本卡片跳转方式(优先级更高)
icon.namestring无Iconify 图标名(集合名:图标名)
icon.urlstring无本地图标文件名(见 9.4 实测限制)
icon.wrapboolean无图标是否加衬底
icon.color / icon.backgroundstring无图标色 / 衬底色(十六进制需引号)
status.enabledbooleanfalse开启 TCP 状态灯
status.animationbooleantrue状态灯动画
status.intervalnumber60状态刷新间隔(秒)
tagsarray[]引用全局标签名,或内联 {name,color}
typestringbase服务类型:base/ip-api/openweathermap
optionsmap无类型专属参数(如天气经纬度)
secretsmap无类型专属密钥(服务端使用,绝不下发)

五、全局参数详解

5.1 title

页面标题。实测 title: Quzuo Home Page 渲染为 <title>Quzuo Home Page</title>(回显见 3.3)。缺省时回读值为 Mafl Home Page。

5.2 lang

界面语言,支持 11 种:en、ru、zh、hi、es、ar、pl、fr、de、gr、nl。实测 lang: zh 后服务端渲染中文界面;未设置时服务端按浏览器语言自动协商(实测无 cookie 首次响应会下发 set-cookie: i18n_redirected=en)。中文用户建议显式写 lang: zh,避免自动协商漂移。

5.3 theme

内置六主题:system(跟随系统,默认)、light、dark、deep、sepia、bluer。实测 theme: dark 在 /api/settings 回显 "theme": "dark",SSR HTML 即带主题标记渲染。

5.4 checkUpdates

新版本横幅开关,默认 true。开启时服务端周期性检查 GitHub Release,发现新版在页面底部提示,不会自动更新;官方文档建议自动升级场景使用 watchtower。生产建议 checkUpdates: false 关闭外呼、由运维手动升级(见 《Mafl 0.15.4 日常运维手册》篇升级章节)。

5.5 behaviour.target

全局跳转方式,取值 _blank/_self/_parent/_top(浏览器语义),默认 _blank。实测 behaviour.target: _self 回显生效;卡片级 target 字段优先级高于全局(官方文档明示,schema 中卡片 target 独立存在)。

5.6 layout.grid

v0.14.0 引入的响应式列数,四档断点 small/medium/large/xlarge,各档取值范围 1-12,可只写一档其余自动。实测写全四档 1/2/3/4 回显一致;缺省为 2/2/3/4。

5.7 tags

全局标签表,卡片按名引用。实测:

tags:
  - name: Infra
    color: green

卡片写 tags: [Infra](字符串列表)即可关联;服务端把字符串名解析回完整标签对象(含颜色),未定义的名字按 {name: 原名, color: "blue"} 兜底(实测未知标签名不报错)。标签类型必须是数组——写成字符串直接崩溃,见 9.2。

六、服务卡片参数详解

三件套构成卡片主体:标题、副标题、跳转链接。link 同时被状态检查复用为探测目标(第八章)。三者都是 schema 可选字段——全拼错也不报错(见 9.3 未知键透传),配置后务必用 /api/settings 回读核对。

6.2 icon

四种图标来源(官方文档):Iconify 名(mdi:view-dashboard、simple-icons:mdbook 等 20 万+图标集)、Emoji、外部 URL、本地文件名。实测 Iconify 名与 wrap/color/background 组合均正常回显:

icon:
  name: mdi:view-dashboard
  wrap: true
  color: '#3dbcf3'

icon.url: test.svg 的本地挂载形态在 v0.15.4 实测不可用(404,机制与结论见 9.4)。

6.3 status

status:
  enabled: true
  interval: 30

enabled 默认 false(不开则无状态灯、API 响应无 ping 字段,实测见第八章);interval 默认 60 秒,官方明确不建议调小(服务多时探测压力大);animation 默认 true。

6.4 type / options / secrets

type 缺省为 base(不写即纯链接卡片)。options 承载类型专属参数、secrets 承载密钥。密钥安全性实测:含 secrets 的配置经 /api/settings 回读时该字段被服务端整体剔除(实测响应中检索不到 secrets 键),即天气 API Key 只存活在服务端进程内,浏览器不可见。

七、服务类型详解

7.1 base(默认)

纯链接卡片,即 6.1-6.3 的全部字段。状态探测响应实测(在线目标):

curl -s "http://127.0.0.1:8132/api/services/base?id=9263c3e0-9579-4ce4-acbf-fbb686e71ad9"
{"ping":{"status":true,"time":0},"data":{}}

7.2 ip-api

显示服务器出口 IP 信息(请求由服务端代发,浏览器不接触第三方 API)。配置:

- title: My Exit IP
  type: ip-api

实测端点响应(服务端所在网络出口):

curl -s --max-time 20 "http://127.0.0.1:8132/api/services/ip-api?id=7589fa22-f00f-4b10-87d4-b9c6c7ef4885"
{"data":{"ip":"182.54.113.29","place":"Zhongwei, Ningxia","country":"cn"}}

不带 id 直接调用返回 400:{"statusCode":400,"statusMessage":"ID can not be null"}——所有 /api/services/* 端点都以卡片 UUID 为入参。

7.3 openweathermap

天气卡片,数据源 OpenWeatherMap。配置(官方文档字段 + 服务端 schema 核对):

- title: Weather
  type: openweathermap
  options:
    lat: 51.5085
    lon: -0.1257
    units: metric
  secrets:
    apiKey: ${OWM_API_KEY}
  • options.lat/lon:必填经纬度(可从 latlong.net 获取);
  • options.units:metric/imperial/standard,默认 metric;
  • secrets.apiKey:OpenWeatherMap 个人 API Key。属第三方密钥,按规范用 ${OWM_API_KEY} 占位,注入方式:export OWM_API_KEY=<你的key> 后由配置渲染工具写入,或直接写明文于受权限保护的 config.yml(该文件仅服务端可读)。

实测无 Key 调用该端点返回 400(缺参即拒)。服务端对天气结果做缓存(defineCachedFunction,maxAge 1440 秒,按经纬度作缓存键),高频刷新页面不会放大对 OpenWeatherMap 的调用。

八、状态检查机制实测

状态灯的本质(服务端源码 @network-utils/tcp-ping 路径实测核对):对 link 解析出的主机 + 端口发起 1 次 TCP 连接,成功即在线。三个实测形态:

# 在线目标(127.0.0.1:3000 有监听)
curl -s "http://127.0.0.1:8132/api/services/base?id=$ID"
{"ping":{"status":true,"time":0},"data":{}}
# 离线目标(127.0.0.1:3999 无监听)
curl -s "http://127.0.0.1:8132/api/services/base?id=$ID2"
{"ping":{"status":false,"time":null},"data":{}}
# 未开启 status.enabled 的卡片
curl -s "http://127.0.0.1:8132/api/services/base?id=$ID3"
{"data":{}}

端口缺省陷阱:链接不带显式端口时探测端口 80(源码 url.port || "80"),https://example.com/ 探的是 80 不是 443——HTTPS 服务请写全端口(如 https://example.com:8443/),否则状态灯恒离线。这是 TCP 探测的固有精度边界:端口通 ≠ 应用健康。

九、配置容错与校验(实测发现)

9.1 缺 config.yml:进程存活但全站 500

挂载目录里没有 config.yml 时,启动日志 Error: Config not found,健康检查照常通过、页面全部 500(实测回显见部署篇 4.2)。配置加载失败不会让进程退出。

9.2 tags 类型错误:先于 schema 校验崩溃

tags: work    # 错误:写成字符串

实测日志:

mafl-v0154-web  | TypeError: tags.reduce is not a function
mafl-v0154-web  |     at createTagMap (file:///app/server/chunks/_/config.mjs:86:15)

页面 500,/api/settings 返回缺省配置并携带 "error":"tags.reduce is not a function" 字段——这个 error 字段是定位配置加载失败的第一现场。根因:标签映射构建发生在 zod 校验之前,tags 非数组直接抛原生 TypeError。

9.3 未知键静默透传:拼错不报错

services:
  - titel: typo

实测:无报错、无告警,titel 原样进入 /api/settings 响应({"titel":"typo","id":"...","tags":[]}),页面渲染一张无标题空卡片。Mafl 的 zod schema 非严格模式,拼写错误只能靠回读自查,没有配置校验端点。

9.4 本地图标挂载 404(v0.15.4 实测限制)

官方文档声明挂载 /app/public/icons 后按文件名引用本地图标。实测在 compose 中加挂 ./icons/:/app/public/icons/、放入 test.svg、配置 icon.url: test.svg 并重建实例:

docker exec mafl-v0154-web ls -la /app/public/icons/
-rw-r--r--    1 root     root           113 Nov  2 18:11 test.svg
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8132/icons/test.svg
404

文件在实例内可见但不被服务。机制:Nitro 2.9.7 的静态资源路由表在构建期固化进服务端代码(实测 runtime.mjs 内逐条列出 /favicons/... 等出厂文件),运行时新增文件不注册路由;/favicons/favicon.ico(构建期已存在)实测 200 佐证。结论:v0.15.4 本地图标/自定义 favicon 挂载实际不可用,图标请用 Iconify 名、Emoji 或外部 URL 三种来源。

十、生产配置模板

适用场景:家庭实验室单节点服务器(16GB 内存 / NVMe SSD / 服务 10-30 个),面板仅内网访问:

title: Homelab
lang: zh
theme: system
checkUpdates: false
behaviour:
  target: _blank
tags:
  - name: core
    color: green
  - name: media
    color: blue
  - name: net
    color: orange
layout:
  grid:
    small: 1
    medium: 2
    large: 3
    xlarge: 4
services:
  核心服务:
    - title: NAS
      description: Synology DS223
      link: http://192.168.1.10:5000/
      icon:
        name: mdi:nas
        wrap: true
      status:
        enabled: true
      tags:
        - core
    - title: Router
      description: Keenetic Peak
      link: http://192.168.1.1/
      icon:
        name: mdi:router-wireless
        wrap: true
      status:
        enabled: true
      tags:
        - net
  媒体服务:
    - title: Music
      description: Navidrome
      link: http://192.168.1.10:4533/
      icon:
        name: mdi:music-circle
        wrap: true
      status:
        enabled: true
      tags:
        - media
    - title: Weather
      description: 本地天气
      type: openweathermap
      options:
        lat: 38.9
        lon: 121.6
        units: metric
      secrets:
        apiKey: ${OWM_API_KEY}

要点:checkUpdates: false 断掉对 GitHub 的周期外呼;状态灯只对常驻服务开启、interval 保持默认 60 秒;HTTPS 服务显式写端口;secrets 用环境变量注入并收紧 config.yml 文件权限(chmod 600)。

十一、常见问题(FAQ)

Q1: 改了配置页面纹丝不动? A: 无浏览器在线时热更新监听未激活,docker compose restart 即可(实测链路见 3.3)。

Q2: /api/settings 里出现 error 字段但进程没崩? A: 配置加载失败被兜底为「缺省配置 + error 信息」,按 error 内容改文件。实测 tags.reduce is not a function 即此类(9.2)。

Q3: 卡片图标不显示? A: 依次检查:Iconify 名格式必须 集合:图标(如 mdi:home);本地图标挂载在 v0.15.4 实际 404(9.4),改用 Iconify/Emoji/URL。

Q4: 状态灯与实际情况不符? A: TCP 探测只看端口,默认探 80(8.章端口陷阱);防火墙放行但应用未监听时也会显示在线。状态灯只作粗筛。

Q5: 天气卡片一直转圈? A: 检查 secrets.apiKey 是否有效与 options.lat/lon 是否数值型;服务端缓存 1440 秒,改配置后旧值可能滞留到缓存过期。

十二、参考链接

Mafl 0.15.4 配置参数详解 - Quzuo