Heimdall Docker Compose 部署指南

Ubuntu 24.04.5 上用 Docker Compose 部署 Heimdall v2.8.4(linuxserver 官方镜像)的实测全流程,含首启自动安装、HTTPS 验证、卡片创建与排障实录。

Heimdall面板Docker部署自托管2026/11/03

Heimdall Docker Compose 部署指南

目标:在 Ubuntu 24.04.5 服务器上用 Docker Compose 部署 Heimdall v2.8.4(linuxserver 官方镜像),完成首启自动安装、HTTPS 验证、卡片创建与数据持久化闭环。本文全部命令与回显为 2026-11-02/03 实测,含 HTTPS 首访 500、root 跑 artisan 引发权限 500、卡片不显示(type 传字符串)等排障实录。

一、环境信息

项目值
主机 OSUbuntu 24.04.5 LTS(内核 x86_64)
Docker29.9.2
Docker Composev5.6.1
组件版本Heimdall v2.8.4(GitHub Release,2026-10-29 发布)
镜像lscr.io/linuxserver/heimdall:2.8.4(ls371 构建,2026-10-30,磁盘占用 332530079 字节 ≈ 332MB)
运行期Alpine Linux 3.24.3 + nginx 1.30.6 + PHP 8.5.12(NTS)+ Laravel Framework 13.39.0 + SQLite 3.53.4
Web 端口宿主 8135→80(HTTP)、8136→443(HTTPS,自签证书)
数据目录宿主 ./data/config 挂载至服务内 /config
网络自定义 bridge heimdall-net,显式网段 10.89.62.0/24,服务实例 IP 10.89.62.2
项目名compose 显式 name: heimdall-2.8.4-stack(实际生效名 heimdall-284-stack,见 FAQ 11.1)

💡 说明:Heimdall 是单容器 PHP 应用(Laravel + SQLite,无外部数据库依赖),版本核实过程与选型背景见《Heimdall 介绍与选型指南》。

二、镜像选型说明

Heimdall 官方推荐的交付形态就是 linuxserver 维护的多架构镜像(应用仓库 README 明确指向 https://hub.docker.com/r/linuxserver/heimdall/)。常用标签对照(2026-11-03 实查 Docker Hub,共 4570 个标签):

标签含义适用场景
latest跟随最新稳定版(当前即 2.8.4)愿意接受自动升级的小白用户
2.8.4应用版本号锁定生产推荐,升级可控
version-v2.8.4应用版本 + v 前缀别名与 GitHub tag 对齐
v2.8.4-ls371应用版本 + lsio 构建号(镜像层修复随 ls 序号走)精确复现实验/排障
amd64-2.8.4 / arm64v8-2.8.4单架构变体(另支持 armhf)树莓派/NAS 等 ARM 设备

关键差异:latest 与 2.8.4 当前指向同一 digest(sha256:80c6a91e8d14...),但 latest 会随上游发版漂移;生产环境一律锁应用版本标签,升级走第十节显式流程。

三、前置条件

3.1 端口空闲核实

部署前先确认计划使用的 8135/8136/8137 未被占用。部署时实测:

$ ss -ltn | awk '{print $4}' | grep -oE '[0-9]+$' | sort -n | uniq | grep -E '^81[0-9][0-9]$'
8125
8128
8129
8130
8132
8133
8138
8141
8143
8147

8135-8137 不在已占列表内,可用。

3.2 网段空闲核实

自定义网络需避开已占用的 10.89.x.0/24:

$ docker network ls -q | xargs -r docker network inspect --format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}' | grep -E '10\.89\.'
auto-mcs-239-stack_auto-mcs-net 10.89.59.0/24
easywi-622-stack_easywi-net 10.89.65.0/24
froxlor-2316-stack_froxlor-net 10.89.68.0/24
gameap-458-stack_gameap-net 10.89.56.0/24

