HomeDocsDaemonDaemon Overview
Daemon

Daemon Overview

Architecture and purpose of the airlinkd node-side agent.

bthavanishBy bthavanish

Daemon Overview

The AirLink daemon (airlinkd) is the node-side agent that manages game server containers. It runs on each machine that hosts servers, listens for HTTP requests from the panel, and executes container operations locally via the Docker API.

The daemon is a standalone Node.js application. It does not depend on the panel codebase and can be installed independently on any machine running Docker.

Architecture

%%{init: {"theme": "dark", "themeVariables": {"primaryColor": "#333", "primaryTextColor": "#e0e0e0", "primaryBorderColor": "#666", "lineColor": "#fff", "secondaryColor": "#444", "tertiaryColor": "#555", "fontFamily": "ui-monospace, SF Mono, Fira Code, monospace"}} }%%
flowchart LR
    A["Panel: Send HTTP request with HMAC signature"] --> B["Daemon: Verify HMAC signature"]
    B --> C["Daemon: Check IP allowlist"]
    C --> D["Daemon: Execute container operation"]
    D --> E["Daemon: Return JSON response"]

    style A fill:#1e40af,stroke:#3b82f6,color:#e0e0e0,stroke-width:2px
    style B fill:#7c2d12,stroke:#f97316,color:#e0e0e0,stroke-width:2px
    style C fill:#7c2d12,stroke:#f97316,color:#e0e0e0,stroke-width:2px
    style D fill:#7c2d12,stroke:#f97316,color:#e0e0e0,stroke-width:2px
    style E fill:#7c2d12,stroke:#f97316,color:#e0e0e0,stroke-width:2px

The daemon communicates with the panel over HTTP using HMAC-SHA256 signed requests. Each request is authenticated, rate-limited, and validated before execution.

The panel is the central hub. Daemons are the spokes. Each daemon maintains its own local state and exposes an HTTP API that the panel calls to perform container operations. There is no persistent connection between the panel and daemons; every interaction is a standalone HTTP request authenticated via HMAC-SHA256.

Core Components

ComponentRole
HTTP serverAccepts panel API requests and serves WebSocket streams
Docker runtime layerWraps the Docker Engine API for container lifecycle mgmt
File system managerReads/writes server files within volume roots
Backup engineCreates and restores zip archives of server directories
SFTP session managerSpins up isolated atmoz/sftp containers on demand
WebSocket hubStreams console output, container status, and node stats

CLI

The daemon is managed through its binary. Commands:

CommandDescription
airlinkd startStart the daemon in the foreground
airlinkd statusPrint current daemon status and connection state
airlinkd versionPrint version string
airlinkd configureInteractively set node ID, address, port, and key
airlinkd healthRun health checks (Docker, disk, memory, panel conn)
airlinkd validateValidate the current configuration file
airlinkd logsTail recent daemon logs from stdout or log file

Examples

airlinkd start
airlinkd start --port 3002
airlinkd status
airlinkd version
airlinkd health
airlinkd validate
airlinkd logs --tail 100

Configuration

All configuration lives in a single .env file at the daemon root. Values are validated at startup using Zod schemas. Invalid configuration causes the daemon to exit immediately with a descriptive error.

Environment Variables

