| title | Self-Hosting Checkgate — Docker & AWS Deployment Guide |
|---|---|
| description | Deploy Checkgate on your own infrastructure using Docker Compose, AWS EC2, or ECS Fargate. Your flag data stays on your servers. Includes environment variable reference, load balancing tips, and upgrade instructions. |
Checkgate is designed to be self-hosted. The all-in-one Docker image bundles PostgreSQL, Redis, the server, and the dashboard into a single container — no external services required.
The simplest way to run Checkgate is with the provided docker-compose.yml:
docker compose up -dThis starts a single container that includes:
- PostgreSQL — persistent flag and user storage
- Redis — pub/sub for real-time multi-instance sync
- Checkgate server — REST API + SSE stream on port
3000 - React dashboard — served at
http://localhost:3000
Create a .env file in the project root:
SESSION_SECRET=your-random-64-char-secret # Required in production
POSTGRES_PASSWORD=strong-db-password # Replaces default "checkgate"
COOKIE_SECURE=true # Set false only for local HTTP developmentThen run:
docker compose up -dOne image is published per release:
| Image | Description |
|---|---|
ghcr.io/thinkgrid-labs/checkgate:latest |
All-in-one: PostgreSQL + Redis + server + dashboard |
ghcr.io/thinkgrid-labs/checkgate:<version> |
Pinned version (e.g. 1.2.0) |
The image is multi-architecture: linux/amd64 and linux/arm64.
| Variable | Default | Description |
|---|---|---|
SESSION_SECRET |
(insecure dev key) | Secret for encrypting session cookies. Use a random ≥32-char string in production. |
DATABASE_URL |
postgres://checkgate:password@localhost/checkgate |
PostgreSQL connection string (used when not using bundled PG) |
REDIS_URL |
redis://localhost:6379 |
Redis connection string (used when not using bundled Redis) |
POSTGRES_PASSWORD |
checkgate |
Password for the bundled PostgreSQL instance |
POSTGRES_USER |
checkgate |
Username for the bundled PostgreSQL instance |
POSTGRES_DB |
checkgate |
Database name for the bundled PostgreSQL instance |
COOKIE_SECURE |
true |
Set false for local HTTP development. Controls the Secure cookie flag. |
SDK_KEY |
(unset) | Legacy env var: adds an extra accepted SDK key without a DB entry |
PUBLIC_DIR |
public |
Directory to serve dashboard static files from |
PORT |
3000 |
Port the server listens on |
DB_MAX_CONNECTIONS |
10 |
PostgreSQL connection pool size |
RUST_LOG |
info |
Log level (error, warn, info, debug, trace) |
Always set SESSION_SECRET in production. Without it, session cookies use a hardcoded dev key that is public knowledge — anyone can forge sessions.
# Generate a secure session secret
openssl rand -hex 32SDK keys are managed through the dashboard Settings page. The first key is auto-generated on first boot. Additional keys can be created and revoked without restarting the server.
To use your own PostgreSQL and Redis instead of the bundled ones, run the image directly and pass the connection strings:
docker run -d -p 3000:3000 \
-e DATABASE_URL="postgres://user:password@your-postgres:5432/checkgate" \
-e REDIS_URL="redis://your-redis:6379" \
-e SESSION_SECRET="your-secret" \
ghcr.io/thinkgrid-labs/checkgate:latest- Launch an EC2 instance (t3.micro is sufficient for most workloads)
- Install Docker:
sudo yum update -y && sudo yum install -y docker sudo systemctl start docker - Set up RDS PostgreSQL and ElastiCache Redis (optional — use the bundled versions for simpler setups)
- Create a
.envfile:DATABASE_URL=postgres://user:pass@rds-endpoint:5432/checkgate REDIS_URL=redis://elasticache-endpoint:6379 SESSION_SECRET=your-random-secret COOKIE_SECURE=true
- Run:
docker run -d --env-file .env -p 3000:3000 \ ghcr.io/thinkgrid-labs/checkgate:latest
A basic task definition:
{
"family": "checkgate",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "checkgate",
"image": "ghcr.io/thinkgrid-labs/checkgate:latest",
"portMappings": [{"containerPort": 3000}],
"environment": [
{"name": "DATABASE_URL", "value": "postgres://..."},
{"name": "REDIS_URL", "value": "redis://..."},
{"name": "SESSION_SECRET", "value": "your-random-secret"},
{"name": "COOKIE_SECURE", "value": "true"}
]
}
]
}Checkgate is stateless — the in-memory flag store is rebuilt from PostgreSQL on startup and kept in sync via Redis pub/sub. Run as many instances as you need behind an ALB.
Important: The SSE stream (/stream) requires sticky sessions or a long-lived HTTP/2 connection. Configure your ALB target group with:
- Protocol: HTTP/1.1 (SSE is not compatible with HTTP/2 connection multiplexing on ALB)
- Stickiness: Enabled (duration-based, any duration)
Or rely on Redis pub/sub fan-out (built-in): all instances subscribe to Redis and will forward updates to their connected SDK clients regardless of which instance received the API write.
The server exposes a health check endpoint:
GET /healthReturns 200 OK with body OK. Use this for load balancer and container health checks (as configured in the Dockerfile's HEALTHCHECK instruction).
Checkgate uses sqlx migrations that run automatically on startup. To upgrade:
docker pull ghcr.io/thinkgrid-labs/checkgate:latest
docker compose up -d --force-recreateThe server applies any new migrations before accepting traffic. Existing data is preserved.
Back up your PostgreSQL database using standard tooling:
pg_dump -h localhost -U checkgate checkgate > checkgate-backup.sqlRedis is used only for pub/sub message passing and does not need to be backed up — no durable state is stored there.