Files
punimtag/docs/DEPLOYMENT.md
T
ilia 8fd0aa8c0a Humanize admin user guide and archive scratch plans
Rewrite the admin USER_GUIDE opening, strip emoji decoration from live
guides, and keep historical PHOTO_VIEWER/FIX plans under docs/archive.
2026-08-05 15:33:22 -04:00

11 KiB

Deployment

Deploy PunimTag to development or production. Homelab host and Caddy details live in the private ansible repo.

Last reviewed: January 6, 2026.

Table of contents

  1. Prerequisites
  2. Development Server Deployment
  3. Production Deployment
  4. Environment Configuration
  5. Service Management
  6. Troubleshooting

Prerequisites

Server Requirements

  • Operating System: Linux (Ubuntu 20.04+ recommended)
  • Python: 3.12 or higher
  • Node.js: 18+ and npm 9+
  • PostgreSQL: 12+ (required)
  • Redis: 6+ (required for background jobs)
  • System Memory: Minimum 4GB RAM (8GB+ recommended for large photo collections)
  • Disk Space: Sufficient space for photos and database

Development Server Information

Development Server:

  • Host:
  • User: appuser
  • Password: [Contact administrator for password]

Development Database:

  • Host: <db-host>
  • Port: 5432
  • User:
  • Password: [Contact administrator for password]

Development server deployment

Step 1: Build Applications

On your local machine or CI/CD pipeline:

# Install dependencies (if not already done)
npm run install:all

# Build all frontends
npm run build:all

# Or use the deployment script
npm run deploy:dev

This will:

  • Build admin-frontend for production
  • Build viewer-frontend for production
  • Prepare deployment package

Step 2: Transfer Files to Server

# Create deployment directory structure
ssh appuser@<backend-host> "mkdir -p /opt/punimtag/{backend,admin-frontend,viewer-frontend,data/uploads,logs}"

