Zoosper CMSDocumentationGitHub

Configuration

Zoosper loads module defaults beneath project configuration. Environment variables are used for deployment-specific values and secrets. Values supplied by the process manager or container take precedence; existing $_ENV values follow, and .env fills only missing keys.

Configuration groups

config/version.php is the central default CMS version source. CMS_VERSION is an optional deployment override.

Never commit .env, credentials, encryption keys or production connection strings.

Admin account lockout

ADMIN_ACCOUNT_LOCKOUT_MAX_ATTEMPTS=5
ADMIN_ACCOUNT_LOCKOUT_SECONDS=900

These variables configure temporary per-account lockout for known active Admin users. The first value is the failed-password threshold and the second is the lock duration in seconds. The shipped example uses five attempts and 900 seconds.

Account lockout and request rate limiting are separate controls. Account lockout persists failure state for a known active Admin identity. Password login and two-factor throttling independently track salted subject, client-IP, and subject-plus-IP dimensions; any enforcing dimension may reject a request. Successful authentication clears subject and paired state but preserves shared IP history. Either control may reject a request independently.

Temporary lockout does not change the Admin user's active/inactive status. Public login output remains neutral and does not reveal lockout state or expiry.

Anonymous frontend session policy

Anonymous frontend GET and HEAD requests that fall through to URL rewrites, published Pages, or frontend 404 handling are classified as stateless before PHP session bootstrap. They do not require a session cookie or server-side session record. Explicit Admin, authentication, password-reset, CSRF, and pending two-factor routes retain their declared stateful behavior.

Rate-limit bucket maintenance

Schedule php8.5 bin/zoosper rate-limit:prune to delete fixed-window rate-limit buckets whose window_ends_at value has expired. The command is module-discovered, resolves its maintenance store through the service container, and does not create MySQL schema at runtime. Apply migrations before enabling production enforcement.

See docs/operations/rate-limit-pruning.md for scheduler-agnostic cron and systemd deployment examples, overlap protection, monitoring, and idempotency guidance.

Admin base-path value types

admin.base_path requires a string. Missing or null values retain /admin. Numeric and boolean scalars, arrays, objects (including Stringable objects), and resources are rejected instead of cast. Existing canonical string normalisation and reserved-prefix checks are unchanged. The optional Admin layout fallback retains legacy string joining, not canonical validation.

ConfigRepository::array() preserves stored keys and mixed value types without coercion. Consumers validate their own boundaries. The Marko adapter is unchanged.