Files
orion/docs/deployment/production.md
Samir Boulahtit 7a9dda282d refactor(scripts): reorganize scripts/ into seed/ and validate/ subfolders
Move 9 init/seed scripts into scripts/seed/ and 7 validation scripts
(+ validators/ subfolder) into scripts/validate/ to reduce clutter in
the root scripts/ directory. Update all references across Makefile,
CI/CD configs, pre-commit hooks, docs (~40 files), and Python imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:35:53 +01:00

484 lines
9.8 KiB
Markdown

# 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
```bash
# 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/seed/init_production.py
# 7. Exit wizamart user
exit
```
---
## Systemd Services
### Main Application
```bash
sudo nano /etc/systemd/system/wizamart.service
```
```ini
[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
```bash
sudo nano /etc/systemd/system/wizamart-celery.service
```
```ini
[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.core.celery_config worker --loglevel=info -Q default,long_running,scheduled --concurrency=4
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
```
### Celery Beat (Scheduler)
```bash
sudo nano /etc/systemd/system/wizamart-celery-beat.service
```
```ini
[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.core.celery_config beat --loglevel=info
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
```
### Flower (Task Monitoring)
```bash
sudo nano /etc/systemd/system/wizamart-flower.service
```
```ini
[Unit]
Description=Wizamart Flower Task Monitor
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.core.celery_config flower --port=5555
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
```
### Enable Services
```bash
sudo systemctl daemon-reload
sudo systemctl enable wizamart wizamart-celery wizamart-celery-beat wizamart-flower
sudo systemctl start wizamart wizamart-celery wizamart-celery-beat wizamart-flower
```
---
## Nginx Configuration
```bash
sudo nano /etc/nginx/sites-available/wizamart
```
```nginx
# 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
```bash
sudo ln -s /etc/nginx/sites-available/wizamart /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
### SSL with Certbot
```bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
```
---
## Firewall
```bash
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
```
---
## Daily Operations
### View Logs
```bash
# 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
```bash
sudo systemctl restart wizamart
sudo systemctl restart wizamart-celery
sudo systemctl restart nginx
```
### Database Access
```bash
# Connect as wizamart user
sudo -u postgres psql wizamart_db
# Or with password
psql -h localhost -U wizamart_user -d wizamart_db
```
### Deploy Updates
```bash
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
```bash
sudo nano /home/wizamart/backup.sh
```
```bash
#!/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"
```
```bash
chmod +x /home/wizamart/backup.sh
```
### Cron Job
```bash
sudo -u wizamart crontab -e
```
```cron
# Daily backup at 2 AM
0 2 * * * /home/wizamart/backup.sh >> /home/wizamart/backup.log 2>&1
```
---
## Monitoring
### Basic Health Check
```bash
curl -s http://localhost:8000/health | jq
```
### Process Monitoring
```bash
# Check all services
systemctl status wizamart wizamart-celery postgresql redis nginx
# Resource usage
htop
df -h
free -h
```
### Set Up Sentry (Error Tracking)
Sentry provides real-time error tracking and performance monitoring.
1. **Create a Sentry account** at [sentry.io](https://sentry.io) (free tier available)
2. **Create a new project** (Python/FastAPI)
3. **Add to `.env`**:
```env
SENTRY_DSN=https://your-key@sentry.io/project-id
SENTRY_ENVIRONMENT=production
SENTRY_TRACES_SAMPLE_RATE=0.1
```
4. **Restart services**:
```bash
sudo systemctl restart wizamart wizamart-celery
```
Sentry will now capture:
- Unhandled exceptions
- API errors with request context
- Celery task failures
- Performance traces (10% sample rate)
---
## Cloudflare R2 Storage
For production, use Cloudflare R2 instead of local storage for scalability and CDN integration.
### Setup
1. **Create R2 bucket** in CloudFlare dashboard
2. **Create API token** with Object Read/Write permissions
3. **Add to `.env`**:
```env
STORAGE_BACKEND=r2
R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key
R2_SECRET_ACCESS_KEY=your_secret_key
R2_BUCKET_NAME=wizamart-media
R2_PUBLIC_URL=https://media.yourdomain.com
```
See [CloudFlare Setup Guide](cloudflare.md) for detailed instructions.
---
## CloudFlare CDN & Proxy
For production, proxy your domain through CloudFlare for:
- Global CDN caching
- DDoS protection
- Free SSL certificates
- WAF (Web Application Firewall)
### Enable CloudFlare Headers
Add to `.env`:
```env
CLOUDFLARE_ENABLED=true
```
This enables proper handling of `CF-Connecting-IP` for real client IPs.
See [CloudFlare Setup Guide](cloudflare.md) for complete configuration.
---
## Troubleshooting
See [Infrastructure Guide - Troubleshooting](infrastructure.md#troubleshooting-guide) for detailed diagnostics.
### Quick Checks
```bash
# 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
```