initial deployment v1.0

This commit is contained in:
RaineAllDay
2026-03-18 03:06:27 -06:00
commit eaaadd39e4
69 changed files with 10755 additions and 0 deletions

372
DEPLOY.md Normal file
View File

@@ -0,0 +1,372 @@
# Deployment Guide — ETC PRS Viewer & Editor
This guide covers deploying the app to a **Digital Ocean Droplet** running Ubuntu 24.04.
---
## Prerequisites
- A Digital Ocean Droplet (1 GB RAM minimum, 2 GB recommended)
- A domain name pointed at your droplet's IP
- SSH access to the droplet
---
## 1. Initial Server Setup
```bash
# Update packages
sudo apt update && sudo apt upgrade -y
# Install Node.js 20 (LTS)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verify
node --version # should be v20.x
npm --version
# Install build tools (needed for better-sqlite3)
sudo apt install -y build-essential python3
# Install PM2 globally
sudo npm install -g pm2
# Install Nginx
sudo apt install -y nginx
# Install Certbot for SSL
sudo apt install -y certbot python3-certbot-nginx
```
---
## 2. Create the App User and Directories
```bash
# Create a dedicated user for the app (no login shell)
sudo useradd --system --shell /bin/false --home /opt/etc-prs prs
# Create app directory
sudo mkdir -p /opt/etc-prs/app
sudo chown -R prs:prs /opt/etc-prs
# Create data directory for SQLite (outside the app, survives redeployment)
sudo mkdir -p /var/lib/etc-prs
sudo chown -R prs:prs /var/lib/etc-prs
# Create log directory
sudo mkdir -p /var/log/etc-prs
sudo chown -R prs:prs /var/log/etc-prs
```
---
## 3. Deploy the Application
```bash
# Clone or copy your project to the server
# Option A: Git
cd /opt/etc-prs
sudo -u prs git clone https://github.com/yourusername/etc-prs-ui.git app
# Option B: Copy files via scp from your local machine
# scp -r ./etc-prs-ui user@your-droplet-ip:/tmp/
# sudo mv /tmp/etc-prs-ui /opt/etc-prs/app
# sudo chown -R prs:prs /opt/etc-prs/app
cd /opt/etc-prs/app
# Install dependencies (as the prs user)
sudo -u prs npm install
# Build the app
sudo -u prs npm run build
```
---
## 4. Environment Configuration
```bash
# Create the production .env file
sudo -u prs nano /opt/etc-prs/app/.env
```
Add the following contents:
```env
DATABASE_URL=/var/lib/etc-prs/personalities.db
RATE_LIMIT_PUBLISH=5
RATE_LIMIT_READ=100
PUBLIC_BASE_URL=https://yourdomain.com
```
Replace `yourdomain.com` with your actual domain.
---
## 5. Configure PM2
Create the PM2 ecosystem file:
```bash
sudo -u prs nano /opt/etc-prs/app/ecosystem.config.cjs
```
```javascript
module.exports = {
apps: [{
name: 'etc-prs',
script: '/opt/etc-prs/app/build/index.js',
cwd: '/opt/etc-prs/app',
user: 'prs',
env: {
NODE_ENV: 'production',
PORT: '3000',
HOST: '127.0.0.1',
},
error_file: '/var/log/etc-prs/error.log',
out_file: '/var/log/etc-prs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
restart_delay: 3000,
max_restarts: 10,
}]
};
```
Start the app with PM2:
```bash
# Start
sudo -u prs pm2 start /opt/etc-prs/app/ecosystem.config.cjs
# Save the process list so PM2 restores it on reboot
sudo -u prs pm2 save
# Set PM2 to start on system boot
sudo pm2 startup systemd -u prs --hp /opt/etc-prs
# Run the command PM2 outputs
```
Verify the app is running:
```bash
sudo -u prs pm2 status
# Should show etc-prs as "online"
# Check logs
sudo -u prs pm2 logs etc-prs --lines 50
```
---
## 6. Configure Nginx
```bash
sudo nano /etc/nginx/sites-available/etc-prs
```
```nginx
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# Security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# Proxy to SvelteKit
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;
# Increase timeout for large uploads
proxy_read_timeout 30s;
client_max_body_size 2M;
}
}
```
Enable and test:
```bash
sudo ln -s /etc/nginx/sites-available/etc-prs /etc/nginx/sites-enabled/
sudo nginx -t # should say "syntax is ok"
sudo systemctl reload nginx
```
---
## 7. SSL with Let's Encrypt
```bash
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
```
Follow the prompts. Certbot will automatically modify your Nginx config to add HTTPS and set up auto-renewal.
Verify auto-renewal works:
```bash
sudo certbot renew --dry-run
```
---
## 8. Database Backups
Set up a nightly cron job to back up the SQLite database:
```bash
sudo mkdir -p /var/backups/etc-prs
# Create backup script
sudo nano /opt/etc-prs/backup.sh
```
```bash
#!/bin/bash
DATE=$(date +%Y-%m-%d)
BACKUP_DIR=/var/backups/etc-prs
DB_PATH=/var/lib/etc-prs/personalities.db
# Create backup using SQLite's online backup
sqlite3 "$DB_PATH" ".backup $BACKUP_DIR/personalities-$DATE.db"
# Keep only the last 30 days of backups
find "$BACKUP_DIR" -name "personalities-*.db" -mtime +30 -delete
echo "Backup completed: personalities-$DATE.db"
```
```bash
sudo chmod +x /opt/etc-prs/backup.sh
# Add to cron (runs at 2am daily)
sudo crontab -e
```
Add this line:
```cron
0 2 * * * /opt/etc-prs/backup.sh >> /var/log/etc-prs/backup.log 2>&1
```
---
## 9. Redeployment
When you push updates:
```bash
cd /opt/etc-prs/app
# Pull latest code
sudo -u prs git pull
# Install any new dependencies
sudo -u prs npm install
# Rebuild
sudo -u prs npm run build
# Restart the app (zero-downtime reload)
sudo -u prs pm2 reload etc-prs
```
The SQLite database at `/var/lib/etc-prs/personalities.db` is **never touched** by redeployment since it lives outside the app directory.
---
## 10. Useful Commands
```bash
# View live logs
sudo -u prs pm2 logs etc-prs
# Restart app
sudo -u prs pm2 restart etc-prs
# Stop app
sudo -u prs pm2 stop etc-prs
# Check Nginx status
sudo systemctl status nginx
# View Nginx error log
sudo tail -f /var/log/nginx/error.log
# Open SQLite database directly
sqlite3 /var/lib/etc-prs/personalities.db
# Example queries
sqlite3 /var/lib/etc-prs/personalities.db "SELECT id, name, manufacturer, channel_count, created_at FROM personalities ORDER BY created_at DESC LIMIT 20;"
sqlite3 /var/lib/etc-prs/personalities.db "SELECT COUNT(*) FROM personalities;"
# Delete a personality by ID (if you need to moderate)
sqlite3 /var/lib/etc-prs/personalities.db "DELETE FROM personalities WHERE id = 'the_id_here';"
```
---
## 11. Firewall
```bash
# Allow SSH, HTTP, and HTTPS
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
```
---
## 12. Creating Admin Users
Admins are managed via a CLI script — there is no self-registration UI.
```bash
# Create your first admin (run from the app directory on the server)
cd /opt/etc-prs/app
node scripts/create-admin.js your-username your-password
# To update an existing admin's password (same command — it upserts)
node scripts/create-admin.js your-username new-password
# To add another admin
node scripts/create-admin.js another-user their-password
```
Requirements:
- Username: 232 characters
- Password: minimum 8 characters (use something strong)
The admin panel is available at `https://yourdomain.com/admin`.
---
## Local Development
```bash
# Install dependencies
npm install
# Start dev server (uses ./dev.db automatically)
npm run dev
# The app runs at http://localhost:5173
# SQLite database is created at ./dev.db on first run
```