Skip to content
Keenpix docs
Self-hosting

Deployment presets

Copy-paste .env starting points for local, single-node, and CDN-fronted deploys.

Three ready-made starting points for .env. Every variable is documented on the Configuration page — these presets just bundle sensible values for common deployment shapes. Always generate your own secret with openssl rand -hex 32.

With the bundled docker-compose.yml, set POSTGRES_PASSWORD and Compose builds DATABASE_URL for the app automatically. Only set DATABASE_URL yourself for a non-Docker run (pnpm start) or an external database.

Local-only (evaluation)

Running on your own machine to try Keenpix. No public URL, no CDN.

POSTGRES_PASSWORD="postgres"
BETTER_AUTH_SECRET="<openssl rand -hex 32>"
BETTER_AUTH_URL="http://localhost:3000"
KEENPIX_SUPER_ADMIN_EMAIL="[email protected]"
KEENPIX_SUPER_ADMIN_PASSWORD="<a real password>"
  • Plain http on localhost, so secure cookies stay off — fine for local only.
  • No SMTP needed: read the OTP code from docker compose logs app.

Single-node production

One server answers both the dashboard and every image transform over HTTPS. No separate CDN.

POSTGRES_PASSWORD="<a long random password>"
BETTER_AUTH_SECRET="<openssl rand -hex 32>"
BETTER_AUTH_URL="https://keenpix.example.com"
KEENPIX_APP_URL="https://keenpix.example.com"
KEENPIX_SUPER_ADMIN_EMAIL="[email protected]"
KEENPIX_SUPER_ADMIN_PASSWORD="<a real password>"

# Deliver staff invitations and OTP codes via SMTP (or use postmark / resend).
EMAIL_PROVIDER="smtp"
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USER="..."
SMTP_PASSWORD="..."
SMTP_FROM_EMAIL="[email protected]"

# This box answers every transform: give the disk cache room, bound concurrency.
KEENPIX_CACHE_MAX_BYTES="10737418240"   # 10 GB
KEENPIX_MAX_CONCURRENCY="4"
KEENPIX_MAX_QUEUE="200"
  • An https:// URL turns on secure cookies automatically.
  • Size KEENPIX_CACHE_MAX_BYTES to the disk volume; the in-memory LRU (KEENPIX_MEMORY_CACHE_MAX_BYTES) keeps the hottest variants in RAM.
  • Set KEENPIX_MAX_CONCURRENCY near the CPU count; load past KEENPIX_MAX_QUEUE sheds with 503 instead of overrunning the box.

CDN-fronted production

A CDN caches /img/* and absorbs repeat traffic, so Keenpix only does cold transforms. See CDN setup.

POSTGRES_PASSWORD="<a long random password>"
BETTER_AUTH_SECRET="<openssl rand -hex 32>"
# Point auth at the DASHBOARD host, not the image host the CDN serves.
BETTER_AUTH_URL="https://admin.keenpix.example.com"
KEENPIX_APP_URL="https://admin.keenpix.example.com"
KEENPIX_SUPER_ADMIN_EMAIL="[email protected]"
KEENPIX_SUPER_ADMIN_PASSWORD="<a real password>"

EMAIL_PROVIDER="smtp"
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USER="..."
SMTP_PASSWORD="..."
SMTP_FROM_EMAIL="[email protected]"

# Cloudflare absorbs repeat traffic, but the origin is still the shared shield
# for edge cold misses and tiered-cache fills.
KEENPIX_CACHE_MAX_BYTES="8589934592"    # 8 GB
KEENPIX_MEMORY_CACHE_MAX_BYTES="268435456" # 256 MB
KEENPIX_CACHE_STALE_MS="86400000"       # 24 hours
KEENPIX_MAX_CONCURRENCY="4"
KEENPIX_MAX_QUEUE="200"

Scope the CDN's cache rule to /img/* only, or keep the dashboard on a host the CDN does not cache. Caching /app or /api/auth breaks sign-in.

  • Use omitted fmt / fmt=auto only when the CDN can vary by Accept. Otherwise, prefer explicit fmt=webp / fmt=avif in generated URLs to maximize edge hit rate, knowing that an explicit format will not fall back for unsupported browsers.
  • Use explicit fmt=svg for optimized SVG delivery. Omitted fmt / fmt=auto rasterizes SVG origins instead of preserving SVG output.
  • Size the origin disk cache to the image working set that still reaches Keenpix after Cloudflare. For small sites 2 GB can be enough; for high-cardinality hotel/CMS libraries, start around 8 GB and watch Operations for eviction churn.

On this page