Configuration

whiz.pub uses a three-tier configuration model. Secrets live in environment variables, application defaults are defined in a YAML file, and runtime settings are stored in the database.

Overview

Source Contains When used
.env Secrets and infrastructure settings Always (read from environment)
whiz.yaml Application defaults (domain, limits, etc.) First startup only (seeds the DB)
DB settings table All runtime configuration Every request (authoritative)

On first startup, values from whiz.yaml (or hardcoded defaults if the file is absent) are written into the database settings table. After that, the database is the single source of truth. Changes made in the admin panel at /admin/config take effect immediately.

Setup

cp .env.example .env
cp whiz.yaml.example whiz.yaml

Edit .env with your database credentials and any optional service keys. Edit whiz.yaml only if you need to change defaults before first startup.

Environment Variables (.env)

These are read from the process environment. They are never stored in the database.

Variable Required Default Description
DATABASE_URL Yes -- PostgreSQL connection string
PORT No 8080 HTTP listen port
WHIZ_CONFIG No ./whiz.yaml Path to the app config file
PLUNK_API_URL No -- Plunk transactional email API URL
PLUNK_SECRET_KEY No -- Plunk API secret key
S3_ENDPOINT No -- S3/R2 endpoint for asset storage
S3_REGION No auto S3/R2 region
S3_BUCKET No -- S3/R2 bucket name
S3_ACCESS_KEY No -- S3/R2 access key
S3_SECRET_KEY No -- S3/R2 secret key
ASSETS_CDN_URL No -- Public CDN URL (e.g. https://cdn.whiz.pub)
CUSTOM_DOMAIN_CNAME_TARGET No proxy.<base_domain> Initial custom-domain CNAME target seed

If PLUNK_SECRET_KEY is empty, transactional emails are logged to stdout instead of sent. This is useful during local development.

If the S3_* variables are not set, favicon upload is disabled.

App Config (whiz.yaml)

This file is read once on first startup to seed the database. After seeding, changes to whiz.yaml have no effect -- use the admin panel instead.

Key Default Description
base_domain localhost:8080 Platform base domain
site_name whiz.pub Display name for branding
custom_domain_cname_target empty CNAME target shown to users for custom domains. Empty uses proxy.<base_domain>.
session_ttl 720h Session duration (Go duration format)
max_title_length 200 Max post title characters
max_content_bytes 102400 Max post content size in bytes (100 KB)
max_tag_length 50 Max characters per tag
max_tags 10 Max tags per post
summary_length 200 Auto-summary truncation length
default_page_size 20 Default pagination size
max_page_size 100 Maximum pagination size
cache_max_age 60 Cache-Control max-age in seconds
body_limit 4194304 HTTP request body limit in bytes (4 MB)
from_name whiz.pub Sender name for transactional emails
from_email [email protected] Sender email address

Example whiz.yaml

base_domain: whiz.pub
site_name: whiz.pub
session_ttl: 720h
max_title_length: 200
max_content_bytes: 102400
max_tag_length: 50
max_tags: 10
summary_length: 200
default_page_size: 20
max_page_size: 100
cache_max_age: 60
body_limit: 4194304
from_name: whiz.pub
from_email: [email protected]

Database Settings

After first startup, all configuration lives in the settings table in PostgreSQL. This is the authoritative source for every request.

Admin Panel

The admin panel at /admin/config provides a live editor for all settings. Changes take effect immediately without a server restart.

How it works

  1. On first startup, whiz reads whiz.yaml and inserts each key-value pair into the settings table.
  2. If a key already exists in the database, it is not overwritten.
  3. On every request, the server reads settings from the database (with caching).
  4. The admin panel reads and writes directly to the settings table.

This means you can safely redeploy without worrying about config drift -- the database always wins.