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)
Prerequisites
Before beginning the installation, ensure you have the following:
| Requirement | Minimum | Recommended |
|---|---|---|
| RAM | 4 GB | 8 GB |
| CPU | 2 vCPUs | 4 vCPUs |
| Storage | 40 GB SSD | 80 GB SSD |
| OS | Ubuntu 22.04 LTS | Ubuntu 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).
Initial Server Setup
Connect to your RamNode VPS via SSH and update the system packages:
sudo apt update && sudo apt upgrade -yInstall essential build tools and dependencies:
sudo apt install -y build-essential git curl wget software-properties-common \
libpq-dev libffi-dev libssl-dev libjpeg-dev zlib1g-dev \
libmagic1 gettextCreate a dedicated user for running Saleor services:
sudo useradd -m -s /bin/bash saleor
sudo usermod -aG sudo saleorInstall PostgreSQL
Saleor requires PostgreSQL as its database backend:
sudo apt install -y postgresql postgresql-contrib
# Start and enable PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresqlCreate a database and user for Saleor:
sudo -u postgres psqlWithin the PostgreSQL prompt, run:
CREATE USER saleor WITH PASSWORD 'your_secure_password_here';
CREATE DATABASE saleor OWNER saleor;
GRANT ALL PRIVILEGES ON DATABASE saleor TO saleor;
\qInstall Redis
Redis is used for caching, Celery task queue, and session management:
sudo apt install -y redis-serverConfigure Redis for production:
sudo nano /etc/redis/redis.confFind and modify these settings:
supervised systemd
maxmemory 256mb
maxmemory-policy allkeys-lrusudo systemctl restart redis-server
sudo systemctl enable redis-server
# Verify Redis is running
redis-cli pingYou should receive PONG as a response.
Install Python 3.12
Saleor requires Python 3.10 or later:
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 --versionInstall Node.js
The Saleor Dashboard requires Node.js. Install Node.js 20 LTS:
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 pnpmInstall and Configure Saleor Core (API)
Switch to the saleor user and set up the application directory:
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.txtConfigure Environment Variables
nano /home/saleor/apps/saleor/.envAdd the following 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=1hGenerate a secure secret key:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"Initialize the 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 --createsuperuserConfigure Gunicorn
Create a Gunicorn configuration file:
nano /home/saleor/apps/saleor/gunicorn_config.pyAdd the following configuration:
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 the logs directory
mkdir -p /home/saleor/logs
# Exit the saleor user session
exitCreate Systemd Services
Saleor API Service
sudo nano /etc/systemd/system/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.targetCelery Worker Service
sudo nano /etc/systemd/system/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.targetCelery Beat Service (Scheduled Tasks)
sudo nano /etc/systemd/system/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.targetEnable and start the 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-beatInstall Saleor 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 .envAdd the following:
API_URI=https://saleor.example.com/graphql/
APP_MOUNT_URI=/
STATIC_URL=/# Build the production assets
pnpm run build
# Exit the saleor user session
exitThe built files will be in the build directory.
Install and Configure Nginx
sudo apt install -y nginxSaleor API Configuration
sudo nano /etc/nginx/sites-available/saleor-apiupstream 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
sudo nano /etc/nginx/sites-available/saleor-dashboardserver {
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 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 -tConfigure SSL with Let's Encrypt
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 nginxCertbot will automatically configure Nginx for SSL and set up automatic certificate renewal.
Configure Firewall
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 statusConfigure Backups
Create a backup script for your Saleor data:
sudo mkdir -p /home/saleor/scripts
sudo nano /home/saleor/scripts/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"sudo chmod +x /home/saleor/scripts/backup.sh
sudo crontab -u saleor -eAdd for daily backups at 2 AM:
0 2 * * * /home/saleor/scripts/backup.sh >> /home/saleor/logs/backup.log 2>&1Verification 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
sudo systemctl status saleor-api saleor-celery saleor-celery-beat nginx redis-server postgresqlTroubleshooting Common Issues
Viewing 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 -fPerformance Optimization
Enable PostgreSQL Connection Pooling
sudo apt install -y pgbouncerConfigure PgBouncer in /etc/pgbouncer/pgbouncer.ini for optimal performance.
Configure Redis Caching
Update your Saleor .env to use Redis caching:
CACHE_URL=redis://localhost:6379/2Security 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.
