<!-- Generated from .vitepress/data/config/wings.ts by .vitepress/plugins/config-docs.ts - do not edit by hand. -->

# Configuration

This page is a reference for all Wings configuration options. The configuration file is located at `/etc/calagopus-wings/config.yml` on Linux (`C:\ProgramData\Calagopus-Wings\config.yml` on Windows).

::: info Migrating from Pterodactyl/Pelican
If no `-c`/`--config` flag is passed and `/etc/calagopus-wings/config.yml` doesn't exist, Wings automatically looks for a config at `/etc/pterodactyl/config.yml`, then `/etc/pelican/config.yml`, then `./config.yml`, in that order, and uses the first one it finds. This means an existing Pterodactyl or Pelican Wings install keeps working without moving its config file, though it's recommended to migrate to the `calagopus-wings` path when convenient.
:::

## Core Configuration

### debug
Enables debug mode for Wings. When enabled, detailed logs are printed for troubleshooting.

Default value:
```yaml
debug: false
```

### app_name
A human-readable name for this Wings instance used to identify the node in log outputs.

Default value:
```yaml
app_name: Calagopus
```

### uuid
Unique identifier for this Wings node.

Default value:
```yaml
uuid: UUID_HERE
```

### token_id
The identifier half of the credentials Wings uses to validate requests from the Panel. Written by `wings configure`.

Default value:
```yaml
token_id: TOKEN_ID_HERE
```

### token
The secret half of the credentials Wings uses to validate requests from the Panel. Must be kept secret. Written by `wings configure`.

Default value:
```yaml
token: TOKEN_HERE
```

## API Settings

### api.host
The IP address Wings binds its internal API to. Alternatively, a Unix socket path can be specified here.

Default value:
```yaml
host: 0.0.0.0
```

### api.port
The port used by the Wings internal API.

Default value:
```yaml
port: 8080
```

### api.ssl.enabled
Determines whether HTTPS is enabled for the Wings API to ensure encrypted communication.

Default value:
```yaml
enabled: false
```

### api.ssl.ktls_enabled
Whether to hand HTTPS connections off to the kernel's TLS implementation (kTLS) once the handshake completes, so the kernel encrypts and decrypts records instead of userspace. This mainly speeds up large file transfers and backup downloads. Linux only, and it requires the `tls` kernel module; Wings probes for kernel support on boot, warns once and stays on userspace TLS if the kernel cannot do it, and falls back per connection when the negotiated cipher suite isn't kTLS compatible. Has no effect unless `api.ssl.enabled` is `true`.

Default value:
```yaml
ktls_enabled: false
```

### api.ssl.cert
The absolute filesystem path to the SSL certificate file used for API encryption.

Default value:
```yaml
cert: ''
```

### api.ssl.key
The absolute filesystem path to the SSL private key file corresponding to the certificate.

Default value:
```yaml
key: ''
```

### api.redirects
Custom HTTP redirects for the API server (e.g. `/ → Panel URL`).

Default value:
```yaml
redirects: {}
```

### api.disable_openapi_docs
Controls the availability of the `/openapi.json` endpoint.

Default value:
```yaml
disable_openapi_docs: false
```

### api.disable_remote_download
Whether to prevent servers from downloading files directly through remote URLs via the file manager or API.

Default value:
```yaml
disable_remote_download: false
```

### api.server_remote_download_limit
The maximum number of concurrent remote file pulls (downloads via URL) allowed for a single server.

Default value:
```yaml
server_remote_download_limit: 3
```

### api.remote_download_blocked_cidrs
A security list of CIDR ranges blocked for remote downloads to prevent SSRF (Server-Side Request Forgery) attacks.

Default value:
```yaml
remote_download_blocked_cidrs:
- 0.0.0.0/8
- 127.0.0.0/8
- 10.0.0.0/8
- 100.64.0.0/10
- 172.16.0.0/12
- 192.168.0.0/16
- 169.254.0.0/16
- 192.0.0.0/24
- 198.18.0.0/15
- 224.0.0.0/4
- 240.0.0.0/4
- '::'
- ::1
- fe80::/10
- fc00::/7
- 2002::/16
- ff00::/8
```

### api.disable_directory_size
Whether to disable the calculation of total directory sizes in the file manager.

Default value:
```yaml
disable_directory_size: false
```

### api.directory_entry_limit
The maximum number of files/folders returned in a single `/list-directory` API call (`0` = unlimited).

Default value:
```yaml
directory_entry_limit: 10000
```

### api.send_offline_server_logs
When enabled, Wings will transmit cached logs from an offline server immediately upon a websocket connection. This only works when containers are not removed on stop.

Default value:
```yaml
send_offline_server_logs: false
```

### api.file_search_threads
The number of concurrent worker threads Wings spawns to crawl and scan through server files during a search request.

Default value:
```yaml
file_search_threads: 4
```

### api.file_copy_threads
The number of concurrent worker threads allocated for duplicating files and directories within the file manager.

Default value:
```yaml
file_copy_threads: 4
```

### api.file_decompression_threads
The number of threads used for extracting archives. Applies to `.tar.xz`, `.tar.lz`, `.zip`, `.ddup`, `.7z`.

Default value:
```yaml
file_decompression_threads: 2
```

### api.file_compression_threads
The number of threads used for creating archives. Applies to `.tar.xz`, `.tar.lz`, `.zip`, `.ddup`, `.7z`.

Default value:
```yaml
file_compression_threads: 2
```

### api.upload_limit
The maximum file size in `MiB` that can be uploaded through the web-based file manager.

Default value:
```yaml
upload_limit: 100
```

### api.max_jwt_uses
The number of times a single JWT can be used for a download or backup before it is invalidated. This provides a security layer to prevent the reuse of temporary access tokens for file and backup downloads.

Default value:
```yaml
max_jwt_uses: 5
```

### api.trusted_proxies
A list of trusted IP addresses from proxy servers (like Cloudflare, NGINX, or a Load Balancer) that Wings uses to resolve the actual IP address of a user using the `X-Forwarded-For` or `X-Real-IP` header.

Default value:
```yaml
trusted_proxies: []
```

## Schedule Steps

These options govern the `HTTP Request` step that server schedules can run. The step sends a request to an arbitrary URL from the node, optionally storing the response status and body into schedule variables.

### api.schedule.steps.http_request.enabled
Whether servers on this node are allowed to run the `HTTP Request` schedule step at all. When disabled, any schedule reaching such a step fails with an error instead of sending the request.

Default value:
```yaml
enabled: true
```

### api.schedule.steps.http_request.requests
The number of `HTTP Request` steps a single server may execute per rate limit window. Once the limit is hit, further requests fail until the window rolls over.

Default value:
```yaml
requests: 5
```

### api.schedule.steps.http_request.window_seconds
The length (in seconds) of the rate limit window that `api.schedule.steps.http_request.requests` is counted against. The window is per server and restarts once it elapses.

Default value:
```yaml
window_seconds: 60
```

### api.schedule.steps.http_request.max_response_size
The maximum size (in bytes) of a response body captured by the step. Only relevant when the step stores the body into a schedule variable; anything past this limit is truncated. This should be kept at or below the 16 KiB schedule variable size limit, since a captured body larger than a variable may hold would fail the step outright.

Default value:
```yaml
max_response_size: 16384
```

### api.schedule.steps.http_request.blocked_cidrs
A security list of CIDR ranges that `HTTP Request` steps may not connect to, preventing SSRF (Server-Side Request Forgery) attacks against services reachable from the node. Enforced both on the URL host and on every address DNS resolves to, so a public hostname pointing at a private address is blocked as well.

Default value:
```yaml
blocked_cidrs:
- 0.0.0.0/8
- 127.0.0.0/8
- 10.0.0.0/8
- 100.64.0.0/10
- 172.16.0.0/12
- 192.168.0.0/16
- 169.254.0.0/16
- 192.0.0.0/24
- 198.18.0.0/15
- 224.0.0.0/4
- 240.0.0.0/4
- '::'
- ::1
- fe80::/10
- fc00::/7
- 2002::/16
- ff00::/8
```

## System Configuration

::: info Path placeholders
`data`, `diffs_directory`, `vmount_directory`, `log_directory`, `archive_directory`, `backup_directory` and `tmp_directory` accept the `{root_directory}` placeholder in their value. It's substituted with the configured `system.root_directory` every time the path is used, so these default to living under `root_directory` and move together if you repoint it. This is also how a freshly generated `config.yml` writes these values: literally as `{root_directory}/...`, not pre-resolved, so editing `root_directory` alone is enough to relocate everything else that still uses the placeholder. `log_directory` and `tmp_directory` default to fixed, independent paths on Unix - see their entries below.
:::