10.89.62.0/24 空闲,本部署显式占用该网段。

3.3 Docker 引擎就绪

$ docker version --format 'Docker {{.Server.Version}}'
Docker 29.9.2
$ docker compose version
Docker Compose version v5.6.1

四、部署步骤

4.1 建立项目目录与 compose 文件

$ mkdir -p /opt/apps/heimdall/compose/data/config
$ cd /opt/apps/heimdall/compose

docker-compose.yml 全文:

name: heimdall-2.8.4-stack
services:
  heimdall:
    image: lscr.io/linuxserver/heimdall:2.8.4
    container_name: heimdall-2.8.4-panel
    hostname: heimdall
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
    volumes:
      - ./data/config:/config
    ports:
      - 8135:80
      - 8136:443
    networks:
      - heimdall-net
    restart: unless-stopped

networks:
  heimdall-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.62.0/24

逐项说明:

  • name: 显式项目名,避免与其他项目目录同名互删;
  • PUID/PGID=1000:以宿主普通用户身份运行应用进程(linuxserver 镜像通用机制);
  • TZ=Asia/Shanghai:影响日志与定时任务时区;
  • ./data/config:/config:全部持久化数据(数据库、图标、证书、nginx/php 定制)都落在 /config,见第五节;
  • 端口只映射 80/443 两路,Heimdall 无其他对外端口。

4.2 拉取镜像

$ docker pull lscr.io/linuxserver/heimdall:2.8.4
13c4850eef55: Pull complete
a01991118954: Pull complete
Digest: sha256:80c6a91e8d14e7ac5b7461a0877b8db8bca659e62ddc944d1f37e5159e7efa55
Status: Downloaded newer image for lscr.io/linuxserver/heimdall:2.8.4
lscr.io/linuxserver/heimdall:2.8.4

4.3 启动栈

$ docker compose up -d
 Network heimdall-284-stack_heimdall-net Creating 
 Network heimdall-284-stack_heimdall-net Created 
 Container heimdall-2.8.4-panel Creating 
 Container heimdall-2.8.4-panel Created 
 Container heimdall-2.8.4-panel Starting 
 Container heimdall-2.8.4-panel Started

注意回显中的网络名已是 heimdall-284-stack_...——compose 对项目名中的点号做了归一化(FAQ 11.1)。

$ docker compose ps
NAME                   IMAGE                                COMMAND   SERVICE    CREATED         STATUS         PORTS
heimdall-2.8.4-panel   lscr.io/linuxserver/heimdall:2.8.4   "/init"   heimdall   9 seconds ago   Up 8 seconds   0.0.0.0:8135->80/tcp, [::]:8135->80/tcp, 0.0.0.0:8136->443/tcp, [::]:8136->443/tcp

4.4 首启自动安装过程(日志取证)

Heimdall 镜像首次启动会自动完成迁移、生成加密密钥、自签证书,无需手工安装:

$ docker logs heimdall-2.8.4-panel 2>&1 | head -40
[migrations] started
[migrations] 01-nginx-site-confs-default: executing...
[migrations] 01-nginx-site-confs-default: succeeded
[migrations] 02-default-location: executing...
[migrations] 02-default-location: succeeded
[migrations] done
───────────────────────────────────────

      ██╗     ███████╗██╗ ██████╗
      ██║     ██╔════╝██║██╔═══██╗
      ██║     ███████╗██║██║   ██║
      ██║     ╚════██║██║██║   ██║
      ███████╗███████║██║╚██████╔╝
      ╚══════╝╚══════╝╚═╝ ╚═════╝

   Brought to you by linuxserver.io
───────────────────────────────────────
...
User UID:    1000
User GID:    1000
───────────────────────────────────────
Linuxserver.io version: v2.8.4-ls371
Build-date: 2026-10-30T22:20:54+00:00
───────────────────────────────────────
    
