# 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 ~/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 ```