Files
picpeak/DEPLOYMENT_GUIDE.md
T
paul 6de64a1df1
Mirror to GitHub / mirror (push) Failing after 40s
Test and Lint / backend-test (push) Successful in 1m40s
Test and Lint / frontend-test (push) Successful in 2m1s
Version and Release / version-bump (push) Successful in 1m6s
Version and Release / trigger-drone (push) Successful in 3s
fix: resolve port configuration issues and database column mismatch
- Fixed database query in adminDashboard.js using non-existent 'created_at' column
  Changed to use 'scheduled_at' for email_queue table queries
- Updated frontend/.env.example to default to Docker configuration (port 3001/api)
- Clarified DEPLOYMENT_GUIDE.md with separate frontend/backend configuration sections
- Added explicit port configuration warnings to prevent future mismatches
- Added beta features section to README for download protection and deployment script

The 500 errors were caused by:
1. Frontend .env pointing to wrong port (3002 instead of 3001)
2. Database query using 'created_at' instead of 'scheduled_at' for email_queue

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-24 11:11:53 +02:00

16 KiB

🚀 PicPeak Deployment Guide

This guide covers deploying PicPeak using Docker Compose with direct port exposure. For internet-facing deployments, you'll need to add a reverse proxy (nginx, Traefik, Caddy, etc.) for SSL/HTTPS.

📋 Table of Contents

Prerequisites

  • Docker and Docker Compose installed
  • Domain name (for production)
  • SMTP server credentials for emails
  • At least 2GB RAM and 20GB storage

🚀 Quick Start

  1. Clone the repository

    git clone https://github.com/the-luap/picpeak.git
    cd picpeak
    
  2. Set up environment

    cp .env.example .env
    nano .env  # Edit with your values
    
  3. Create required directories

    mkdir -p events/active events/archived data logs backup storage
    chmod -R 755 events data logs backup storage
    
  4. Deploy

    docker compose up -d
    
  5. Check logs

    docker compose logs -f
    

🔧 Configuration

Essential Environment Variables

Generate secure values:

# JWT Secret
openssl rand -base64 64

# Database Password (avoid $ character - see warning below)
openssl rand -base64 32 | tr -d '$'

# Redis Password (avoid $ character - see warning below)
openssl rand -base64 32 | tr -d '$'

⚠️ PASSWORD WARNING: Docker Compose interprets $ as variable substitution. Either:

  • Avoid $ in passwords (recommended - use the commands above)
  • Escape $ as $$ (e.g., Pass$$word instead of Pass$word)
  • Quote the entire value: DB_PASSWORD='Pass$word' (less reliable)

Backend Configuration (.env)

