Files
orion/docs/deployment/production.md
Samir Boulahtit 3614d448e4 chore: PostgreSQL migration compatibility and infrastructure improvements
Database & Migrations:
- Update all Alembic migrations for PostgreSQL compatibility
- Remove SQLite-specific syntax (AUTOINCREMENT, etc.)
- Add database utility helpers for PostgreSQL operations
- Fix services to use PostgreSQL-compatible queries

Documentation:
- Add comprehensive Docker deployment guide
- Add production deployment documentation
- Add infrastructure architecture documentation
- Update database setup guide for PostgreSQL-only
- Expand troubleshooting guide

Architecture & Validation:
- Add migration.yaml rules for SQL compatibility checking
- Enhance validate_architecture.py with migration validation
- Update architecture rules to validate Alembic migrations

Development:
- Fix duplicate install-all target in Makefile
- Add Celery/Redis validation to install.py script
- Add docker-compose.test.yml for CI testing
- Add squash_migrations.py utility script
- Update tests for PostgreSQL compatibility
- Improve test fixtures in conftest.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 17:52:28 +01:00

7.7 KiB

Traditional VPS Deployment

This guide covers deploying Wizamart to a traditional VPS (Ubuntu 22.04+) without containers.

Best for: Teams who want direct server access and familiar Linux administration.


Prerequisites

  • Ubuntu 22.04 LTS or newer
  • 4GB+ RAM recommended
  • Root or sudo access
  • Domain name with DNS configured

Quick Start

# 1. Install system packages
sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx postgresql-15 redis-server python3.11 python3.11-venv git curl

# 2. Create application user
sudo useradd -m -s /bin/bash wizamart

# 3. Setup PostgreSQL
sudo -u postgres createuser wizamart_user
sudo -u postgres createdb wizamart_db -O wizamart_user
sudo -u postgres psql -c "ALTER USER wizamart_user WITH PASSWORD 'your-secure-password';"

# 4. Clone and setup application
sudo su - wizamart
git clone <repository-url> ~/app
cd ~/app
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# 5. Configure environment
cp .env.example .env
nano .env  # Edit with production values

# 6. Initialize database
alembic upgrade head
python scripts/init_production.py

# 7. Exit wizamart user
exit

Systemd Services

Main Application

sudo nano /etc/systemd/system/wizamart.service
[Unit]
Description=Wizamart API Server
After=network.target postgresql.service redis.service

[Service]
User=wizamart
Group=wizamart
WorkingDirectory=/home/wizamart/app
Environment="PATH=/home/wizamart/app/.venv/bin"
EnvironmentFile=/home/wizamart/app/.env
ExecStart=/home/wizamart/app/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 4
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Celery Worker (when implemented)

sudo nano /etc/systemd/system/wizamart-celery.service
[Unit]
Description=Wizamart Celery Worker
After=network.target redis.service postgresql.service

[Service]
User=wizamart
Group=wizamart
WorkingDirectory=/home/wizamart/app
Environment="PATH=/home/wizamart/app/.venv/bin"
EnvironmentFile=/home/wizamart/app/.env
ExecStart=/home/wizamart/app/.venv/bin/celery -A app.celery worker --loglevel=info --concurrency=4
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Celery Beat (Scheduler)

sudo nano /etc/systemd/system/wizamart-celery-beat.service
[Unit]
Description=Wizamart Celery Beat Scheduler
After=network.target redis.service

[Service]
User=wizamart
Group=wizamart
WorkingDirectory=/home/wizamart/app
Environment="PATH=/home/wizamart/app/.venv/bin"
EnvironmentFile=/home/wizamart/app/.env
ExecStart=/home/wizamart/app/.venv/bin/celery -A app.celery beat --loglevel=info
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Enable Services

sudo systemctl daemon-reload
sudo systemctl enable wizamart wizamart-celery wizamart-celery-beat
sudo systemctl start wizamart wizamart-celery wizamart-celery-beat

Nginx Configuration

sudo nano /etc/nginx/sites-available/wizamart
# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

# Main HTTPS server
server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL (managed by Certbot)
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Logging
    access_log /var/log/nginx/wizamart.access.log;
    error_log /var/log/nginx/wizamart.error.log;

    # Static files (served directly)
    location /static {
        alias /home/wizamart/app/static;
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Uploaded files
    location /uploads {
        alias /home/wizamart/app/uploads;
        expires 7d;
        add_header Cache-Control "public";
    }

    # Application
    location / {
        proxy_pass http://127.0.0.1:8000;
        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;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Block sensitive files
    location ~ /\. {
        deny all;
    }
    location ~ \.env$ {
        deny all;
    }
}

Enable Site

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

SSL with Certbot

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Firewall

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Daily Operations

View Logs

# Application logs
sudo journalctl -u wizamart -f

# Celery logs
sudo journalctl -u wizamart-celery -f

# Nginx logs
sudo tail -f /var/log/nginx/wizamart.access.log
sudo tail -f /var/log/nginx/wizamart.error.log

# PostgreSQL logs
sudo tail -f /var/log/postgresql/postgresql-15-main.log

Restart Services

sudo systemctl restart wizamart
sudo systemctl restart wizamart-celery
sudo systemctl restart nginx

Database Access

# Connect as wizamart user
sudo -u postgres psql wizamart_db

# Or with password
psql -h localhost -U wizamart_user -d wizamart_db

Deploy Updates

sudo su - wizamart
cd ~/app
git pull origin main
source .venv/bin/activate
pip install -r requirements.txt
alembic upgrade head
exit
sudo systemctl restart wizamart wizamart-celery

Backups

Database Backup Script

sudo nano /home/wizamart/backup.sh
#!/bin/bash
BACKUP_DIR=/home/wizamart/backups
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database
pg_dump -U wizamart_user wizamart_db | gzip > $BACKUP_DIR/db_$DATE.sql.gz

# Backup uploads
tar -czf $BACKUP_DIR/uploads_$DATE.tar.gz -C /home/wizamart/app uploads/

# Keep last 7 days
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete

echo "Backup completed: $DATE"
chmod +x /home/wizamart/backup.sh

Cron Job

sudo -u wizamart crontab -e
# Daily backup at 2 AM
0 2 * * * /home/wizamart/backup.sh >> /home/wizamart/backup.log 2>&1

Monitoring

Basic Health Check

curl -s http://localhost:8000/health | jq

Process Monitoring

# Check all services
systemctl status wizamart wizamart-celery postgresql redis nginx

# Resource usage
htop
df -h
free -h

Set Up Sentry (Error Tracking)

Add to .env:

SENTRY_DSN=https://your-sentry-dsn

Troubleshooting

See Infrastructure Guide - Troubleshooting for detailed diagnostics.

Quick Checks

# Is the app running?
systemctl status wizamart

# Can we connect to the database?
pg_isready -h localhost -U wizamart_user

# Is Redis running?
redis-cli ping

# Check open ports
ss -tlnp | grep -E '(8000|5432|6379|80|443)'

# View recent errors
journalctl -u wizamart --since "1 hour ago" | grep -i error