Under Construction: The site is currently being updated. That means its NOT FINISHED AND IS BEING BUILT!!!!!!
Docs / Administration / Deployment Guide
Administration

Deployment Guide

Production deployment with Docker, PostgreSQL, and Redis.

Deployment

System Requirements

  • Node.js 18+ (installer auto-installs latest LTS)
  • PostgreSQL 14+ (or SQLite for small setups)
  • Redis 6+
  • Docker (on each node machine)

Quick Install

The installer handles everything: Node.js, pnpm, PostgreSQL, Redis, Docker, nginx, SSL, and PM2 clustering.

bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh)

What it does automatically:

  • Detects your OS (Ubuntu/Debian/Fedora/RHEL/Arch/Alpine)
  • Installs Node.js LTS, pnpm, Docker
  • Clones the panel to /var/www/panel
  • Installs dependencies, runs migrations, builds the project
  • Sets up systemd services for panel and daemon
  • Configures nginx reverse proxy with SSL via Certbot

Non-interactive install

# Install both panel and daemon
bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh) \
  --panel-only

# Install daemon only
bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh) \
  --daemon-only \
  --panel-addr 203.0.113.10 \
  --daemon-port 3002 \
  --daemon-key YOUR_NODE_KEY

# Install with addons
bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh) \
  --panel-only \
  --addons "modrinth,parachute"

Available flags:

Flag Description
--panel-only Install panel only
--daemon-only Install daemon only
--name Panel display name
--port Panel port (default: 3000)
--panel-addr Panel address for daemon connection
--daemon-port Daemon port (default: 3002)
--daemon-key Node authentication key
--addons Comma-separated addon list

Manual Installation

Prerequisites

# Ubuntu/Debian
apt update && apt install -y curl git openssl unzip

# Install Node.js (via NodeSource)
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs

# Install pnpm
npm install -g pnpm

# Install Docker
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker

Clone and install

git clone https://github.com/airlinklabs/panel.git /var/www/panel
cd /var/www/panel
pnpm install
pnpm approve-builds --all
pnpm run setup

Start

pnpm run start

The panel starts on port 3000 by default.


Production Setup with PM2

PM2 provides process management, clustering, auto-restart, and log rotation.

Install PM2

npm install -g pm2

Start with clustering

pm2 start dist/app.js -i max --name airlink

-i max spawns one worker per CPU core.

Save process list

pm2 save

Auto-start on boot

pm2 startup

Follow the output instructions (it prints a command to run).

Monitor

pm2 monit

Logs

pm2 logs airlink

Useful PM2 commands

pm2 status            # list all processes
pm2 restart airlink   # restart the panel
pm2 stop airlink      # stop the panel
pm2 delete airlink    # remove from PM2
pm2 logs airlink --lines 100  # last 100 lines

Daemon Installation

Each node machine needs the Airlink daemon to manage containers.

Via installer script

bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh) \
  --daemon-only \
  --panel-addr http://your-panel-ip:3000 \
  --daemon-port 3002 \
  --daemon-key YOUR_NODE_KEY

Manual installation

# Download the latest release
mkdir -p /etc/daemon
cd /etc/daemon

# Get the download URL from https://github.com/airlinklabs/daemon/releases/latest
# Download and extract (example for linux-x64):
curl -fsSL -o airlinkd.zip <download-url>
unzip airlinkd.zip
chmod +x airlinkd

Configure

Create /etc/daemon/.env:

remote=http://your-panel-ip:3000
key=YOUR_NODE_KEY
port=3002
DEBUG=false
version=1.0.0
environment=production
STATS_INTERVAL=10000

The node key is found in the panel under Nodes > Create Node.

Start via systemd

cat > /etc/systemd/system/airlink-daemon.service << 'EOF'
[Unit]
Description=Airlink Daemon
After=network.target docker.service

[Service]
Type=simple
User=root
WorkingDirectory=/etc/daemon
EnvironmentFile=/etc/daemon/.env
ExecStart=/etc/daemon/airlinkd
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now airlink-daemon

Verify

systemctl status airlink-daemon

Reverse Proxy (nginx)

nginx configuration

server {
    listen 80;
    server_name panel.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name panel.example.com;

    ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
    }

    location /socket.io {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
    }

    location /api/v1/servers {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
        proxy_cache off;
        chunked_transfer_encoding off;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

SSL with Certbot

# Install Certbot
apt install -y certbot python3-certbot-nginx

# Get certificate
certbot --nginx -d panel.example.com

# Auto-renewal (usually pre-configured)
certbot renew --dry-run

Behind reverse proxy

In the panel admin settings, enable Behind Reverse Proxy. This tells the panel to trust X-Forwarded-* headers from the proxy.


Environment Variables

See configuration/environment.md for the full reference.

Key variables:

Variable Description Default
NAME Panel display name Airlink
NODE_ENV Environment development
URL Panel URL http://localhost:3000
PORT Listen port 3000
DATABASE_URL Database connection file:./dev.db
SESSION_SECRET Session encryption key (required)

Updating

Via installer

Run the installer again. It detects an existing installation and updates files while preserving your .env and database.

bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh)

Manual update

cd /var/www/panel
git pull
pnpm install
pnpm run build
pnpm run migrate:deploy
pm2 restart airlink

Or use the admin overview page to check for and apply updates.


Troubleshooting

Panel won't start

# Check logs
pm2 logs airlink --lines 50

# Check if port is in use
lsof -i :3000

# Verify .env exists and is correct
cat /var/www/panel/.env

Database connection errors

# Verify DATABASE_URL in .env
cat /var/www/panel/.env | grep DATABASE_URL

# For SQLite, ensure the file exists and is writable
ls -la /var/www/panel/storage/

# Re-run migrations
cd /var/www/panel
pnpm run migrate:deploy

Daemon unreachable from panel

# Check daemon status on the node
systemctl status airlink-daemon

# Verify the key matches what's in the panel
cat /etc/daemon/.env

# Test connectivity from panel server
curl -s http://NODE_IP:3002/api/health

# Check firewall
ufw status
# Ensure port 3002 is open on the node

Session issues

# Check Redis is running
redis-cli ping

# Verify REDIS_URL in .env if using Redis sessions
cat /var/www/panel/.env | grep REDIS

# Clear sessions
redis-cli FLUSHDB

Build failures

# Ensure Node.js 18+ is installed
node -v

# Clear and reinstall dependencies
cd /var/www/panel
rm -rf node_modules
pnpm install

# Check for TypeScript errors
pnpm run typecheck

nginx 502 Bad Gateway

# Panel is not running or wrong port
pm2 status
# or
systemctl status airlink-panel

# Verify nginx config
nginx -t

# Check nginx is proxying to the correct port
grep proxy_pass /etc/nginx/sites-enabled/*

WebSocket disconnects

Ensure the nginx config includes the /socket.io location block with WebSocket upgrade headers. Also check proxy_read_timeout is set high enough (86400 seconds recommended).


Development Mode

pnpm run dev

This runs Prisma generate + db push, Tailwind CSS watch, and Nodemon for auto-restart. Not recommended for production.