Back to self-hosting
Setup Guide

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 amd64 and arm64.
  • 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 .env

You 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.com

4. 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 -d

This 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 caddy

For 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

  1. Open the Google Cloud Console → Credentials page.
  2. Create a new OAuth 2.0 Client ID (type: Web application).
  3. Add this authorised redirect URI: https://coraldash.yourdomain.com/auth/v1/callback.
  4. Enable the Google Drive API (required for Sheets sync).
  5. 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.sql

Daily 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.gz

Updating

cd /path/to/coraldash
docker compose pull coraldash
docker compose up -d

Migrations 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

VariableRequiredDescription
LICENSE_KEYYesYour licence key (UUID format)
SITE_URLYesPublic URL — must match your DNS and reverse proxy host
POSTGRES_PASSWORDYesPostgreSQL password
JWT_SECRETYesJWT signing secret (min 32 chars)
ANON_KEYYesSupabase anonymous key (from generate-keys.sh)
SERVICE_ROLE_KEYYesSupabase service role key (from generate-keys.sh)
GOOGLE_OAUTH_CLIENT_IDYesGoogle OAuth client ID
GOOGLE_OAUTH_CLIENT_SECRETYesGoogle OAuth client secret
CRON_SECRETYesSecret for internal cron job authentication
ALLOWED_EMAILNoRestrict access to a single email address
SYNC_SCHEDULENoCron expression for sync schedule (default: 0 6 * * *)
TRADING212_ENCRYPTION_KEYNoEncryption 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 Cron

Check container health

docker compose ps
docker compose logs coraldash --tail 100

All 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.