VariableRequiredDefaultDescription
NODE_IDYesUnique node identifier (assigned by panel)
NODE_SECRETYesShared secret for HMAC authentication
PORTNo3002HTTP listen port
SFTP_PORTNo3003SFTP proxy listen port
PANEL_URLYesFull URL of the panel (e.g. https://panel.example.com)
DEBUGNofalseEnable verbose debug logging
STATS_INTERVALNo10000Node stats reporting interval in milliseconds
ALLOWED_IPSNo*Comma-separated IP allowlist for incoming requests
BACKUP_PATHNo./backupsDirectory for backup archives
SERVER_PATHNo./serversRoot directory for server volumes
LOG_PATHNo./logsDirectory for daemon log files
MAX_UPLOAD_SIZENo104857600Maximum upload size in bytes (default 100 MB)
MAX_CONNECTIONSNo200Maximum concurrent WebSocket connections

Zod Validation

On startup, the daemon validates every environment variable against its Zod schema. Required variables must be present. Type coercion is applied to numeric values. If validation fails, the daemon logs the first error and exits with code 1.

Error: Invalid configuration
  - NODE_SECRET: Required
  - PORT: Expected number, received "abc"

Directory Structure

The daemon creates and manages the following directories at runtime:

/etc/daemon/                    # Daemon installation root
  .env                          # Configuration file
  dist/                         # Compiled application
  node_modules/                 # Dependencies
  data/                         # Runtime data root
    servers/                    # Server volume mounts
      {server-uuid}/            # Per-server directory
        container/              # Container filesystem overlay
        backups/                # Per-server backup storage
    backups/                    # Global backup archive storage
    logs/                       # Daemon log files
    tmp/                        # Temporary files (builds, extractions)

Volume Layout

Each server gets a directory under data/servers/{uuid}/. The daemon mounts this into the container at the path specified by the image definition. Backups are zip archives stored in data/backups/ or per-server subdirectories.

Bootstrap Sequence

When the daemon starts, it runs through these steps in order:

  1. Parse configuration — Load .env, validate with Zod, apply defaults
  2. Check Docker — Verify Docker daemon is reachable via the socket
  3. Resolve panels — Attempt to reach the panel at PANEL_URL
  4. Register node — POST to /api/v2/nodes with the node ID and stats
  5. Start HTTP server — Bind to PORT and begin accepting requests
  6. Start WebSocket server — Attach to the same HTTP server
  7. Start stats reporter — Begin periodic stats collection and reporting
  8. Log ready state — Print version and listen address to stdout

If any step fails (Docker unreachable, panel unreachable, bind failure), the daemon logs the error and exits.

Dependencies

PackagePurpose
dockerodeDocker Engine API client for container operations
ssh2SSH server for SFTP session management
archiverZip archive creation for backups
zodConfiguration and input validation
minecraft-statusMinecraft server query protocol support
expressHTTP server framework
wsWebSocket server

Native Modules

The daemon includes native modules in a libs/ directory that are compiled separately during installation. These handle low-level operations like path resolution for the security layer and system information gathering.

cd libs
npm install
npm rebuild

Communication Protocol

The daemon exposes two interfaces to the panel:

HTTP API

All REST-style operations go through the HTTP API. Authentication uses HMAC-SHA256 signatures with timestamps, nonces, and IP allowlisting. See daemon/security.md for the full protocol specification.

Key endpoints:

MethodPathPurpose
GET/healthHealth check
GET/versionReturn daemon version
POST/servers/:uuid/startStart a container
POST/servers/:uuid/stopStop a container
POST/servers/:uuid/restartRestart a container
DELETE/servers/:uuidDestroy a container
GET/servers/:uuid/files/**Read files
POST/servers/:uuid/files/**Write/upload files
DELETE/servers/:uuid/files/**Delete files
POST/servers/:uuid/backupCreate backup
GET/statsNode resource stats

WebSocket

Real-time streams for console, container status, and node stats. Connections are authenticated with capability tokens (JWT signed by the daemon secret). See daemon/websocket.md for the full protocol specification.

EndpointPurpose
/container/:idInteractive console (stdin/stdout)
/containerstatus/:idContainer state and resource stats
/containerevents/:idContainer lifecycle events
/nodestatsHost-level resource statistics

Systemd Service

The installer creates a systemd unit for the daemon:

[Unit]
Description=AirLink Daemon
After=network.target docker.service
Requires=docker.service

[Service]
Type=simple
User=root
WorkingDirectory=/etc/daemon
ExecStart=/usr/bin/node dist/app/app.js
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

The daemon requires Docker to be running before it starts. It restarts automatically on failure with a 5-second delay.

Managing the Service

systemctl status airlink-daemon
systemctl restart airlink-daemon
journalctl -u airlink-daemon -f

Resource Stats

The daemon collects and reports host-level resource usage on a configurable interval (STATS_INTERVAL). Stats include:

  • CPU usage percentage
  • Memory usage (used vs total)
  • Disk usage (used vs total)
  • Network I/O (bytes in/out)

These are available via the /stats HTTP endpoint and the /nodestats WebSocket stream. The panel polls /stats periodically to update node health in the dashboard.

Backup System

Backups are zip archives of a server’s volume directory. The daemon creates them locally and the panel can download or restore from them.

PropertyValue
FormatZip
Storage locationdata/backups/ or per-server
Max concurrent1 per server
Progress trackingVia polling endpoint

The panel can also trigger backups from scheduled jobs. Backups are created in a temporary directory, compressed, and moved to the final location atomically.

SFTP

SFTP access is on-demand. When a user connects, the daemon spins up an isolated atmoz/sftp container with a short-lived port and temporary credentials. The container is destroyed when the session ends.

This means no permanent SFTP server is running and no extra ports are left open between sessions.