PanelInstallation

Docker

Deploy the Struxa Panel using Docker Compose.

This guide covers a manual Docker installation. For a fully automated setup that handles Docker, nginx, SSL, and secrets generation in one command, see the automated installer section in the Introduction guide (coming soon).

Prerequisites

  • Linux VPS - Ubuntu 22.04+ or Debian 12+ recommended
  • Root access
  • A domain name pointed at your server
  • curl and openssl available

System Requirements

ResourceMinimumRecommended
CPU1 vCPU2 vCPU
RAM512 MB1 GB
Disk5 GB20 GB
OSUbuntu 22.04 / Debian 12Ubuntu 22.04 LTS

Step 1: Install Docker

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

Verify:

docker --version
docker compose version

Step 2: Create Directory

mkdir -p /opt/struxa

Step 3: Fetch Compose File

curl -fsSL https://raw.githubusercontent.com/struxadotcloud/struxa/main/docker-compose.prod.yml \
  -o /opt/struxa/docker-compose.prod.yml

Step 4: Generate Secrets

MYSQL_ROOT_PASSWORD=$(openssl rand -hex 32)
MYSQL_PASSWORD=$(openssl rand -hex 32)
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
DATABASE_ENCRYPTION_KEY=$(openssl rand -hex 32)

# RSA key pair for Wings authentication
openssl genrsa -out /tmp/priv.pem 2048
openssl rsa -in /tmp/priv.pem -pubout -out /tmp/pub.pem
JWT_PRIVATE_KEY=$(base64 -w0 < /tmp/priv.pem)
JWT_PUBLIC_KEY=$(base64 -w0 < /tmp/pub.pem)
rm /tmp/priv.pem /tmp/pub.pem

Step 5: Write .env.prod

Replace panel.example.com with your actual domain.

cat > /opt/struxa/.env.prod << EOF
GITHUB_REPOSITORY_OWNER=struxadotcloud
IMAGE_TAG=latest

MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE=struxa
MYSQL_USER=struxa
MYSQL_PASSWORD=${MYSQL_PASSWORD}
DATABASE_URL=mysql://struxa:${MYSQL_PASSWORD}@mysql:3306/struxa

BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
BETTER_AUTH_URL=https://panel.example.com
CORS_ORIGIN=https://panel.example.com
APP_URL=https://panel.example.com

JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY}
JWT_PUBLIC_KEY=${JWT_PUBLIC_KEY}
DATABASE_ENCRYPTION_KEY=${DATABASE_ENCRYPTION_KEY}
EOF
chmod 600 /opt/struxa/.env.prod

.env.prod contains all secrets for your installation. Keep it secure - never commit it to version control.

Step 6: Configure nginx

server {
    listen 443 ssl;
    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;

    location / {
        proxy_pass         http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection 'upgrade';
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400;
    }
}

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

Obtain an SSL certificate:

certbot --nginx -d panel.example.com --non-interactive --agree-tos \
  -m you@example.com --redirect

Step 7: Start Services

cd /opt/struxa
docker compose -f docker-compose.prod.yml --env-file .env.prod pull
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d

Step 8: Verify

docker compose -f docker-compose.prod.yml ps

Both the web and mysql containers should show status Up.

Docker Compose Services

ServiceImageInternal Port
webghcr.io/struxadotcloud/struxa:latest3001
mysqlmysql:8.03306 (internal only)

On this page