Heimdall Docker Compose 部署指南
Ubuntu 24.04.5 上用 Docker Compose 部署 Heimdall v2.8.4(linuxserver 官方镜像)的实测全流程,含首启自动安装、HTTPS 验证、卡片创建与排障实录。
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 传字符串)等排障实录。
一、环境信息
| 项目 | 值 |
|---|---|
| 主机 OS | Ubuntu 24.04.5 LTS(内核 x86_64) |
| Docker | 29.9.2 |
| Docker Compose | v5.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/.env | Laravel 环境文件,含 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 访问与错误日志 | 可选 |
.migrations | lsio 镜像层迁移记录(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 对照):
| 变量 | 实测值 | 默认 | 说明 |
|---|---|---|---|
PUID | 1000 | 911 | 应用进程属主 UID(lsio 机制,改后需保证 /config 可写) |
PGID | 1000 | 911 | 应用进程属主 GID |
TZ | Asia/Shanghai | UTC | 时区,影响日志时间与 Trianglify 等定时逻辑 |
ALLOW_INTERNAL_REQUESTS | 未设置(默认 false) | false | SSRF 防护开关。为 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 配置参数详解》):
- 运行时环境变量:第六节 4 项;
/config/www/.env:Laravel 框架级参数(APP_KEY、SESSION_LIFETIME、AUTH_ROLES_* 等 40+ 键);- 应用内设置:Web「Settings」页,落
settings表(language、search_provider、trianglify、skip_tls_verification 等 15 键); - 文件级定制:
/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)或停掉占用进程即可。
十二、参考链接
- Heimdall 应用仓库:https://github.com/linuxserver/Heimdall(默认分支 2.x,MIT,Copyright (c) 2018 Chris Hunt)
- 镜像仓库与参数文档:https://hub.docker.com/r/linuxserver/heimdall/
- 官网:https://heimdall.site
- 站内相关:《Heimdall 介绍与选型指南》、《Heimdall 2.8.4 配置参数详解》、《Heimdall 2.8.4 常用 CLI 命令与工具详解》