Skip to content
Keenpix docs
Self-hosting

Configuration

Environment variables for a self-hosted instance.

Set these in .env (or your orchestrator's secrets).

Core

VariableRequiredDefaultPurpose
DATABASE_URLyesPostgres connection string
POSTGRES_PASSWORDyes (compose)Password for the bundled Compose Postgres service
BETTER_AUTH_SECRETyes (prod)Session secret; must be 32+ random chars
BETTER_AUTH_URLnohttp://localhost:3000Public base URL for auth callbacks and secure-cookie behavior
KEENPIX_APP_URLnoBETTER_AUTH_URLCanonical app URL for generated metadata, docs links, and OG URLs
KEENPIX_SUPER_ADMIN_EMAILyesEmail for the bootstrapped super admin account
KEENPIX_SUPER_ADMIN_PASSWORDyesPassword for the bootstrapped super admin account
KEENPIX_ADMIN_EMAILlegacy aliasBackward-compatible alias for KEENPIX_SUPER_ADMIN_EMAIL
KEENPIX_ADMIN_PASSWORDlegacy aliasBackward-compatible alias for KEENPIX_SUPER_ADMIN_PASSWORD
KEENPIX_RUN_MIGRATIONSnotrue in DockerDocker entrypoint switch for running migrations before start
KEENPIX_RUN_SEEDnotrue in DockerDocker entrypoint switch for seeding the default org and super admin before start
KEENPIX_CACHE_DIRno./.keenpix-cacheWhere transformed images are cached on disk
KEENPIX_MODEnoselfhostselfhost (default) or cloud. Self-host disables the marketing site, self-signup, and billing
LOG_LEVELnoinfoServer log level: fatal, error, warn, info, debug, trace, or silent

Browser public URLs

These Vite variables are only needed when the browser bundle must call a non-default public app or auth URL.

VariableDefaultPurpose
VITE_KEENPIX_PUBLIC_URLBrowser-facing app URL
VITE_KEENPIX_AUTH_URLBackward-compatible auth URL alias
VITE_BETTER_AUTH_URLBackward-compatible Better Auth URL alias

Transactional email

Verification, password reset, and teammate invitation emails go through exactly one provider, selected with EMAIL_PROVIDER. Email is configured entirely from the environment — there is no in-app email settings screen. Leave EMAIL_PROVIDER unset to disable email (fine for a single-admin install that never invites teammates). When it is set, the selected provider's required variables must be present or the app fails to start.

VariableDefaultPurpose
EMAIL_PROVIDERpostmark, resend, or smtp (unset = off)

EMAIL_PROVIDER=postmark

VariableDefaultPurpose
POSTMARK_API_KEYPostmark server token (required)
POSTMARK_FROMVerified sender, e.g. Keenpix <no-reply@…> (required)
POSTMARK_MESSAGE_STREAMoutboundMessage stream to send on

EMAIL_PROVIDER=resend

VariableDefaultPurpose
RESEND_API_KEYResend API key (required)
RESEND_FROMVerified sender, e.g. Keenpix <no-reply@…> (required)

EMAIL_PROVIDER=smtp

Point at any SMTP relay (a provider, or a self-hosted Postfix/Mailpit).

VariableDefaultPurpose
SMTP_HOSTSMTP server hostname (required)
SMTP_FROM_EMAILSender email address (required)
SMTP_PORT587SMTP server port
SMTP_SECUREfalsetrue for implicit TLS, false for STARTTLS
SMTP_USERSMTP username
SMTP_PASSWORDSMTP password
SMTP_FROM_NAMESender display name

Cloudflare edge analytics

Optional. Wire a Cloudflare API token so keenpix can show real edge cache hit-rate alongside its origin-shield figures (see edge analytics). keenpix now persists hourly edge rollups, so edge analytics covers any range and accumulates history beyond Cloudflare's ~24h adaptive window — coverage grows forward as the dashboard is used. Manage it from Settings → CDN cache; when database-managed settings are enabled with a token and zone, they take precedence over the environment variables below. The token only needs the zone-scoped Analytics → Read permission. It is stored encrypted at rest with a key derived from BETTER_AUTH_SECRET, so the encrypted value is per-instance and cannot be copied between instances — re-enter the token on each instance.

VariableDefaultPurpose
CLOUDFLARE_API_TOKENZone-scoped API token with Analytics → Read
CLOUDFLARE_ZONE_ID32-character hex zone id for the image hostname
CLOUDFLARE_HOSTOptional. A Cloudflare zone can serve several subdomains and edge analytics only filter by path (/img/*), so set this to the keenpix hostname (e.g. images.example.com) when the zone also hosts other sites that use a /img path. Leave blank to count the whole zone.

Limits & performance

VariableDefaultPurpose
KEENPIX_CACHE_MAX_BYTESapp default: 2147483648 (2GB); Docker/Coolify: 8589934592 (8GB)Disk cache LRU cap
KEENPIX_CACHE_STALE_MS86400000 (24h)Serve stale disk entries immediately and refresh them in the background; 0 disables stale refresh
KEENPIX_MEMORY_CACHE_MAX_BYTESapp default: 67108864 (64MB); Docker/Coolify: 268435456 (256MB)In-process hot variant LRU cap; 0 disables memory caching
KEENPIX_MAX_ORIGIN_BYTES52428800 (50MB)Max bytes pulled from an origin before 413
KEENPIX_MAX_CONCURRENCYCPU countMax simultaneous transforms before queueing
KEENPIX_MAX_QUEUE100Queue depth before shedding load with 503
KEENPIX_MAX_INPUT_PIXELS50000000Decode-time pixel ceiling (decompression-bomb guard)
KEENPIX_MAX_DIMENSION4096Longest output side when a request gives no w/h
KEENPIX_ORIGIN_TIMEOUT_MS10000Per-attempt origin fetch timeout before 504

On this page