Installation
Production
Deploy XyraPanel on a bare-metal Ubuntu VPS using the official one-line installer.
Use the one-line installer
Run this as root on a fresh Ubuntu 22.04 / 24.04 or Debian 11 / 12 VPS:
bash <(curl -fsSL https://xyrapanel.com/install)
The installer prompts for your domain, admin credentials, and database password - then handles everything automatically: dependencies, database, build, PM2, Nginx, and TLS.
Point your domain's A record to the server IP before running the installer so Let's Encrypt can issue the certificate in one pass.
Install manually
Prefer full control? Follow these steps:
Install Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs git build-essential
Install pnpm
curl -fsSL https://github.com/pnpm/pnpm/releases/latest/download/pnpm-linux-x64 -o /usr/local/bin/pnpm
chmod +x /usr/local/bin/pnpm
Install PM2
npm install -g pm2@latest
Install PostgreSQL 16
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
| gpg --dearmor -o /usr/share/keyrings/postgresql.gpg
echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
> /etc/apt/sources.list.d/pgdg.list
sudo apt update && sudo apt install -y postgresql-16
sudo systemctl enable --now postgresql
sudo -u postgres psql -c "CREATE USER xyrapanel WITH PASSWORD 'your_strong_password';"
sudo -u postgres psql -c "CREATE DATABASE xyrapanel OWNER xyrapanel;"
Install Redis
sudo apt install -y redis-server
sudo systemctl enable --now redis-server
Install Nginx and Certbot
sudo apt install -y nginx certbot python3-certbot-nginx
sudo systemctl enable nginx
Clone and configure
git clone --depth 1 https://github.com/XyraPanel/panel.git /opt/xyrapanel
cp /opt/xyrapanel/.env.example /opt/xyrapanel/.env
Edit /opt/xyrapanel/.env with your values:
.env
APP_NAME="XyraPanel"
NODE_ENV="production"
DATABASE_URL="postgresql://xyrapanel:your_strong_password@127.0.0.1:5432/xyrapanel"
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
BETTER_AUTH_URL=https://panel.yourdomain.com
BETTER_AUTH_TRUSTED_ORIGINS=https://panel.yourdomain.com
NUXT_PUBLIC_APP_URL=https://panel.yourdomain.com
XYRA_PASTE_URL=https://paste.xyrapanel.com
BETTER_AUTH_SECRET= # openssl rand -base64 32
SEED_SECRET= # openssl rand -base64 32
PANEL_PUBLIC_URL=https://panel.yourdomain.com
PANEL_INTERNAL_URL=http://127.0.0.1:3000
NUXT_SECURITY_CORS_ORIGIN=https://panel.yourdomain.com
NUXT_SECURITY_CONNECT_SRC=https://panel.yourdomain.com
NUXT_SECURITY_RATE_LIMIT_DRIVER=redis
NUXT_SECURITY_RATE_LIMIT_TOKENS=1000
NUXT_SECURITY_RATE_LIMIT_INTERVAL_MS=60000
Build the panel
cd /opt/xyrapanel
pnpm install --frozen-lockfile
pnpm run generate-pwa-assets
NODE_OPTIONS="--max-old-space-size=4096" pnpm build
Start with PM2
Create a launcher that loads .env before starting the server:
cat > /opt/xyrapanel/start.mjs << 'EOF'
import { readFileSync } from 'fs'
const lines = readFileSync('/opt/xyrapanel/.env', 'utf8').split('\n')
for (const line of lines) {
const trimmed = line.trim()
if (!trimmed || trimmed.startsWith('#')) continue
const idx = trimmed.indexOf('=')
if (idx === -1) continue
const key = trimmed.slice(0, idx).trim()
let val = trimmed.slice(idx + 1).trim()
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) val = val.slice(1, -1)
if (!(key in process.env)) process.env[key] = val
}
await import('/opt/xyrapanel/.output/server/index.mjs')
EOF
pm2 start /opt/xyrapanel/start.mjs --name xyrapanel -i max
pm2 save
env PATH="$PATH:/usr/bin:/usr/local/bin" pm2 startup systemd -u root --hp /root | grep -E '^sudo|^env ' | bash
Configure Nginx
sudo mkdir -p /var/www/certbot
/etc/nginx/sites-available/xyrapanel
server {
listen 80;
server_name panel.yourdomain.com;
location /.well-known/acme-challenge/ { root /var/www/certbot; }
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl;
server_name panel.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/panel.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/panel.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
client_max_body_size 25M;
proxy_read_timeout 300s;
location / {
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_cache_bypass $http_upgrade;
}
}
sudo ln -sf /etc/nginx/sites-available/xyrapanel /etc/nginx/sites-enabled/xyrapanel
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
Enable SSL
Follow the SSL Setup guide to issue a certificate and enable HTTPS.
- Updating - keep the panel up to date
