# Architecture

> How FeatherPanel is built - FrankenPHP backend, Next.js frontend, Rust async runner, MCP server, MariaDB, Redis, FeatherWings and FeatherQuilld nodes.

Source: https://featherpanel.com/docs/getting-started/architecture/

FeatherPanel is split into a **panel** that you install once and **daemons** that you install on every machine that runs
workloads. The panel never runs game servers or websites itself: it stores state, checks permissions and tells the daemons
what to do.

## The big picture

```text
                      Browser / API client / MCP client
                                   │ HTTPS
                     your reverse proxy (nginx, Apache, Caddy, Cloudflare Tunnel)
                                   │ http://127.0.0.1:4831
┌──────────────────────────── panel host (Docker) ─────────────────────────────┐
│ frontendv2  (Caddy + Next.js)  ── /api, /pma, /webmail, /addons ──► backend   │
│        │   └─ /mcp, OAuth ──► mcp (Node.js)                         │         │
│        └─ /vnc-proxy ──► async-runner (Rust) ◄── Redis pub/sub ─────┤         │
│                                                    MariaDB ◄────────┤ Redis   │
└──────────────────────────────────────────────────────────────────────┼────────┘
           ┌───────────────────────────────┬─────────────────────────┘
           ▼ HTTPS + node token            ▼ HTTPS + node token          ▼ Proxmox API
   FeatherWings (game nodes)      FeatherQuilld (web nodes)       Proxmox VE (VDS nodes)
   Docker, SFTP :2022, API :8080  WebSpaces, proxy, DNS, mail,     VMs and LXC containers
                                  SFTP :2222, FTP :21, API :8989
```

## Panel services

The Docker install (`docker-compose.yml`) runs these containers:

