WP_*, DB_*, the eight *_KEY / *_SALT)
are the consuming site’s responsibility.
runtime (Caddy + FrankenPHP + Souin)
| Var | Default | Purpose |
|---|---|---|
REDIS_URL | redis:6379 | Redis backing Souin’s HTTP cache |
FP_CACHE_TTL | 5m | Default cache entry TTL |
FP_CACHE_STALE | 1h | Stale-while-revalidate window |
FP_CACHE_DEFAULT_CONTROL | public, s-maxage=300 | Cache-Control fallback |
FP_CACHE_BYPASS_EXTRA | (empty) | Extra alternation fragment appended to the path-bypass regex (e.g. |^/api/private/). See components/runtime → Cacheability model. |
FP_DOCROOT | /app/web | WordPress webroot inside the container |
FP_PORT | 8080 | Public HTTP listen port |
FP_METRICS_PORT | 9145 | Prometheus metrics listen port |
mu-plugin: S3UploadsBootstrap
| Var | Default | Required |
|---|---|---|
FP_S3_BUCKET | — | ✓ |
FP_S3_KEY | — | ✓ |
FP_S3_SECRET | — | ✓ |
FP_S3_REGION | us-east-1 | |
FP_S3_BUCKET_URL | — | Public URL clients use to fetch media. CDN URL or raw bucket URL for AWS S3 / R2 / GCS XML; port-forward or HTTPRoute URL for the bundled MinIO subchart. When unset, humanmade/s3-uploads bakes canonical https://<bucket>.s3.amazonaws.com URLs into attachment GUIDs and post content — required for any non-AWS bucket. Changing this on an existing site does not rewrite already-stored URLs; use wp search-replace. |
FP_S3_ENDPOINT | — | optional, for non-AWS S3-compatible (MinIO, R2, GCS XML) |
FP_S3_OBJECT_ACL | (empty — no ACL) | optional S3 object ACL. Leave unset for buckets with Object Ownership = “Bucket owner enforced” (the AWS new-bucket default since April 2023). Set to public-read / private / authenticated-read only for ACL-enabled buckets. |
FP_S3_DISABLED | auto: on in-cluster, off out-of-cluster | tri-state. Truthy (1/true/yes/on) → off. Falsy (0/false/no/off) → force on. Unset → default gates on KUBERNETES_SERVICE_HOST (kubelet-injected on every pod): production stays on, local dev skips the s3:// stream wrapper so admin install flows hit local disk. Force on locally with FP_S3_DISABLED=0. |
wp_handle_upload_prefilter to refuse uploads with a clear error
message rather than silently fall back to local disk.
mu-plugin: SouinInvalidator
| Var | Default | Purpose |
|---|---|---|
FP_SOUIN_REDIS_HOST | redis | Redis hostname |
FP_SOUIN_REDIS_PORT | 6379 | Redis port |
FP_SOUIN_REDIS_PASSWORD | (empty) | Redis AUTH password |
FP_SOUIN_REDIS_DB | 0 | Logical database |
FP_SOUIN_REDIS_TIMEOUT | 1.0 | Connect timeout (seconds) |
FP_SOUIN_DISABLED | false | Truthy → no-op the invalidator (cache then expires only by TTL) |
ext-redis isn’t loaded or the connection fails, the invalidator
becomes a silent no-op. Errors are logged via error_log.
WordPress site (site-template)
These are read by config/application.php in the site template. None
are FrankenPress-specific — they’re standard WordPress config.
| Var | Default | Purpose |
|---|---|---|
WP_ENV | production | Selects which config/environments/*.php overrides load |
WP_HOME | (required) | Site URL (no trailing slash) |
WP_SITEURL | (required) | WordPress core URL (typically ${WP_HOME}/wp) |
DB_HOST | localhost | Database host |
DB_NAME, DB_USER, DB_PASSWORD | (required) | Database connection |
DB_PREFIX | wp_ | Table prefix |
AUTH_KEY etc. (8 keys+salts) | (required) | WP auth secrets — auto-generated by the Helm chart’s bootstrap Job by default |
FORCE_SSL_ADMIN | true | Force SSL for admin (the chart sets X-Forwarded-Proto pass-through) |
DISABLE_WP_CRON | false | Disable WP’s in-process pseudo-cron. The Helm chart sets this to true automatically when wpCron.enabled is on, so the CronJob is the only driver. Sites built from site-template v0.2.3+ honour this; older images ignore it. |
mu-plugin: SMTPMailer
| Var | Default | Required | Notes |
|---|---|---|---|
FP_SMTP_HOST | (unset) | yes (when opting in) | SMTP server hostname. Component is a no-op when unset. |
FP_SMTP_PORT | 587 | TCP port | |
FP_SMTP_ENCRYPTION | tls | tls (STARTTLS), ssl (implicit TLS), none (local dev only) | |
FP_SMTP_USERNAME | (unset) | yes (when opting in) | SMTP auth username |
FP_SMTP_PASSWORD | (unset) | yes (when opting in) | SMTP auth password |
FP_SMTP_FROM_EMAIL | (WP admin_email) | wp_mail_from filter target | |
FP_SMTP_FROM_NAME | (WP blogname) | wp_mail_from_name filter target | |
FP_SMTP_DISABLED | false | Truthy → mu-plugin bootstrap is a no-op. Local-dev only; the Helm chart never sets this. |
FP_SMTP_HOST is unset, wp_mail() falls through to PHP’s
mail() and fails silently because runtime ships no MTA. The chart
sets smtp.enabled=true to wire the env above; see
Operations → Email for provider recipes.
mu-plugin: SnapshotExporter
Daily wp-cron + admin-button capture-and-upload to a per-tenant S3 snapshot bucket. Drives the prod-side half offp pull.
Dormant when FP_SNAPSHOT_BUCKET is unset — zero overhead on
non-opted-in tenants.
| Var | Default | Required | Notes |
|---|---|---|---|
FP_SNAPSHOT_BUCKET | (unset) | yes (when opting in) | Snapshot bucket name (e.g. sts-production-snapshots-eu-west-2-533158516642). Component is dormant when unset. |
FP_SNAPSHOT_KEY | (unset) | yes (when opting in) | AWS access key id for the snapshot-bucket service user |
FP_SNAPSHOT_SECRET | (unset) | yes (when opting in) | AWS secret access key for the same user |
FP_SNAPSHOT_REGION | eu-west-2 | AWS region of the snapshot bucket | |
FP_APPLY_REMAP_AUTHORS | (unset) | Apply-time only — set transiently by Restorer before wp import to rewrite imported post_author to the local admin. Never set this manually. |
snapshotExport.* values surface map to these env vars
(see components/charts). The K8s Secret is
typically projected from AWS Secrets Manager via ExternalSecret.
Build args (runtime)
Set at image build time with--build-arg:
| Arg | Default | Purpose |
|---|---|---|
PHP_VERSION | 8.3 | PHP series |
FRANKENPHP_VERSION | 1.12.2 | Pinned FrankenPHP base tag |
CACHE_HANDLER_VERSION | v0.16.0 | Souin cache-handler module |
STORAGES_GO_REDIS_VERSION | v0.0.19 | Souin Redis storage |
CADDY_CBROTLI_VERSION | v1.0.1 | Brotli encoding |
WP_CLI_VERSION | 2.12.0 | WP-CLI release |
FP_MU_PLUGIN_VERSION | v0.1.1 | mu-plugin tag to bake; set to "" to skip |
Helm values (site chart)
A condensed reference of the most-used values — seecharts/charts/site/values.yaml
for every annotated parameter.
Password rotation
Two passwords participate in rotation: the WordPress admin password and the database password. They behave differently because of where WordPress reads each one.Database password
DB_PASSWORD is read from a secretKeyRef by the Deployment, the
wpcron CronJob, and the install Job. When the Secret value changes
(manual edit, External Secrets Operator sync, sealed-secret rotation,
etc.), restart the Deployment and pods pick up the new value. No
chart-side reconciliation is required.
WordPress admin password
WordPress stores a hash of the admin password inwp_users, so simply
updating the Secret value won’t change the live login. The chart’s
sync-admin-credentials initContainer (default on, chart v0.4.0+)
reconciles wp_users against the install Secret on every Pod start.
Pair it with Reloader
and rotation is self-driving:
syncAdminCredentials: false to skip the initContainer (e.g. when
an external IdP owns the WP admin user, or when you treat wp-admin as
the canonical credential store). Full flow, verification, and failure
modes are in Admin credential rotation.