11 KiB
Production Deployment Guide
This guide covers deploying Wownerogue to a production environment.
Prerequisites
- Node.js 22.x LTS or later
- PostgreSQL 12+
- Wownero or Monero wallet-rpc running and synced
- A domain with SSL certificate (via reverse proxy)
Deployment Checklist
- Set
NODE_ENV=production - Configure TLS via reverse proxy (Nginx/Caddy)
- Set secure database credentials
- Configure wallet-rpc with authentication
- Set
ADMIN_API_KEYfor admin endpoints - Firewall: expose only 80/443
- Protect
/admin.htmlwith basic auth - Set up database backups (see LOGS_AND_BACKUP.md)
- Configure log rotation
- Run database migrations
Create Dedicated User
Create an isolated system user for security:
# Create system user with no login shell and dedicated home
sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/www/wownerogue --create-home wownerogue
# Create .ssh directory for deploy key
sudo mkdir -p /var/www/wownerogue/.ssh
sudo chmod 700 /var/www/wownerogue/.ssh
sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh
# Create log directory
sudo mkdir -p /var/log/wownerogue
sudo chown wownerogue:wownerogue /var/log/wownerogue
Setup Deploy Key and Clone Repository
Generate an SSH deploy key for the wownerogue user:
# Generate deploy key (as root, since user has no shell)
sudo ssh-keygen -t ed25519 -C "wownerogue-deploy" -f /var/www/wownerogue/.ssh/id_ed25519 -N ""
# Set correct ownership and permissions
sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh/id_ed25519*
sudo chmod 600 /var/www/wownerogue/.ssh/id_ed25519
sudo chmod 644 /var/www/wownerogue/.ssh/id_ed25519.pub
# Display the public key
sudo cat /var/www/wownerogue/.ssh/id_ed25519.pub
Add the deploy key to GitHub:
- Go to your repository → Settings → Deploy keys
- Click Add deploy key
- Paste the public key from the command above
- Leave "Allow write access" unchecked (read-only is sufficient)
- Click Add key
Configure SSH for GitHub:
# Create SSH config for the wownerogue user
sudo tee /var/www/wownerogue/.ssh/config << 'EOF'
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
StrictHostKeyChecking accept-new
EOF
sudo chown wownerogue:wownerogue /var/www/wownerogue/.ssh/config
sudo chmod 600 /var/www/wownerogue/.ssh/config
Clone the repository:
# Clone as the wownerogue user (replace YOUR_USERNAME with your GitHub username)
sudo -u wownerogue git clone git@github.com:YOUR_USERNAME/wownerogue.git /var/www/wownerogue/app
Install Node.js
Install Node.js LTS using NodeSource (run as root):
# Install Node.js 22.x LTS (or check https://nodejs.org for current LTS)
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y nodejs
# Verify installation
node --version
npm --version
Install dependencies and audit for vulnerabilities:
cd /var/www/wownerogue/app/src
sudo -u wownerogue npm install
# Check for known vulnerabilities
sudo -u wownerogue npm audit
# Auto-fix vulnerabilities where possible
sudo -u wownerogue npm audit fix
Set File Permissions
# Set ownership of application files
sudo chown -R wownerogue:wownerogue /var/www/wownerogue
# Restrict permissions (owner only, no world access)
sudo chmod 750 /var/www/wownerogue
sudo chmod 640 /var/www/wownerogue/app/src/.env
Database permissions - create a restricted PostgreSQL role:
-- Create role with minimal privileges
CREATE USER wownerogue WITH PASSWORD 'secure-password-here';
CREATE DATABASE wownerogue OWNER wownerogue;
-- Revoke dangerous permissions
REVOKE CREATE ON SCHEMA public FROM wownerogue;
-- Grant only what's needed
GRANT CONNECT ON DATABASE wownerogue TO wownerogue;
GRANT USAGE ON SCHEMA public TO wownerogue;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO wownerogue;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO wownerogue;
Filesystem isolation (optional, for extra hardening):
# Prevent the user from accessing other users' home directories
sudo chmod 700 /home/*
# Mount application directory with noexec for uploads (if applicable)
# Add to /etc/fstab if using separate partition
Database Setup
Run Migrations
Database migrations run automatically on server start (via databaseManager.runMigrations()), but you can also run them manually:
cd /var/www/wownerogue/app/src
# Source environment variables
source .env
# Run migrations manually if needed
psql -h $DB_HOST -U $DB_USER -d $DB_NAME -f migrations/001_initial_schema.sql
# ... repeat for each migration file in order
Database Reset (Development Only)
npm run db:drop # Drop all tables
npm run db:create # Recreate schema
systemd Service
Save to /etc/systemd/system/wownerogue.service:
[Unit]
Description=Wownerogue Game Server
After=network.target postgresql.service
[Service]
Type=simple
User=wownerogue
Group=wownerogue
# Adjust paths if you cloned to a different location
WorkingDirectory=/var/www/wownerogue/app/src
EnvironmentFile=/var/www/wownerogue/app/src/.env
ExecStart=/usr/bin/node index.js
Restart=on-failure
RestartSec=10
# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/www/wownerogue /var/log/wownerogue
[Install]
WantedBy=multi-user.target
Enable and start:
# Create .env from example first!
sudo -u wownerogue cp /var/www/wownerogue/app/src/.env.example /var/www/wownerogue/app/src/.env
sudo vim /var/www/wownerogue/app/src/.env # Edit with your settings
# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable wownerogue
sudo systemctl start wownerogue
sudo systemctl status wownerogue
The systemd hardening options:
NoNewPrivileges- prevents privilege escalationProtectSystem=strict- mounts filesystem read-only except allowed pathsProtectHome=yes- hides /home, /root, /run/userPrivateTmp=yes- isolates /tmpReadWritePaths- whitelists writable directories
Reverse Proxy (Nginx Proxy Manager)
If using Nginx Proxy Manager:
-
Add Proxy Host
- Domain Names:
yourdomain.com - Scheme:
http - Forward Hostname/IP: Your server's LAN IP (e.g.,
192.168.1.100) - Forward Port:
3000 - Enable "Websockets Support" toggle
- Domain Names:
-
SSL Tab
- Request a new SSL certificate
- Enable "Force SSL"
-
Advanced Tab - Paste this config for WebSocket support:
location /socket.io/ {
proxy_pass http://192.168.1.100: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_read_timeout 86400s;
proxy_send_timeout 86400s;
}
Updating the Deployment
cd /var/www/wownerogue/app
sudo -u wownerogue git pull
cd src && sudo -u wownerogue npm install
sudo -u wownerogue npm audit fix
sudo systemctl restart wownerogue
Multi-Instance Deployment
To run multiple instances (e.g., Wownero on port 3000 and Monero stagenet on port 3001):
Directory Structure
/var/www/
├── wownerogue/ # Wownero instance (port 3000)
│ └── app/src/.env
└── monerogue/ # Monero instance (port 3001)
└── app/src/.env
Configuration Differences
| Setting | Wownero Instance | Monero Instance |
|---|---|---|
PORT |
3000 | 3001 |
CRYPTO_TYPE |
WOW | XMR |
MONERO_NETWORK |
mainnet | stagenet |
DB_NAME |
wownerogue | monerogue_stagenet |
PRIMARY_WALLET_ENDPOINT |
http://127.0.0.1:34570 | http://127.0.0.1:38070 |
PRIMARY_RPC_ENDPOINT |
http://127.0.0.1:34568 | http://127.0.0.1:38081 |
Separate systemd Service
Create /etc/systemd/system/monerogue.service:
[Unit]
Description=Monerogue Game Server (Stagenet)
After=network.target postgresql.service
[Service]
Type=simple
User=monerogue
WorkingDirectory=/var/www/monerogue/app/src
EnvironmentFile=/var/www/monerogue/app/src/.env
ExecStart=/usr/bin/node index.js
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Wallet Output Management
Wownero (and Monero) lock change outputs for several blocks after spending. If the wallet has only one large output and multiple payouts fire in quick succession, the second payout will fail because the change output from the first is still locked.
Solution: Pre-split wallet outputs into many smaller ones. The game server includes a CLI tool for this:
# Preview what would happen (no transaction sent)
node scripts/splitOutputs.js --amount 10 --count 30 --dry-run
# Split into 30 outputs of 10 WOW each (requires ~300 WOW + fees)
node scripts/splitOutputs.js --amount 10 --count 30
This creates 30 independently-spendable outputs, allowing up to 30 concurrent payouts before any output locking becomes an issue.
When to re-split: As payouts go out, outputs get consumed and consolidated via change. Periodically check the wallet and re-split when the number of spendable outputs drops low. The server also batches payouts that happen within 5 seconds of each other into a single transaction to conserve outputs.
Recommended setup: After initial wallet funding, run the split script. For a game with typical traffic, 20-30 outputs of 10 WOW each provides good concurrency headroom.
Monitoring
Check Service Status
systemctl status wownerogue
journalctl -u wownerogue -f # Follow logs
Health Endpoint
curl http://localhost:3000/health
Returns server uptime, memory usage, wallet status, and balance.
Admin Dashboard
Access /admin.html with your ADMIN_API_KEY for:
- Wallet balance and connection status
- Pending/failed payouts
- Game statistics
- User search
Troubleshooting
Server Won't Start
# Check logs for errors
journalctl -u wownerogue -n 50
# Verify environment file
sudo -u wownerogue cat /var/www/wownerogue/app/src/.env
# Test database connection
psql -h localhost -U wownerogue -d wownerogue -c "SELECT 1;"
Wallet RPC Issues
# Test wallet RPC directly
curl -u user:password -X POST http://127.0.0.1:34570/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"get_balance"}' \
-H 'Content-Type: application/json'
Database Migrations
If migrations fail, check the migrations table:
SELECT * FROM migrations ORDER BY id;
Migrations are tracked by name to prevent duplicate execution.