Kyrux
Back

Configuration (.env)

# ── Environment ───────────────────────────────────────────────────
# development → debug, hot reload and pprof enabled automatically
# production  → optimized mode, debug disabled
APP_ENV=development

# ── Server ────────────────────────────────────────────────────────
SERVER_HOST=0.0.0.0     # bind — see the note below before opening it in a browser
SERVER_PORT=8000
SERVER_WORKERS=4        # omit to use all available CPUs

# ── Allowed hosts ─────────────────────────────────────────────────
# Ignored in development. Required in production.
ALLOWED_HOSTS=mysite.com,www.mysite.com

# ── Canonical URL (optional) ───────────────────────────────────────
# No trailing slash. Used by the built-in "meta" app (apps/meta) to build
# absolute URLs in robots.txt, sitemap.xml and security.txt — see SEO &
# Security.txt. Empty until configured; in that case those files ship
# without a domain (still valid, just incomplete).
# APP_URL=https://mysite.com

# ── Timezone (optional) ──────────────────────────────────────────────
# IANA name used by the admin to DISPLAY automatic timestamps
# (created_at/updated_at, history log) — never affects what's written to
# the database (TIMESTAMPTZ columns store the absolute instant). Defaults
# to UTC if unset; an invalid name falls back to UTC with a log warning,
# never blocks boot.
# APP_TIMEZONE=America/Sao_Paulo

# ── Database ──────────────────────────────────────────────────────
# Each DB_NAME block starts a new database. The first one is the default.
DB_NAME=main
DB_ENABLED=true
DB_DRIVER=postgres
DB_DSN=postgres://user:password@localhost:5432/mydb?sslmode=disable

# DB_NAME=analytics
# DB_ENABLED=true
# DB_DRIVER=postgres
# DB_DSN=postgres://user:password@localhost:5432/analytics?sslmode=disable

# ── Cache ─────────────────────────────────────────────────────────
CACHE_ENABLED=false
CACHE_DRIVER=memory
CACHE_ADDR=localhost:6379

# ── Queue (background task queue) ──────────────────────────────────
QUEUE_ENABLED=false
QUEUE_DRIVER=memory     # memory | redis (roadmap)
QUEUE_ADDR=localhost:6379
QUEUE_WORKERS=4

# ── Admin (opt-in panel per model — requires admin.Register[T] in code)
ADMIN_ENABLED=false
ADMIN_PATH=/admin/

# Optional — creates the initial superuser at boot, if no one with this
# login already exists (does not reset the password of an existing account)
# ADMIN_SUPERUSER_USERNAME=admin
# ADMIN_SUPERUSER_PASSWORD=change-this-temporary-password

# ── Security ──────────────────────────────────────────────────────
SECRET_KEY=your-strong-secret-key-here
SESSION_TTL=3600        # session duration in seconds

# Pepper applied before the Argon2id hash — never store it in the database
# Generate with: openssl rand -base64 32
PASSWORD_PEPPER=your-strong-pepper-here

# AES-256-GCM key for kyrux:"encrypt" fields — never store it in the database
# Generate with: openssl rand -base64 32
FIELD_ENCRYPTION_KEY=your-strong-encryption-key-here

# ── Runtime (optional) ────────────────────────────────────────────
# Go's GC percentage. Default: 100. Lowering it (e.g. 75) reduces heap size, increases GC frequency.
# RUNTIME_GOGC=75

In production, SECRET_KEY, PASSWORD_PEPPER, FIELD_ENCRYPTION_KEY, and ALLOWED_HOSTS are required — the server refuses to start without them.

SERVER_HOST=0.0.0.0 is the bind address, not the access address

0.0.0.0 tells the server to listen on all of the machine's network interfaces — it isn't a real address a browser can connect to. Typing http://0.0.0.0:8000 in the address bar results in ERR_CONNECTION_REFUSED (or inconsistent behavior, depending on the OS).

Address What it is Use
0.0.0.0 Wildcard for "all interfaces" Only for SERVER_HOST (bind)
127.0.0.1 Loopback — this machine, always present and routable Access locally
localhost Name the OS resolves to 127.0.0.1 (or ::1) Access locally

To access a locally running server, always use http://127.0.0.1:PORT or http://localhost:PORT — never 0.0.0.0, even with SERVER_HOST=0.0.0.0 configured (the bind still applies to all interfaces; only the access address changes). Kyrux already translates this on its own in the messages it prints (console, welcome page, debug dashboard) — they all show 127.0.0.1, never 0.0.0.0.