One-command Heimdall for homelab beginners — official images, backup-before-update.
git clone https://github.com/johnycsf/heimdall-docker.git
cd heimdall-docker
chmod +x manage.sh
./manage.sh./manage.sh opens a ↑/↓ menu with a > cursor (j/k and Enter also work). Open http://YOUR_IP:8080/ (or the HTTP_PORT from .env).
Uses the official php:8.4-apache image and builds Heimdall from the upstream release (no LinuxServer container runtime).
Kubernetes version: heimdall-k8s
Updating an older clone?
git pullalone will not wipe data. Re-running install/compose can break a LinuxServer-based install. Read BREAKING-CHANGES.md first.
./manage.shcontrol center — install, update, backup, status/doctor, uninstall- Interactive colored install with step progress
- Auto-detects your OS and installs missing host tools
- Safe
./manage.sh updatewith automatic pre-update backup - Incremental hardlink
./manage.sh backup+ restore - Official upstream images only
- A Linux host (Debian/Ubuntu, Fedora/RHEL, Arch, openSUSE, Alpine) or macOS with Homebrew
sudoso./manage.shcan install missing tools (Docker, curl, openssl, rsync, …)- Enough disk for your data
Edit .env (created from .env.example):
| Variable | Default | Purpose |
|---|---|---|
TZ |
America/New_York |
Timezone |
HTTP_PORT |
8080 |
Host port (Docker users may set 80) |
ALLOW_INTERNAL_REQUESTS |
true |
Allow Heimdall to reach LAN app IPs |
APP_URL |
http://localhost:8080 |
Public URL (set this if you use a reverse proxy) |
./manage.sh updateBefore updating, the script runs ./manage.sh backup into ./backups (incremental, SQLite-safe). Afterward it asks whether to keep that snapshot and how many copies to retain.
Prefer an external drive or NAS (hardlinks need one filesystem):
./manage.sh backup --dest /mnt/backup --keep 5Each run writes /mnt/backup/heimdall-docker/snapshots/....
Restore (this machine or a new one after ./manage.sh / with compose present):
./manage.sh backup --restore --from /mnt/usb/heimdall-docker-backups
# or a local snapshot tree:
./manage.sh backup --restore --from ./backupsEach snapshot includes SHA256SUMS plus a snapshot_sha256 key in META.txt. Restore warns (does not abort) if integrity is lost.
Database safety: Heimdall (SQLite) is stopped, WAL-checkpointed when sqlite3 is available, integrity-checked, then copied. Incremental hardlinks apply to file trees; each dump is a full verified file with a SHA-256 in META.txt.
Older backups/update-* tarball folders (from previous script versions) are no longer used by ./manage.sh update; use each folder's RESTORE.txt if you still need one, or delete them to free space.
Only for installs already on this repo's official-php image — see BREAKING-CHANGES.md.
docker compose down
# optional: delete local data
rm -rf dataOr use Uninstall in ./manage.sh.
During ./manage.sh (or Manage → Install / reconfigure), the script checks whether default host ports are free, lets you keep the defaults or choose different ports, and saves them in .env. Re-running install keeps your current ports unless you change them.
Non-interactive: set the port variables in .env (or the environment) and use SKIP_PORT_PROMPTS=1.
Defaults are kept unique across the johnycsf stacks so you can run several on one host without a clash:
| Stack | Variable | Default host port |
|---|---|---|
heimdall-docker |
HTTP_PORT |
8080 |
vaultwarden-docker |
PORT |
8081 |
nextcloud-office-docker |
NEXTCLOUD_PORT |
8082 |
nextcloud-office-docker |
COLLABORA_PORT |
9980 |
immich-docker |
IMMICH_PORT |
2283 |
Install also refuses a port another stack checked out beside this one already claims in its .env — even when that stack is stopped — and offers the next free port instead.
All defaults are >= 1024 because rootless Podman cannot publish privileged ports (80, 443). On Docker you may still set HTTP_PORT=80 if you want.
During ./manage.sh → Install you can choose Docker or Podman. The choice is saved as CONTAINER_ENGINE in .env and reused for every manage action (update, backup, restore, status, …) via a shared compose helper. Restore preserves that host choice (and host ports) even if the backup’s .env is older.
Note: After containers start, some files under
data/may be root-owned. Install/restore automatically fixes ownership for the invoking user so host-sidersyncbackup/restore does not fail with permission errors.
Local snapshots stay as incremental hardlink trees (fast rollback). Optionally create a compressed offsite copy with ./manage.sh backup --dest ./backups --archive tar.gz|tar.xz|zip (add --archive-password for zip password or age-passphrase on tar). For stronger key-based encryption use --encrypt (age). See repo-framework docs/BACKUP_ENCRYPTION.md.
This repo packages or configures upstream software. See CREDITS.md for the main developers and projects this work builds on.
This project is provided as is. The author is not responsible for any loss, damage, data corruption, downtime, security issues, or other consequences from using it. Full text: DISCLAIMER.md.
If you hit an error, please open a GitHub Issue and follow CONTRIBUTING.md. Fixes via Pull Request are welcome. GitHub Issues/PRs are the supported way to report problems—there is no private support channel.
See SECURITY.md for how to report vulnerabilities.
Sponsorship funds testing and maintenance: github.com/sponsors/johnycsf.
