Self-host Coral Dash with Docker
A complete walkthrough — from licence key to first sync — for running Coral Dash on your own server. Roughly 15 minutes if your domain and Google Cloud project are ready.
Prerequisites
- Docker and Docker Compose v2+
- A server that can run Docker — VPS, Raspberry Pi 4/5, NAS, or any Linux/macOS host. Docker images are built for both
amd64andarm64. - A domain name with DNS pointed to your server (HTTPS is required for Google OAuth)
- A Google Cloud project with OAuth credentials (for sign-in and Sheets sync)
- A Coral Dash licence key — start a free trial or buy a permanent licence at coraldash.com/self-hosting
1. Get your licence key
Visit coraldash.com/self-hosting and either:
- Start a 7-day free trial — instant, no card required
- Purchase a permanent licence — £30 one-time via Stripe
Your key (a UUID) appears in your account settings. Copy it.
2. Download the configuration
Clone the public setup repository:
git clone https://github.com/coraldash/self-hosted.git coraldash
cd coraldash
cp .env.example .envYou should now have docker-compose.yml, .env.example, docker/kong.yml, and docker/generate-keys.sh.
3. Configure environment
Edit .env and fill in these values:
# Your licence key (trial or permanent)
LICENSE_KEY=xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx
# Your domain (must match DNS + reverse proxy)
SITE_URL=https://coraldash.yourdomain.com
# Generate secure passwords/secrets
POSTGRES_PASSWORD=$(openssl rand -base64 24)
JWT_SECRET=$(openssl rand -base64 32)
CRON_SECRET=$(openssl rand -hex 16)
# Google OAuth (see step 6 below)
GOOGLE_OAUTH_CLIENT_ID=your-google-client-id
GOOGLE_OAUTH_CLIENT_SECRET=your-google-client-secret
# Recommended for single-user installs: restrict access to one email
ALLOWED_EMAIL=you@gmail.com4. Generate Supabase keys
The bundled script derives ANON_KEY and SERVICE_ROLE_KEY from your JWT_SECRET:
chmod +x docker/generate-keys.sh
./docker/generate-keys.sh "$JWT_SECRET"Copy the two output keys into .env.
5. Start the stack
docker compose up -dThis starts five services: PostgreSQL, GoTrue (Supabase auth), PostgREST, Kong (API gateway), and the Coral Dash app.
On first boot, the app activates your licence (one HTTPS call to coraldash.com), runs database migrations, and starts the web server plus cron scheduler. After activation, the container runs fully offline — no telemetry, no phone-home.
6. Set up reverse proxy
Coral Dash needs HTTPS. Your reverse proxy must route both the Next.js app (port 3000) and the Supabase API gateway (port 8000) through the same domain — the browser reaches Supabase auth and REST APIs at /auth/v1/ and /rest/v1/ on your domain.
We recommend Caddyfor automatic Let's Encrypt certificate management:
sudo apt install -y caddy
sudo tee /etc/caddy/Caddyfile << 'EOF'
coraldash.yourdomain.com {
# Supabase Auth API
handle /auth/v1/* {
reverse_proxy localhost:8000
}
# Supabase REST API
handle /rest/v1/* {
reverse_proxy localhost:8000
}
# Next.js application
handle {
reverse_proxy localhost:3000
}
}
EOF
sudo systemctl reload caddyFor Nginx or Traefik, see docker/nginx.conf.example in the setup repository — the rule is the same: /auth/v1/* and /rest/v1/* must proxy to Kong (port 8000), everything else to Next.js (port 3000).
7. Sign in and connect your Google Sheet
Visit https://coraldash.yourdomain.com, sign in with Google, and follow the onboarding flow to pick the Google Sheet holding your Monzo export. The first sync runs immediately, then daily at 06:00 UTC by default (configurable via SYNC_SCHEDULE).
Google OAuth setup
- Open the Google Cloud Console → Credentials page.
- Create a new OAuth 2.0 Client ID (type: Web application).
- Add this authorised redirect URI:
https://coraldash.yourdomain.com/auth/v1/callback. - Enable the Google Drive API (required for Sheets sync).
- Copy the Client ID and Client Secret into your
.env.
Backups
Back up the bundled PostgreSQL database with pg_dump:
# Create a backup
docker compose exec db pg_dump -U postgres postgres > backup_$(date +%Y%m%d).sql
# Restore from backup
docker compose exec -T db psql -U postgres postgres < backup_20260315.sqlDaily automated backups via cron:
0 2 * * * cd /path/to/coraldash && docker compose exec -T db pg_dump -U postgres postgres | gzip > /backups/coraldash_$(date +\%Y\%m\%d).sql.gzUpdating
cd /path/to/coraldash
docker compose pull coraldash
docker compose up -dMigrations run automatically on startup. Always back up your database before updating. The self-hosted edition receives the same updates as the cloud version — track upcoming releases on the roadmap.
Environment variables
| Variable | Required | Description |
|---|---|---|
LICENSE_KEY | Yes | Your licence key (UUID format) |
SITE_URL | Yes | Public URL — must match your DNS and reverse proxy host |
POSTGRES_PASSWORD | Yes | PostgreSQL password |
JWT_SECRET | Yes | JWT signing secret (min 32 chars) |
ANON_KEY | Yes | Supabase anonymous key (from generate-keys.sh) |
SERVICE_ROLE_KEY | Yes | Supabase service role key (from generate-keys.sh) |
GOOGLE_OAUTH_CLIENT_ID | Yes | Google OAuth client ID |
GOOGLE_OAUTH_CLIENT_SECRET | Yes | Google OAuth client secret |
CRON_SECRET | Yes | Secret for internal cron job authentication |
ALLOWED_EMAIL | No | Restrict access to a single email address |
SYNC_SCHEDULE | No | Cron expression for sync schedule (default: 0 6 * * *) |
TRADING212_ENCRYPTION_KEY | No | Encryption key for Trading 212 API keys |
Troubleshooting
Container won't start — licence error
Verify LICENSE_KEY in .env is a valid UUID (xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx). Get one at coraldash.com/self-hosting.
Container won't start — trial expired
Your 7-day trial has ended. Purchase a permanent licence, update LICENSE_KEY in .env, and run docker compose restart coraldash.
Container won't start — key already activated
Each licence key activates on a single instance. Deactivate the old one in your account settings, then restart.
Auth or API requests fail in the browser
Ensure your reverse proxy routes /auth/v1/* and /rest/v1/*to Kong on port 8000 (not directly to the Next.js app on port 3000). Fixed in v2.3.3+; pull the latest image if you're on an older version.
Google OAuth redirect error
Check the redirect URI in Google Cloud Console exactly matches https://your-domain/auth/v1/callback. Note the /auth/v1/ prefix — it points at GoTrue, not Next.js.
Sync not running
Inspect the cron worker logs:
docker compose logs coraldash | grep CronCheck container health
docker compose ps
docker compose logs coraldash --tail 100All services should report healthy. If Kong or PostgREST are unhealthy, check their individual logs (docker compose logs kong, docker compose logs rest).
Full reference on GitHub
This page covers the most common path. The canonical setup repository on GitHub contains every supported configuration, migration notes, and the full troubleshooting matrix.