Server requirements
Check your VPS before installing:
free -h # RAM
df -h # Disk space
nproc # CPU cores
node -v # Node.js (need 20.9+)
npm -v| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 2 GB | 4 GB (8 GB for builds) |
| Disk | 20 GB | 40 GB+ |
| CPU | 2 cores | 2+ cores |
| Node.js | 20.9+ | 22 LTS |
| FFmpeg | Required | For video/audio features |
Works on DigitalOcean, Hetzner, Linode, Contabo, AWS EC2, and similar Ubuntu/Debian VPS providers.
Install required software
sudo apt update && sudo apt upgrade -y
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v
sudo npm install -g pm2
sudo apt install -y nginx ffmpeg certbot python3-certbot-nginx gitAdd swap space (prevent OOM kills)
Next.js production builds are memory-intensive. Add swap on 2–4 GB RAM instances:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hUpload project to VPS
Option A — Git (recommended)
sudo mkdir -p /var/www/voralis-web
sudo chown $USER:$USER /var/www/voralis-web
cd /var/www/voralis-web
git clone https://github.com/your-username/your-project.git .Option B — rsync from local machine
rsync -avz --exclude node_modules --exclude .next \
./ root@your-vps-ip:/var/www/voralis-web/Configure environment variables
cd /var/www/voralis-web
cp deploy/env.example .env.production
nano .env.production
ln -sf .env.production .env.local
openssl rand -base64 32Minimum production values:
NODE_ENV=production
NEXT_PUBLIC_APP_URL=https://yourdomain.com
NEXTAUTH_URL=https://yourdomain.com
NEXTAUTH_SECRET=generate_with_openssl_rand_base64_32
JWT_SECRET=generate_with_openssl_rand_base64_32
ENCRYPTION_KEY=generate_with_openssl_rand_base64_32
NEON_DATABASE_URL=postgresql://user:pass@host:5432/dbname?sslmode=require
DATABASE_URL=postgresql://user:pass@host:5432/dbname?sslmode=require
NEXT_PUBLIC_BRAIN_SERVER_URL=https://your-brain-server.com
GEMINI_API_KEY=your-gemini-key
# Optional — background video worker
REDIS_URL=redis://127.0.0.1:6379See deploy/env.example in the project for the full variable list.
Database setup
- Create a PostgreSQL database (Neon recommended).
- Run Prisma migrations on the VPS:
cd /var/www/voralis-web
npm run prisma:generate
npm run prisma:migrate:deployOn first visit, complete the in-app License Setup Wizard (domain → license → migrate → admin seed).
Install dependencies and build
cd /var/www/voralis-web
npm ci
npx prisma generate
pm2 stop all 2>/dev/null || true
NODE_OPTIONS="--max-old-space-size=3072" npm run build
cp -r .next/static .next/standalone/.next/static
cp -r public .next/standalone/public
cp -r lib/generated .next/standalone/lib/generated 2>/dev/null || trueOr run bash deploy/install-vps.sh which performs the same steps.
Create logs folder and start with PM2
mkdir -p /var/www/voralis-web/logs
node -e "require('./ecosystem.config.cjs')" && echo "Config OK"
cd /var/www/voralis-web
pm2 start ecosystem.config.cjs
pm2 save
pm2 startupRun the command printed by pm2 startup to enable boot on reboot. App listens on port 3000 (process name: voralis-web).
Optional — video worker (requires Redis)
sudo apt install -y redis-server
# Set REDIS_URL=redis://127.0.0.1:6379 in .env.production
pm2 restart ecosystem.config.cjsVerify the app is running
pm2 list
pm2 logs voralis-web --lines 30
curl http://127.0.0.1:3000/api/healthConfigure Nginx and SSL
Point DNS A records to your VPS IP, then:
sudo nano /etc/nginx/sites-available/voralisHTTPS example (after Certbot or manual cert paths):
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
access_log /var/log/nginx/voralis.access.log;
error_log /var/log/nginx/voralis.error.log;
client_max_body_size 50M;
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;
proxy_read_timeout 300s;
}
}sudo ln -s /etc/nginx/sites-available/voralis /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.comSSL auto-renewal
sudo certbot renew --dry-run
sudo systemctl status certbot.timerDeployment workflow (future updates)
cd /var/www/voralis-web
git pull origin main
npm ci
pm2 stop voralis-web
NODE_OPTIONS="--max-old-space-size=3072" npm run build
cp -r .next/static .next/standalone/.next/static
cp -r public .next/standalone/public
cp -r lib/generated .next/standalone/lib/generated 2>/dev/null || true
pm2 restart voralis-web
pm2 logs voralis-web --lines 20Useful PM2 commands
pm2 list
pm2 logs voralis-web
pm2 logs voralis-web --lines 50
pm2 restart voralis-web
pm2 stop voralis-web
pm2 delete voralis-web
pm2 monit
pm2 reload voralis-webQuick troubleshooting
| Problem | Fix |
|---|---|
| Build SIGKILL / OOM | Add swap, pm2 stop all, NODE_OPTIONS=--max-old-space-size=3072 |
| App not on port 3000 | pm2 list; restart with ecosystem.config.cjs |
| Nginx 502 | Check pm2 logs voralis-web |
| SSL cert fails | Verify DNS A records point to VPS IP |
| .env not loading | Confirm .env.production exists and is linked to .env.local |
| Permission denied | sudo chown -R $USER:$USER /var/www/voralis-web |
| License wizard stuck | Verify NEXT_PUBLIC_BRAIN_SERVER_URL and database URL |