Self-Hosting
Run EarlyPass on your own infrastructure. Your waitlist data stays on your servers.
Docker Compose (recommended)
The fastest way to self-host EarlyPass. You need Docker and Docker Compose installed.
1. Create a docker-compose.yml
version: "3.9"
services:
earlypass:
image: ghcr.io/earlypass/earlypass:latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://earlypass:earlypass@postgres:5432/earlypass?sslmode=disable
REDIS_URL: redis://redis:6379
BASE_URL: https://earlypass.example.com
DASHBOARD_JWT_SECRET: ${DASHBOARD_JWT_SECRET}
EMAIL_FROM: [email protected]
RESEND_API_KEY: ${RESEND_API_KEY:-}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: earlypass
POSTGRES_PASSWORD: earlypass
POSTGRES_DB: earlypass
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U earlypass"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
volumes:
pgdata:
redisdata: 2. Generate a JWT secret
export DASHBOARD_JWT_SECRET=$(openssl rand -hex 32) Without this, dashboard sessions won't survive container restarts.
3. Start the stack
docker compose up -d Database migrations run automatically on startup. After a few seconds, your instance is ready:
curl http://localhost:3000/healthz
# → {"status":"ok","components":{"database":"ok","redis":"ok"}} 4. Access the dashboard
Open http://localhost:3000/dashboard/login in your browser. Create an account with a magic link (requires email configuration — see below).
Updating
docker compose pull
docker compose up -d Single container
If you already have PostgreSQL and Redis running, you can run EarlyPass as a single container:
docker run -d \
-p 3000:3000 \
-e DATABASE_URL="postgres://user:pass@host:5432/earlypass" \
-e REDIS_URL="redis://host:6379" \
-e DASHBOARD_JWT_SECRET="$(openssl rand -hex 32)" \
-e BASE_URL="https://earlypass.example.com" \
ghcr.io/earlypass/earlypass:latest Kubernetes (Helm)
For teams already running Kubernetes, EarlyPass provides an OCI Helm chart.
Install
helm install earlypass \
oci://ghcr.io/earlypass/charts/earlypass \
--set secrets.databaseUrl="postgres://user:pass@host:5432/earlypass" \
--set secrets.dashboardJwtSecret="$(openssl rand -hex 32)" This assumes you bring your own PostgreSQL and Redis. The chart does not deploy databases.
Key values
| Value | Description |
|---|---|
secrets.databaseUrl | PostgreSQL connection string (required) |
secrets.dashboardJwtSecret | HMAC key for dashboard auth (required) |
secrets.redisUrl | Redis connection string |
secrets.resendApiKey | Resend API key for transactional email |
config.baseUrl | Public URL of your instance |
config.emailFrom | From address for emails |
ingress.enabled | Enable Ingress resource (default: false) |
autoscaling.enabled | Enable HPA (default: false, 2-10 replicas) |
See the full chart source for all available values.
Configuration
All configuration is via environment variables. The same variables work for both Docker and Kubernetes deployments.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | yes | PostgreSQL connection string |
REDIS_URL | yes | Redis connection string |
BASE_URL | recommended | Public URL of your instance (e.g. https://earlypass.example.com). Used to build links in emails. No trailing slash. |
DASHBOARD_JWT_SECRET | recommended | HMAC-SHA256 key for dashboard auth cookies. Generate with openssl rand -hex 32. If unset, a random key is generated per process — sessions won't survive restarts. |
EMAIL_FROM | no | From address for transactional emails |
RESEND_API_KEY | no | Resend API key. Leave empty to disable email (magic links will be logged to stdout instead). |
TRUSTED_PROXIES | no | Comma-separated CIDR ranges trusted to set X-Forwarded-For (e.g. 10.0.0.0/8) |
PORT | no | HTTP port (default: 3000) |
OTEL_EXPORTER_OTLP_ENDPOINT | no | OTLP collector endpoint for OpenTelemetry traces |
Reverse proxy
In production, place EarlyPass behind a reverse proxy (Caddy, nginx, Traefik) that handles TLS. Point the proxy at localhost:3000 and set BASE_URL to your public domain. Set TRUSTED_PROXIES to your proxy's IP range so rate limiting uses the real client IP.
Health check
GET /healthz → {"status":"ok","components":{"database":"ok","redis":"ok"}} Use this for load balancer health checks, Docker HEALTHCHECK, or Kubernetes liveness/readiness probes.
Data & backups
All persistent state is in PostgreSQL. Redis is used only for rate limiting and idempotency keys — it can be flushed without data loss. Back up your PostgreSQL database regularly:
docker compose exec postgres pg_dump -U earlypass earlypass > backup.sql Next steps
- Getting Started — create a campaign and embed the widget
- Widget Reference — point the widget at your self-hosted instance
- API Reference — full REST API documentation
- MCP Server — AI agent integration