Self-Hosting
heaper can be self-hosted, giving you complete control over your data and infrastructure.
Prerequisites
- Docker
- Domain (recommended for TLS via a reverse proxy like Caddy or nginx)
Platform Architecture
The heaper image is built for x64 (amd64) and ARM64 (aarch64) devices.
Docker run
docker run -d --name heaper-selfhost \
-p 3010:80 \
# ... other options
ghcr.io/janlunge/heaper:latest
Quick Start
Create a docker-compose.yml:
services:
heaper:
image: ghcr.io/janlunge/heaper:latest
platform: linux/amd64 # Required on ARM (Raspberry Pi, Apple Silicon)
container_name: heaper
restart: unless-stopped
mem_limit: 4g
memswap_limit: 4g
ports:
- "3010:80"
# - "5432:5432" # Uncomment to expose PostgreSQL externally
environment:
- HOSTNAME=localhost
- POSTGRES_USER=heaper
- POSTGRES_PASSWORD=change-me-please
- POSTGRES_DB=heaper
- ENABLE_INTERNAL_POSTGRES=true
volumes:
- ./heaper-data/postgres:/var/lib/postgresql/data
- ./heaper-data/data:/usr/src/app/data
- ./heaper-data/config:/usr/src/app/config
- ./heaper-data/thumbnails:/mnt/thumbnails
- ./heaper-data/storage:/mnt/storage
- ./heaper-data/backups:/mnt/backups
Info: When using Podman instead of Docker, the Postgres volume (
/var/lib/postgresql/data) cannot be bind-mounted to a host path — Postgres requires specific permissions that Podman does not allow for bind mounts. Use a named volume (e.g.postgres_data:/var/lib/postgresql/data) instead.
Change POSTGRES_PASSWORD to a secure password, then:
docker-compose up -d
Access: http://localhost:3010
For more details (docker run, environment variables, volumes) see the All-in-one setup guide.
Looking for a setup with a separate PostgreSQL container? See the Separate containers guide.
Updating
docker-compose pull
docker-compose up -d
Docker run: Pull the new image, remove the old container, then run your original docker run command again.
Nightly Test Builds
If you want to test a pre-release build before it goes live, replace ghcr.io/janlunge/heaper:latest with ghcr.io/janlunge/heaper:nightly.
Nightly is an opt-in testing channel for the combined self-hosted image. It may include unfinished changes and is less stable than latest.
Backup & Restore
Automated Backups
Heaper supports automated daily database backups. Backups run automatically when the /mnt/backups volume is mounted.
| Variable | Default | Description |
|---|---|---|
BACKUP_ENCRYPTION_KEY | (optional) | Passphrase for AES-256-GCM encryption |
BACKUP_RETENTION_DAYS | 7 | Number of days to keep backups |
BACKUP_HOUR | 3 | Hour (UTC) to run daily backup (0-23) |
Docker Compose: The compose file already mounts ./heaper-data/backups:/mnt/backups. Add to the service environment to enable encrypted backups:
- BACKUP_ENCRYPTION_KEY=your-secure-passphrase
Docker run — enable automated backups:
docker run -d --name heaper-selfhost \
--volume /path/to/heaper/backups:/mnt/backups \
# ... other options
ghcr.io/janlunge/heaper:latest
Docker run — encrypted backups (recommended):
docker run -d --name heaper-selfhost \
-e BACKUP_ENCRYPTION_KEY=your-secure-passphrase \
--volume /path/to/heaper/backups:/mnt/backups \
# ... other options
ghcr.io/janlunge/heaper:latest
Backup filenames:
- Unencrypted:
heaper_backup_20240115_030000.sql - Encrypted:
heaper_backup_20240115_030000.sql.enc
Manual Database Backup
All-in-one setup (container name heaper with compose, heaper-selfhost with docker run):
docker exec heaper pg_dump -U heaper heaper > backup.sql
Separate containers setup:
docker exec heaper-selfhost-postgres pg_dump -U heaper heaper > backup.sql
Restore Database
All-in-one setup:
docker exec -i heaper psql -U heaper heaper < backup.sql
Separate containers setup:
docker exec -i heaper-selfhost-postgres psql -U heaper heaper < backup.sql
Decrypt Backup (for encrypted backups)
Encrypted backups (.sql.enc) use AES-256-GCM with the nonce prepended. To restore:
- Unencrypted backups can be restored directly with
psql - Encrypted backups must be decrypted first (key derived via SHA-256 from passphrase)
File Backup
Back up your mounted volumes regularly:
/var/lib/postgresql/data— Database files/usr/src/app/config— Configuration/mnt/thumbnails— Thumbnails/mnt/storage— User files/mnt/backups— Encrypted database backups
Troubleshooting
Check Service Health
# Check container health (use heaper for compose, heaper-selfhost for docker run)
docker inspect --format='{{.State.Health.Status}}' heaper
# Backend API health (use 3010 for compose default)
curl http://localhost:3010/api
# Sync server health
curl http://localhost:3010/sync/health
# PostgreSQL health (single container / compose)
docker exec heaper pg_isready -h localhost -U heaper
View Logs
# All logs (container name: heaper with compose, heaper-selfhost with docker run)
docker logs -f heaper
# Follow specific service logs (via supervisor)
docker exec heaper tail -f /var/log/supervisor/*.log
Connect to PostgreSQL
With Docker Compose, PostgreSQL is not exposed by default. Uncomment - "5432:5432" in the compose file to expose it. Then:
# Using psql
psql -h localhost -p 5432 -U heaper -d heaper
# Using a GUI tool (TablePlus, pgAdmin, etc.)
# Host: localhost (or your server IP)
# Port: 5432
# User: heaper
# Password: your-secure-password
# Database: heaper
Connecting to Your Server
To use your self-hosted instance in the heaper app, first login to your cloud account then add a new server via Settings → Heaps → Pull Heap and enter the IP or hostname of your server.
Note: For TLS encryption, use a reverse proxy (e.g. Caddy, nginx) in front of heaper with a valid domain and certificate.