### system.root_directory
This is the root directory where Wings stores its own persistent data (mainly state of servers so it can restore them on restart).

Default value:
```yaml
root_directory: /var/lib/calagopus-wings
```

### system.log_directory
This is the directory where Wings stores its logs.

Default value:
```yaml
log_directory: /var/log/calagopus-wings
```

::: info
Unlike the other directories on this page, `log_directory` defaults to a fixed path on Unix and does **not** move with `root_directory`. On Windows, it defaults to `{root_directory}\logs` and does follow it.
:::

### system.data
This is the directory where Wings stores server data. This is the directory that gets bind-mounted to server containers and is where all server files are stored.

Default value:
```yaml
data: '{root_directory}/volumes'
```

### system.diffs_directory
This is the directory where Wings stores the per-server SQLite databases used by [file history](#system-file-history-enabled) to track diffs/revisions of edited files.

Default value:
```yaml
diffs_directory: '{root_directory}/diffs'
```

### system.vmount_directory
This is the directory where Wings stores virtual mounts for servers. Currently mainly used for spoofing hardware UUIDs for containers. This directory **should not** be located on a tmpfs (temporary filesystem).

Default value:
```yaml
vmount_directory: '{root_directory}/vmounts'
```

### system.archive_directory
This is the directory where Wings stores server archives. This is 100% unused in current code and is simply there for compatibility with Pterodactyl's codebase; it may be used in the future.

Default value:
```yaml
archive_directory: '{root_directory}/archives'
```

### system.backup_directory
This is the directory where Wings stores server backups. This applies to backups using the `Wings` backup driver; `btrfs` and `zfs` backups also use this directory for snapshots.

Default value:
```yaml
backup_directory: '{root_directory}/backups'
```

### system.tmp_directory
This is the directory where Wings stores temporary files. This is used for various temporary files that Wings needs to create during its operation.

Default value:
```yaml
tmp_directory: /tmp/calagopus-wings
```

### system.username
The operating system user account that the Wings process runs under on the host.

Default value:
```yaml
username: calagopus
```

### system.timezone
The timezone used by Wings (e.g., `+00:00`) for logs and containers. It is auto-detected from the host, falls back to UTC if detection fails, and is passed into all created containers.

Default value:
```yaml
timezone: +00:00
```

### system.user.rootless.enabled
Enables rootless container execution, allowing Wings to run containers without requiring root privileges on the host. When enabled, Wings takes `system.username`, `system.user.uid` and `system.user.gid` from the user it runs as and derives `docker.userns_mode` from the container UID/GID below.

Default value:
```yaml
enabled: false
```

### system.user.rootless.container_uid
The UID the server process runs as inside rootless containers. Left at `0` the server runs as container root, which the default rootless mapping already points at the user running Wings; setting it to that user's own UID works too, since Wings derives a matching `docker.userns_mode`. Unlike the other user settings, this one is never filled in automatically.

Default value:
```yaml
container_uid: 0
```

### system.user.rootless.container_gid
The GID the server process runs as inside rootless containers. Follows the same rules as `system.user.rootless.container_uid`.

Default value:
```yaml
container_gid: 0
```

### system.user.uid
The User ID (UID) on the host system that Wings uses when managing server files.

Default value:
```yaml
uid: 995
```

### system.user.gid
The Group ID (GID) on the host system that Wings uses when managing server files.

Default value:
```yaml
gid: 985
```

### system.passwd.enabled
Whether to enable dynamic generation of `/etc/passwd` files inside containers to ensure proper username resolution.

Default value:
```yaml
enabled: false
```

### system.passwd.directory
The absolute filesystem path where Wings generates and stores the dynamic passwd files.

Default value:
```yaml
directory: /run/calagopus-wings/etc
```

### system.machine_id.enabled
Controls whether a unique, generated `machine-id` file should be mounted into each server container.

Default value:
```yaml
enabled: true
```

### system.disk_check_concurrency
The number of concurrent allowed disk scans Wings can perform across all servers. This limits the number of simultaneous disk usage checks to prevent excessive background resource consumption on large nodes.

Default value:
```yaml
disk_check_concurrency: 2
```

### system.disk_check_interval
Defines how often (in seconds) Wings performs incremental disk usage checks using inotify. These checks are lightweight and rely on filesystem events rather than scanning the entire disk.

Default value:
```yaml
disk_check_interval: 150
```

### system.full_disk_check_every
Number of inotify disk check intervals before performing a full disk scan. Periodic full scans prevent desync between the OS and Wings (e.g. 150s × 4 = 600s / 10 min).

Default value:
```yaml
full_disk_check_every: 4
```

### system.disk_check_use_inotify
Uses inotify for selective scanning to reduce scanning overhead of large servers. When disabled, Wings will perform a full disk scan every time instead of relying on inotify events. Disabling this can lead to increased CPU and disk usage, especially on servers with large file counts, but may be necessary in environments where inotify is unreliable or unavailable.

Default value:
```yaml
disk_check_use_inotify: true
```

### system.disk_limiter_mode
::: info
**Switching between drivers may require additional manual work**. Enabling the quota driver requires specific filesystem support (like `prjquota` on `XFS` or `ext4`) and manual mounting configurations on the host machine. If not configured correctly at the OS level, Wings will fail to start or manage disk limits.
:::

The backend driver used to enforce storage quotas on servers. Available Options:

`none`, `btrfs_subvolume`, `zfs_dataset`, `xfs_quota` or the experimental `fuse_quota`

Default value:
```yaml
disk_limiter_mode: none
```

### system.activity_send_interval
The amount of time (in seconds) that elapses between sending aggregated server activity to the Panel. Wings collects activity over this period and sends it in a single batch.

Default value:
```yaml
activity_send_interval: 60
```

### system.activity_send_count
The number of activity events to send per batch to the Panel. This limits how many collected events are transmitted during each interval.

Default value:
```yaml
activity_send_count: 100
```

### system.check_permissions_on_boot
Whether to check and correct file permissions for a server whenever its process is booted. This can cause boot delays if the server has a large amount of files.

Default value:
```yaml
check_permissions_on_boot: true
```

### system.check_permissions_on_boot_threads
The number of concurrent threads used to verify and correct file permissions (chown) during the server startup process.

Default value:
```yaml
check_permissions_on_boot_threads: 4
```

### system.websocket_log_count
The number of lines to send when a user connects to the server websocket. This provides the initial "backlog" of console history visible in the Panel.

Default value:
```yaml
websocket_log_count: 150
```

### system.tcp_congestion_control
The TCP congestion control algorithm applied to the sockets Wings owns: the API listener, the SFTP listener, and the outgoing connections used for server transfers and S3 backup uploads (those are routed through a loopback proxy so the algorithm applies to them as well). Linux only, and the algorithm has to be available to the kernel - Wings looks it up in `/proc/sys/net/ipv4/tcp_available_congestion_control`, tries `modprobe tcp_<algorithm>` once if it is missing, and keeps the system default with a warning if it still is not there. Set to an empty string to leave congestion control alone entirely.

Default value:
```yaml
tcp_congestion_control: bbr
```

## SFTP Configuration

### system.sftp.enabled
Whether to enable the integrated SFTP (SSH) server.

Default value:
```yaml
enabled: true
```

### system.sftp.bind_address
The IP address that the internal SFTP/SSH server binds to.

Default value:
```yaml
bind_address: 0.0.0.0
```

### system.sftp.bind_port
The port that the internal SFTP/SSH server binds to for incoming connections.

Default value:
```yaml
bind_port: 2022
```

### system.sftp.read_only
Whether the SFTP server should operate in read-only mode. If enabled, users can view and download files, but cannot upload, delete, or modify any content.

Default value:
```yaml
read_only: false
```

### system.sftp.key_algorithm
The cryptographic algorithm used for generating the SSH host key.

Default value:
```yaml
key_algorithm: ssh-ed25519
```

### system.sftp.disable_password_auth
If enabled, only SSH key authentication is permitted for SFTP/SSH.

Default value:
```yaml
disable_password_auth: false
```

### system.sftp.directory_entry_limit
The maximum number of files and folders returned in a single directory listing. This prevents the SFTP server from hanging when opening folders with massive amounts of data.

Default value:
```yaml
directory_entry_limit: 20000
```

### system.sftp.directory_entry_send_amount
The number of directory entries to send in each response chunk to the SFTP client.

Default value:
```yaml
directory_entry_send_amount: 500
```

### system.sftp.limits.authentication_password_attempts
The maximum number of failed password attempts allowed within the cooldown window before the connection is dropped.

Default value:
```yaml
authentication_password_attempts: 3
```

### system.sftp.limits.authentication_pubkey_attempts
The maximum number of failed public key authentication attempts allowed within the cooldown window before the connection is dropped.

Default value:
```yaml
authentication_pubkey_attempts: 20
```

### system.sftp.limits.authentication_cooldown
Cooldown period in seconds once attempts are exceeded. This is a sliding window based on the most recent attempt. (3 failed attempts in 1min = 60s wait time from the last attempt)

Default value:
```yaml
authentication_cooldown: 60
```

### system.sftp.limits.max_connections_per_user
The maximum number of simultaneous SFTP connections allowed per user account. This prevents a single user from opening too many connections and overwhelming the server.

Default value:
```yaml
max_connections_per_user: 10
```

### system.sftp.limits.max_channels_per_connection
The maximum number of concurrent channels (e.g., SFTP sessions, shell sessions) allowed within a single SSH connection. This limits the resources consumed by a single connection.

Default value:
```yaml
max_channels_per_connection: 10
```

### system.sftp.limits.max_handles_per_channel
The maximum number of open file handles allowed per channel in the SFTP server. This prevents resource exhaustion from too many open files in a single session.

Default value:
```yaml
max_handles_per_channel: 32
```

### system.sftp.limits.max_handles_total
The maximum total number of open file handles across all channels and connections in the SFTP server. This is a global limit to prevent overall resource exhaustion.

Default value:
```yaml
max_handles_total: 1024
```

### system.sftp.shell.enabled
Determines whether to allow server management and command-line access via the Wings remote shell over SSH.

Default value:
```yaml
enabled: true
```

### system.sftp.shell.cli.name
The name used for the internal CLI tool when accessing a server via the remote shell. This is the command users type (e.g., `.wings help`) to interact with the Wings shell helper.

Default value:
```yaml
name: .wings
```

### system.sftp.activity.log_logins
Whether successful SFTP logins are recorded and displayed in the server's activity log.

Default value:
```yaml
log_logins: false
```

### system.sftp.activity.log_file_reads
Whether reading or downloading files via SFTP is recorded in the server's activity log.

Default value:
```yaml
log_file_reads: false
```

## Crash Detection

### system.crash_detection.enabled
Enables or disables the automatic crash detection system for all servers on the node.

Default value:
```yaml
enabled: true
```

### system.crash_detection.detect_clean_exit_as_crash
Whether to treat a "clean" exit (an exit code of `0`) as a server crash.

Default value:
```yaml
detect_clean_exit_as_crash: true
```

### system.crash_detection.timeout
The amount of time in seconds, that Wings waits after a server process stops before determining it has crashed and attempting a restart.

Default value:
```yaml
timeout: 60
```

## File History Configuration

### system.file_history.enabled
Enables or disables the file history tracking system. When enabled, Wings records a diff-based changelog of edits made to server files through the file manager and SFTP, allowing users to view and restore previous versions.

Default value:
```yaml
enabled: true
```

### system.file_history.zstd_level
The [Zstandard](https://facebook.github.io/zstd/) compression level used when storing snapshots and delta entries in the history database. Higher values produce smaller stored history at the cost of more CPU time. Valid range is `1`–`22`.

Default value:
```yaml
zstd_level: 19
```

### system.file_history.anchor_interval
The number of delta (diff) entries written in a chain before Wings stores a full snapshot (anchor) instead. A lower value creates anchors more frequently, making history reconstruction faster at the cost of more disk space.

Default value:
```yaml
anchor_interval: 4
```

### system.file_history.keep_chains
The number of diff chains to retain per file. Once a new chain is started (after an anchor), older chains beyond this count are pruned. Increasing this retains more history depth.

Default value:
```yaml
keep_chains: 5
```

### system.file_history.file_size_cap
The maximum size (in bytes) of file content that Wings will read and track through the HTTP file manager. File writes whose pre-write or post-write content exceeds this size are silently skipped and not recorded in history.

Default value:
```yaml
file_size_cap: 1048576
```

### system.file_history.per_file_disk_budget
The maximum amount of disk space (in bytes) that the history database may use for a single file. When exceeded, Wings drops the oldest diff chains for that file until the budget is met.

Default value:
```yaml
per_file_disk_budget: 5242880
```

### system.file_history.per_server_disk_budget
The maximum total disk space (in bytes) that the history database may use across all files for a single server. When exceeded, Wings drops the globally oldest diff chains until the budget is met.

Default value:
```yaml
per_server_disk_budget: 209715200
```

### system.file_history.maintenance_interval
The interval (in seconds) between background maintenance runs that clean up stale history entries and enforce disk budgets.

Default value:
```yaml
maintenance_interval: 3600
```

## File Collaboration Configuration

### system.file_collaboration.enabled
Enables or disables the live file collaboration system. When enabled, multiple users can open and edit the same server file simultaneously through the file manager, seeing each other's changes in real time.

Default value:
```yaml
enabled: true
```

### system.file_collaboration.file_size_cap
The maximum size (in bytes) of a file that can be opened for collaborative editing. Files larger than this cannot be opened in a collaborative session.

Default value:
```yaml
file_size_cap: 1048576
```

### system.file_collaboration.max_sessions_per_server
The maximum number of concurrent collaborative editing sessions (distinct open files) allowed per server.

Default value:
```yaml
max_sessions_per_server: 16
```

### system.file_collaboration.max_sessions_per_connection
The maximum number of concurrent collaborative editing sessions a single websocket connection may subscribe to at once.

Default value:
```yaml
max_sessions_per_connection: 8
```

### system.file_collaboration.max_editors_per_session
The maximum number of editors (participants actively editing) allowed to join a single collaborative editing session at once.

Default value:
```yaml
max_editors_per_session: 32
```

### system.file_collaboration.max_cursors_per_connection
The maximum number of remote cursors a single websocket connection will track across its subscribed collaborative sessions.

Default value:
```yaml
max_cursors_per_connection: 64
```

### system.file_collaboration.session_grace_period
The amount of time (in seconds) Wings keeps a collaborative session alive after the last participant leaves before tearing it down. This allows a user to briefly disconnect and rejoin without losing the session state.

Default value:
```yaml
session_grace_period: 30
```

## Websocket Configuration

### system.websocket.max_message_size
The maximum size (in bytes) of a single websocket message Wings accepts on a server console connection. A larger message closes the connection instead of being processed.

Default value:
```yaml
max_message_size: 1048576
```

### system.websocket.max_frame_size
The maximum size (in bytes) of a single websocket frame. A message may be split across multiple frames, so this bounds an individual frame rather than the whole message.

Default value:
```yaml
max_frame_size: 1048576
```

### system.websocket.read_buffer_size
The size (in bytes) of the read buffer allocated for each websocket connection. Raising it lowers the number of reads on busy consoles at the cost of memory per open connection.

Default value:
```yaml
read_buffer_size: 8192
```

### system.websocket.authentication_timeout
The amount of time (in seconds) a websocket connection may stay unauthenticated before Wings closes it. It is checked on the same 30 second interval as the connection ping, so the close lands on the first ping past the timeout (`0` = unlimited).

Default value:
```yaml
authentication_timeout: 60
```

### system.websocket.unauthenticated_connections_per_ip
The number of websocket connections a single IP address may hold open before sending a valid token. The slot is released the moment a connection authenticates, so this only bounds connections sitting in the pre-authentication state. Connections past the limit are rejected with `429 Too Many Requests` (`0` = unlimited).

Default value:
```yaml
unauthenticated_connections_per_ip: 32
```

::: info
Connections are counted against the client IP Wings resolved, so `api.trusted_proxies` has to be correct when Wings sits behind a reverse proxy. Without it every connection is attributed to the proxy and a single busy panel exhausts the limit for everyone.
:::

### system.websocket.max_connections_total
The maximum number of websocket connections Wings holds open across all servers at once, authenticated or not. Connections past the limit are rejected with `429 Too Many Requests` (`0` = unlimited).

Default value:
```yaml
max_connections_total: 0
```

## Backups Configuration

### system.backups.write_limit
The maximum disk write speed (in `MiB/s`) for creating backups. This prevents restoration processes from saturating the disk I/O and slowing down the rest of the node (`0` = unlimited).

Default value:
```yaml
write_limit: 0
```

### system.backups.read_limit
The maximum disk read speed (in `MiB/s`) when restoring backups. Prevents backups from slowing down the rest of the node (`0` = unlimited).

Default value:
```yaml
read_limit: 0
```

### system.backups.compression_level
Defines the CPU vs. compression ratio. Higher compression saves disk space but uses more CPU (`best_speed` = fastest, `best_compression` = smallest file).

Available options:

`best_speed`, `good_speed`, `good_compression`, `best_compression`

Default value:
```yaml
compression_level: best_speed
```

### system.backups.mounting.enabled
Allows users to browse and interact with backup contents directly via the File Manager without needing to download them first.

Default value:
```yaml
enabled: true
```

### system.backups.mounting.path
The path prefix used for the virtual backup mount (e.g., `.backups/<uuid>`).

Default value:
```yaml
path: .backups
```

### system.backups.wings.create_threads
The number of CPU threads used when compressing local backups. This applies specifically to `.tar.gz`, `.tar.xz`, `.tar.lz`, `.tar.zst`, and `.7z`.

Default value:
```yaml
create_threads: 4
```

### system.backups.wings.restore_threads
The number of CPU threads used for extracting local backup archives. This applies specifically to `.tar.xz`, `.tar.lz`, `.zip`, `.ddup` and `.7z`.

Default value:
```yaml
restore_threads: 4
```

### system.backups.wings.archive_format
The compression format used for local backups.

Available options:

`tar`, `tar_gz`, `tar_xz`, `tar_lzip`, `tar_bz2`, `tar_lz4`, `tar_zstd`, `zip`, `seven_zip`

Default value:
```yaml
archive_format: tar_gz
```

### system.backups.s3.create_threads
The number of CPU threads used when compressing backups for S3 storage. This applies specifically to `.tar.gz`, `.tar.xz`, `.tar.lz` and `.tar.zst`.

Default value:
```yaml
create_threads: 4
```

### system.backups.s3.part_upload_timeout
The maximum time (in seconds) to wait for a single part of a multipart upload.

Default value:
```yaml
part_upload_timeout: 7200
```

### system.backups.s3.retry_limit
The number of retry attempts for each failed upload part.

Default value:
```yaml
retry_limit: 10
```

### system.backups.ddup_bak.create_threads
The number of threads used for `ddup-bak` backup creation.

Default value:
```yaml
create_threads: 4
```

### system.backups.ddup_bak.compression_format
The compression format used for each `ddup-bak` chunk.

Available options:

`none`, `deflate`, `gzip`, `brotli`

Default value:
```yaml
compression_format: deflate
```

### system.backups.restic.repository
::: info
All restic options only apply when using Pterodactyl. On Calagopus, restic is fully managed by the panel, and these local configuration settings are ignored.
:::

The Restic repository path used for backups. This must already be initialized and can be overridden by the panel.

Default value:
```yaml
repository: '{root_directory}/backups/restic'
```

### system.backups.restic.password_file
The local path to the file containing the Restic repository password used for authentication. This can be overridden by the panel.

Default value:
```yaml
password_file: '{root_directory}/backups/restic_password'
```

### system.backups.restic.retry_lock_seconds
The amount of time (in seconds) Wings will wait if the Restic repository is locked by another process before failing the backup task. This can be overridden by the panel.

Default value:
```yaml
retry_lock_seconds: 60
```

### system.backups.restic.environment
The environment variables passed to the restic process for authentication and configuration. This can be overridden by the panel.

Default value:
```yaml
environment: {}
```

### system.backups.btrfs.restore_threads
The number of threads used for restoring Btrfs snapshots. Each thread processes one file, so with 4 threads, up to 4 files are restored concurrently.

Default value:
```yaml
restore_threads: 4
```

### system.backups.btrfs.create_read_only
Whether to create read-only snapshots to prevent data modification after the backup is taken.

Default value:
```yaml
create_read_only: true
```

### system.backups.zfs.restore_threads
The number of threads used for restoring ZFS snapshots. Each thread processes one file, so with 4 threads, up to 4 files are restored concurrently.

Default value:
```yaml
restore_threads: 4
```

### system.backups.pbs.create_threads
The number of threads used when creating Proxmox Backup Server (PBS) backups. Each thread processes one file concurrently while the backup is being uploaded.

Default value:
```yaml
create_threads: 4
```

### system.backups.pbs.download_concurrency
The number of chunks downloaded concurrently when restoring a Proxmox Backup Server (PBS) backup.

Default value:
```yaml
download_concurrency: 4
```

## Transfers

### system.transfers.download_limit
The download rate limit for transfers in MiB/s (`0` = unlimited).

Default value:
```yaml
download_limit: 0
```

## Docker Configuration

### docker.socket
The path to the Docker daemon socket or HTTP address.

Default value:
```yaml
socket: /var/run/docker.sock
```

### docker.server_name_in_container_name
Whether to include the server's name within the Docker container name for easier identification in tools like `docker ps`.

Default value:
```yaml
server_name_in_container_name: false
```

### docker.delete_container_on_stop
When enabled, containers are deleted as soon as a server stops, is killed, or crashes. This significantly reduces long-term CPU/resource overhead.

Default value:
```yaml
delete_container_on_stop: true
```

### docker.network.interface
The specific IP interface used for the Docker network bridge.

Default value:
```yaml
interface: 172.18.0.1
```

### docker.network.disable_interface_binding
Whether to disable binding containers to a specific network interface on the host.

Default value:
```yaml
disable_interface_binding: false
```

### docker.network.dns
The list of DNS servers used by containers for name resolution.

Default value:
```yaml
dns:
- 1.1.1.1
- 1.0.0.1
```

### docker.network.dns_options
Resolver options (as used in `/etc/resolv.conf`'s `options` line) applied to containers alongside `docker.network.dns`.

Default value:
```yaml
dns_options:
- ndots:0
- timeout:2
- attempts:3
- single-request-reopen
```

### docker.network.name
The name of the Docker network used by Wings to manage container communication.

Default value:
```yaml
name: calagopus_nw
```

### docker.network.ispn
The flag that determines if the Docker network used by Wings is "internal", meaning it has no access to the external internet.

Default value:
```yaml
ispn: false
```

### docker.network.driver
The Docker network driver used for the container network (e.g. `bridge`).

Default value:
```yaml
driver: bridge
```

### docker.network.mode
The network mode containers are attached to, passed to the Docker daemon as-is. This should match `docker.network.name`; if `name` is changed without changing `mode`, Wings warns on startup that containers are being attached to a network that does not exist. Also accepted under the legacy key `network_mode`.

Default value:
```yaml
mode: calagopus_nw
```

### docker.network.is_internal
Whether to mark the network as internal-only, restricting containers from accessing the outside internet.

Default value:
```yaml
is_internal: false
```

### docker.network.enable_icc
Enables Inter-Container Communication, allowing containers on the same network to talk to one another.

Default value:
```yaml
enable_icc: true
```

### docker.network.network_mtu
Sets the Maximum Transmission Unit (MTU) size for the container network.

Default value:
```yaml
network_mtu: 1500
```

### docker.network.interfaces.v4.enabled
Whether to enable IPv4 on the Docker network bridge. At least one of `docker.network.interfaces.v4.enabled` and `docker.network.interfaces.v6.enabled` must stay `true` - Wings refuses to create the network if both are disabled.

Default value:
```yaml
enabled: true
```

### docker.network.interfaces.v4.subnet
The IPv4 subnet range used by the Docker network.

Default value:
```yaml
subnet: 172.18.0.0/16
```

### docker.network.interfaces.v4.gateway
The IPv4 gateway address for the Docker network. This will automatically be incremented if the address is already in use by another network on the host.

Default value:
```yaml
gateway: 172.18.0.1
```

### docker.network.interfaces.v6.enabled
Whether to enable IPv6 on the Docker network bridge. At least one of `docker.network.interfaces.v4.enabled` and `docker.network.interfaces.v6.enabled` must stay `true` - Wings refuses to create the network if both are disabled.

Default value:
```yaml
enabled: true
```

### docker.network.interfaces.v6.subnet
The IPv6 subnet range used by the Docker network.

Default value:
```yaml
subnet: fdba:17c8:6c94::/64
```

### docker.network.interfaces.v6.gateway
The IPv6 gateway address for the Docker network.

Default value:
```yaml
gateway: fdba:17c8:6c94::1011
```

### docker.firewall.backend
Which backend Wings uses to apply per-server firewall rules on the host.

- `auto` - Pick a backend on boot. Wings prefers `nftables`, falls back to `iptables`, and uses the helper container when it runs inside a container that has its own network namespace.
- `nftables` - Run `nft` directly on the host.
- `iptables` - Run `iptables` directly on the host.
- `container` - Run `nft` through a helper container started from the Wings image. Use this when Wings runs as a container without host networking, where rules applied in its own network namespace would never see server traffic.
- `disabled` - Never apply rules.

Default value:
```yaml
backend: auto
```

::: warning
Server firewalls are Linux only, and are not supported with a rootless container engine - published port traffic does not traverse the host netfilter forward path there.

When no backend ends up usable - an unsupported platform, a rootless engine, neither `nft` nor `iptables` present, or a helper container that fails to start - a server that has firewall rules configured refuses to start rather than running unprotected. Set this to `disabled` to start such servers anyway, in which case Wings logs a warning per server and leaves its rules unapplied.
:::

### docker.firewall.source_file_max_entries
The maximum number of entries Wings loads from the source file of a firewall rule. A file holding more than this is rejected as a whole, and the rule keeps the entries it last loaded.

Default value:
```yaml
source_file_max_entries: 10000
```

### docker.firewall.source_file_max_bytes
The maximum size (in bytes) of the source file of a firewall rule. A file larger than this is rejected as a whole, and the rule keeps the entries it last loaded.

Default value:
```yaml
source_file_max_bytes: 1048576
```

### docker.domainname
The domain name assigned to containers, useful for internal networking resolution.

Default value:
```yaml
domainname: ''
```

### docker.registries
The Docker registry authentication configurations used for pulling private images.

Default value:
```yaml
registries: {}
```

### docker.registry_image_fetch_cache.enabled
Whether to enable caching of image metadata (e.g., digests, tags) from Docker registries to reduce API calls and speed up repeated server starts.

Default value:
```yaml
enabled: true
```

### docker.registry_image_fetch_cache.duration
The duration (in seconds) that cached image metadata is considered valid before it is refreshed with a new request to the Docker registry.

Default value:
```yaml
duration: 300
```

### docker.registry_image_fetch_cache.background_refresh
Whether a stale image is refreshed in the background instead of holding up the server boot. When enabled and the image already exists on the host, Wings boots the server from the local copy right away and pulls the newer image in a background task, so the update only takes effect on the next start. Images that are not on the host yet are still pulled before the server boots.

Default value:
```yaml
background_refresh: false
```

### docker.tmpfs_size
The size (in `MiB`) of the `/tmp` directory mounted as a tmpfs in containers.

Default value:
```yaml
tmpfs_size: 100
```

### docker.shm_size
The size (in `MiB`) of `/dev/shm` inside containers. `0` leaves Docker's own default (64 MiB) in place. Raise it for games that map large amounts of shared memory.

Default value:
```yaml
shm_size: 0
```

### docker.container_pid_limit
The maximum number of processes (PIDs) allowed to run simultaneously within a single container.

Default value:
```yaml
container_pid_limit: 5120
```

### docker.container_apply_seccomp
Whether to apply a modified seccomp profile with additional syscalls toggled from the panel, this can break on podman.

Default value:
```yaml
container_apply_seccomp: true
```

### docker.container_apparmor_profile
The name of an AppArmor profile to confine server containers with, passed to Docker as `apparmor=<profile>`. The profile must already be loaded on the host. Leaving this empty lets Docker apply its own `docker-default` profile.

Default value:
```yaml
container_apparmor_profile: ''
```

### docker.container_ulimits
Per-container resource limits, applied to every server container Wings creates. Each entry is a `name`, a `soft` limit and a `hard` limit, matching the `--ulimit` flag of `docker run` (`-1` means unlimited). An empty list leaves the daemon defaults in place. A `nofile` hard limit larger than what the host lets Wings raise its own limit to is clamped down to that ceiling, with a warning logged once.

Default value:
```yaml
container_ulimits: []
```

::: info
Each entry is a map, so a raised file descriptor limit looks like this:

```yaml
container_ulimits:
- name: nofile
  soft: 65535
  hard: 65535
```
:::

### docker.container_sysctls
Kernel parameters set inside every server container, matching the `--sysctl` flag of `docker run`. Only namespaced sysctls can be set this way; the Docker daemon rejects the container outright for anything else. Entries starting with `net.` are skipped for containers that share a foreign network namespace (`host` or `container:<id>` network modes), since those sysctls belong to the namespace owner.

Default value:
```yaml
container_sysctls: {}
```

### docker.numa_memory_binding
Whether to bind a container's memory to the NUMA nodes its pinned CPU threads live on, keeping allocations local instead of spread across sockets. Only takes effect on a multi-node host for servers that have CPU pinning set; single-node machines and unpinned servers are unaffected.

Default value:
```yaml
numa_memory_binding: true
```

### docker.cpu_period
The CFS scheduling period (in microseconds) used for container CPU limits. A server's CPU limit is turned into a quota of `limit% × cpu_period`, so a shorter period hands out CPU time in smaller, more frequent slices, at the cost of more scheduler overhead. Values are clamped to the kernel's accepted range of `1000` - `1000000`.

Default value:
```yaml
cpu_period: 100000
```

### docker.cfs_burst.enabled
Whether to grant containers CFS burst, letting a server bank unused CPU time within a period and spend it on a later spike instead of being throttled. Requires a kernel with CFS burst support (`cpu.max.burst` on cgroup v2, `cpu.cfs_burst_us` on v1); where it is unsupported, Wings leaves it alone and warns about it once. Servers without a CPU limit are unaffected, they are not throttled to begin with.

Default value:
```yaml
enabled: true
```

### docker.cfs_burst.multiple
The fraction of a server's CPU quota that may be banked as burst. `1.0` allows a full extra period's worth of CPU time, `0.5` half of it, `0` disables bursting for the same effect as turning `enabled` off. The kernel refuses a burst larger than the quota, so values above `1.0` are clamped.

Default value:
```yaml
multiple: 1.0
```

### docker.startup_boost.enabled
Whether to lift a server's CPU limit while it is booting. With this on, a starting container runs without a CPU quota until it reports as running (or `docker.startup_boost.timeout` elapses), after which the configured limit and CFS burst are put back. This mainly helps single-threaded boot work like world generation or mod loading. Servers without a CPU limit are unaffected, they are already unthrottled. These are the node-wide defaults and can be overridden by the panel, which may give an individual server its own `enabled` and `timeout` to use in place of the values here.

Default value:
```yaml
enabled: false
```

### docker.startup_boost.timeout
The maximum time (in seconds) a server may stay boosted. Once the server leaves the starting state or this many seconds pass, whichever comes first, its CPU quota is restored.

Default value:
```yaml
timeout: 120
```

### docker.startup_boost.max_concurrent
The number of servers that may be boosted at the same time on this node. Servers that start while this many boosts are already active simply boot with their normal CPU limit, so a mass restart cannot hand out unlimited CPU to every server at once. Unlike the other options in this block, this one is always taken from the node config, a per-server override from the panel cannot raise it.

Default value:
```yaml
max_concurrent: 3
```

### docker.runtime_boost.enabled
Whether to temporarily raise a server's CPU quota when it is pinned against its limit while running. Wings watches the per-second CPU samples it already collects for the stats websocket, and once a server has sat at or above `docker.runtime_boost.threshold` of its limit for `docker.runtime_boost.sustained` samples in a row it hands out extra quota for `docker.runtime_boost.duration` seconds before restoring the configured limit. Unlike `docker.startup_boost`, this applies to a server that is already running, so it covers spikes like a large world save or a burst of players joining rather than boot work. Servers without a CPU limit are unaffected, they are already unthrottled, and a server that is currently startup boosted is never boosted again on top of it. These are the node-wide defaults and can be overridden by the panel, which may give an individual server its own values for every option below except `docker.runtime_boost.max_concurrent`.

Default value:
```yaml
enabled: false
```

### docker.runtime_boost.threshold
The share (`%`) of a server's configured CPU limit that counts as pinned. A server limited to `200%` with the default threshold of `90` has to use at least `180%` CPU for a sample to count towards a boost.

Default value:
```yaml
threshold: 90
```

### docker.runtime_boost.sustained
The number of consecutive one second samples a server must spend at or above the threshold before it is boosted, so brief spikes do not trigger one. The streak resets whenever a sample falls below the threshold, the server leaves the running state, or a boost is granted.

Default value:
```yaml
sustained: 10
```

### docker.runtime_boost.multiple
The multiplier applied to the server's CPU quota while boosted. `2.0` gives it twice its configured limit for the duration of the boost. Values below `1.0` are clamped to `1.0`, since a boost never hands out less CPU than the server already has.

Default value:
```yaml
multiple: 2.0
```

### docker.runtime_boost.duration
How long (in seconds) a boost lasts. Once this elapses the server's configured CPU limit and CFS burst are put back, whether or not it is still pinned.

Default value:
```yaml
duration: 60
```

### docker.runtime_boost.cooldown
How long (in seconds) a server has to wait after a boost ends before it may be boosted again, so a permanently overloaded server cannot simply run at its boosted limit forever.

Default value:
```yaml
cooldown: 300
```

### docker.runtime_boost.max_concurrent
The number of servers that may be boosted at the same time on this node. While this many boosts are active, a server that hits the threshold keeps its normal CPU limit and its streak resets, so a node-wide load spike cannot boost every server at once. Unlike the other options in this block, this one is always taken from the node config, a per-server override from the panel cannot raise it.

Default value:
```yaml
max_concurrent: 3
```

### docker.installer_limits.timeout
The maximum time (in seconds) allowed for an installation container to run before it is considered failed (`0` = no limit).

Default value:
```yaml
timeout: 1800
```

### docker.installer_limits.memory
The memory limit (in `MiB`) for installer containers. This will be overwritten with the server's memory limit **if it is higher**.

Default value:
```yaml
memory: 1024
```

### docker.installer_limits.cpu
The CPU limit (`%`) for installer containers. This will be overwritten with the server's CPU limit **if it is higher**.

Default value:
```yaml
cpu: 100
```

### docker.overhead.override
The toggle to enable or disable custom memory overhead multipliers.

Default value:
```yaml
override: false
```

### docker.overhead.default_multiplier
The default multiplier applied to a server's memory limit to account for Docker container overhead.

Default value:
```yaml
default_multiplier: 1.05
```

### docker.overhead.multipliers
A map of specific memory thresholds to custom multipliers, allowing for granular overhead control based on server size.

Default value:
```yaml
multipliers: {}
```

### docker.userns_mode
The user namespace mode for containers, used to isolate container users from host users for enhanced security. Left empty with `system.user.rootless.enabled` on, Wings derives `keep-id:uid=<container_uid>,gid=<container_gid>` from the rootless settings; setting it explicitly opts out of that and is passed through untouched.

Default value:
```yaml
userns_mode: ''
```

### docker.log_config.type
The Docker logging driver type used to capture and store container output.

Default value:
```yaml
type: local
```

### docker.log_config.config.compress
Whether to enable compression for stored log files to save disk space.

Default value:
```yaml
compress: 'false'
```

### docker.log_config.config.max-file
The maximum number of log files to retain before the oldest ones are rotated out.

Default value:
```yaml
max-file: '1'
```

### docker.log_config.config.max-size
The maximum size allowed for a single log file before it is rotated.

Default value:
```yaml
max-size: 5m
```

### docker.log_config.config.mode
The delivery mode for logs (e.g. `non-blocking`), determining how Docker handles log data when the buffer is full.

Default value:
```yaml
mode: non-blocking
```

## Throttles

### throttles.enabled
The toggle to enable or disable console output throttling for all containers.

Default value:
```yaml
enabled: true
```

### throttles.lines
The maximum number of console lines stored in the buffer for each server.

Default value:
```yaml
lines: 2000
```

### throttles.line_reset_interval
The interval (in seconds) at which the console line counters are reset.

Default value:
```yaml
line_reset_interval: 100
```

## Private Network

Tundra is the daemon that carries the [private network](/docs/panel/features/server/network/connections), the encrypted node-to-node tunnel servers use to reach each other without going over the public internet. It runs as a privileged container Wings manages, and it is **off by default** on every node.

Turning it on here only makes the node capable of it. An administrator still has to put the node on the network from its [Private Network](/docs/panel/features/admin/nodes#private-network) tab in the panel. That tab is also where you set the host and UDP port other nodes dial this one on.

::: warning
The private network is Linux only. Rootless Podman carries it, because the daemon runs in the same user namespace that owns the server containers, so it can still bind sockets inside their network namespaces. Rootless Docker cannot: host networking there is RootlessKit's own namespace rather than the host's, so peers never reach the tunnel port. Wings does not check for this, so a rootless Docker node with `enabled` set still reports itself as supported in the panel.
:::

### tundra.enabled
Whether Wings runs the tundra daemon on this node. With this off, servers on the node cannot join the private network, and the panel reports the node as unable to run it.

Default value:
```yaml
enabled: false
```

### tundra.data_directory
Where the daemon's persistent state lives, including the node's local CA, its identity and the control socket Wings talks to it over.

Default value:
```yaml
data_directory: '{root_directory}/tundra'
```

### tundra.binary
Path to a tundra binary to run instead of the bundled one. Leave empty and Wings extracts the binary from `source_image`.

Default value:
```yaml
binary: ''
```

### tundra.image
The base image the daemon container runs on.

Default value:
```yaml
image: debian:trixie-slim
```

### tundra.source_image
The image the tundra binary is extracted from when `binary` is empty. Pin this to control which tundra version the node runs.

Default value:
```yaml
source_image: ghcr.io/calagopus/tundra:1.0.0
```

### tundra.metrics_port
The loopback port the daemon serves its metrics on, which is what feeds the node's live peer links in the panel. It is not the port peers connect on; that one is set per node in the panel.

Default value:
```yaml
metrics_port: 7101
```

## Remote Configuration

### remote
The URL of the Panel instance that this Wings node communicates with.

Default value:
```yaml
remote: https://panel.example.com
```

### remote_headers
Custom HTTP headers that Wings includes in every outgoing HTTP request to the Panel.

Default value:
```yaml
remote_headers: {}
```

### remote_query.timeout
The maximum number of retries for critical API requests. This uses an exponential backoff strategy.

Default value:
```yaml
timeout: 30
```

### remote_query.boot_servers_per_page
The number of servers Wings requests from the Panel API in a single batch during the initial boot sequence.

Default value:
```yaml
boot_servers_per_page: 50
```

### remote_query.retry_limit
The maximum number of times Wings will attempt to re-send a failed request to the Panel before giving up.

Default value:
```yaml
retry_limit: 10
```

## Security / Behaviour Flags

### allowed_mounts
A security whitelist defining which specific directories or files on the host system are permitted to be mounted into a server's Docker container.

Default value:
```yaml
allowed_mounts: []
```

### allowed_origins
A list of specific URLs (origins) that are permitted to make cross-origin requests to the Wings API. By default, the URL defined in the `remote:` setting is the only allowed origin.

Default value:
```yaml
allowed_origins: []
```

### allow_cors_private_network
Determines whether Wings permits Cross-Origin Resource Sharing (CORS) requests originating from private network addresses.

Default value:
```yaml
allow_cors_private_network: false
```

### ignore_panel_config_updates
When set to `true`, Wings will ignore configuration update commands sent by the Panel.

Default value:
```yaml
ignore_panel_config_updates: false
```

::: info Options the panel can never change
Even with panel config updates enabled, a set of paths is stripped out of every patch the panel sends, so they can only be changed by editing `config.yml` on the node itself:

- Node identity: `uuid`, `token`, `token_id`, `remote`, `remote_headers`
- Paths: `system.root_directory`, `system.log_directory`, `system.data`, `system.diffs_directory`, `system.vmount_directory`, `system.archive_directory`, `system.backup_directory`, `system.tmp_directory`, `system.passwd.directory`, `system.backups.restic.repository`, `system.backups.restic.password_file`, `system.backups.mounting.path`, `tundra.data_directory`, `tundra.binary`
- Host access: `system.username`, `system.user`, `system.passwd`, `docker.socket`, `tundra.image`, `tundra.source_image`, `allowed_mounts`
- Listener and egress: `api.host`, `api.port`, `api.ssl`, `api.trusted_proxies`, `api.disable_remote_download`, `api.remote_download_blocked_cidrs`, `api.schedule.steps.http_request`
- The flags themselves: `ignore_panel_config_updates`, `ignore_panel_wings_upgrades`

The rest of the patch still applies, the forbidden keys are dropped silently rather than failing the whole update.
:::

### ignore_panel_wings_upgrades
When set to `true`, Wings will ignore remote upgrade commands sent by the Panel.

Default value:
```yaml
ignore_panel_wings_upgrades: false
```

## SSL Configuration

::: info
This section assumes you've already generated a certificate. See [Generating SSL Certificates](/docs/additional/ssl-certificates) if you haven't. Replace `<domain>` with your actual node domain.
:::

### Enabling SSL
SSL is disabled by default. To secure Wings' communication, set `enabled` to `true` under `api.ssl` and point `cert`/`key` to your certificate files.

If you're using Let's Encrypt, your config should look like this:

```yaml
api:
  host: 0.0.0.0
  port: 8080
  ssl:
    enabled: true
    cert: /etc/letsencrypt/live/<domain>/fullchain.pem
    key: /etc/letsencrypt/live/<domain>/privkey.pem
```

### Applying Changes
After saving `config.yml`, restart Wings for the new SSL configuration to take effect:

```bash
sudo systemctl restart wings
```

## Example Config

The following is an example of a standard generated `config.yml` for Wings with standard values. A handful of defaults differ between platforms (mainly paths and the Unix-only `passwd`/`machine_id` sections), so both are shown below.

::::tabs
=== Unix

```yaml
debug: false
app_name: Calagopus
uuid: UUID_HERE
token_id: TOKEN_ID_HERE
token: TOKEN_HERE
api:
  host: 0.0.0.0
  port: 8080
  ssl:
    enabled: false
    ktls_enabled: false
    cert: ''
    key: ''
  redirects: {}
  disable_openapi_docs: false
  disable_remote_download: false
  server_remote_download_limit: 3
  remote_download_blocked_cidrs:
  - 0.0.0.0/8
  - 127.0.0.0/8
  - 10.0.0.0/8
  - 100.64.0.0/10
  - 172.16.0.0/12
  - 192.168.0.0/16
  - 169.254.0.0/16
  - 192.0.0.0/24
  - 198.18.0.0/15
  - 224.0.0.0/4
  - 240.0.0.0/4
  - '::'
  - ::1
  - fe80::/10
  - fc00::/7
  - 2002::/16
  - ff00::/8
  disable_directory_size: false
  directory_entry_limit: 10000
  send_offline_server_logs: false
  file_search_threads: 4
  file_copy_threads: 4
  file_decompression_threads: 2
  file_compression_threads: 2
  upload_limit: 100
  max_jwt_uses: 5
  trusted_proxies: []
  schedule:
    steps:
      http_request:
        enabled: true
        requests: 5
        window_seconds: 60
        max_response_size: 16384
        blocked_cidrs:
        - 0.0.0.0/8
        - 127.0.0.0/8
        - 10.0.0.0/8
        - 100.64.0.0/10
        - 172.16.0.0/12
        - 192.168.0.0/16
        - 169.254.0.0/16
        - 192.0.0.0/24
        - 198.18.0.0/15
        - 224.0.0.0/4
        - 240.0.0.0/4
        - '::'
        - ::1
        - fe80::/10
        - fc00::/7
        - 2002::/16
        - ff00::/8
system:
  root_directory: /var/lib/calagopus-wings
  log_directory: /var/log/calagopus-wings
  data: '{root_directory}/volumes'
  diffs_directory: '{root_directory}/diffs'
  vmount_directory: '{root_directory}/vmounts'
  archive_directory: '{root_directory}/archives'
  backup_directory: '{root_directory}/backups'
  tmp_directory: /tmp/calagopus-wings
  username: calagopus
  timezone: +00:00
  user:
    rootless:
      enabled: false
      container_uid: 0
      container_gid: 0
    uid: 995
    gid: 985
  passwd:
    enabled: false
    directory: /run/calagopus-wings/etc
  machine_id:
    enabled: true
  disk_check_concurrency: 2
  disk_check_interval: 150
  full_disk_check_every: 4
  disk_check_use_inotify: true
  disk_limiter_mode: none
  activity_send_interval: 60
  activity_send_count: 100
  check_permissions_on_boot: true
  check_permissions_on_boot_threads: 4
  websocket_log_count: 150
  tcp_congestion_control: bbr
  sftp:
    enabled: true
    bind_address: 0.0.0.0
    bind_port: 2022
    read_only: false
    key_algorithm: ssh-ed25519
    disable_password_auth: false
    directory_entry_limit: 20000
    directory_entry_send_amount: 500
    limits:
      authentication_password_attempts: 3
      authentication_pubkey_attempts: 20
      authentication_cooldown: 60
      max_connections_per_user: 10
      max_channels_per_connection: 10
      max_handles_per_channel: 32
      max_handles_total: 1024
    shell:
      enabled: true
      cli:
        name: .wings
    activity:
      log_logins: false
      log_file_reads: false
  crash_detection:
    enabled: true
    detect_clean_exit_as_crash: true
    timeout: 60
  file_history:
    enabled: true
    zstd_level: 19
    anchor_interval: 4
    keep_chains: 5
    file_size_cap: 1048576
    per_file_disk_budget: 5242880
    per_server_disk_budget: 209715200
    maintenance_interval: 3600
  file_collaboration:
    enabled: true
    file_size_cap: 1048576
    max_sessions_per_server: 16
    max_sessions_per_connection: 8
    max_editors_per_session: 32
    max_cursors_per_connection: 64
    session_grace_period: 30
  websocket:
    max_message_size: 1048576
    max_frame_size: 1048576
    read_buffer_size: 8192
    authentication_timeout: 60
    unauthenticated_connections_per_ip: 32
    max_connections_total: 0
  backups:
    write_limit: 0
    read_limit: 0
    compression_level: best_speed
    mounting:
      enabled: true
      path: .backups
    wings:
      create_threads: 4
      restore_threads: 4
      archive_format: tar_gz
    s3:
      create_threads: 4
      part_upload_timeout: 7200
      retry_limit: 10
    ddup_bak:
      create_threads: 4
      compression_format: deflate
    restic:
      repository: '{root_directory}/backups/restic'
      password_file: '{root_directory}/backups/restic_password'
      retry_lock_seconds: 60
      environment: {}
    btrfs:
      restore_threads: 4
      create_read_only: true
    zfs:
      restore_threads: 4
    pbs:
      create_threads: 4
      download_concurrency: 4
  transfers:
    download_limit: 0
docker:
  socket: /var/run/docker.sock
  server_name_in_container_name: false
  delete_container_on_stop: true
  network:
    interface: 172.18.0.1
    disable_interface_binding: false
    dns:
    - 1.1.1.1
    - 1.0.0.1
    dns_options:
    - ndots:0
    - timeout:2
    - attempts:3
    - single-request-reopen
    name: calagopus_nw
    ispn: false
    driver: bridge
    mode: calagopus_nw
    is_internal: false
    enable_icc: true
    network_mtu: 1500
    interfaces:
      v4:
        enabled: true
        subnet: 172.18.0.0/16
        gateway: 172.18.0.1
      v6:
        enabled: true
        subnet: fdba:17c8:6c94::/64
        gateway: fdba:17c8:6c94::1011
  firewall:
    backend: auto
    source_file_max_entries: 10000
    source_file_max_bytes: 1048576
  domainname: ''
  registries: {}
  registry_image_fetch_cache:
    enabled: true
    duration: 300
    background_refresh: false
  tmpfs_size: 100
  shm_size: 0
  container_pid_limit: 5120
  container_apply_seccomp: true
  container_apparmor_profile: ''
  container_ulimits: []
  container_sysctls: {}
  numa_memory_binding: true
  cpu_period: 100000
  cfs_burst:
    enabled: true
    multiple: 1.0
  startup_boost:
    enabled: false
    timeout: 120
    max_concurrent: 3
  runtime_boost:
    enabled: false
    threshold: 90
    sustained: 10
    multiple: 2.0
    duration: 60
    cooldown: 300
    max_concurrent: 3
  installer_limits:
    timeout: 1800
    memory: 1024
    cpu: 100
  overhead:
    override: false
    default_multiplier: 1.05
    multipliers: {}
  userns_mode: ''
  log_config:
    type: local
    config:
      compress: 'false'
      max-file: '1'
      max-size: 5m
      mode: non-blocking
throttles:
  enabled: true
  lines: 2000
  line_reset_interval: 100
tundra:
  enabled: false
  data_directory: '{root_directory}/tundra'
  binary: ''
  image: debian:trixie-slim
  source_image: ghcr.io/calagopus/tundra:1.0.0
  metrics_port: 7101
remote: https://panel.example.com
remote_headers: {}
remote_query:
  timeout: 30
  boot_servers_per_page: 50
  retry_limit: 10
allowed_mounts: []
allowed_origins: []
allow_cors_private_network: false
ignore_panel_config_updates: false
ignore_panel_wings_upgrades: false
```

=== Windows

```yaml
debug: false
app_name: Calagopus
uuid: UUID_HERE
token_id: TOKEN_ID_HERE
token: TOKEN_HERE
api:
  host: 0.0.0.0
  port: 8080
  ssl:
    enabled: false
    ktls_enabled: false
    cert: ''
    key: ''
  redirects: {}
  disable_openapi_docs: false
  disable_remote_download: false
  server_remote_download_limit: 3
  remote_download_blocked_cidrs:
  - 0.0.0.0/8
  - 127.0.0.0/8
  - 10.0.0.0/8
  - 100.64.0.0/10
  - 172.16.0.0/12
  - 192.168.0.0/16
  - 169.254.0.0/16
  - 192.0.0.0/24
  - 198.18.0.0/15
  - 224.0.0.0/4
  - 240.0.0.0/4
  - '::'
  - ::1
  - fe80::/10
  - fc00::/7
  - 2002::/16
  - ff00::/8
  disable_directory_size: false
  directory_entry_limit: 10000
  send_offline_server_logs: false
  file_search_threads: 4
  file_copy_threads: 4
  file_decompression_threads: 2
  file_compression_threads: 2
  upload_limit: 100
  max_jwt_uses: 5
  trusted_proxies: []
  schedule:
    steps:
      http_request:
        enabled: true
        requests: 5
        window_seconds: 60
        max_response_size: 16384
        blocked_cidrs:
        - 0.0.0.0/8
        - 127.0.0.0/8
        - 10.0.0.0/8
        - 100.64.0.0/10
        - 172.16.0.0/12
        - 192.168.0.0/16
        - 169.254.0.0/16
        - 192.0.0.0/24
        - 198.18.0.0/15
        - 224.0.0.0/4
        - 240.0.0.0/4
        - '::'
        - ::1
        - fe80::/10
        - fc00::/7
        - 2002::/16
        - ff00::/8
system:
  root_directory: C:\ProgramData\Calagopus-Wings
  log_directory: '{root_directory}\logs'
  data: '{root_directory}\volumes'
  diffs_directory: '{root_directory}\diffs'
  vmount_directory: '{root_directory}\vmounts'
  archive_directory: '{root_directory}\archives'
  backup_directory: '{root_directory}\backups'
  tmp_directory: '{root_directory}\tmp'
  username: calagopus
  timezone: +00:00
  user:
    rootless:
      enabled: false
      container_uid: 0
      container_gid: 0
    uid: 995
    gid: 985
  disk_check_concurrency: 2
  disk_check_interval: 150
  full_disk_check_every: 4
  disk_check_use_inotify: true
  disk_limiter_mode: none
  activity_send_interval: 60
  activity_send_count: 100
  check_permissions_on_boot: true
  check_permissions_on_boot_threads: 4
  websocket_log_count: 150
  tcp_congestion_control: bbr
  sftp:
    enabled: true
    bind_address: 0.0.0.0
    bind_port: 2022
    read_only: false
    key_algorithm: ssh-ed25519
    disable_password_auth: false
    directory_entry_limit: 20000
    directory_entry_send_amount: 500
    limits:
      authentication_password_attempts: 3
      authentication_pubkey_attempts: 20
      authentication_cooldown: 60
      max_connections_per_user: 10
      max_channels_per_connection: 10
      max_handles_per_channel: 32
      max_handles_total: 1024
    shell:
      enabled: true
      cli:
        name: .wings
    activity:
      log_logins: false
      log_file_reads: false
  crash_detection:
    enabled: true
    detect_clean_exit_as_crash: true
    timeout: 60
  file_history:
    enabled: true
    zstd_level: 19
    anchor_interval: 4
    keep_chains: 5
    file_size_cap: 1048576
    per_file_disk_budget: 5242880
    per_server_disk_budget: 209715200
    maintenance_interval: 3600
  file_collaboration:
    enabled: true
    file_size_cap: 1048576
    max_sessions_per_server: 16
    max_sessions_per_connection: 8
    max_editors_per_session: 32
    max_cursors_per_connection: 64
    session_grace_period: 30
  websocket:
    max_message_size: 1048576
    max_frame_size: 1048576
    read_buffer_size: 8192
    authentication_timeout: 60
    unauthenticated_connections_per_ip: 32
    max_connections_total: 0
  backups:
    write_limit: 0
    read_limit: 0
    compression_level: best_speed
    mounting:
      enabled: true
      path: .backups
    wings:
      create_threads: 4
      restore_threads: 4
      archive_format: tar_gz
    s3:
      create_threads: 4
      part_upload_timeout: 7200
      retry_limit: 10
    ddup_bak:
      create_threads: 4
      compression_format: deflate
    restic:
      repository: '{root_directory}\backups\restic'
      password_file: '{root_directory}\backups\restic_password'
      retry_lock_seconds: 60
      environment: {}
    btrfs:
      restore_threads: 4
      create_read_only: true
    zfs:
      restore_threads: 4
    pbs:
      create_threads: 4
      download_concurrency: 4
  transfers:
    download_limit: 0
docker:
  socket: //./pipe/docker_engine
  server_name_in_container_name: false
  delete_container_on_stop: true
  network:
    interface: 172.18.0.1
    disable_interface_binding: false
    dns:
    - 1.1.1.1
    - 1.0.0.1
    dns_options:
    - ndots:0
    - timeout:2
    - attempts:3
    - single-request-reopen
    name: calagopus_nw
    ispn: false
    driver: bridge
    mode: calagopus_nw
    is_internal: false
    enable_icc: true
    network_mtu: 1500
    interfaces:
      v4:
        enabled: true
        subnet: 172.18.0.0/16
        gateway: 172.18.0.1
      v6:
        enabled: true
        subnet: fdba:17c8:6c94::/64
        gateway: fdba:17c8:6c94::1011
  firewall:
    backend: auto
    source_file_max_entries: 10000
    source_file_max_bytes: 1048576
  domainname: ''
  registries: {}
  registry_image_fetch_cache:
    enabled: true
    duration: 300
    background_refresh: false
  tmpfs_size: 100
  shm_size: 0
  container_pid_limit: 5120
  container_apply_seccomp: true
  container_apparmor_profile: ''
  container_ulimits: []
  container_sysctls: {}
  numa_memory_binding: true
  cpu_period: 100000
  cfs_burst:
    enabled: true
    multiple: 1.0
  startup_boost:
    enabled: false
    timeout: 120
    max_concurrent: 3
  runtime_boost:
    enabled: false
    threshold: 90
    sustained: 10
    multiple: 2.0
    duration: 60
    cooldown: 300
    max_concurrent: 3
  installer_limits:
    timeout: 1800
    memory: 1024
    cpu: 100
  overhead:
    override: false
    default_multiplier: 1.05
    multipliers: {}
  userns_mode: ''
  log_config:
    type: local
    config:
      compress: 'false'
      max-file: '1'
      max-size: 5m
      mode: non-blocking
throttles:
  enabled: true
  lines: 2000
  line_reset_interval: 100
tundra:
  enabled: false
  data_directory: '{root_directory}\tundra'
  binary: ''
  image: debian:trixie-slim
  source_image: ghcr.io/calagopus/tundra:1.0.0
  metrics_port: 7101
remote: https://panel.example.com
remote_headers: {}
remote_query:
  timeout: 30
  boot_servers_per_page: 50
  retry_limit: 10
allowed_mounts: []
allowed_origins: []
allow_cors_private_network: false
ignore_panel_config_updates: false
ignore_panel_wings_upgrades: false
```

::::
