Separate Containers Setup
For more control over your database — e.g. using an existing Postgres instance, custom tuning, or separate scaling — run PostgreSQL and heaper as separate containers.
This setup uses ghcr.io/janlunge/heaper-postgres:latest which includes the ULID extension required by heaper.
Docker Compose
services:
postgres:
image: ghcr.io/janlunge/heaper-postgres:latest
platform: linux/amd64 # Required on ARM devices
container_name: heaper-selfhost-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=heaper
- POSTGRES_PASSWORD=change-me-please
- POSTGRES_DB=heaper
volumes:
- ./heaper-data/postgres:/var/lib/postgresql/data
# Uncomment to expose PostgreSQL externally:
# ports:
# - "5432:5432"
heaper:
image: ghcr.io/janlunge/heaper:latest
platform: linux/amd64 # Required on ARM devices
container_name: heaper-selfhost
restart: unless-stopped
mem_limit: 4g
memswap_limit: 4g
depends_on:
- postgres
ports:
- "3010:80"
environment:
- HOSTNAME=localhost
- ENABLE_INTERNAL_POSTGRES=false
- DB_HOST=postgres:5432
- DB_USER=heaper
- DB_PASS=change-me-please
- DB_NAME=heaper
volumes:
- ./heaper-data/config:/usr/src/app/config
- ./heaper-data/data:/usr/src/app/data
- ./heaper-data/thumbnails:/mnt/thumbnails
- ./heaper-data/storage:/mnt/storage
- ./heaper-data/backups:/mnt/backups
Before first run: Change POSTGRES_PASSWORD and DB_PASS to the same secure password.
Start it:
docker-compose up -d
Access: http://localhost:3010
Docker Run
# Create network
docker network create heaper
# Run PostgreSQL
docker run -d --name heaper-selfhost-postgres --platform linux/amd64 \
-e POSTGRES_USER=heaper \
-e POSTGRES_PASSWORD=YOURPASSWORD \
-e POSTGRES_DB=heaper \
-p "5432:5432" \
--volume /path/to/heaper/postgres:/var/lib/postgresql/data \
--network heaper \
ghcr.io/janlunge/heaper-postgres:latest
# Run Heaper
docker run -d --name heaper-selfhost --platform linux/amd64 \
-p 3010:80 \
-e HOSTNAME=your-domain.com \
-e ENABLE_INTERNAL_POSTGRES=false \
-e DB_HOST=heaper-selfhost-postgres:5432 \
-e DB_USER=heaper \
-e DB_PASS=YOURPASSWORD \
-e DB_NAME=heaper \
--volume /path/to/heaper/config:/usr/src/app/config \
--volume /path/to/heaper/thumbnails:/mnt/thumbnails \
--volume /path/to/heaper/storage:/mnt/storage \
--network heaper \
ghcr.io/janlunge/heaper:latest
Environment Variables
PostgreSQL Container
| Variable | Default | Description |
|---|---|---|
POSTGRES_USER | heaper | PostgreSQL username |
POSTGRES_PASSWORD | — | PostgreSQL password |
POSTGRES_DB | heaper | PostgreSQL database name |
Heaper Container
| Variable | Default | Description |
|---|---|---|
HOSTNAME | localhost | Your domain name |
ENABLE_INTERNAL_POSTGRES | false | Must be false for this setup |
DB_HOST | — | Postgres host and port (e.g. postgres:5432) |
DB_USER | — | Postgres username |
DB_PASS | — | Postgres password |
DB_NAME | — | Postgres database name |
Using an Existing PostgreSQL Instance
If you already have a PostgreSQL server, you can skip the postgres container entirely. Make sure your database has the ULID extension installed, then point the heaper container at your instance via the DB_* environment variables.