> ## Documentation Index
> Fetch the complete documentation index at: https://docs.levelrail.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Runtime settings

> Every runtime setting with its type, default, range, environment seed variable and where to change it.

Runtime settings are the controls operators change in production. A stored value always wins, the environment variable only seeds the default while nothing is stored, and a setting marked live applies without a restart. There are 84 settings.

Change one in the dashboard under Settings > Runtime, or with the CLI:

```bash theme={"dark"}
levelrail-cli settings runtime list
levelrail-cli settings runtime get <key>
levelrail-cli settings runtime set <key> <value>
levelrail-cli settings runtime reset <key>
```

The environment variables that seed these defaults are also listed on [Environment variables](https://docs.levelrail.com/environment-variables.md#runtime-settings).

## Security

| Key | Type | Default | Range | Env seed | Live | Description | CLI | Dashboard |
| - | - | - | - | - | - | - | - | - |
| `api.rate_limit_read_rpm` | int | `600` | value must be between 60 and 10000000 | `APP_API_RATE_LIMIT_READ_RPM` | yes | Read requests per minute allowed for each API token, signed-in user or client address. Requests over the budget get HTTP 429 with a Retry-After header. Minimum 60 so the dashboard keeps working; a change applies at once and keeps each caller's current budget. A limit cannot be switched off: an environment value of 0 or below the minimum is raised to the minimum (older releases treated 0 as off). Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set api.rate_limit_read_rpm` | Settings > Runtime, Security card |
| `api.rate_limit_redeem_rpm` | int | `10` | value must be between 3 and 10000000 | `APP_API_RATE_LIMIT_TOKEN_REDEEM_RPM` | yes | Password reset and invite accept requests per minute allowed from one client address. Requests over the budget get HTTP 429. Minimum 3; a change applies at once. A limit cannot be switched off: an environment value of 0 or below the minimum is raised to the minimum (older releases treated 0 as off). Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set api.rate_limit_redeem_rpm` | Settings > Runtime, Security card |
| `api.rate_limit_write_rpm` | int | `120` | value must be between 20 and 10000000 | `APP_API_RATE_LIMIT_WRITE_RPM` | yes | Write and deploy requests per minute allowed for each API token, signed-in user or client address. Requests over the budget get HTTP 429 with a Retry-After header. Minimum 20 so an operator cannot lock themselves out; a change applies at once. A limit cannot be switched off: an environment value of 0 or below the minimum is raised to the minimum (older releases treated 0 as off). Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set api.rate_limit_write_rpm` | Settings > Runtime, Security card |
| `auth.engine_rate_limit_per_email` | int | `60` | value must be between 10 and 100000 | `APP_AUTH_ENGINE_RATE_LIMIT_PER_EMAIL` | no, restart | Credential requests per minute allowed for one account name from any address before it gets HTTP 429. This slows targeted password guessing; it cannot be turned off and the minimum is 10 so the owner can still sign in. An environment value below 10 is raised to 10. Needs a restart because the auth library holds the budget. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set auth.engine_rate_limit_per_email` | Settings > Runtime, Security card |
| `auth.engine_rate_limit_per_ip` | int | `60` | value must be between 10 and 100000 | `APP_AUTH_ENGINE_RATE_LIMIT_PER_IP` | no, restart | Credential requests (sign in, password reset, MFA) per minute allowed from one client address before it gets HTTP 429. This slows credential stuffing; it cannot be turned off and the minimum is 10 so an admin can still sign in. An environment value below 10 is raised to 10. Needs a restart because the auth library holds the budget. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set auth.engine_rate_limit_per_ip` | Settings > Runtime, Security card |
| `desktop.session_ttl` | duration | `12h` | any valid duration | `APP_DESKTOP_SESSION_TTL` | yes | How long a dashboard session issued to the desktop app stays valid before it must exchange its token again. | `levelrail-cli settings runtime get\|set desktop.session_ttl` | Settings > Runtime, Security card |
| `firewall.confirm_window` | duration | `60s` | value must be a duration between 10s and 10m0s | `APP_FIREWALL_CONFIRM_WINDOW` | yes | How long a port restriction applied from the dashboard or CLI stays before it is rolled back unless someone confirms it, from 10s to 10m. The next restriction uses a changed value. | `levelrail-cli settings runtime get\|set firewall.confirm_window` | Settings > Runtime, Security card |
| `mcp.default_token_scope` | string | `read_only` | one of read\_only, read\_write | `APP_MCP_DEFAULT_TOKEN_SCOPE` | yes | Scope given to a new API token or MCP client token created without explicit abilities: read\_only (view only) or read\_write (also change config). A token can still be created with explicit abilities. Existing tokens keep their scope. The environment variable only seeds the default. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set mcp.default_token_scope` | Settings > Runtime, Security card |
| `security.audit_sensitive_reads` | bool | `true` | any valid bool | `APP_AUDIT_SENSITIVE_READS` | yes | Record an audit entry when logs, env exports and other sensitive data are read. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set security.audit_sensitive_reads` | Settings > Runtime, Security card |
| `security.bind_allowed_roots` | string\_list | empty | colon separated list | `APP_BIND_ALLOWED_ROOTS` | yes | When not empty, bind mounts must sit inside one of these directories. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set security.bind_allowed_roots` | Settings > Runtime, Security card |
| `security.bind_block_credential_dirs` | bool | `true` | any valid bool | `APP_BIND_BLOCK_CREDENTIAL_DIRS` | yes | Refuse bind mounts of .ssh, .aws, .kube and similar credential directories. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set security.bind_block_credential_dirs` | Settings > Runtime, Security card |
| `security.build_network` | string | `open` | one of open, none, block-private | `APP_BUILD_NETWORK` | yes | Network for RUN steps of a build: open (no restriction), none, or block-private (reserved: builds fail until it can be enforced). Read on every build; the environment variable only seeds the default. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set security.build_network` | Settings > Runtime, Security card |
| `security.webhook_replay_protection` | bool | `true` | any valid bool | `APP_WEBHOOK_REPLAY_PROTECTION` | yes | Ignore a signed git webhook body that was already delivered within the replay window. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set security.webhook_replay_protection` | Settings > Runtime, Security card |
| `security.webhook_replay_window` | duration | `10m` | any valid duration | `APP_WEBHOOK_REPLAY_WINDOW` | yes | How long an identical signed webhook body is remembered. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set security.webhook_replay_window` | Settings > Runtime, Security card |

## Networking

| Key | Type | Default | Range | Env seed | Live | Description | CLI | Dashboard |
| - | - | - | - | - | - | - | - | - |
| `api.max_body_bytes` | int | `16777216` | value must be between 1048576 and 1073741824 | `APP_API_MAX_BODY_BYTES` | yes | Largest JSON request body in bytes the API reads before any handler runs; a bigger body is cut off and the request fails with HTTP 413. Source uploads, git pushes and asset uploads have their own limits. Between 1 MiB and 1 GiB; a change applies to the next request. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set api.max_body_bytes` | Settings > Runtime, Networking card |
| `assets.upload_max_bytes` | int | `1073741824` | value must be between 1048576 and 1099511627776 | `APP_ASSETS_UPLOAD_MAX_BYTES` | yes | Largest single asset object in bytes accepted by a direct or presigned upload; a bigger upload is refused with HTTP 413. Between 1 MiB and 1 TiB; direct uploads are exempt from the API request body limit and obey only this one. A change applies to the next upload. | `levelrail-cli settings runtime get\|set assets.upload_max_bytes` | Settings > Runtime, Networking card |
| `cutover.verify_cert_fail_days` | int | `7` | value must be between 1 and 365 | `APP_CUTOVER_VERIFY_CERT_FAIL_DAYS` | yes | Days left on a domain's certificate at or below which the cutover verifier fails the certificate line, from 1 to 365. The next check uses a changed value. | `levelrail-cli settings runtime get\|set cutover.verify_cert_fail_days` | Settings > Runtime, Networking card |
| `cutover.verify_cert_warn_days` | int | `21` | value must be between 1 and 365 | `APP_CUTOVER_VERIFY_CERT_WARN_DAYS` | yes | Days left on a domain's certificate at or below which the cutover verifier shows a warning, from 1 to 365. It should be at least the failure threshold; if it is lower, the failure threshold is used. The next check uses a changed value. | `levelrail-cli settings runtime get\|set cutover.verify_cert_warn_days` | Settings > Runtime, Networking card |
| `cutover.verify_hsts_min_age` | int | `15552000` | value must be between 3600 and 63072000 | `APP_CUTOVER_VERIFY_HSTS_MIN_AGE_SECONDS` | yes | Smallest HSTS max-age in seconds that the cutover verifier counts as enabled, from 3600 to 63072000 (two years). The next check uses a changed value. | `levelrail-cli settings runtime get\|set cutover.verify_hsts_min_age` | Settings > Runtime, Networking card |
| `cutover.verify_min_interval` | duration | `10s` | value must be a duration between 1s and 1h0m0s | `APP_CUTOVER_VERIFY_MIN_INTERVAL` | yes | Shortest wait before the same person can run the cutover verifier again on the same domain, from 1s to 1h. Other people can check that domain after a quarter of this wait. The next check uses a changed value. | `levelrail-cli settings runtime get\|set cutover.verify_min_interval` | Settings > Runtime, Networking card |
| `cutover.verify_slow_ttfb` | duration | `1500ms` | value must be a duration between 100ms and 30s | `APP_CUTOVER_VERIFY_SLOW_TTFB` | yes | Time to first byte above which the cutover verifier warns about the response, from 100ms to 30s. The next check uses a changed value. | `levelrail-cli settings runtime get\|set cutover.verify_slow_ttfb` | Settings > Runtime, Networking card |
| `cutover.verify_timeout` | duration | `5s` | value must be a duration between 1s and 1m0s | `APP_CUTOVER_VERIFY_REQUEST_TIMEOUT` | yes | How long each request of the cutover verifier may take, from 1s to 1m. The whole check is allowed four times this long. It is separate from the wait after a scheduled cutover. The next check uses a changed value. | `levelrail-cli settings runtime get\|set cutover.verify_timeout` | Settings > Runtime, Networking card |
| `domains.dns_wait_budget` | duration | `10m` | any valid duration | `APP_DOMAINS_DNS_WAIT_BUDGET` | yes | How long a domain may wait for DNS before the Domains page stops saying it is fine and lists concrete checks. It only changes the wording; it never blocks onboarding. | `levelrail-cli settings runtime get\|set domains.dns_wait_budget` | Settings > Runtime, Networking card |
| `games.status_cache` | duration | `5s` | any valid duration | `APP_GAME_STATUS_CACHE` | yes | How long one game server status answer is reused, so many dashboards and CLI calls ping a game port at most once in this time. 0s turns the cache off. | `levelrail-cli settings runtime get\|set games.status_cache` | Settings > Runtime, Networking card |
| `games.status_timeout` | duration | `3s` | any valid duration | `APP_GAME_STATUS_TIMEOUT` | yes | How long the game server status ping waits for a game port to answer before reporting it offline. Values under 200ms are raised to 200ms. | `levelrail-cli settings runtime get\|set games.status_timeout` | Settings > Runtime, Networking card |
| `ingress.ca_switch_retry_base` | duration | `1m` | any valid duration | `APP_INGRESS_CA_RETRY_BACKOFF` | yes | First wait before retrying a certificate authority switch that failed to load; it doubles on each failure up to the maximum. | `levelrail-cli settings runtime get\|set ingress.ca_switch_retry_base` | Settings > Runtime, Networking card |
| `ingress.ca_switch_retry_max` | duration | `1h` | any valid duration | `APP_INGRESS_CA_RETRY_BACKOFF_MAX` | yes | Upper bound on the wait between retries of a failed certificate authority switch. | `levelrail-cli settings runtime get\|set ingress.ca_switch_retry_max` | Settings > Runtime, Networking card |
| `ingress.cloudflare_ips_max_bytes` | int | `1048576` | value must be between 4096 and 16777216 | `APP_CLOUDFLARE_IPS_MAX_BYTES` | yes | Largest answer in bytes accepted from the Cloudflare address endpoint, from 4096 to 16 MiB. | `levelrail-cli settings runtime get\|set ingress.cloudflare_ips_max_bytes` | Settings > Runtime, Networking card |
| `ingress.cloudflare_ips_min_ranges` | int | `10` | value must be between 1 and 1000 | `APP_CLOUDFLARE_IPS_MIN_RANGES` | yes | A fetched Cloudflare list with fewer ranges than this is treated as truncated and ignored, so a bad answer cannot shrink the trusted set. | `levelrail-cli settings runtime get\|set ingress.cloudflare_ips_min_ranges` | Settings > Runtime, Networking card |
| `ingress.cloudflare_ips_refresh` | duration | `24h` | value must be a duration between 1h0m0s and 720h0m0s | `APP_CLOUDFLARE_IPS_REFRESH` | yes | How often the Cloudflare address list is fetched from Cloudflare's official endpoint, from 1h to 720h. The list shipped in the binary is used until the first fetch succeeds, and the last good list is kept when a fetch fails. | `levelrail-cli settings runtime get\|set ingress.cloudflare_ips_refresh` | Settings > Runtime, Networking card |
| `ingress.cloudflare_ips_timeout` | duration | `15s` | value must be a duration between 1s and 2m0s | `APP_CLOUDFLARE_IPS_TIMEOUT` | yes | How long one fetch of the Cloudflare address list may take, from 1s to 2m. | `levelrail-cli settings runtime get\|set ingress.cloudflare_ips_timeout` | Settings > Runtime, Networking card |
| `ingress.dns01_all_hosts` | bool | `false` | any valid bool | `APP_INGRESS_DNS01_ALL_HOSTS` | yes | Issue certificates for single hosts over DNS-01 as well as wildcards, so servers with port 80 closed can still get one. Needs a connected DNS provider; not yet verified against a real CA. | `levelrail-cli settings runtime get\|set ingress.dns01_all_hosts` | Settings > Runtime, Networking card |
| `ingress.fallback_certs` | string | `eager` | one of eager, lazy | `APP_INGRESS_FALLBACK_CERTS` | yes | When an app has no domain and gets an automatic sslip.io style hostname, eager orders its certificate as soon as the route exists (today's behavior) and lazy orders it on the first TLS request for that hostname. Lazy keeps a burst of new apps from spending certificate rate limits on hosts nobody opens. A saved change re-renders the ingress config at once, with no restart; domains you configured yourself are always eager. | `levelrail-cli settings runtime get\|set ingress.fallback_certs` | Settings > Runtime, Networking card |
| `ingress.max_body_bytes` | int | `1073741824` | value must be between 1048576 and 10737418240 | `APP_INGRESS_MAX_BODY_BYTES` | yes | Largest request body in bytes the ingress accepts for each route before answering HTTP 413, from 1 MiB to 10 GiB. A saved change re-renders the ingress config at once, with no restart; a per-app override still applies. An environment value below the minimum is raised to it and 0 no longer disables the cap. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set ingress.max_body_bytes` | Settings > Runtime, Networking card |
| `ingress.proxy_cert_wait` | duration | `5m0s` | value must be a duration between 1m0s and 24h0m0s | `APP_PROXY_CERT_WAIT` | yes | How long a domain behind an existing proxy may be without a certificate before the status says the proxy is stuck instead of still requesting one, from 1m to 24h. The dashboard also rechecks on its own for this long; a change applies on the next check. | `levelrail-cli settings runtime get\|set ingress.proxy_cert_wait` | Settings > Runtime, Networking card |
| `ingress.trusted_proxy_preset` | string | `none` | one of none, cloudflare | `APP_INGRESS_TRUSTED_PROXY_PRESET` | yes | cloudflare makes the ingress take the visitor address from CF-Connecting-IP, but only when the connection comes from Cloudflare's published ranges (kept current in the background); a spoofed header from any other peer is ignored. Any Cloudflare customer can reach your server through a proxied record of their own, so this does not prove a request came through your zone. APP\_INGRESS\_TRUSTED\_PROXIES entries stay trusted as well. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set ingress.trusted_proxy_preset` | Settings > Runtime, Networking card |
| `security.trust_loopback_forwarded_headers` | bool | `true` | any valid bool | `APP_TRUST_LOOPBACK_FORWARDED` | no, restart | Believe X-Forwarded-For when the request arrives from this host. Turn off when nothing local proxies to the control plane. | `levelrail-cli settings runtime get\|set security.trust_loopback_forwarded_headers` | Settings > Runtime, Networking card |

## Deploys

| Key | Type | Default | Range | Env seed | Live | Description | CLI | Dashboard |
| - | - | - | - | - | - | - | - | - |
| `backup.local_root` | string | empty | path must be an absolute directory other than / | `APP_BACKUP_LOCAL_ROOT` | yes | Absolute directory on the control plane that confines local backup targets. Empty uses backups/ under the data directory. The next backup or restore uses a changed value; target paths stay relative to it and cannot leave it. | `levelrail-cli settings runtime get\|set backup.local_root` | Settings > Runtime, Deploys card |
| `boot.event_recheck` | duration | `3s` | value must be a duration between 1s and 1h0m0s | `APP_BOOT_EVENT_RECHECK` | no, restart | How long after the first Docker event the control plane runs one more reconcile pass, from 1s to 1h. Read at start. | `levelrail-cli settings runtime get\|set boot.event_recheck` | Settings > Runtime, Deploys card |
| `boot.rechecks` | string\_list | `3s:10s` | colon separated list | `APP_BOOT_RECHECKS` | no, restart | Offsets after start, colon separated (for example 3s:10s), at which the control plane runs extra reconcile passes so routes are fixed when Docker publishes ports late after a host reboot. Each offset is at least 1s. Read at start. | `levelrail-cli settings runtime get\|set boot.rechecks` | Settings > Runtime, Deploys card |
| `builds.memory_limit_mb` | int | `0` | value must be 0 (auto) or between 256 and 1048576 MiB | `APP_BUILD_MEMORY_MB` | yes | Memory in MiB one build may use (256 to 1048576). 0 means auto: 60 percent of the host memory, at least 512 and always leaving a reserve for the control plane (APP\_BUILD\_MEMORY\_PERCENT and APP\_BUILD\_MEMORY\_RESERVE\_MB tune the formula). The cap also limits swap, and Node builds get a matching --max-old-space-size. A change applies to the next build; running builds keep their limit. A saved per-app or global value from build limits still wins. | `levelrail-cli settings runtime get\|set builds.memory_limit_mb` | Settings > Runtime, Deploys card |
| `compose.depends_on_timeout` | duration | `120s` | value must be a duration between 5s and 1h0m0s | `APP_COMPOSE_DEPENDS_ON_TIMEOUT` | yes | How long a compose service waits for a depends\_on dependency to start, pass its health check or exit 0 before the deploy fails naming that dependency, from 5s to 1h; a change applies on the next reconcile pass. | `levelrail-cli settings runtime get\|set compose.depends_on_timeout` | Settings > Runtime, Deploys card |
| `containers.restart_policy` | string | `unless-stopped` | one of unless-stopped, on-failure, no | `APP_CONTAINERS_RESTART_POLICY` | yes | Docker restart policy for long-running app containers, so apps come back after a host reboot or Docker restart. On a small host (1 GB) many apps starting at boot at once compete for memory; use no to rely on the control plane's sequential start. Applies to containers created on the next deploy or recreate; existing containers keep their old policy. | `levelrail-cli settings runtime get\|set containers.restart_policy` | Settings > Runtime, Deploys card |
| `databases.pooler_default` | string | `off` | one of off, on | `APP_DATABASES_POOLER_DEFAULT` | yes | When on, new Postgres databases get the connection pooler enabled at creation. Existing databases never change. Apps that rely on session features through the pooled url (prepared statements, SET, temp tables) should use direct\_url. | `levelrail-cli settings runtime get\|set databases.pooler_default` | Settings > Runtime, Deploys card |
| `deploy.drain_timeout` | duration | `15s` | value must be a duration between 1s and 10m0s | `APP_DEPLOY_DRAIN_TIMEOUT` | yes | How long the previous release keeps serving after a cutover so in-flight requests finish, from 1s to 10m. Below the longest request your app serves, a deploy can cut requests short. Read on every reconcile pass, so it applies to the next deploy; a per-app override still wins. | `levelrail-cli settings runtime get\|set deploy.drain_timeout` | Settings > Runtime, Deploys card |
| `deploy.max_concurrent` | int | `0` | value must be between 0 and 1000 | `APP_DEPLOY_MAX_CONCURRENT` | yes | How many deploys may run at once across all apps; extra deploys wait in the queue and start when one finishes. 0 means no limit. A change applies to the next queue decision. | `levelrail-cli settings runtime get\|set deploy.max_concurrent` | Settings > Runtime, Deploys card |
| `deploy.previous_release_hold` | duration | `3m` | value must be a duration between 0s and 1h0m0s | `APP_DEPLOY_PREVIOUS_RELEASE_HOLD` | yes | How long the previous release stays running after a cutover as an instant rollback target, from 0 (remove at once) to 1h. The effective hold is never shorter than the drain timeout, and with auto-rollback on it also covers the watch window. Applies on the next deploy. | `levelrail-cli settings runtime get\|set deploy.previous_release_hold` | Settings > Runtime, Deploys card |
| `deploy.stable_window` | duration | `10s` | value must be a duration between 1s and 10m0s | `APP_DEPLOY_STABLE_WINDOW` | yes | How long a new container must stay running with no restart or OOM kill before it takes traffic, from 1s to 10m. Applies on the next deploy; a per-app override still wins. | `levelrail-cli settings runtime get\|set deploy.stable_window` | Settings > Runtime, Deploys card |
| `deploy.watch_window` | duration | `5m` | value must be a duration between 0s and 24h0m0s | `APP_DEPLOY_WATCH_WINDOW` | yes | How long a new release is watched for restarts and 5xx before it counts as healthy, from 0 (no watch) to 24h. Auto-rollback needs the previous release held for this long. Applies to the next evaluation; a per-app override still wins. | `levelrail-cli settings runtime get\|set deploy.watch_window` | Settings > Runtime, Deploys card |
| `volumes.import_overwrite` | bool | `false` | any valid bool | `APP_VOLUMES_IMPORT_OVERWRITE` | yes | When on, an import with the overwrite flag may replace a volume that already holds files. Off by default: imports only fill an empty volume. Take a backup first when you turn it on. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set volumes.import_overwrite` | Settings > Runtime, Deploys card |
| `volumes.transfer_max_bytes` | int | `10737418240` | value must be between 1048576 and 4398046511104 | `APP_VOLUMES_TRANSFER_MAX_BYTES` | yes | Largest volume archive in bytes that an export may produce or an import may unpack; a bigger transfer stops with HTTP 413. Between 1 MiB and 4 TiB. A change applies to the next transfer. | `levelrail-cli settings runtime get\|set volumes.transfer_max_bytes` | Settings > Runtime, Deploys card |
| `volumes.transfer_max_concurrent` | int | `1` | value must be between 1 and 16 | `APP_VOLUMES_TRANSFER_MAX_CONCURRENT` | yes | How many volume imports this control plane stages at once, from 1 to 16. A further import is refused with HTTP 429 until one finishes. A change applies to the next import. | `levelrail-cli settings runtime get\|set volumes.transfer_max_concurrent` | Settings > Runtime, Deploys card |
| `volumes.transfer_spool_dir` | string | `volume-transfer` | any valid string | `APP_VOLUMES_TRANSFER_SPOOL_DIR` | yes | Folder name under the data directory where an import archive is staged while it is checked. A plain name, no slashes. Leftover files in it are removed when the control plane starts. A change applies to the next import. | `levelrail-cli settings runtime get\|set volumes.transfer_spool_dir` | Settings > Runtime, Deploys card |
| `volumes.transfer_timeout` | duration | `30m` | value must be a duration between 1m0s and 24h0m0s | `APP_VOLUMES_TRANSFER_TIMEOUT` | yes | How long one volume export or import may run before it is cancelled, from 1m to 24h. A change applies to the next transfer. | `levelrail-cli settings runtime get\|set volumes.transfer_timeout` | Settings > Runtime, Deploys card |

## Observability

| Key | Type | Default | Range | Env seed | Live | Description | CLI | Dashboard |
| - | - | - | - | - | - | - | - | - |
| `disk.critical_free_mb` | int | `512` | value must be between 16 and 1048576 | `APP_DISK_CRITICAL_FREE_MB` | yes | Free space in MiB below which builds, image pulls and backups are refused and the disk reserve is released (16 to 1048576). A value above the low threshold is treated as equal to it. | `levelrail-cli settings runtime get\|set disk.critical_free_mb` | Settings > Runtime, Observability card |
| `disk.low_free_mb` | int | `1024` | value must be between 64 and 1048576 | `APP_DISK_LOW_FREE_MB` | yes | Free space in MiB on the data or Docker volume below which the disk guard raises a low-disk warning and alert (64 to 1048576). Critical is clamped to this value when it is higher. | `levelrail-cli settings runtime get\|set disk.low_free_mb` | Settings > Runtime, Observability card |
| `disk.reserve_mb` | int | `16` | value must be between 0 and 4096 | `APP_DISK_RESERVE_MB` | yes | Size in MiB of the placeholder file kept in the data dir so SQLite can still commit when the disk fills; it is released below the critical threshold (0 to 4096, 0 turns the reserve off). | `levelrail-cli settings runtime get\|set disk.reserve_mb` | Settings > Runtime, Observability card |
| `heartbeat.job_backoff_base` | duration | `2s` | any valid duration | `APP_HEARTBEAT_JOB_BACKOFF_BASE` | yes | First wait before retrying a failed job ping; it doubles on each retry up to the maximum. | `levelrail-cli settings runtime get\|set heartbeat.job_backoff_base` | Settings > Runtime, Observability card |
| `heartbeat.job_backoff_max` | duration | `30s` | any valid duration | `APP_HEARTBEAT_JOB_BACKOFF_MAX` | yes | Upper bound on the wait between job ping retries. | `levelrail-cli settings runtime get\|set heartbeat.job_backoff_max` | Settings > Runtime, Observability card |
| `heartbeat.job_max_attempts` | int | `3` | value must be between 1 and 20 | `APP_HEARTBEAT_JOB_MAX_ATTEMPTS` | yes | How many times a per-job heartbeat ping is tried before it is given up. | `levelrail-cli settings runtime get\|set heartbeat.job_max_attempts` | Settings > Runtime, Observability card |
| `heartbeat.job_queue` | int | `64` | value must be between 1 and 10000 | `APP_HEARTBEAT_JOB_QUEUE` | yes | How many job pings may wait to be sent before new ones are dropped. A change applies at once. | `levelrail-cli settings runtime get\|set heartbeat.job_queue` | Settings > Runtime, Observability card |
| `monitors.raw_retention` | duration | `48h` | value must be a duration between 1h0m0s and 8760h0m0s | `APP_MONITOR_RAW_RETENTION` | yes | How long each uptime monitor check result is kept before the prune job deletes it, from 1h to 8760h; hourly rollups are kept on their own window. | `levelrail-cli settings runtime get\|set monitors.raw_retention` | Settings > Runtime, Observability card |
| `telemetry.access_log_retention` | duration | `8760h0m0s` | value must be a duration between 1h0m0s and 8760h0m0s | `APP_ACCESS_LOG_RETENTION` | yes | How long the recent-requests view keeps a request, from 1h to 8760h; the ring still holds only the latest entries per route. The next read uses a changed value. An environment value of 0 now means the maximum. | `levelrail-cli settings runtime get\|set telemetry.access_log_retention` | Settings > Runtime, Observability card |
| `telemetry.log_budget_mb` | int | `0` | value must be 0 (unlimited) or between 16 and 10485760 MiB | `APP_LOG_BUDGET_MB` | yes | Stored log size in MiB each app may use before the sweep trims its oldest lines; 0 means unlimited, otherwise 16 to 10485760. A per-app budget overrides it. | `levelrail-cli settings runtime get\|set telemetry.log_budget_mb` | Settings > Runtime, Observability card |
| `telemetry.logs_retention` | duration | `360h` | value must be a duration between 1h0m0s and 8760h0m0s | `APP_LOGS_RETENTION` | yes | How long stored app logs, traces and error events are kept before the hourly sweep deletes them, from 1h to 8760h; the next sweep uses a changed value. | `levelrail-cli settings runtime get\|set telemetry.logs_retention` | Settings > Runtime, Observability card |
| `telemetry.metrics_retention` | duration | `360h` | value must be a duration between 1h0m0s and 8760h0m0s | `APP_METRICS_RETENTION` | yes | How long raw container metric samples are kept before the prune job deletes them, from 1h to 8760h; older data stays available in the coarser rollup tiers. | `levelrail-cli settings runtime get\|set telemetry.metrics_retention` | Settings > Runtime, Observability card |

## Data retention

| Key | Type | Default | Range | Env seed | Live | Description | CLI | Dashboard |
| - | - | - | - | - | - | - | - | - |
| `backup.default_retention_hours` | int | `168` | one of 0, 24, 48, 168, 720, 1440, 2160 | `APP_BACKUP_DEFAULT_RETENTION_HOURS` | yes | Hours a scheduled backup is kept when its database or volume has no count or age rule of its own. The newest backup is never removed. 0 keeps them until a rule or a person deletes them. | `levelrail-cli settings runtime get\|set backup.default_retention_hours` | Settings > Runtime, Data retention card |
| `cleanup.enabled` | bool | `true` | any valid bool | `APP_CLEANUP_ENABLED` | yes | Turn the scheduled cleanup off entirely. Manual cleanups still work. | `levelrail-cli settings runtime get\|set cleanup.enabled` | Settings > Runtime, Data retention card |
| `cleanup.interval` | duration | `6h` | must be at least 15m0s | `APP_CLEANUP_INTERVAL` | yes | How often the scheduled cleanup checks every data type. The minimum is 15 minutes. | `levelrail-cli settings runtime get\|set cleanup.interval` | Settings > Runtime, Data retention card |
| `retention.ai_history_days` | int | `90` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_AI_HISTORY_DAYS` | yes | Days an idle assistant chat and its usage metering are kept. A chat with newer messages is kept whole. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.ai_history_days` | Settings > Runtime, Data retention card |
| `retention.alert_history_days` | int | `30` | one of 0, 30, 60, 90, 180, 365 | `APP_ALERT_HISTORY_RETENTION` | yes | Days an alert history entry is kept. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.alert_history_days` | Settings > Runtime, Data retention card |
| `retention.app_history_days` | int | `90` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_APP_HISTORY_DAYS` | yes | Days app lifecycle events, scheduled deploy history and last canary outcomes are kept. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.app_history_days` | Settings > Runtime, Data retention card |
| `retention.audit_log_days` | int | `90` | one of 0, 30, 60, 90, 180, 365; retention cannot be shorter than 90 days, choose 90 or more (or 0 to keep forever) | `APP_AUDIT_LOG_RETENTION_DAYS` | yes | Days an audit log entry is kept before the cleanup removes it. Sign-in and policy entries follow their own, longer window. 0 keeps everything. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set retention.audit_log_days` | Settings > Runtime, Data retention card |
| `retention.audit_security_days` | int | `365` | one of 0, 30, 60, 90, 180, 365; retention cannot be shorter than 365 days, choose 365 or more (or 0 to keep forever) | `APP_AUDIT_LOG_SECURITY_RETENTION_DAYS` | yes | Days sign-in, step-up, token and policy audit entries are kept. Never shorter than the general window. 0 keeps them forever. Weakening it asks for confirmation. | `levelrail-cli settings runtime get\|set retention.audit_security_days` | Settings > Runtime, Data retention card |
| `retention.auth_expired_days` | int | `30` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_AUTH_EXPIRED_DAYS` | yes | Days an expired session, device login code or magic link stays stored after it expired. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.auth_expired_days` | Settings > Runtime, Data retention card |
| `retention.email_log_days` | int | `30` | one of 0, 30, 60, 90, 180, 365 | `APP_EMAIL_LOG_RETENTION_DAYS` | yes | Days an email delivery log row is kept. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.email_log_days` | Settings > Runtime, Data retention card |
| `retention.event_webhook_days` | int | `30` | one of 0, 30, 60, 90, 180, 365 | `APP_EVENT_WEBHOOK_RETENTION` | yes | Days a finished outbound event webhook delivery is kept. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.event_webhook_days` | Settings > Runtime, Data retention card |
| `retention.expired_token_days` | int | `90` | one of 0, 30, 60, 90, 365 | `APP_RETENTION_EXPIRED_TOKEN_DAYS` | yes | Days an expired API token stays listed before the cleanup removes it. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.expired_token_days` | Settings > Runtime, Data retention card |
| `retention.probe_attempt_days` | int | `90` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_PROBE_ATTEMPT_DAYS` | yes | Days the per-attempt readiness probe detail of a deploy is kept. 0 keeps it forever. | `levelrail-cli settings runtime get\|set retention.probe_attempt_days` | Settings > Runtime, Data retention card |
| `retention.restore_history_days` | int | `90` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_RESTORE_HISTORY_DAYS` | yes | Days a finished restore, point-in-time restore or backup drill record is kept. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.restore_history_days` | Settings > Runtime, Data retention card |
| `retention.revoked_token_days` | int | `90` | one of 0, 30, 60, 90, 365 | `APP_RETENTION_REVOKED_TOKEN_DAYS` | yes | Days a revoked API token stays listed before the cleanup removes it. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.revoked_token_days` | Settings > Runtime, Data retention card |
| `retention.status_incident_days` | int | `365` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_STATUS_INCIDENT_DAYS` | yes | Days a resolved incident or completed maintenance stays on the status page record. Open ones are never removed. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.status_incident_days` | Settings > Runtime, Data retention card |
| `retention.usage_cost_days` | int | `90` | one of 0, 30, 60, 90, 180, 365 | `APP_RETENTION_USAGE_COST_DAYS` | yes | Days a daily cost showback snapshot is kept. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.usage_cost_days` | Settings > Runtime, Data retention card |
| `retention.webhook_delivery_days` | int | `30` | one of 0, 30, 60, 90, 180, 365 | `APP_WEBHOOK_DELIVERY_RETENTION_DAYS` | yes | Days a received git webhook delivery is kept for troubleshooting. 0 keeps them forever. | `levelrail-cli settings runtime get\|set retention.webhook_delivery_days` | Settings > Runtime, Data retention card |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.