Skip to main content

Docker Deployment

Rampart ships as a single Docker image that includes the Go server and embedded admin UI. This guide covers running Rampart with Docker, configuring it for production, and setting up health checks.

Docker Run (Single Container)

If you already have PostgreSQL running, you can start Rampart with a single docker run command:

docker run -d \
--name rampart \
-p 8080:8080 \
-e RAMPART_DB_URL="postgres://rampart:changeme@host.docker.internal:5432/rampart?sslmode=disable" \
-e RAMPART_SIGNING_KEY_PATH="/data/rampart-signing-key.pem" \
-v rampart-data:/data \
ghcr.io/manimovassagh/rampart:latest

For a complete stack, use Docker Compose. Create a docker-compose.yml:

services:
rampart:
image: ghcr.io/manimovassagh/rampart:latest
ports:
- "8080:8080"
environment:
RAMPART_DB_URL: "postgres://rampart:changeme@postgres:5432/rampart?sslmode=disable"
RAMPART_LOG_LEVEL: "info"
RAMPART_ISSUER: "http://localhost:8080"
RAMPART_SIGNING_KEY_PATH: "/data/rampart-signing-key.pem"
volumes:
- rampart-data:/data
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
interval: 10s
timeout: 5s
retries: 3
start_period: 5s
restart: unless-stopped
read_only: true
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp:noexec,nosuid,size=64m

postgres:
image: postgres:16.6-alpine
environment:
POSTGRES_DB: rampart
POSTGRES_USER: rampart
POSTGRES_PASSWORD: changeme
ports:
- "127.0.0.1:5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U rampart"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped

volumes:
pgdata:
rampart-data:

Start the stack:

docker compose up -d

Environment Variables

VariableDescriptionDefault
RAMPART_DB_URLPostgreSQL connection string(required)
RAMPART_PORTHTTP listen port8080
RAMPART_ISSUERBase URL used in OIDC Discovery and token iss claimhttp://localhost:8080
RAMPART_SIGNING_KEY_PATHPath to RSA private key for JWT signingAuto-generated
RAMPART_LOG_LEVELLog level: debug, info, warn, errorinfo
RAMPART_LOG_FORMATLog format: json, text, prettypretty
RAMPART_ALLOWED_ORIGINSComma-separated list of allowed CORS origins
RAMPART_SESSION_TTLSession time-to-live24h
RAMPART_ACCESS_TOKEN_TTLAccess token lifetime900s
RAMPART_REFRESH_TOKEN_TTLRefresh token lifetime7d
RAMPART_HSTS_ENABLEDEnable HTTP Strict Transport Security headerfalse
RAMPART_RATE_LIMIT_RPSRequests per second rate limit10
RAMPART_RATE_LIMIT_BURSTRate limit burst size20
RAMPART_SECURE_COOKIESSet Secure flag on cookies (enable behind TLS)false

See the Configuration reference for the full list.

Health Checks

Rampart exposes a health check endpoint:

GET /healthz

Response when healthy:

{
"status": "ok"
}

The health check verifies connectivity to PostgreSQL. Use this endpoint for Docker health checks, load balancer probes, and Kubernetes liveness/readiness probes. A readiness probe is also available at GET /readyz.

Volume Mounts

Signing Keys

Rampart uses RSA keys for JWT signing. If no key is provided, one is generated on first startup and stored at the configured path (/data/rampart-signing-key.pem by default in Docker). To persist keys across container restarts, mount a volume:

-v rampart-data:/data

In production, you should provide your own RSA private key and mount it read-only:

-v /path/to/signing.pem:/data/rampart-signing-key.pem:ro

Database Data

Mount a volume for PostgreSQL data to ensure persistence:

-v pgdata:/var/lib/postgresql/data

Production Tips

Use a Reverse Proxy

In production, place Rampart behind a reverse proxy (Nginx, Caddy, or Traefik) that handles TLS termination:

server {
listen 443 ssl http2;
server_name auth.example.com;

ssl_certificate /etc/ssl/certs/auth.example.com.pem;
ssl_certificate_key /etc/ssl/private/auth.example.com.key;

location / {
proxy_pass http://rampart:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

Set the Issuer URL

Always set RAMPART_ISSUER to the public-facing URL of your Rampart instance. This value appears in JWT iss claims and OIDC Discovery responses:

RAMPART_ISSUER=https://auth.example.com

Restrict CORS Origins

In production, specify your application domains explicitly:

RAMPART_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com

Resource Limits

Rampart is lightweight, but you should still set resource limits in production:

deploy:
resources:
limits:
memory: 256M
cpus: "1.0"
reservations:
memory: 64M
cpus: "0.25"

Security Settings

Harden the Rampart container with a read-only filesystem and prevent privilege escalation:

read_only: true
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp:noexec,nosuid,size=64m

The read_only flag makes the container filesystem immutable. The no-new-privileges option prevents processes from gaining additional privileges via setuid/setgid. A tmpfs mount provides a writable scratch space for temporary files without persisting anything to disk.

Database Connection Pooling

For high-traffic deployments, consider using PgBouncer between Rampart and PostgreSQL to manage connection pooling efficiently.

Log Format

The default log format is pretty for local development. Use JSON logging in production for structured log aggregation:

RAMPART_LOG_FORMAT=json
RAMPART_LOG_LEVEL=info