Setting resolver to  127.0.0.11
Setting worker_processes to 6
generating self-signed keys in /config/keys, you can replace these with your own keys if required
-----
New container detected, installing Heimdall
Creating app key. This may take a while on slower systems

   INFO  Application key set successfully.  

[custom-init] No custom files found, skipping...
[ls.io-init] done.

关键行解读:Linuxserver.io version: v2.8.4-ls371 确认应用版本与构建号;New container detected, installing Heimdall 表示首启安装被触发;Application key set successfully 即 Laravel APP_KEY 已生成写入 /config/www/.env;generating self-signed keys in /config/keys 为 HTTPS 生成自签证书。

4.5 HTTP 入口验证

$ curl -s -m 10 -i http://127.0.0.1:8135/ | head -12
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.5.12
Cache-Control: no-cache, private
Date: Mon, 02 Nov 2026 16:35:43 GMT
Set-Cookie: XSRF-TOKEN=eyJpdiI6...; expires=Mon, 02 Nov 2026 18:35:43 GMT; Max-Age=7200; path=/; samesite=lax
Set-Cookie: heimdall_session=eyJpdiI6...; expires=Mon, 02 Nov 2026 18:35:43 GMT; Max-Age=7200; path=/; httponly; samesite=lax
Strict-Transport-Security: max-age=63072000

X-Powered-By: PHP/8.5.12 与 heimdall_session Cookie 证实 Laravel 应用已在响应。响应头里的 Strict-Transport-Security 由镜像 nginx 配置注入。

4.6 HTTPS 入口验证

$ curl -sk -m 10 -o /dev/null -w "%{http_code} %{ssl_verify_result}\n" https://127.0.0.1:8136/
200 18

ssl_verify_result=18 为自签证书校验失败的预期值(深度 18 表示自签根)。首访曾返回 500,属冷启动缓存权限竞态,复现与修复见 FAQ 11.3。

4.7 创建第一张卡片(表单闭环实测)

Heimdall 2.x 首启自动创建默认用户(users 表 username=admin、email=admin@test.com、密码为空),Web 界面默认无需登录即可使用(见 FAQ 11.6)。用 curl 模拟表单建卡:

