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) only. On ARM devices (Raspberry Pi, Apple Silicon, etc.) you must add the platform flag to run via emulation:

Docker Compose — add platform: linux/amd64 to the service:

services:
  heaper:
    image: ghcr.io/janlunge/heaper:latest
    platform: linux/amd64   # Required on ARM devices
    container_name: heaper
    # ... rest of config

Docker run — add --platform linux/amd64:

docker run -d --name heaper-selfhost --platform linux/amd64 \
  -p 3010:80 \
  # ... other options
  ghcr.io/janlunge/heaper:latest

Note: Running amd64 on ARM uses QEMU emulation and may be slower. Ensure Docker's binfmt support is available (Docker Desktop handles this automatically).

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

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.

Backup & Restore

Automated Backups

Heaper supports automated daily database backups. Backups run automatically when the /mnt/backups volume is mounted.

VariableDefaultDescription
BACKUP_ENCRYPTION_KEY(optional)Passphrase for AES-256-GCM encryption
BACKUP_RETENTION_DAYS7Number of days to keep backups
BACKUP_HOUR3Hour (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:

  1. Unencrypted backups can be restored directly with psql
  2. 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.