Deployment Guide

    Deploy Saleor

    Saleor is a powerful GraphQL-first e-commerce platform built with Python and Django. This guide covers deploying Saleor on RamNode's reliable VPS hosting with PostgreSQL, Redis, Celery, and production-ready Nginx configuration.

    Ubuntu 22.04/24.04
    GraphQL API
    ⏱️ 60-90 minutes
    1

    Introduction

    Saleor is a powerful, open-source, GraphQL-first e-commerce platform built with Python and Django. It offers a modern architecture that separates the backend API from the frontend, providing flexibility for headless commerce implementations.

    Saleor Components:

    • Saleor Core (API): Python/Django backend providing GraphQL API for products, orders, customers, and all e-commerce functionality
    • Saleor Dashboard: React-based admin panel for store management
    • Storefront: Your customer-facing store (build with any frontend framework)
    2

    Prerequisites

    Before beginning the installation, ensure you have the following:

    RequirementMinimumRecommended
    RAM4 GB8 GB
    CPU2 vCPUs4 vCPUs
    Storage40 GB SSD80 GB SSD
    OSUbuntu 22.04 LTSUbuntu 24.04 LTS

    You'll also need root or sudo access and domain names pointed to your server (e.g., saleor.example.com, dashboard.example.com).

    3

    Initial Server Setup

    Connect to your RamNode VPS via SSH and update the system packages:

    Update system
    sudo apt update && sudo apt upgrade -y

    Install essential build tools and dependencies:

    Install dependencies
    sudo apt install -y build-essential git curl wget software-properties-common \
      libpq-dev libffi-dev libssl-dev libjpeg-dev zlib1g-dev \
      libmagic1 gettext

    Create a dedicated user for running Saleor services:

    Create user
    sudo useradd -m -s /bin/bash saleor
    sudo usermod -aG sudo saleor
    4

    Install PostgreSQL

    Saleor requires PostgreSQL as its database backend:

    Install PostgreSQL
    sudo apt install -y postgresql postgresql-contrib
    
    # Start and enable PostgreSQL
    sudo systemctl start postgresql
    sudo systemctl enable postgresql

    Create a database and user for Saleor:

    Access PostgreSQL
    sudo -u postgres psql

    Within the PostgreSQL prompt, run:

    Create database
    CREATE USER saleor WITH PASSWORD 'your_secure_password_here';
    CREATE DATABASE saleor OWNER saleor;
    GRANT ALL PRIVILEGES ON DATABASE saleor TO saleor;
    \q
    5

    Install Redis

    Redis is used for caching, Celery task queue, and session management:

    Install Redis
    sudo apt install -y redis-server

    Configure Redis for production:

    Edit Redis config
    sudo nano /etc/redis/redis.conf

    Find and modify these settings:

    Redis settings
    supervised systemd
    maxmemory 256mb
    maxmemory-policy allkeys-lru
    Restart Redis
    sudo systemctl restart redis-server
    sudo systemctl enable redis-server
    
    # Verify Redis is running
    redis-cli ping

    You should receive PONG as a response.

    6

    Install Python 3.12

    Saleor requires Python 3.10 or later:

    Install Python
    sudo add-apt-repository ppa:deadsnakes/ppa -y
    sudo apt update
    sudo apt install -y python3.12 python3.12-venv python3.12-dev python3-pip
    
    # Verify the installation
    python3.12 --version
    7

    Install Node.js

    The Saleor Dashboard requires Node.js. Install Node.js 20 LTS:

    Install Node.js
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt install -y nodejs
    
    # Verify the installation
    node --version
    npm --version
    
    # Install pnpm (Saleor's preferred package manager)
    sudo npm install -g pnpm
    8

    Install and Configure Saleor Core (API)

    Switch to the saleor user and set up the application directory:

    Clone Saleor
    sudo su - saleor
    mkdir -p /home/saleor/apps
    cd /home/saleor/apps
    
    # Clone the Saleor repository
    git clone https://github.com/saleor/saleor.git
    cd saleor
    git checkout main
    
    # Create a Python virtual environment
    python3.12 -m venv venv
    source venv/bin/activate
    
    # Install Python dependencies
    pip install --upgrade pip wheel setuptools
    pip install -r requirements.txt

    Configure Environment Variables

    Create .env
    nano /home/saleor/apps/saleor/.env

    Add the following configuration:

    .env configuration
    # Database
    DATABASE_URL=postgres://saleor:your_secure_password_here@localhost:5432/saleor
    
    # Redis
    REDIS_URL=redis://localhost:6379/0
    CELERY_BROKER_URL=redis://localhost:6379/1
    
    # Security
    SECRET_KEY=your_very_long_random_secret_key_here
    DEBUG=False
    
    # Allowed hosts and CORS
    ALLOWED_HOSTS=saleor.example.com,localhost,127.0.0.1
    ALLOWED_CLIENT_HOSTS=saleor.example.com,dashboard.example.com
    
    # Static and media files
    STATIC_URL=/static/
    MEDIA_URL=/media/
    
    # Dashboard URL
    DASHBOARD_URL=https://dashboard.example.com/
    STOREFRONT_URL=https://store.example.com/
    
    # JWT settings
    JWT_TTL_ACCESS=5m
    JWT_TTL_REFRESH=30d
    JWT_TTL_REQUEST_EMAIL_CHANGE=1h

    Generate a secure secret key:

    Generate secret key
    python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

    Initialize the Database

    Setup database
    # Apply database migrations
    python manage.py migrate
    
    # Create a superuser account
    python manage.py createsuperuser
    
    # Collect static files
    python manage.py collectstatic --noinput
    
    # Optionally, populate with sample data
    python manage.py populatedb --createsuperuser
    9

    Configure Gunicorn

    Create a Gunicorn configuration file:

    Create config
    nano /home/saleor/apps/saleor/gunicorn_config.py

    Add the following configuration:

    gunicorn_config.py
    import multiprocessing
    
    bind = "127.0.0.1:8000"
    workers = multiprocessing.cpu_count() * 2 + 1
    worker_class = "uvicorn.workers.UvicornWorker"
    timeout = 120
    keepalive = 5
    max_requests = 1000
    max_requests_jitter = 50
    accesslog = "/home/saleor/logs/gunicorn_access.log"
    errorlog = "/home/saleor/logs/gunicorn_error.log"
    loglevel = "info"
    Create logs directory
    # Create the logs directory
    mkdir -p /home/saleor/logs
    
    # Exit the saleor user session
    exit
    10

    Create Systemd Services

    Saleor API Service

    Create service file
    sudo nano /etc/systemd/system/saleor-api.service
    saleor-api.service
    [Unit]
    Description=Saleor API
    After=network.target postgresql.service redis-server.service
    Requires=postgresql.service redis-server.service
    
    [Service]
    Type=notify
    User=saleor
    Group=saleor
    WorkingDirectory=/home/saleor/apps/saleor
    Environment="PATH=/home/saleor/apps/saleor/venv/bin"
    EnvironmentFile=/home/saleor/apps/saleor/.env
    ExecStart=/home/saleor/apps/saleor/venv/bin/gunicorn saleor.asgi:application -c gunicorn_config.py
    ExecReload=/bin/kill -s HUP $MAINPID
    Restart=always
    RestartSec=10
    KillMode=mixed
    TimeoutStopSec=30
    
    [Install]
    WantedBy=multi-user.target

    Celery Worker Service

    Create Celery service
    sudo nano /etc/systemd/system/saleor-celery.service
    saleor-celery.service
    [Unit]
    Description=Saleor Celery Worker
    After=network.target postgresql.service redis-server.service
    Requires=redis-server.service
    
    [Service]
    Type=forking
    User=saleor
    Group=saleor
    WorkingDirectory=/home/saleor/apps/saleor
    Environment="PATH=/home/saleor/apps/saleor/venv/bin"
    EnvironmentFile=/home/saleor/apps/saleor/.env
    ExecStart=/home/saleor/apps/saleor/venv/bin/celery -A saleor worker --loglevel=info --concurrency=2 --detach --logfile=/home/saleor/logs/celery.log
    ExecStop=/bin/kill -s TERM $MAINPID
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target

    Celery Beat Service (Scheduled Tasks)

    Create Celery Beat service
    sudo nano /etc/systemd/system/saleor-celery-beat.service
    saleor-celery-beat.service
    [Unit]
    Description=Saleor Celery Beat
    After=network.target redis-server.service
    Requires=redis-server.service
    
    [Service]
    Type=forking
    User=saleor
    Group=saleor
    WorkingDirectory=/home/saleor/apps/saleor
    Environment="PATH=/home/saleor/apps/saleor/venv/bin"
    EnvironmentFile=/home/saleor/apps/saleor/.env
    ExecStart=/home/saleor/apps/saleor/venv/bin/celery -A saleor beat --loglevel=info --detach --logfile=/home/saleor/logs/celery-beat.log
    ExecStop=/bin/kill -s TERM $MAINPID
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target

    Enable and start the services:

    Enable services
    sudo systemctl daemon-reload
    sudo systemctl enable saleor-api saleor-celery saleor-celery-beat
    sudo systemctl start saleor-api saleor-celery saleor-celery-beat
    
    # Verify the services are running
    sudo systemctl status saleor-api
    sudo systemctl status saleor-celery
    sudo systemctl status saleor-celery-beat
    11

    Install Saleor Dashboard

    Clone Dashboard
    sudo su - saleor
    cd /home/saleor/apps
    
    # Clone the Dashboard repository
    git clone https://github.com/saleor/saleor-dashboard.git
    cd saleor-dashboard
    
    # Install dependencies
    pnpm install
    
    # Create the environment configuration
    nano .env

    Add the following:

    .env
    API_URI=https://saleor.example.com/graphql/
    APP_MOUNT_URI=/
    STATIC_URL=/
    Build Dashboard
    # Build the production assets
    pnpm run build
    
    # Exit the saleor user session
    exit

    The built files will be in the build directory.

    12

    Install and Configure Nginx

    Install Nginx
    sudo apt install -y nginx

    Saleor API Configuration

    Create API config
    sudo nano /etc/nginx/sites-available/saleor-api
    saleor-api
    upstream saleor_api {
        server 127.0.0.1:8000;
        keepalive 32;
    }
    
    server {
        listen 80;
        server_name saleor.example.com;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name saleor.example.com;
    
        # SSL configuration (will be configured by Certbot)
        ssl_certificate /etc/letsencrypt/live/saleor.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/saleor.example.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;
    
        client_max_body_size 100M;
    
        location /static/ {
            alias /home/saleor/apps/saleor/static/;
            expires 30d;
            add_header Cache-Control "public, immutable";
        }
    
        location /media/ {
            alias /home/saleor/apps/saleor/media/;
            expires 7d;
            add_header Cache-Control "public";
        }
    
        location / {
            proxy_pass http://saleor_api;
            proxy_http_version 1.1;
            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;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_redirect off;
            proxy_buffering off;
        }
    }

    Saleor Dashboard Configuration

    Create Dashboard config
    sudo nano /etc/nginx/sites-available/saleor-dashboard
    saleor-dashboard
    server {
        listen 80;
        server_name dashboard.example.com;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name dashboard.example.com;
    
        ssl_certificate /etc/letsencrypt/live/dashboard.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/dashboard.example.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
        root /home/saleor/apps/saleor-dashboard/build;
        index index.html;
    
        gzip on;
        gzip_types text/plain text/css application/json application/javascript text/xml;
        gzip_min_length 1000;
    
        location / {
            try_files $uri $uri/ /index.html;
            expires 1h;
            add_header Cache-Control "public";
        }
    
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
    Enable sites
    # Enable the sites
    sudo ln -s /etc/nginx/sites-available/saleor-api /etc/nginx/sites-enabled/
    sudo ln -s /etc/nginx/sites-available/saleor-dashboard /etc/nginx/sites-enabled/
    sudo rm /etc/nginx/sites-enabled/default
    
    # Test the configuration
    sudo nginx -t
    13

    Configure SSL with Let's Encrypt

    Install Certbot
    sudo apt install -y certbot python3-certbot-nginx
    
    # Obtain SSL certificates
    sudo certbot --nginx -d saleor.example.com -d dashboard.example.com
    
    # Restart Nginx
    sudo systemctl restart nginx

    Certbot will automatically configure Nginx for SSL and set up automatic certificate renewal.

    14

    Configure Firewall

    Configure UFW
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow ssh
    sudo ufw allow 'Nginx Full'
    sudo ufw enable
    
    # Verify firewall status
    sudo ufw status
    15

    Configure Backups

    Create a backup script for your Saleor data:

    Create backup script
    sudo mkdir -p /home/saleor/scripts
    sudo nano /home/saleor/scripts/backup.sh
    backup.sh
    #!/bin/bash
    BACKUP_DIR="/home/saleor/backups"
    DATE=$(date +%Y%m%d_%H%M%S)
    mkdir -p $BACKUP_DIR
    
    # Database backup
    pg_dump -U saleor saleor | gzip > $BACKUP_DIR/saleor_db_$DATE.sql.gz
    
    # Media files backup
    tar -czf $BACKUP_DIR/saleor_media_$DATE.tar.gz -C /home/saleor/apps/saleor media
    
    # Cleanup backups older than 7 days
    find $BACKUP_DIR -type f -mtime +7 -delete
    
    echo "Backup completed: $DATE"
    Enable backup cron
    sudo chmod +x /home/saleor/scripts/backup.sh
    sudo crontab -u saleor -e

    Add for daily backups at 2 AM:

    Crontab entry
    0 2 * * * /home/saleor/scripts/backup.sh >> /home/saleor/logs/backup.log 2>&1

    Verification and Testing

    Test the GraphQL API

    Access the GraphQL Playground at: https://saleor.example.com/graphql/

    Access the Dashboard

    Navigate to: https://dashboard.example.com/ and log in with your superuser credentials.

    Verify Services

    Check services
    sudo systemctl status saleor-api saleor-celery saleor-celery-beat nginx redis-server postgresql
    16

    Troubleshooting Common Issues

    Viewing Logs

    View logs
    # Saleor API logs
    tail -f /home/saleor/logs/gunicorn_error.log
    
    # Celery logs
    tail -f /home/saleor/logs/celery.log
    
    # Nginx logs
    sudo tail -f /var/log/nginx/error.log
    
    # System journal
    sudo journalctl -u saleor-api -f

    Performance Optimization

    Enable PostgreSQL Connection Pooling

    Install PgBouncer
    sudo apt install -y pgbouncer

    Configure PgBouncer in /etc/pgbouncer/pgbouncer.ini for optimal performance.

    Configure Redis Caching

    Update your Saleor .env to use Redis caching:

    Add to .env
    CACHE_URL=redis://localhost:6379/2

    Security Best Practices

    • Keep systems updated: Regularly run apt update && apt upgrade
    • Monitor logs: Set up log rotation and monitoring
    • Use strong passwords: Ensure all database and admin passwords are complex
    • Enable fail2ban: Protect against brute-force attacks
    • Regular backups: Test your backup and restore procedures
    • Limit SSH access: Use key-based authentication

    Ready to Deploy Saleor?

    Get started with a RamNode VPS optimized for e-commerce applications with powerful CPU, ample RAM, and NVMe storage.