| Service | Image | What it does |
|---------|-------|--------------|
| `frontendv2` | `ghcr.io/mythicalltd/featherpanel-frontendv2` | The only published container (host port `4831` by default). A Caddy server in front of the Next.js app that also routes API, MCP and VNC traffic to the other services. |
| `backend` | `ghcr.io/mythicalltd/featherpanel-backend` | The PHP API on FrankenPHP (Caddy with PHP built in), plus cron and the bundled phpMyAdmin and webmail. |
| `async-runner` | `ghcr.io/mythicalltd/featherpanel-async-runner` | A Rust worker. Sends queued mail, creates Proxmox VMs and proxies VNC consoles. |
| `mcp` | `ghcr.io/mythicalltd/featherpanel-mcp` | The [Model Context Protocol server](https://featherpanel.com/docs/panel/mcp-server) for AI assistants. |
| `mysql` | `mariadb:latest` | The panel database. |
| `redis` | `redis:latest` | Cache, rate limit and account lockout counters, two-factor challenges, the player status cache and the pub/sub queue for the async runner. |

### How requests are routed

The Caddy server inside `frontendv2` decides where each request goes:

| Path | Goes to |
|------|---------|
| `/api*`, `/pma*`, `/webmail*`, `/attachments*`, `/addons*`, `/components*` | `backend` |
| `/mcp*`, `/authorize`, `/token`, `/register`, `/revoke`, `/oauth*`, OAuth `/.well-known/*` documents | `mcp` |
| `/vnc-proxy*` | `async-runner` on port 9100 |
| everything else | Next.js |

Requests may be up to 250 MB. Event streams (`/api/mercure` and the chatbot streams) are not compressed so they reach the
browser immediately.

### Inside the backend

The backend runs PHP on [FrankenPHP](https://frankenphp.dev/). By default it uses **worker mode**: the app boots once and
stays in memory, which removes the per-request bootstrap cost. There are two worker pools:

- `featherpanel-api` serves `/api/*`. It starts `2 x CPU` threads and can grow to `3 x CPU` (at most 32) under load.
- `featherpanel-slow` serves long responses (chatbot streams, file and backup downloads) so a few of them cannot block the
  rest of the API.

Set `FRANKENPHP_WORKER=false` to fall back to classic mode. See [Cron, workers and runner](https://featherpanel.com/docs/panel/cron-and-workers) for
every knob.

The backend also hosts the [Mercure](https://featherpanel.com/docs/panel/realtime) hub that pushes live updates to the browser, and runs the cron
jobs every minute.

### The async runner

The runner listens on three Redis channels:

- `featherpanel:mail:pending` sends queued e-mail over SMTP, so a slow mail server never slows down a request.
- `featherpanel:vm:pending` creates VDS instances on Proxmox and reports progress.
- `featherpanel:settings:reload` reloads settings after an admin changes them.

It also serves the browser VNC console for VDS instances at `/vnc-proxy`.

## Daemons

### FeatherWings (game servers)

[FeatherWings](https://featherpanel.com/docs/wings) is a Go daemon, forked from Pterodactyl Wings. Each game node runs one. It creates a Docker
container per server, streams the console over a websocket, serves SFTP on port 2022 and takes backups. The panel talks to it
over HTTPS on port 8080 with the node token; Wings calls back to the panel with `token_id.token`.

A node's **daemon type** can also be `wings_rs` ([Calagopus Wings](https://github.com/calagopus/wings)). Those nodes default
to `/etc/calagopus-wings/config.yml`, `/var/lib/calagopus-wings/volumes` and the `wings` systemd unit. The panel keeps a
feature matrix per daemon type (`DaemonCapabilities`) and hides what a node cannot do:

| Only on FeatherWings nodes | Only on Calagopus Wings nodes |
|----------------------------|-------------------------------|
| modules, live config, host terminal, trash, node firewall, FastDL, diagnostics, Docker disk view, proxy, server import, file sharing, reconcile, container exec | system logs, install abort, directory download, file operation progress, backup browsing, server scripts, live websocket permissions, file fingerprints, paginated file lists, transfer backups, 7z compression |

Both support the core server API, Docker, file search, archive browsing, deauthorize, self update, file history and
file collaboration.

### FeatherQuilld (web hosting)

[FeatherQuilld](https://featherpanel.com/docs/quilld) is a .NET daemon for web nodes. It runs customer **WebSpaces** in Docker, manages a reverse
proxy (Caddy, nginx or Traefik), DNS through PowerDNS, mail through docker-mailserver or mailcow, and SFTP/FTP. Its API listens
on port 8989.

### Proxmox VE (VDS)

VDS hosting needs no FeatherPanel daemon. The panel stores a Proxmox API token per VDS node and drives Proxmox directly; the
async runner does the long-running VM creation. The installer has a **Proxmox VNC Agent** option that you run on the
Proxmox node; it adds noVNC files for PVE token forwarding so the in-panel console works.

## Data and state

| What | Where |
|------|-------|
| Users, servers, nodes, settings, activity | MariaDB (225 migrations at the time of writing) |
| Secrets in the database (node tokens, API client keys, SMTP password, OIDC secrets and more) | Encrypted with `DATABASE_ENCRYPTION_KEY` (XChaCha20) |
| Uploaded files, plugins, translations, snapshots, logs | Docker volumes `featherpanel_attachments`, `featherpanel_addons`, `featherpanel_translations`, `featherpanel_snapshots`, `featherpanel_logs` |
| `.env` and other config | Volume `featherpanel_config` (`backend/storage/config`) |
| Game server files and backups | On each Wings node (`/var/lib/featherpanel`) |
| WebSpace files and backups | On each Quilld node (`/var/lib/featherquilld`) |

## Optional parts

- **phpMyAdmin** (`/pma`) and **webmail** (`/webmail`) are served by the backend. phpMyAdmin is installed with
  `featherpanel module install pma`.
- **Telemetry**: the `UmamiTelemetryReporter` cron job sends one event per day with aggregate counts (users, servers,
  backups, nodes, schedules, webspaces, VMs and similar). The hostname is sent as the fixed string `featherpanel`. Turn it off
  with the `telemetry` setting, or force it off for the whole install with `UMAMI_ENABLED=false`.
- **Plugins** add PHP routes, event listeners, cron jobs and frontend pages. See [Plugins](https://featherpanel.com/docs/plugins).

## Frequently asked questions

### Does FeatherPanel need FeatherWings?

Only for game servers. Proxmox VDS hosting talks to the Proxmox API directly and web hosting uses FeatherQuilld. A panel with only the web or VDS module enabled needs no Wings node.

### Can FeatherPanel use Calagopus Wings instead of FeatherWings?

Yes. A node's daemon type can be set to Calagopus Wings (wings_rs). The panel keeps a feature matrix per daemon type and hides features a node does not support, such as modules, the node firewall and FastDL on Calagopus Wings nodes.
