Airlink, Open-source game server management that actually works -_-
See the code[!CAUTION]
⚠️ THIS SOFTWARE IS HIGHLY UNSTABLE — DO NOT USE IN PRODUCTION ⚠️
Airlink Panel is in early BETA. Expect breaking changes, data loss, security vulnerabilities, and incomplete features with every update. APIs, database schemas, configuration formats, and stored data may change without notice between releases.
This is a development preview only. We are not responsible for any data loss, security incidents, or damages resulting from use of this software. If you need a stable game server panel today, this is not it.
Open-source game server management panel
Website · Documentation · Discord · Report a Bug · Request a Feature
Airlink Panel is a web-based control panel for deploying, monitoring, and managing game servers across multiple machines. It communicates with daemons on each node to handle Docker containers, files, and SFTP.
Core features:
Documentation: airlinklabs.xyz/docs/quick-start/
npm install -g pnpm)127.0.0.1:6379)127.0.0.1:5432)[!NOTE] MariaDB/MySQL is no longer supported. The database engine was migrated to PostgreSQL.
sudo su
bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh)
The installer handles Node.js, Docker, PostgreSQL, Redis, database setup, build, and systemd service registration.
cd /var/www/
git clone https://github.com/AirlinkLabs/panel.git
cd panel
node public/scripts/setup.mjs
pnpm run start
Setup flags:
| Flag | Description |
|---|---|
--yes, -y | Non-interactive mode (accepts all defaults) |
--skip-services | Don't install or start Redis / PostgreSQL |
--skip-build | Don't run package install, tsc, or tailwindcss |
--db-host HOST | PostgreSQL host (default: 127.0.0.1) |
--db-port PORT | PostgreSQL port (default: 5432) |
--db-name NAME | Database name (default: airlink) |
--db-user USER | Database username (default: airlink) |
--redis-url URL | Redis URL (default: redis://127.0.0.1:6379) |
--url URL | Panel public URL (default: http://localhost:3000) |
--trust-proxy | Enable X-Forwarded-* headers |
--cookie-domain DOMAIN | Cookie domain for cross-subdomain sessions |
--asset-base-url URL | Base URL for static assets (CDN) |
--csp-enabled | Force Content Security Policy on |
--rate-limit MAX | Request rate limit per IP (default: 500) |
--log-level LEVEL | Log level (default: info) |
--smtp-host HOST | SMTP server host |
--smtp-port PORT | SMTP server port (default: 587) |
--smtp-user USER | SMTP username |
--smtp-pass PASS | SMTP password |
Examples:
node public/scripts/setup.mjs # Interactive
node public/scripts/setup.mjs --yes # CI / unattended
node public/scripts/setup.mjs --skip-services --db-host=db.internal --yes
cd /var/www/
git clone https://github.com/AirlinkLabs/panel.git
cd panel
cp example.env .env
# Edit .env with your values (see Configuration below)
pnpm install
npx prisma generate
npx prisma db push
pnpm run build
pnpm run start
systemctl start airlink-panel
systemctl stop airlink-panel
systemctl restart airlink-panel
journalctl -u airlink-panel -f
npm install -g pm2
pm2 start "pnpm run start" --name airlink-panel
pm2 save
pm2 startup
Copy example.env to .env and configure the values for your environment.
| Variable | Required | Default | Description |
|---|---|---|---|
URL | Yes | http://localhost:3000 | Full URL the panel is accessible from |
PORT | No | 3000 | Port to listen on |
NAME | No | Airlink | Panel display name |
NODE_ENV | No | development | Set to production for live deployments |
SESSION_SECRET | Yes | — | Random secret for session signing. Generate with openssl rand -hex 32 |
STORAGE_DIR | No | ./storage | Base directory for all panel data |
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | Yes | — | PostgreSQL connection string |
PGHOST | No | 127.0.0.1 | PostgreSQL host |
PGPORT | No | 5432 | PostgreSQL port |
PGUSER | No | airlink | PostgreSQL username |
PGPASSWORD | No | — | PostgreSQL password |
[!IMPORTANT]
DATABASE_URLmust use thepostgresql://scheme. MariaDB/MySQL is no longer supported.
| Variable | Required | Default | Description |
|---|---|---|---|
REDIS_URL | No | redis://127.0.0.1:6379 | Redis connection string |
| Variable | Required | Default | Description |
|---|---|---|---|
TRUST_PROXY | No | false | Enable X-Forwarded-* headers (required behind reverse proxies) |
COOKIE_DOMAIN | No | — | Cookie domain for cross-subdomain sessions |
ALLOWED_ORIGINS | No | — | Comma-separated list of allowed CORS origins |
CSP_ENABLED | No | false | Force Content Security Policy headers on |
| Variable | Required | Default | Description |
|---|---|---|---|
TLS_CERT_PATH | No | — | Path to TLS certificate file |
TLS_KEY_PATH | No | — | Path to TLS private key file |
When both are set, the panel starts an HTTPS server directly (with HTTP fallback). Otherwise, use a reverse proxy.
| Variable | Required | Default | Description |
|---|---|---|---|
RATE_LIMIT_MAX | No | 500 | Max requests per window per IP |
RATE_LIMIT_WINDOW_MS | No | 60000 | Rate limit window in milliseconds |
| Variable | Required | Default | Description |
|---|---|---|---|
SMTP_HOST | No | — | SMTP server hostname |
SMTP_PORT | No | 587 | SMTP server port |
SMTP_USER | No | — | SMTP username |
SMTP_PASS | No | — | SMTP password |
| Variable | Required | Default | Description |
|---|---|---|---|
LOG_LEVEL | No | info | Log level (debug, info, warn, error) |
[!IMPORTANT] Set
URLto the actual IP or hostname the panel is accessible from. Usinghttp://localhostwill block external access and cause CSP errors.
| Layer | Technology |
|---|---|
| Runtime | Node.js 22+ (cluster mode) |
| Language | TypeScript (CommonJS output) |
| Framework | Express 5 |
| Templating | EJS + Alpine.js + HTMX |
| Styling | Tailwind CSS v4 |
| ORM | Prisma 7 |
| Database | PostgreSQL |
| Cache / Sessions | Redis |
| Container runtime | Docker (via node-docker-api) |
airlink:sess:*) with a user index (airlink:usr:{id}) for admin revocationcheckNodeStatus results cached 15s per node/api/search results cached 30s per user+querypanel/
├── src/ # TypeScript source
│ ├── config/ # Configuration (mime, auth, limits, etc.)
│ ├── handlers/ # Middleware, utilities, realtime
│ ├── modules/ # Route handlers (admin, api, auth, user)
│ ├── services/ # Business logic (backup, daemon, file, i18n)
│ ├── types/ # TypeScript type definitions
│ └── utils/ # Shared utilities
├── views/ # EJS templates
│ ├── admin/ # Admin panel views
│ ├── auth/ # Login, register, 2FA
│ ├── components/ # Shared UI components
│ └── user/ # User dashboard, server management
├── public/ # Static assets
│ ├── javascript/ # Client-side JS + vendor bundles
│ ├── styles/ # CSS (Tailwind input)
│ └── scripts/ # Setup / install scripts
├── storage/ # Runtime data
│ ├── prisma/ # Schema + migrations
│ ├── lang/ # i18n translation files (10 languages)
│ └── addons/ # Addon storage
├── tests/ # Vitest unit tests + Docker test infra
│ └── docker/ # Dockerfile, entrypoint.sh, docker-compose.test.yml
├── docs/ # API spec and documentation
└── .github/workflows/ # CI pipeline (10 jobs)
| Command | Description |
|---|---|
pnpm run dev | Start with auto-restart on file changes |
pnpm run build | Production build (tsc + tailwindcss) |
pnpm run start | Start the panel (node --env-file=.env dist/app.js) |
pnpm run typecheck | Type checking |
pnpm run lint | ESLint |
pnpm run test | Run unit tests (Vitest) |
pnpm run test:watch | Run tests in watch mode |
pnpm run test:coverage | Run tests with coverage |
pnpm run test:e2e | Run Playwright e2e tests |
pnpm run test:docker | Run tests in Docker (PostgreSQL + Redis) |
pnpm run test:all | Run unit + e2e tests |
pnpm run db:generate | Generate Prisma client |
pnpm run db:push | Push schema to database |
pnpm run db:migrate | Create and apply a migration |
pnpm run db:migrate:deploy | Apply pending migrations |
pnpm run db:reset | Reset database and reapply migrations |
pnpm run db:studio | Open Prisma Studio |
pnpm run db:status | Show migration status |
pnpm run db:seed | Seed initial data |
The panel exposes a REST API with 138 HTTP routes and 4 WebSocket endpoints. See docs/specsheet.md for the full route catalog, request/response formats, authentication details, and notes on daemon communication.
Addons let you extend the panel without modifying core files. They live under storage/addons/ and can be managed from the /admin/addons page.
See storage/addons/README.md for the structure and API reference.
Unit tests use Vitest. E2e tests use Playwright.
pnpm run test # Run all unit tests
pnpm run test:e2e # Run e2e tests (requires Chromium)
pnpm run test:docker # Run full test suite in Docker
Tests mock Redis and database connections where needed. The CI pipeline runs all checks across 10 jobs: SAST, Dependency Review, Audit, Lint, Typecheck, Unit Tests, Build, and more.
pnpm install
pnpm run dev # Start with auto-restart on file changes
pnpm run typecheck # Type checking
pnpm run lint # Linting
pnpm run build # Production build
git checkout -b feature/your-featuregit commit -m 'feat: describe your change'mainPlease run pnpm run lint and pnpm run typecheck before submitting.
Contributions of all sizes are welcome. Take a look at the open issues if you're not sure where to start.
Made with contrib.rocks
MIT. See LICENSE for details.
TypeScript
72.8%
EJS
18.9%
JavaScript
4.5%
CSS
2.9%
Airlink, Open-source game server management that actually works -_-
See the code[!CAUTION]
⚠️ THIS SOFTWARE IS HIGHLY UNSTABLE — DO NOT USE IN PRODUCTION ⚠️
Airlink Panel is in early BETA. Expect breaking changes, data loss, security vulnerabilities, and incomplete features with every update. APIs, database schemas, configuration formats, and stored data may change without notice between releases.
This is a development preview only. We are not responsible for any data loss, security incidents, or damages resulting from use of this software. If you need a stable game server panel today, this is not it.
Open-source game server management panel
Website · Documentation · Discord · Report a Bug · Request a Feature
Airlink Panel is a web-based control panel for deploying, monitoring, and managing game servers across multiple machines. It communicates with daemons on each node to handle Docker containers, files, and SFTP.
Core features:
Documentation: airlinklabs.xyz/docs/quick-start/
npm install -g pnpm)127.0.0.1:6379)127.0.0.1:5432)[!NOTE] MariaDB/MySQL is no longer supported. The database engine was migrated to PostgreSQL.
sudo su
bash <(curl -s https://raw.githubusercontent.com/airlinklabs/panel/refs/heads/main/installer.sh)
The installer handles Node.js, Docker, PostgreSQL, Redis, database setup, build, and systemd service registration.
cd /var/www/
git clone https://github.com/AirlinkLabs/panel.git
cd panel
node public/scripts/setup.mjs
pnpm run start
Setup flags:
| Flag | Description |
|---|---|
--yes, -y | Non-interactive mode (accepts all defaults) |
--skip-services | Don't install or start Redis / PostgreSQL |
--skip-build | Don't run package install, tsc, or tailwindcss |
--db-host HOST | PostgreSQL host (default: 127.0.0.1) |
--db-port PORT | PostgreSQL port (default: 5432) |
--db-name NAME | Database name (default: airlink) |
--db-user USER | Database username (default: airlink) |
--redis-url URL | Redis URL (default: redis://127.0.0.1:6379) |
--url URL | Panel public URL (default: http://localhost:3000) |
--trust-proxy | Enable X-Forwarded-* headers |
--cookie-domain DOMAIN | Cookie domain for cross-subdomain sessions |
--asset-base-url URL | Base URL for static assets (CDN) |
--csp-enabled | Force Content Security Policy on |
--rate-limit MAX | Request rate limit per IP (default: 500) |
--log-level LEVEL | Log level (default: info) |
--smtp-host HOST | SMTP server host |
--smtp-port PORT | SMTP server port (default: 587) |
--smtp-user USER | SMTP username |
--smtp-pass PASS | SMTP password |
Examples:
node public/scripts/setup.mjs # Interactive
node public/scripts/setup.mjs --yes # CI / unattended
node public/scripts/setup.mjs --skip-services --db-host=db.internal --yes
cd /var/www/
git clone https://github.com/AirlinkLabs/panel.git
cd panel
cp example.env .env
# Edit .env with your values (see Configuration below)
pnpm install
npx prisma generate
npx prisma db push
pnpm run build
pnpm run start
systemctl start airlink-panel
systemctl stop airlink-panel
systemctl restart airlink-panel
journalctl -u airlink-panel -f
npm install -g pm2
pm2 start "pnpm run start" --name airlink-panel
pm2 save
pm2 startup
Copy example.env to .env and configure the values for your environment.
| Variable | Required | Default | Description |
|---|---|---|---|
URL | Yes | http://localhost:3000 | Full URL the panel is accessible from |
PORT | No | 3000 | Port to listen on |
NAME | No | Airlink | Panel display name |
NODE_ENV | No | development | Set to production for live deployments |
SESSION_SECRET | Yes | — | Random secret for session signing. Generate with openssl rand -hex 32 |
STORAGE_DIR | No | ./storage | Base directory for all panel data |
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | Yes | — | PostgreSQL connection string |
PGHOST | No | 127.0.0.1 | PostgreSQL host |
PGPORT | No | 5432 | PostgreSQL port |
PGUSER | No | airlink | PostgreSQL username |
PGPASSWORD | No | — | PostgreSQL password |
[!IMPORTANT]
DATABASE_URLmust use thepostgresql://scheme. MariaDB/MySQL is no longer supported.
| Variable | Required | Default | Description |
|---|---|---|---|
REDIS_URL | No | redis://127.0.0.1:6379 | Redis connection string |
| Variable | Required | Default | Description |
|---|---|---|---|
TRUST_PROXY | No | false | Enable X-Forwarded-* headers (required behind reverse proxies) |
COOKIE_DOMAIN | No | — | Cookie domain for cross-subdomain sessions |
ALLOWED_ORIGINS | No | — | Comma-separated list of allowed CORS origins |
CSP_ENABLED | No | false | Force Content Security Policy headers on |
| Variable | Required | Default | Description |
|---|---|---|---|
TLS_CERT_PATH | No | — | Path to TLS certificate file |
TLS_KEY_PATH | No | — | Path to TLS private key file |
When both are set, the panel starts an HTTPS server directly (with HTTP fallback). Otherwise, use a reverse proxy.
| Variable | Required | Default | Description |
|---|---|---|---|
RATE_LIMIT_MAX | No | 500 | Max requests per window per IP |
RATE_LIMIT_WINDOW_MS | No | 60000 | Rate limit window in milliseconds |
| Variable | Required | Default | Description |
|---|---|---|---|
SMTP_HOST | No | — | SMTP server hostname |
SMTP_PORT | No | 587 | SMTP server port |
SMTP_USER | No | — | SMTP username |
SMTP_PASS | No | — | SMTP password |
| Variable | Required | Default | Description |
|---|---|---|---|
LOG_LEVEL | No | info | Log level (debug, info, warn, error) |
[!IMPORTANT] Set
URLto the actual IP or hostname the panel is accessible from. Usinghttp://localhostwill block external access and cause CSP errors.
| Layer | Technology |
|---|---|
| Runtime | Node.js 22+ (cluster mode) |
| Language | TypeScript (CommonJS output) |
| Framework | Express 5 |
| Templating | EJS + Alpine.js + HTMX |
| Styling | Tailwind CSS v4 |
| ORM | Prisma 7 |
| Database | PostgreSQL |
| Cache / Sessions | Redis |
| Container runtime | Docker (via node-docker-api) |
airlink:sess:*) with a user index (airlink:usr:{id}) for admin revocationcheckNodeStatus results cached 15s per node/api/search results cached 30s per user+querypanel/
├── src/ # TypeScript source
│ ├── config/ # Configuration (mime, auth, limits, etc.)
│ ├── handlers/ # Middleware, utilities, realtime
│ ├── modules/ # Route handlers (admin, api, auth, user)
│ ├── services/ # Business logic (backup, daemon, file, i18n)
│ ├── types/ # TypeScript type definitions
│ └── utils/ # Shared utilities
├── views/ # EJS templates
│ ├── admin/ # Admin panel views
│ ├── auth/ # Login, register, 2FA
│ ├── components/ # Shared UI components
│ └── user/ # User dashboard, server management
├── public/ # Static assets
│ ├── javascript/ # Client-side JS + vendor bundles
│ ├── styles/ # CSS (Tailwind input)
│ └── scripts/ # Setup / install scripts
├── storage/ # Runtime data
│ ├── prisma/ # Schema + migrations
│ ├── lang/ # i18n translation files (10 languages)
│ └── addons/ # Addon storage
├── tests/ # Vitest unit tests + Docker test infra
│ └── docker/ # Dockerfile, entrypoint.sh, docker-compose.test.yml
├── docs/ # API spec and documentation
└── .github/workflows/ # CI pipeline (10 jobs)
| Command | Description |
|---|---|
pnpm run dev | Start with auto-restart on file changes |
pnpm run build | Production build (tsc + tailwindcss) |
pnpm run start | Start the panel (node --env-file=.env dist/app.js) |
pnpm run typecheck | Type checking |
pnpm run lint | ESLint |
pnpm run test | Run unit tests (Vitest) |
pnpm run test:watch | Run tests in watch mode |
pnpm run test:coverage | Run tests with coverage |
pnpm run test:e2e | Run Playwright e2e tests |
pnpm run test:docker | Run tests in Docker (PostgreSQL + Redis) |
pnpm run test:all | Run unit + e2e tests |
pnpm run db:generate | Generate Prisma client |
pnpm run db:push | Push schema to database |
pnpm run db:migrate | Create and apply a migration |
pnpm run db:migrate:deploy | Apply pending migrations |
pnpm run db:reset | Reset database and reapply migrations |
pnpm run db:studio | Open Prisma Studio |
pnpm run db:status | Show migration status |
pnpm run db:seed | Seed initial data |
The panel exposes a REST API with 138 HTTP routes and 4 WebSocket endpoints. See docs/specsheet.md for the full route catalog, request/response formats, authentication details, and notes on daemon communication.
Addons let you extend the panel without modifying core files. They live under storage/addons/ and can be managed from the /admin/addons page.
See storage/addons/README.md for the structure and API reference.
Unit tests use Vitest. E2e tests use Playwright.
pnpm run test # Run all unit tests
pnpm run test:e2e # Run e2e tests (requires Chromium)
pnpm run test:docker # Run full test suite in Docker
Tests mock Redis and database connections where needed. The CI pipeline runs all checks across 10 jobs: SAST, Dependency Review, Audit, Lint, Typecheck, Unit Tests, Build, and more.
pnpm install
pnpm run dev # Start with auto-restart on file changes
pnpm run typecheck # Type checking
pnpm run lint # Linting
pnpm run build # Production build
git checkout -b feature/your-featuregit commit -m 'feat: describe your change'mainPlease run pnpm run lint and pnpm run typecheck before submitting.
Contributions of all sizes are welcome. Take a look at the open issues if you're not sure where to start.
Made with contrib.rocks
MIT. See LICENSE for details.
TypeScript
72.8%
EJS
18.9%
JavaScript
4.5%
CSS
2.9%