Update .env with:

  • JWT_SECRET - Authentication secret (REQUIRED - generate a secure random value)
  • DB_PASSWORD - PostgreSQL password
  • REDIS_PASSWORD - Redis password
  • SMTP_* - Email configuration
  • URL Configuration (for backend CORS):
    • FRONTEND_URL - Frontend URL (e.g., http://localhost:3000 for Docker)
    • ADMIN_URL - Admin URL (e.g., http://localhost:3000 for Docker)

Frontend Configuration (frontend/.env)

Create frontend/.env from frontend/.env.example:

cp frontend/.env.example frontend/.env

Update frontend/.env with:

  • VITE_API_URL - Backend API URL
    • For Docker deployment: http://localhost:3001/api
    • For non-Docker local dev: http://localhost:3001
    • For production with reverse proxy: /api

⚠️ IMPORTANT PORT CONFIGURATION:

  • The frontend runs on port 3000 in Docker (exposed via nginx)
  • The backend API runs on port 3001
  • The frontend .env file MUST point to the correct backend port (3001)
  • Default .env.example is configured for Docker deployment

Email Configuration Examples

Gmail

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-specific-password

SendGrid

SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key

📦 Deployment

Build and Start Services

# Build images
docker compose build

# Start all services
docker compose up -d

# View running containers
docker compose ps

Access Points

By default, services are exposed on:

Initial Admin Setup

When deploying for the first time, an admin account is automatically created with a secure, randomly generated password. This password is displayed in the Docker logs during initialization and must be changed on first login.

Finding the Auto-Generated Admin Password

The admin password is automatically generated during the first startup and displayed in the backend container logs. Here's how to find it:

Option 1: Search Docker logs for admin password (recommended)

# Find the auto-generated admin password in logs
docker compose logs backend | grep "Admin password"

You should see output like:

✅ Admin password generated: BraveTiger6231!

Option 2: View the complete initialization logs

# View the complete admin setup logs
docker compose logs backend | grep -A 10 "Admin user created"

Option 3: Check the saved credentials file

# The password is also saved in the backend container
docker exec picpeak-backend cat data/ADMIN_CREDENTIALS.txt

Option 4: Use the helper script

# Show current admin username and email (password is hidden)
docker exec picpeak-backend node scripts/show-admin-credentials.js

# Reset the admin password to a new random password
docker exec picpeak-backend node scripts/show-admin-credentials.js --reset

Important Security Notes

  • Login requires the email address, not username
  • The admin password is only displayed once during initial setup
  • Password change is MANDATORY on first login - the system will force you to change it
  • If you lose the password before first login, use the --reset option to generate a new one
  • New password requirements: minimum 12 characters, mixed case, numbers, and special characters

🔐 First Login

After deployment, you must complete the first login process which includes mandatory password change for security.

Step 1: Locate Your Admin Password

  1. Find the auto-generated password from the credentials file:

    # Docker deployment
    docker compose exec backend cat /app/data/ADMIN_CREDENTIALS.txt
    
    # Or directly from the host (if you have access)
    cat data/ADMIN_CREDENTIALS.txt
    
  2. Note the admin email (default: admin@example.com unless customized)

Step 2: Access Admin Panel

  1. Navigate to your admin panel URL (e.g., http://your-domain.com:3001/admin or https://your-domain.com/admin)
  2. Login using:
    • Email: admin@example.com (or your custom admin email)
    • Password: The auto-generated password from the logs

Step 3: Mandatory Password Change

Upon first login, the system will automatically redirect you to change your password:

  1. You cannot skip this step - it's enforced for security
  2. Enter the current auto-generated password
  3. Create a new secure password meeting these requirements:
    • Minimum 12 characters
    • At least one uppercase letter
    • At least one lowercase letter
    • At least one number
    • At least one special character (!@#$%^&*)

Security Best Practices for New Password

  • Use a unique password not used elsewhere
  • Consider a password manager for generation and storage
  • Include mixed characters: MySecureP@ssw0rd2024!
  • Avoid personal information (names, dates, etc.)
  • Save securely - you cannot recover this password easily

If You Lose Access

If you lose your admin credentials after the first login, you'll need to manually reset the password in the database or create a new admin user through the database.

Note: The credentials file (ADMIN_CREDENTIALS.txt) is only created during initial deployment and contains the first admin password. After changing the password, this file becomes outdated but is kept for reference.

Configuring Admin Email

By default, the admin email is admin@example.com. To use a different email address, set it in your .env file before first deployment:

# .env
ADMIN_EMAIL=your-email@yourdomain.com

Note: This only works on first deployment. To change the admin email after deployment, you'll need to update it in the database or create a new admin user through the admin panel.

🔒 Reverse Proxy Setup

For production deployments, you should use a reverse proxy for SSL/HTTPS. The application exposes ports directly, allowing you to use any reverse proxy solution.

Option 1: Nginx

Install nginx and create /etc/nginx/sites-available/picpeak:

server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # Frontend
    location / {
        proxy_pass http://localhost:3000;
        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;
    }

    # Backend API
    location /api {
        proxy_pass http://localhost:3001;
        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;
    }

    # Protected photos and uploads
    location ~ ^/(photos|thumbnails|uploads) {
        proxy_pass http://localhost:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Admin routes
    location /admin {
        proxy_pass http://localhost:3001;
        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;
    }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/picpeak /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Option 2: Traefik

Add labels to docker-compose.override.yml:

version: '3.8'

services:
  frontend:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.picpeak.rule=Host(`your-domain.com`)"
      - "traefik.http.routers.picpeak.entrypoints=websecure"
      - "traefik.http.routers.picpeak.tls.certresolver=letsencrypt"
      - "traefik.http.services.picpeak.loadbalancer.server.port=80"

  backend:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.picpeak-api.rule=Host(`your-domain.com`) && PathPrefix(`/api`)"
      - "traefik.http.routers.picpeak-api.entrypoints=websecure"
      - "traefik.http.routers.picpeak-api.tls.certresolver=letsencrypt"
      - "traefik.http.services.picpeak-api.loadbalancer.server.port=3001"

Option 3: Caddy

Create a Caddyfile:

your-domain.com {
    # Frontend
    handle /* {
        reverse_proxy localhost:3000
    }

    # Backend API and admin
    handle /api/* {
        reverse_proxy localhost:3001
    }
    
    handle /admin/* {
        reverse_proxy localhost:3001
    }

    # Protected resources
    handle /photos/* {
        reverse_proxy localhost:3001
    }

    handle /thumbnails/* {
        reverse_proxy localhost:3001
    }

    handle /uploads/* {
        reverse_proxy localhost:3001
    }
}

SSL Certificates

For any reverse proxy, you can use Let's Encrypt:

# With Certbot
sudo certbot certonly --webroot -w /var/www/certbot -d your-domain.com

# Or use your reverse proxy's built-in ACME support

🔧 Maintenance

Viewing Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f backend
docker compose logs -f frontend

Backup

Manual Backup

# Database backup
docker exec picpeak-postgres pg_dump -U picpeak picpeak_prod > backup/db_$(date +%Y%m%d_%H%M%S).sql

# Files backup
tar -czf backup/photos_$(date +%Y%m%d_%H%M%S).tar.gz events/

Automated Backup

The application includes a built-in backup service. Configure it in the admin panel:

  1. Login to admin panel
  2. Go to Settings → Backup
  3. Configure destination and schedule
  4. Enable backup service

Updates

# Pull latest changes
git pull

# Rebuild and restart
docker compose down
docker compose build
docker compose up -d

Database Migrations

Migrations run automatically on startup, but you can run them manually:

docker exec picpeak-backend npm run migrate

🚨 Troubleshooting

Common Issues

502 Bad Gateway / Login Failures

This is the most common deployment issue! Usually caused by misconfigured URLs or network problems:

  1. CORS Configuration Errors:

    # WRONG - Missing port will cause CORS errors
    FRONTEND_URL=http://10.0.252.12
    
    # CORRECT - Include the port you're accessing from
    FRONTEND_URL=http://10.0.252.12:3000
    

    The backend validates Origin headers against FRONTEND_URL for CORS. If they don't match exactly, you'll get 500 errors on login.

  2. After Container Restarts:

    • Nginx may have cached old container IPs
    • Solution: docker restart picpeak-frontend
    • Always wait 30-60 seconds for health checks
  3. Backend Not Starting After Migrations:

    • The logs may only show migrations completed
    • Check if server is actually running: docker exec picpeak-backend ps aux | grep node
    • Should see node server.js process
  4. Login After Fresh Install:

    • Check backend logs for auto-generated admin password: docker compose logs backend | grep "Admin password"
    • Email: admin@example.com (or your custom admin email from .env)
    • Password: Auto-generated and shown in logs (e.g., BraveTiger6231!)
    • Remember: Password MUST be changed on first login
  5. Complete Fix Sequence:

    # 1. Fix your .env file URLs
    # 2. Full restart
    docker-compose down
    docker-compose up -d
    
    # 3. Wait for healthy status
    sleep 60
    docker ps  # All should show (healthy)
    
    # 4. Test backend directly
    curl http://localhost:3001/health
    
    # 5. Test through frontend
    curl http://localhost:3000/api/public/settings
    

Port Already in Use

# Check what's using the port
sudo lsof -i :3000
sudo lsof -i :3001

# Change ports in .env
FRONTEND_PORT=3002
BACKEND_PORT=3003

Docker Compose Variable Substitution Errors

If you see warnings like:

WARN[0000] The "fgbf" variable is not set. Defaulting to a blank string.

This means your password contains $ which Docker Compose interprets as a variable. Solutions:

  1. Best: Generate passwords without $: openssl rand -base64 32 | tr -d '$'
  2. Alternative: Escape $ as $$ in your .env file
  3. Example: DB_PASSWORD=Pass@#$$fgbf instead of DB_PASSWORD=Pass@#$fgbf

Permission Errors

# Fix ownership
sudo chown -R 1000:1000 events data logs backup storage
chmod -R 755 events data logs backup storage

Database Connection Issues

# Check if database is running
docker compose ps
docker compose logs postgres

# Test connection
docker exec picpeak-postgres pg_isready

Email Not Sending

  • Verify SMTP settings in .env
  • Check email queue: docker exec picpeak-backend psql -U picpeak -d picpeak_prod -c "SELECT * FROM email_queue ORDER BY created_at DESC LIMIT 10;"
  • For Gmail, use app-specific password
  • Check logs: docker compose logs backend | grep email

Health Checks

# Backend health
curl http://localhost:3001/api/health

# Frontend health
curl http://localhost:3000

# Database health
docker exec picpeak-postgres pg_isready

Useful Commands

# Enter backend container
docker exec -it picpeak-backend sh

# Enter database
docker exec -it picpeak-postgres psql -U picpeak picpeak_prod

# Reset admin password
docker exec picpeak-backend node scripts/show-admin-credentials.js --reset

# Check disk usage
df -h
du -sh events/ storage/ backup/

# View running processes
docker compose top

Security Recommendations

  1. Use HTTPS: Always use a reverse proxy with SSL in production
  2. Firewall: Only expose necessary ports (80, 443)
  3. Secure passwords: Use strong, unique passwords for all services
  4. Regular updates: Keep Docker images and system packages updated
  5. Backup strategy: Set up automated backups and test restoration
  6. Monitor logs: Regularly check logs for suspicious activity
  7. Rate limiting: The app includes built-in rate limiting, configure as needed

Support

For issues and questions:

  • Check logs first: docker compose logs
  • Review documentation in the repository
  • Check existing issues on GitHub
  • Create a new issue with:
    • Error messages
    • Log output
    • Environment details (without secrets)
    • Steps to reproduce