# Transfer backend
scp -r backend/* appuser@<backend-host>:/opt/punimtag/backend/
scp requirements.txt appuser@<backend-host>:/opt/punimtag/

# Transfer built frontends
scp -r admin-frontend/dist/* appuser@<backend-host>:/opt/punimtag/admin-frontend/
scp -r viewer-frontend/.next/* appuser@<backend-host>:/opt/punimtag/viewer-frontend/

# Transfer configuration files
scp .env.example appuser@<backend-host>:/opt/punimtag/.env

Step 3: Server Setup

SSH into the development server:

ssh appuser@<backend-host>
cd /opt/punimtag

Install System Dependencies

# Update package list
sudo apt update

# Install PostgreSQL client (if not already installed)
sudo apt install -y postgresql-client

# Install Redis (if not already installed)
sudo apt install -y redis-server
sudo systemctl start redis-server
sudo systemctl enable redis-server

# Install Python dependencies
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Configure Environment

Edit .env file:

nano .env

Set the following variables:

# Development Database
DATABASE_URL=postgresql+psycopg2://<db-user>:[PASSWORD]@<db-host>:5432/punimtag
DATABASE_URL_AUTH=postgresql+psycopg2://<db-user>:[PASSWORD]@<db-host>:5432/punimtag_auth

# JWT Secrets (change in production!)
SECRET_KEY=dev-secret-key-change-in-production
ADMIN_USERNAME=admin
ADMIN_PASSWORD=<choose-a-strong-password>

# Photo storage
PHOTO_STORAGE_DIR=/opt/punimtag/data/uploads

# Redis
REDIS_URL=redis://localhost:6379/0

# API Configuration
API_HOST=0.0.0.0
API_PORT=8000

Configure Frontend Environment

Admin Frontend: Create admin-frontend/.env:

VITE_API_URL=http://<backend-host>:8000

Viewer Frontend: Create viewer-frontend/.env:

DATABASE_URL=postgresql://<db-user>:[PASSWORD]@<db-host>:5432/punimtag
DATABASE_URL_AUTH=postgresql://<db-user>:[PASSWORD]@<db-host>:5432/punimtag_auth
NEXTAUTH_URL=http://<backend-host>:3001
NEXTAUTH_SECRET=dev-secret-key-change-in-production

Generate Prisma client:

cd viewer-frontend
npx prisma generate
cd ..

Step 4: Set Up Systemd Services

Create systemd service files for automatic startup:

Backend API Service

sudo nano /etc/systemd/system/punimtag-api.service
[Unit]
Description=PunimTag API Server
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/punimtag
Environment="PATH=/opt/punimtag/venv/bin"
Environment="PYTHONPATH=/opt/punimtag"
ExecStart=/opt/punimtag/venv/bin/uvicorn backend.app:app --host 0.0.0.0 --port 8000
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

RQ Worker Service

sudo nano /etc/systemd/system/punimtag-worker.service
[Unit]
Description=PunimTag RQ Worker
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/punimtag
Environment="PATH=/opt/punimtag/venv/bin"
Environment="PYTHONPATH=/opt/punimtag"
ExecStart=/opt/punimtag/venv/bin/python -m rq worker --url redis://localhost:6379/0
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Admin Frontend Service (using PM2 or nginx)

For production, use nginx to serve the built frontend. Alternatively, use PM2:

npm install -g pm2
cd /opt/punimtag/admin-frontend
pm2 serve dist 3000 --name punimtag-admin
pm2 save
pm2 startup

Viewer Frontend Service

cd /opt/punimtag/viewer-frontend
pm2 start npm --name punimtag-viewer -- start
pm2 save

Step 5: Start Services

# Enable and start services
sudo systemctl enable punimtag-api
sudo systemctl enable punimtag-worker
sudo systemctl start punimtag-api
sudo systemctl start punimtag-worker

# Check status
sudo systemctl status punimtag-api
sudo systemctl status punimtag-worker

Step 6: Verify Deployment

  1. Check API Health:

    curl http://<backend-host>:8000/api/v1/health
    
  2. Check API Documentation: Open browser: http://<backend-host>:8000/docs

  3. Access Admin Frontend: Open browser: http://<backend-host>:3000

  4. Access Viewer Frontend: Open browser: http://<backend-host>:3001


Production deployment

Additional Production Considerations

  1. Security:

    • Change all default passwords
    • Use strong JWT secrets
    • Enable HTTPS with SSL certificates
    • Configure firewall rules
    • Restrict database access
    • Use read-only database users where possible
  2. Performance:

    • Use nginx as reverse proxy
    • Enable gzip compression
    • Configure caching headers
    • Use CDN for static assets (optional)
    • Set up database connection pooling
    • Configure Redis persistence
  3. Monitoring:

    • Set up log aggregation
    • Configure health check endpoints
    • Set up alerting for service failures
    • Monitor database performance
    • Track API response times
  4. Backup:

    • Automated database backups
    • Photo storage backups
    • Configuration file backups
    • Disaster recovery plan

Nginx Configuration Example

# /etc/nginx/sites-available/punimtag

# Admin Frontend
server {
    listen 80;
    server_name admin.punimtag.example.com;

    root /opt/punimtag/admin-frontend/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Viewer Frontend
server {
    listen 80;
    server_name viewer.punimtag.example.com;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# API (optional, if exposing directly)
server {
    listen 80;
    server_name api.punimtag.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Environment configuration

Required Environment Variables

Backend (.env):

# Database (PostgreSQL - required)
DATABASE_URL=postgresql+psycopg2://user:password@host:5432/punimtag
DATABASE_URL_AUTH=postgresql+psycopg2://user:password@host:5432/punimtag_auth

# JWT Configuration
SECRET_KEY=your-secret-key-here
ADMIN_USERNAME=admin
ADMIN_PASSWORD=secure-password

# Photo Storage
PHOTO_STORAGE_DIR=/path/to/photos

# Redis
REDIS_URL=redis://localhost:6379/0

# API Configuration
API_HOST=0.0.0.0
API_PORT=8000

Admin Frontend (admin-frontend/.env):

VITE_API_URL=http://your-api-url:8000

Viewer Frontend (viewer-frontend/.env):

DATABASE_URL=postgresql://user:password@host:5432/punimtag
DATABASE_URL_AUTH=postgresql://user:password@host:5432/punimtag_auth
NEXTAUTH_URL=http://your-viewer-url:3001
NEXTAUTH_SECRET=your-nextauth-secret

Service management

Systemd Commands

# Start services
sudo systemctl start punimtag-api
sudo systemctl start punimtag-worker

# Stop services
sudo systemctl stop punimtag-api
sudo systemctl stop punimtag-worker

# Restart services
sudo systemctl restart punimtag-api
sudo systemctl restart punimtag-worker

# Check status
sudo systemctl status punimtag-api
sudo systemctl status punimtag-worker

# View logs
sudo journalctl -u punimtag-api -f
sudo journalctl -u punimtag-worker -f

PM2 Commands

# Start services
pm2 start punimtag-admin
pm2 start punimtag-viewer

# Stop services
pm2 stop punimtag-admin
pm2 stop punimtag-viewer

# Restart services
pm2 restart punimtag-admin
pm2 restart punimtag-viewer

# View logs
pm2 logs punimtag-admin
pm2 logs punimtag-viewer

# Monitor
pm2 monit

Troubleshooting

Common Issues

  1. Database Connection Errors:

    • Verify PostgreSQL is running
    • Check connection string in .env
    • Verify database exists and user has permissions
    • Check firewall rules
  2. Redis Connection Errors:

    • Verify Redis is running: redis-cli ping
    • Check Redis URL in .env
    • Verify Redis is accessible
  3. API Not Starting:

    • Check logs: sudo journalctl -u punimtag-api -n 50
    • Verify Python virtual environment is activated
    • Check PYTHONPATH is set correctly
    • Verify all dependencies are installed
  4. Frontend Build Errors:

    • Clear node_modules and reinstall
    • Check Node.js version (18+)
    • Verify all environment variables are set
  5. Worker Not Processing Jobs:

    • Check worker logs: sudo journalctl -u punimtag-worker -f
    • Verify Redis connection
    • Check job queue: redis-cli
    • Restart worker service

Log Locations

  • Systemd logs: sudo journalctl -u <service-name>
  • PM2 logs: pm2 logs
  • Application logs: /opt/punimtag/logs/ (if configured)

Health Checks

# API Health
curl http://localhost:8000/api/v1/health

# Redis
redis-cli ping

# PostgreSQL
psql -h <db-host> -U <db-user> -d punimtag -c "SELECT 1;"

Deployment Checklist

  • Build all frontends
  • Transfer files to server
  • Install system dependencies
  • Set up Python virtual environment
  • Configure environment variables
  • Set up systemd services
  • Configure nginx (production)
  • Set up SSL certificates (production)
  • Configure firewall rules
  • Test all services
  • Set up monitoring
  • Configure backups
  • Document deployment process

For additional help, see:

  • README.md - Main documentation
  • docs/ARCHITECTURE.md - System architecture
  • docs/USER_GUIDE.md - User guide