Files
wownerogue/docs/DEPLOY.md
T

425 lines
11 KiB
Markdown

# 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_KEY` for admin endpoints
- [ ] Firewall: expose only 80/443
- [ ] Protect `/admin.html` with basic auth
- [ ] Set up database backups (see [LOGS_AND_BACKUP.md](./LOGS_AND_BACKUP.md))
- [ ] Configure log rotation
- [ ] Run database migrations
---
## Create Dedicated User
Create an isolated system user for security:
```bash
# 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:
```bash
# 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:
1. Go to your repository → **Settings** → **Deploy keys**
2. Click **Add deploy key**
3. Paste the public key from the command above
4. Leave "Allow write access" unchecked (read-only is sufficient)
5. Click **Add key**
Configure SSH for GitHub:
```bash
# 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:
```bash
# 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):
```bash
# 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:
```bash
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
```bash
# 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:
```sql
-- 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):
```bash
# 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:
```bash
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)
```bash
npm run db:drop # Drop all tables
npm run db:create # Recreate schema
```
---
## systemd Service
Save to `/etc/systemd/system/wownerogue.service`:
```ini
[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:
```bash
# 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 escalation
- `ProtectSystem=strict` - mounts filesystem read-only except allowed paths
- `ProtectHome=yes` - hides /home, /root, /run/user
- `PrivateTmp=yes` - isolates /tmp
- `ReadWritePaths` - whitelists writable directories
---
## Reverse Proxy (Nginx Proxy Manager)
If using Nginx Proxy Manager:
1. **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
2. **SSL Tab**
- Request a new SSL certificate
- Enable "Force SSL"
3. **Advanced Tab** - Paste this config for WebSocket support:
```nginx
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
```bash
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`:
```ini
[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:
```bash
# 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
```bash
systemctl status wownerogue
journalctl -u wownerogue -f # Follow logs
```
### Health Endpoint
```bash
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
```bash
# 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
```bash
# 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:
```sql
SELECT * FROM migrations ORDER BY id;
```
Migrations are tracked by name to prevent duplicate execution.