$ rm -f cj.txt
$ TOKEN=$(curl -s -c cj.txt -m 10 http://127.0.0.1:8135/items/create | grep -oE 'name="_token" value="[^"]*"' | head -1 | sed 's/.*value="//;s/"//')
$ echo "token_len=${#TOKEN}"
token_len=40
$ curl -s -b cj.txt -c cj.txt -m 10 -X POST http://127.0.0.1:8135/items \
    -H 'Accept: application/json' \
    -d "_token=$TOKEN&title=Portainer&url=http://10.89.62.1:9443&type=0&colour=%23f0a30a&size=md&pin=0" -w "\nHTTP:%{http_code}\n"
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url='http://127.0.0.1:8135'" />
        <title>Redirecting to http://127.0.0.1:8135</title>
    </head>
    <body>
        Redirecting to <a href="http://127.0.0.1:8135">http://127.0.0.1:8135</a>.
    </body>
</html>

HTTP:302

302 回首页即建卡成功。用只读 API 验证:

$ curl -s -m 10 http://127.0.0.1:8135/api/item -H 'Accept: application/json'
[{"title":"Portainer","colour":"#f0a30a","url":"http:\/\/10.89.62.1:9443","description":null,"appid":null,"appdescription":null,"pinned":0,"pinned_order":0,"tags":[]}]

⚠️ 注意:type 字段必须传 0(链接类)。若按直觉传字符串 link,卡片会入库但首页与 API 都不显示(API 按 type='0' 过滤),排障过程见 FAQ 11.4。

五、数据持久化说明

全部状态收敛在 /config 卷(宿主 ./data/config)。首启后目录实况:

$ ls -la data/config/
total 32
drwxr-xr-x 7 yahui yahui 4096 Nov  3 00:35 .
drwxr-xr-x 3 root  root  4096 Nov  3 00:35 ..
drwxr-xr-x 2 yahui yahui 4096 Nov  3 00:35 keys
drwxr-xr-x 5 yahui yahui 4096 Nov  3 00:35 log
-rw-r--r-- 1 yahui yahui   48 Nov  3 00:35 .migrations
drwxrwxr-x 3 yahui yahui 4096 Nov  3 00:35 nginx
drwxr-xr-x 2 yahui yahui 4096 Nov  3 00:35 php
drwxr-xr-x 7 yahui yahui 4096 Nov  3 00:35 www

$ ls data/config/www/
app.sqlite  avatars  backgrounds  icons  index.html  logs  searchproviders.yaml  SupportedApps
路径内容备份优先级
www/app.sqlite唯一数据库:卡片(items)、标签(tags/item_tag)、设置(settings)、用户(users)、应用注册缓存(applications)必背
www/.envLaravel 环境文件,含 APP_KEY(加密会话/凭据的根密钥)必背
www/searchproviders.yaml搜索条配置(可自定义,见配置篇)建议
www/icons/、www/backgrounds/、www/avatars/上传的图标、背景图、头像建议
www/logs/Laravel 按日应用日志(排障用)可选
keys/自签 HTTPS 证书 cert.crt/cert.key可选
nginx/、php/nginx 站点配置与 PHP 定制(php-local.ini 等)建议
log/nginx/php 访问与错误日志可选
.migrationslsio 镜像层迁移记录(01-nginx-site-confs-default、02-default-location)不动

持久化验证(重建栈数据不丢):

$ docker compose down
 Container heimdall-2.8.4-panel Removed 
 Network heimdall-284-stack_heimdall-net Removing 
 Network heimdall-284-stack_heimdall-net Removed 
$ docker compose up -d
 Container heimdall-2.8.4-panel Starting 
 Container heimdall-2.8.4-panel Started 
$ curl -s -m 8 http://127.0.0.1:8135/api/item -H 'Accept: application/json'
[{"title":"Portainer","colour":"#f0a30a","url":"http:\/\/10.89.62.1:9443","description":null,"appid":null,"appdescription":null,"pinned":0,"pinned_order":0,"tags":[]}]

💡 说明:备份即打包 /config 目录:tar czf heimdall-config-$(date +%F).tar.gz -C data config。恢复时解包回同路径再起栈即可;APP_KEY 必须与 app.sqlite 同批备份,否则库内加密字段(Enhanced 应用凭据)不可解。

六、环境变量表

镜像支持的运行时变量(docker inspect 实测生效值 + 官方 README 对照):

变量实测值默认说明
PUID1000911应用进程属主 UID(lsio 机制,改后需保证 /config 可写)
PGID1000911应用进程属主 GID
TZAsia/ShanghaiUTC时区,影响日志时间与 Trianglify 等定时逻辑
ALLOW_INTERNAL_REQUESTS未设置(默认 false)falseSSRF 防护开关。为 false 时,图标抓取与 Enhanced 应用 API 拒绝访问内网/回环地址;增强应用与 Heimdall 不同网段时需设 true(实测拦截回显见 FAQ 11.5)
$ docker inspect heimdall-2.8.4-panel --format '{{.Config.Env}}'
[TZ=Asia/Shanghai PUID=1000 PGID=1000 PATH=/lsiopy/bin:/usr/local/sbin:... PHP_INI_SCAN_DIR=:/config/php LSIO_FIRST_PARTY=true]

回显中 PHP_INI_SCAN_DIR=:/config/php 是镜像把 /config/php 挂进 PHP 附加 ini 扫描目录的机制——这正是第八节 php-local.ini 生效的原因。

七、配置参数说明

本镜像的配置面分四层(全部参数逐项详解见《Heimdall 2.8.4 配置参数详解》):

  1. 运行时环境变量:第六节 4 项;
  2. /config/www/.env:Laravel 框架级参数(APP_KEY、SESSION_LIFETIME、AUTH_ROLES_* 等 40+ 键);
  3. 应用内设置:Web「Settings」页,落 settings 表(language、search_provider、trianglify、skip_tls_verification 等 15 键);
  4. 文件级定制:/config/php/php-local.ini(PHP 直改)、/config/nginx/site-confs/default.conf(站点)、/config/www/searchproviders.yaml(搜索条)。

八、配置文件挂载

/config 整体即宿主 bind mount,无需额外挂载。定制示例——背景图上传限 2MB 的放开(FAQ 11.2 同源问题):

$ printf "upload_max_filesize = 30M\npost_max_size = 30M\n" >> data/config/php/php-local.ini
$ cat data/config/php/php-local.ini
; Edit this file to override php.ini directives

date.timezone = Asia/Shanghai
upload_max_filesize = 30M
post_max_size = 30M

$ docker compose restart
 Container heimdall-2.8.4-panel Restarting 
 Container heimdall-2.8.4-panel Started 

$ docker exec heimdall-2.8.4-panel php -i 2>/dev/null | grep -E "upload_max_filesize|post_max_size"
post_max_size => 30M => 30M
upload_max_filesize => 30M => 30M

默认值 upload_max_filesize=2M、post_max_size=8M(改前实测),追加行后重启即覆盖生效。

nginx 层同理可改 data/config/nginx/site-confs/default.conf(完整解读与 basic auth 开关见配置篇),改完在容器内执行:

$ docker exec heimdall-2.8.4-panel nginx -s reload
$ echo $?
0

九、等价 docker run

compose 与 docker run 参数等价。独立实例实测(换 8137 端口、独立数据目录,验证与 compose 栈并行无冲突):

$ docker run -d --name heimdall-2.8.4-run \
    -p 8137:80 \
    -e PUID=1000 -e PGID=1000 -e TZ=Asia/Shanghai \
    -v /opt/apps/heimdall/run-data:/config \
    --network heimdall-284-stack_heimdall-net \
    lscr.io/linuxserver/heimdall:2.8.4
254c7a1820886701987d3367871a73d1a90f57199d97c6ee7a357bd11c4c6e38

$ curl -s -m 10 -o /dev/null -w "run instance: %{http_code}\n" http://127.0.0.1:8137/
run instance: 200

$ curl -s -m 8 http://127.0.0.1:8137/api/item -H 'Accept: application/json'
[]

新实例返回空列表 [],证明数据完全由各自 /config 卷决定、互不串扰。验证完清理:

$ docker rm -f heimdall-2.8.4-run
heimdall-2.8.4-run

十、常用运维命令

# 状态与日志
$ docker compose ps
NAME                   IMAGE                                COMMAND   SERVICE    CREATED         STATUS         PORTS
heimdall-2.8.4-panel   lscr.io/linuxserver/heimdall:2.8.4   "/init"   heimdall   9 minutes ago   Up 9 minutes   0.0.0.0:8135->80/tcp, [::]:8135->80/tcp, 0.0.0.0:8136->443/tcp, [::]:8136->443/tcp

$ docker compose logs --tail 5
heimdall-2.8.4-panel  |     
heimdall-2.8.4-panel  | using keys found in /config/keys
heimdall-2.8.4-panel  | New container detected, installing Heimdall
heimdall-2.8.4-panel  | [custom-init] No custom files found, skipping...
heimdall-2.8.4-panel  | [ls.io-init] done.

# 进入服务环境(务必带 --user abc,原因见 FAQ 11.3;exec 默认 root)
$ docker exec --user abc heimdall-2.8.4-panel bash -c 'whoami; pwd'
abc
/

# 内部服务状态(s6 监管:nginx / php-fpm / queue / cron 四个服务)
# 注意 s6-svstat 只接受一个服务参数,多传只回第一行,需逐服务执行:
$ docker exec heimdall-2.8.4-panel s6-svstat /run/service/svc-nginx
up (pid 264 pgid 264) 584 seconds
$ docker exec heimdall-2.8.4-panel s6-svstat /run/service/svc-php-fpm
up (pid 263 pgid 263) 584 seconds
$ docker exec heimdall-2.8.4-panel s6-svstat /run/service/svc-queue
up (pid 262 pgid 262) 584 seconds
$ docker exec heimdall-2.8.4-panel s6-svstat /run/service/svc-cron
up (pid 265 pgid 265) 584 seconds

# 维护模式(升级/排障时挡流量)
$ docker exec --user abc heimdall-2.8.4-panel bash -c 'cd /app/www && php artisan down'

   INFO  Application is now in maintenance mode.  

$ curl -s -m 5 -o /dev/null -w "down: %{http_code}\n" http://127.0.0.1:8135/
down: 503
$ docker exec --user abc heimdall-2.8.4-panel bash -c 'cd /app/www && php artisan up'

   INFO  Application is now live.  

$ curl -s -m 5 -o /dev/null -w "up: %{http_code}\n" http://127.0.0.1:8135/
up: 200

# 升级:改 compose 里的 image 标签后
$ docker compose pull
$ docker compose up -d
$ docker compose logs | grep "Linuxserver.io version"
Linuxserver.io version: v2.8.4-ls371

# 停止与卸载(数据卷在宿主 ./data/config,down 不删数据)
$ docker compose down

升级说明:Heimdall 更新即换镜像(应用仓库 README:「copy it over the old installation」,容器形态等价于换 tag);数据库迁移在新版本启动时自动执行,升级前备份 data/config 即可。

十一、常见问题

11.1 compose 项目名中的点号被归一化

name: heimdall-2.8.4-stack 起栈后,网络实际叫 heimdall-284-stack_heimdall-net(回显见 4.3)。compose 规范会剥掉项目名里的 .——按项目名引用资源(docker compose -p、跨 compose 挂网络)时必须用归一化后的名字,直接写 heimdall-2.8.4-stack 会找不到。

11.2 背景图上传超过 2MB 不生效

现象:Settings 页选了大图,保存后背景不变、也无报错。根因:PHP 默认 upload_max_filesize=2M(实测见第八节),超限文件被 PHP 静默丢弃。解决:往 /config/php/php-local.ini 追加 upload_max_filesize = 30M(第八节实测闭环)。官方 README 亦点名此坑并要求 php_fileinfo 扩展开启。

11.3 首访 HTTPS 返回 500 / 跑过 artisan 后全站 500(权限实录)

现象一:首启后 https:// 首次访问返回 500(HTTP 正常),日志:

[2026-11-02 16:38:48] local.ERROR: fopen(/app/www/storage/framework/cache/data/15/ba/15ba45b99994fa55e478b5b6d8dc9af9bd206fe9): Failed to open stream: Permission denied

再访问即恢复 200。现象二(同一根因的持续形态):以 root 身份进容器执行 php artisan down 之后,全站持续 500:

$ docker exec heimdall-2.8.4-panel bash -c 'find /app/www/storage/framework/cache/data -user root'
/app/www/storage/framework/cache/data/15
/app/www/storage/framework/cache/data/15/ba

定位:镜像内应用进程(php-fpm/queue worker)以 abc(UID 1000) 运行,而 docker exec 默认 root;root 执行 artisan 时 Laravel 启动过程新建的缓存子目录属主为 root(755),php-fpm 无法在其中写文件 → 500。解决:

$ docker exec heimdall-2.8.4-panel bash -c 'chown -R abc:users /app/www/storage'
$ curl -s -m 5 -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8135/
200

纪律:凡在容器内跑 artisan,一律 docker exec --user abc(本文第十节命令均已带)。首启安装脚本以 root 跑过一次 artisan 生成 APP_KEY,属镜像内置行为,不影响后续。

11.4 卡片建好了但首页和 API 都不显示

现象:4.7 节若把 type 传成字符串 link,POST 照样返回 302 成功,但 /api/item 不返回新卡片、首页也不显示。实测复现(卡片标题 TestLink):

$ curl -s -b cj.txt -c cj.txt -m 10 -X POST http://127.0.0.1:8135/items \
    -H 'Accept: application/json' \
    -d "_token=$TOKEN&title=TestLink&url=http://example.com&type=link&colour=%23161b1f&size=md&pin=0" -o /dev/null -w "POST HTTP:%{http_code}\n"
POST HTTP:302
$ docker exec heimdall-2.8.4-panel php -r '$p=new PDO("sqlite:/config/www/app.sqlite");$p->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);foreach($p->query("select id,title,type from items") as $r){echo json_encode($r),"\n";}'
{"id":2,"title":"Portainer","type":0}
{"id":6,"title":"TestLink","type":"link"}
$ curl -s -m 10 http://127.0.0.1:8135/api/item -H 'Accept: application/json'
[{"title":"Portainer","colour":"#f0a30a","url":"http:\/\/10.89.62.1:9443","description":null,"appid":null,"appdescription":null,"pinned":0,"pinned_order":0,"tags":[]}]

定位:行确实入库(type 成了字符串 "link"),但 API 与首页查询条件是 where('type','0')(链接类=0),'link' 不等于 '0' 被过滤。解决:修正字段值即恢复显示:

$ docker exec heimdall-2.8.4-panel php -r '$p=new PDO("sqlite:/config/www/app.sqlite");echo $p->exec("update items set type=0 where id=6")," rows\n";'
1 rows
$ curl -s -m 10 http://127.0.0.1:8135/api/item -H 'Accept: application/json'
[{"title":"Portainer","colour":"#f0a30a","url":"http:\/\/10.89.62.1:9443","description":null,"appid":null,"appdescription":null,"pinned":0,"pinned_order":0,"tags":[]},{"title":"TestLink","colour":"#161b1f","url":"http:\/\/example.com","description":null,"appid":null,"appdescription":null,"pinned":0,"pinned_order":0,"tags":[]}]

Web 表单正常操作不会出现此坑(表单提交的 type 本就是数字),主要防 API/脚本直连用户。

11.5 Enhanced 应用/图标指向内网地址返回 500

现象:给卡片填 http://10.89.62.2/ 这类内网 URL 触发网站抓取时:

$ curl -s -m 10 -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:8135/items/websitelookup/http://10.89.62.2/"
500

根因:SSRF 防护默认开启(.env 中 ALLOW_INTERNAL_REQUESTS=false,http(s) 之外与内网/回环地址一律拒绝)。若仪表盘与被监控应用同处一台宿主/同一内部网络,在 compose 的 environment: 加 - ALLOW_INTERNAL_REQUESTS=true 后 docker compose up -d 重建即放开。公网部署建议保持 false。

11.6 Heimdall 2.x 没有登录页,任何访客都能改面板?

实测:首启自动建默认用户 admin(无密码),直接访问 / 即仪表盘,/settings 可达;/login 路由存在但默认账号无密码不可用。2.x 的访问控制思路是部署侧防护:反代加认证、或打开容器 nginx 配置中被注释的 auth_basic 两行(配置篇有实测写法),亦可用 AUTH_ROLES_* 环境变量对接反传 Header 的角色体系(配置篇详解)。不要把裸面板直接暴露公网。

11.7 端口被占

若 8135 已被占用,起栈会报:

docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint heimdall-2.8.4-porttest (...): Bind for 0.0.0.0:8135 failed: port is already allocated

换端口(-p 8138:80)或停掉占用进程即可。

十二、参考链接