PM2 Deployment Guide
This guide covers PM2-based deployment for Hyperscape, including secrets management, database mode detection, and streaming configuration.Overview
Hyperscape uses PM2 for production process management on Vast.ai and other GPU servers. The deployment system includes:- Automatic secrets loading from
/tmp/hyperscape-secrets.env - Database mode auto-detection (local vs remote)
- Xvfb virtual display for WebGPU streaming
- Chrome Beta for stable streaming capture
- Multi-platform RTMP streaming with auto-detection
Quick Start
Deploy to Vast.ai
- Pulls latest code from
origin/main - Installs system dependencies (Chrome Beta, FFmpeg, Xvfb)
- Loads secrets from
/tmp/hyperscape-secrets.env - Auto-detects database mode from
DATABASE_URL - Builds core packages
- Applies database migrations
- Starts Xvfb virtual display
- Launches duel stack via PM2
PM2 Commands
Secrets Management
Secrets File Format
PM2 loads secrets from/tmp/hyperscape-secrets.env at config load time:
Why Direct File Loading?
Problem:bunx pm2 doesn’t reliably inherit exported environment variables from the deploy shell script.
Solution: ecosystem.config.cjs reads the secrets file directly at config load time:
Creating Secrets File
GitHub Actions (.github/workflows/deploy-vast.yml):
Database Mode Auto-Detection
How It Works
The deployment system automatically detects whether to use local or remote PostgreSQL:Local Mode
Triggers:DATABASE_URLcontainslocalhost,127.0.0.1,0.0.0.0, or::1- OR
DUEL_DATABASE_MODE=localexplicitly set
- Starts local PostgreSQL via
pg_ctlcluster - Creates database and user if needed
- Sets
USE_LOCAL_POSTGRES=true
Remote Mode
Triggers:DATABASE_URLcontains any other hostname- OR
DUEL_DATABASE_MODE=remoteexplicitly set
- Uses external PostgreSQL (Neon, Railway, etc.)
- Skips local PostgreSQL setup
- Sets
USE_LOCAL_POSTGRES=false
Manual Override
PostgreSQL Connection Pool
Configuration
Why 20 Connections?
- Concurrent Agents: Up to 10 AI agents querying database simultaneously
- Bank Queries: Each agent can make 5 concurrent bank queries
- Server Queries: Game server needs connections for player data
- Headroom: Extra capacity for spikes and migrations
Tuning
If you see “timeout exceeded when trying to connect” errors:Xvfb Virtual Display
Why Xvfb?
WebGPU requires a window context, even on headless servers. Xvfb provides a virtual X11 display.Startup Order
Critical: Xvfb must start BEFORE PM2:PM2 Environment
ecosystem.config.cjs explicitly forwards DISPLAY:
Troubleshooting
Error:cannot open display
Solution:
Chrome Beta Streaming
Why Chrome Beta?
- Stability: More stable than Dev/Canary channels
- WebGPU Support: Full WebGPU support with ANGLE backend
- Compatibility: Better driver compatibility than native Vulkan
Installation
Configuration
ANGLE Backend Selection
Default (Recommended):- Automatically selects best backend for the system
- Tries Vulkan → OpenGL → D3D11 in order
- Most compatible across different GPUs
- Native Vulkan backend
- Can crash on incompatible drivers
- Not recommended for production
RTMP Streaming
Auto-Detection
Stream destinations are auto-detected from available keys:Supported Platforms
| Platform | Key Variable | URL Variable |
|---|---|---|
| Twitch | TWITCH_STREAM_KEY or TWITCH_RTMP_STREAM_KEY | TWITCH_STREAM_URL (default: rtmp://live.twitch.tv/app) |
| Kick | KICK_STREAM_KEY | KICK_RTMP_URL (default: rtmps://fa723fc1b171.global-contribute.live-video.net/app) |
| YouTube | YOUTUBE_STREAM_KEY or YOUTUBE_RTMP_STREAM_KEY | YOUTUBE_STREAM_URL (default: rtmp://a.rtmp.youtube.com/live2) |
Manual Configuration
Health Checks
Local Services
The deploy script waits for services to become healthy:PM2 Status
Port Proxying
Vast.ai requires port proxying for external access:Logs
PM2 Logs
Log Files
Troubleshooting
Server Crashes on Startup
Check logs:- Missing
DATABASE_URL→ Check/tmp/hyperscape-secrets.env - Database connection timeout → Increase
POSTGRES_POOL_MAX - WebGPU initialization failed → Check GPU driver and Xvfb
Streaming Not Starting
Check streaming state:- Missing stream keys → Check
TWITCH_STREAM_KEY,KICK_STREAM_KEY - Xvfb not running →
ps aux | grep Xvfb - Chrome Beta not installed →
google-chrome-beta --version - DISPLAY not set →
echo $DISPLAY(should be:99)
Database Connection Errors
Error:timeout exceeded when trying to connect
Solutions:
-
Increase connection pool:
-
Check database is accessible:
-
Verify connection string:
PM2 Not Forwarding Environment Variables
Problem: Environment variables set in shell are not available to PM2 processes. Solution: Use/tmp/hyperscape-secrets.env instead of shell exports:
Advanced Configuration
Custom Database Mode
Custom Streaming Configuration
Custom Xvfb Display
Monitoring
Process Health
Service Health
Auto-Restart Configuration
Deployment Checklist
- Secrets file created at
/tmp/hyperscape-secrets.env -
DATABASE_URLset (local or remote) - Stream keys set (if streaming enabled)
- Chrome Beta installed
- FFmpeg installed
- Xvfb running on
:99 - GPU display driver active (
gpu_display_active=trueon Vast.ai) - Port proxies configured (35143, 35079, 35144)
- PM2 process started
- Health checks passing
Related Files
ecosystem.config.cjs- PM2 configurationscripts/deploy-vast.sh- Deployment script.github/workflows/deploy-vast.yml- CI/CD workflowpackages/server/.env.example- Environment variable documentationdocs/duel-stack.md- Duel stack documentation