# FeatherQuilld config.yml reference

> All 183 FeatherQuilld configuration keys with type and default, generated from the Quilld source (Utils/Config).

Source: https://featherpanel.com/docs/quilld/config-reference/

## About the file

-   Location: `/etc/featherquilld/config.yml`. The configure command from the panel writes it (see [Configuration](https://featherpanel.com/docs/quilld/configuration/)).
-   Keys use snake\_case (YamlDotNet's underscored naming of the C# properties), nested with dots below.
-   Defaults are the C# property initialisers. An empty default means the type's zero value.
-   Error reporting (`sentry`) is enabled by default and sends crash reports to MythicalSystems' GlitchTip. Set `sentry.enabled: false` to turn it off.
-   With `api.docs.enabled: true` (off by default) Quilld serves Scalar API docs at `/scalar` and the spec at `/openapi/v1.json`.

## Keys

### Top-level keys

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `debug` | `bool` |  |  |
| `quiet` | `bool` |  |  |
| `app_name` | `string` | `FeatherQuilld` |  |
| `uuid` | `Guid` | `(generated)` |  |
| `token_id` | `string` | `(generated)` |  |
| `token` | `string` | `(generated)` |  |

### `api`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `api` | `object` |  |  |
| `api.host` | `string` | `0.0.0.0` |  |
| `api.port` | `int` | `8989` |  |
| `api.docs` | `object` |  |  |
| `api.docs.enabled` | `bool` |  | OpenAPI/Scalar docs. Off by default for production hardening. |
| `api.ssl` | `object` |  |  |
| `api.ssl.enabled` | `bool` |  |  |
| `api.ssl.cert` | `string` | `cert.pem` |  |
| `api.ssl.key` | `string` | `key.pem` |  |
| `api.ssl.password` | `string` |  | Optional password for PKCS#12 (.pfx / .p12) certificates. |
| `api.disable_remote_download` | `bool` |  |  |
| `api.remote_download` | `object` |  |  |
| `api.remote_download.max_redirects` | `int` | `10` |  |
| `api.upload_limit` | `int` | `100` | Max upload size in megabytes. |
| `api.trusted_proxies` | `List<string>` | `[]` |  |
| `api.ignore_certificate_errors` | `bool` |  |  |
| `api.allowed_origins` | `List<string>` | `["http://localhost:3000", "http://localhost:3001"]` |  |

### `system`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `system` | `object` |  |  |
| `system.root_directory` | `string` | `/var/lib/featherquilld` |  |
| `system.log_directory` | `string` | `/var/log/featherquilld` |  |
| `system.data` | `string` | `/var/lib/featherquilld/volumes` |  |
| `system.websites` | `string` | `/var/lib/featherquilld/websites` |  |
| `system.archive_directory` | `string` | `/var/lib/featherquilld/archives` |  |
| `system.backup_directory` | `string` | `/var/lib/featherquilld/backups` |  |
| `system.backups` | `object` |  |  |
| `system.backups.provider` | `string` | `local` | local, s3, restic, or pbs. |
| `system.backups.s3` | `object` |  |  |
| `system.backups.s3.endpoint` | `string` |  |  |
| `system.backups.s3.region` | `string` | `us-east-1` |  |
| `system.backups.s3.bucket` | `string` | `featherquilld-backups` |  |
| `system.backups.s3.access_key` | `string` |  |  |
| `system.backups.s3.secret_key` | `string` |  |  |
| `system.backups.s3.prefix` | `string` | `webspaces/` |  |
| `system.backups.s3.force_path_style` | `bool` |  |  |
| `system.backups.restic` | `object` |  |  |
| `system.backups.restic.repository` | `string` |  | restic repository URL (e.g. s3:s3.amazonaws.com/bucket or /var/backups/restic). |
| `system.backups.restic.password` | `string` |  | Password for the repository (RESTIC\_PASSWORD). |
| `system.backups.restic.binary` | `string` | `restic` | Optional path to restic binary (default: restic on PATH). |
| `system.backups.pbs` | `object` |  |  |
| `system.backups.pbs.repository` | `string` |  | Proxmox Backup Server repository, e.g. user@pbs@host:datastore. |
| `system.backups.pbs.password` | `string` |  | API token / password for PBS. |
| `system.backups.pbs.fingerprint` | `string` |  | Optional fingerprint for TLS verification. |
| `system.backups.pbs.binary` | `string` | `proxmox-backup-client` | Optional path to proxmox-backup-client (default on PATH). |
| `system.tmp_directory` | `string` | `/tmp/featherquilld` |  |
| `system.eggs_directory` | `string` | `/var/lib/featherquilld/eggs` |  |
| `system.vmount_directory` | `string` | `/var/lib/featherquilld/vmounts` |  |
| `system.fusequota_path` | `string` | `fusequota` |  |
| `system.fqctl_path` | `string` | `fqctl` | Path to the fqctl helper (umount-lazy / chown-r / mount-bind). Override with env FQCTL\_BIN. Falls back to system umount/chown when missing. |
| `system.disk_limiter_mode` | `string` | `fuse_quota` | none or fuse\_quota. Default is FuseQuota. Explicit none/off/disabled hard-disables FUSE. |
| `system.proxy` | `object` |  |  |
| `system.proxy.enabled` | `bool` | `true` |  |
| `system.proxy.provider` | `string` | `caddy` | caddy, nginx, or traefik. |
| `system.proxy.config_path` | `string` |  |  |
| `system.proxy.acme_email` | `string` |  | Operator ACME fallback. Per-WebSpace owner email is preferred when present. |
| `system.proxy.acme_staging` | `bool` |  | Use Let's Encrypt staging directory (safer for tests). |
| `system.proxy.backend_port_min` | `int` | `20000` | Inclusive low end of loopback backend ports for Docker runtimes. |
| `system.proxy.backend_port_max` | `int` | `29999` | Inclusive high end of loopback backend ports for Docker runtimes. |
| `system.proxy.backend_host` | `string` | `127.0.0.1` | Upstream address written into generated proxy configs (Caddy/nginx/Traefik). Default 127.0.0.1 when proxy runs on the same host as FeatherQuilld. |
| `system.proxy.backend_bind_host` | `string` | `127.0.0.1` | Host/interface where WebSpace container ports and static backends are published. Default 127.0.0.1 (not reachable off-box). Use 0.0.0.0 or the node IP when an external reverse proxy must reach backends on this machine. |
| `system.dns` | `object` |  |  |
| `system.dns.powerdns_api_url` | `string` | `http://127.0.0.1:8081` | PowerDNS Authoritative HTTP API base URL (localhost only). |
| `system.dns.powerdns_api_key` | `string` |  | API key for PowerDNS webserver/API. Generated on install if empty. |
| `system.mail` | `object` |  |  |
| `system.mail.enabled` | `bool` | `true` |  |
| `system.mail.backend` | `string` | `docker-mailserver` | Mail stack backend: docker-mailserver (default) or mailcow. Unknown values are reported by the mail API instead of silently switching. |
| `system.mail.hostname` | `string` |  | Public mail hostname for MX records (defaults to mail.{domain}). |
| `system.mail.webmail_hostname` | `string` |  | Public hostname for node Roundcube (proxied HTTPS), e.g. webmail.node.example.com. |
| `system.mail.data_path` | `string` |  |  |
| `system.mail.smtp_port` | `int` | `587` |  |
| `system.mail.imap_port` | `int` | `993` |  |
| `system.mail.dkim_selector` | `string` | `mail` |  |
| `system.mail.mailcow` | `object` |  | Settings that only apply when Backend is mailcow. |
| `system.mail.mailcow.path` | `string` |  | Directory that holds mailcow's compose file and its data/ tree. |
| `system.mail.mailcow.url` | `string` |  | Base URL of the mailcow UI used for API calls, e.g. https://mail.example.com. When empty the panel derives it from mail.hostname plus the HTTPS port. |
| `system.mail.mailcow.api_key` | `string` |  | API key with write access. When empty the panel reads feather-api-key next to the compose file. |
| `system.mail.mailcow.http_port` | `int` | `8080` | Host port of the mailcow UI/HTTP endpoint (default avoids clashing with the panel's Traefik). |
| `system.mail.mailcow.https_port` | `int` | `8443` | Host port of the mailcow UI/HTTPS endpoint. |
| `system.mail.mailcow.skip_acme` | `bool` | `true` | Skip mailcow's own ACME client (default true): certificates are expected to come from the panel's reverse proxy instead of mailcow binding port 80. |
| `system.mail.mailcow.mail_host` | `string` |  | IMAP/SMTP host used for probes; falls back to mail.hostname. |
| `system.mail.mailcow.domain_mailbox_limit` | `int` | `10` | Max. number of mailboxes mailcow allows per domain the panel creates. mailcow reads this as a hard cap (functions.mailbox.inc.php: count &gt;= mailboxes), so 0 means "no mailboxes at all"; a real number is required, otherwise every mailbox on an auto-created domain fails with max\_mailbox\_exceeded. |
| `system.mail.mailcow.insecure_tls` | `bool` |  | Accept mailcow's certificate even when it is self-signed (typical when the panel's reverse proxy terminates ACME and mailcow serves its default cert). |
| `system.username` | `string` | `featherquilld` |  |
| `system.timezone` | `string` | `UTC` |  |
| `system.user` | `object` |  |  |
| `system.user.rootless` | `object` |  |  |
| `system.user.rootless.enabled` | `bool` |  |  |
| `system.user.rootless.container_uid` | `int` |  |  |
| `system.user.rootless.container_gid` | `int` |  |  |
| `system.user.uid` | `int` |  |  |
| `system.user.gid` | `int` |  |  |
| `system.user.mount_passwd` | `bool` | `true` |  |
| `system.user.passwd_file` | `string` | `/etc/featherquilld/passwd` |  |
| `system.disk_check_interval` | `int` | `150` |  |
| `system.quotas` | `object` |  |  |
| `system.quotas.enabled` | `bool` | `true` | Hard disk quotas via FuseQuota. On by default for WebSpaces. |

### `plugins`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `plugins` | `object` |  |  |
| `plugins.enabled` | `bool` |  | Plugins are off by default; enabling them is an explicit root-equivalent trust decision. |
| `plugins.directory` | `string` | `/var/lib/featherquilld/plugins` |  |
| `plugins.strict` | `bool` |  |  |
| `plugins.disabled` | `List<string>` | `[]` | Plugin IDs to skip even if present on disk. |

### `remote`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `remote` | `object` |  |  |
| `remote.panel` | `string` |  |  |
| `remote.config_path` | `string` | `/api/quilld-remote/config` | Panel route for runtime config YAML (/api/quilld-remote/config). |
| `remote.health_path` | `string` | `/api/quilld-remote/health` | Panel route for health JSON (/api/quilld-remote/health). |
| `remote.app_name` | `string` | `FeatherPanel` |  |
| `remote.timeout` | `int` | `30` | Request timeout in seconds for panel API calls. |
| `remote.retry_limit` | `int` | `10` |  |
| `remote.custom_headers` | `Dictionary<string, string>` | `[]` |  |

### `sftp`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `sftp` | `object` |  |  |
| `sftp.enabled` | `bool` | `true` |  |
| `sftp.port` | `int` | `2222` | Listen port for the SFTP (SSH) server. |
| `sftp.key_algorithm` | `string` | `ssh-ed25519` |  |
| `sftp.disable_password_auth` | `bool` |  |  |
| `sftp.directory_entry_limit` | `int` | `20_000` | Max entries returned by readdir; 0 means unlimited. |
| `sftp.directory_entry_send_amount` | `int` | `500` | Entries sent per readdir call (chunk size). |
| `sftp.limits` | `object` |  |  |
| `sftp.limits.authentication_password_attempts` | `int` | `3` |  |
| `sftp.limits.authentication_pubkey_attempts` | `int` | `20` |  |
| `sftp.limits.authentication_cooldown` | `int` | `60` | Cooldown in seconds after max auth attempts (0 disables cooldown). |
| `sftp.limits.max_connections_per_user` | `int` | `10` |  |
| `sftp.limits.max_channels_per_connection` | `int` | `10` |  |
| `sftp.limits.max_handles_per_channel` | `int` | `32` |  |
| `sftp.limits.max_handles_total` | `int` | `1024` |  |

### `ftp`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `ftp` | `object` |  |  |
| `ftp.enabled` | `bool` |  |  |
| `ftp.port` | `int` | `21` | Listen port for classic FTP (control channel). |
| `ftp.passive_host` | `string` |  | Public hostname/IP advertised in PASV responses. Falls back to bind address when empty. |
| `ftp.passive_port_min` | `int` | `50_000` |  |
| `ftp.passive_port_max` | `int` | `50_100` |  |
| `ftp.disable_password_auth` | `bool` |  |  |

### `docker`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `docker` | `object` |  |  |
| `docker.network` | `object` |  |  |
| `docker.network.interface` | `string` | `172.19.0.1` |  |
| `docker.network.dns` | `List<string>` | `["1.1.1.1", "1.0.0.1"]` |  |
| `docker.network.name` | `string` | `featherquilld_nw` |  |
| `docker.network.ispn` | `bool` |  |  |
| `docker.network.ipv6` | `bool` | `true` |  |
| `docker.network.driver` | `string` | `bridge` |  |
| `docker.network.network_mode` | `string` | `featherquilld_nw` |  |
| `docker.network.is_internal` | `bool` |  |  |
| `docker.network.enable_icc` | `bool` | `true` |  |
| `docker.network.network_mtu` | `int` | `1500` |  |
| `docker.network.interfaces` | `object` |  |  |
| `docker.domainname` | `string` |  |  |
| `docker.registries` | `Dictionary<string, object>` | `[]` |  |
| `docker.tmpfs_size` | `int` | `100` |  |
| `docker.container_pid_limit` | `int` | `512` |  |
| `docker.installer_limits` | `object` |  |  |
| `docker.installer_limits.memory` | `int` | `6144` |  |
| `docker.installer_limits.cpu` | `int` | `200` |  |
| `docker.overhead` | `object` |  |  |
| `docker.overhead.override` | `bool` |  |  |
| `docker.overhead.default_multiplier` | `double` | `1.05` |  |
| `docker.overhead.multipliers` | `Dictionary<string, double>` | `[]` |  |
| `docker.use_performant_inspect` | `bool` | `true` |  |
| `docker.runtime_reconciliation` | `object` |  |  |
| `docker.runtime_reconciliation.enabled` | `bool` | `true` |  |
| `docker.runtime_reconciliation.interval_seconds` | `int` | `30` |  |
| `docker.runtime_reconciliation.inspect_timeout_seconds` | `int` | `5` |  |
| `docker.runtime_reconciliation.stuck_stopping_seconds` | `int` | `720` |  |
| `docker.runtime_reconciliation.stuck_starting_seconds` | `int` | `300` |  |
| `docker.runtime_reconciliation.unresponsive_threshold` | `int` | `2` |  |
| `docker.runtime_reconciliation.recovery_cooldown_seconds` | `int` | `300` |  |
| `docker.userns_mode` | `string` |  |  |
| `docker.web_space_security` | `object` |  | Linux capability handling for WebSpace containers. |
| `docker.web_space_security.drop_capabilities` | `bool` | `true` | Drop every capability except Capabilities. Switching this off leaves the container with the Docker engine default set - only for plates that need more. |
| `docker.web_space_security.capabilities` | `List<string>` | `[.. RequiredByPackageInstalls]` | Capabilities kept while DropCapabilities is on. An empty list drops every capability: strongest hardening, but plates that install packages at boot (PHP) need a prebuilt image then. |
| `docker.web_space_security.no_new_privileges` | `bool` | `true` | Set no-new-privileges on the container. |
| `docker.system_ips` | `List<string>` | `[]` |  |
| `docker.enable_native_kvm` | `bool` | `true` |  |
| `docker.log_config` | `object` |  |  |
| `docker.log_config.type` | `string` | `local` |  |
| `docker.socket` | `string` | `/var/run/docker.sock` | Docker engine Unix socket (or unix:///path). |

### `sentry`

| Key | Type | Default | Description |
| --- | --- | --- | --- |
| `sentry` | `object` |  | Error reporting via GlitchTip (Sentry-compatible). Enabled by default; set Enabled to false or clear Dsn to disable. |
| `sentry.enabled` | `bool` | `true` | When true and Dsn is set, the SDK is initialized at daemon start. |
| `sentry.dsn` | `string` | `(built-in GlitchTip DSN)` |  |
| `sentry.traces_sample_rate` | `double` | `0.01` | Fraction of transactions to send (0 to 1). Keep low in production. |
