Installing and Configuring Saleor (Django/GraphQL)
Saleor is a Django application with PostgreSQL as the primary database, Celery+Redis for queues, and S3-compatible storage for media files. Production deployment requires configuring all four components plus separate deployments of Dashboard (React) and Storefront (Next.js).
Server Requirements
- Python 3.11+
- PostgreSQL 15+ (16 recommended)
- Redis 7+
- Node.js 18+ (for Dashboard/Storefront only)
- RAM: at least 2 GB for backend + Celery workers
- S3-compatible storage: AWS S3, MinIO, Hetzner Object Storage
Docker Compose for Development
# docker-compose.yml (official)
version: "3.8"
services:
api:
image: ghcr.io/saleor/saleor:3.20
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://saleor:saleor@db/saleor
- CELERY_BROKER_URL=redis://redis:6379/0
- SECRET_KEY=change-me-in-production
- DEBUG=False
- ALLOWED_HOSTS=localhost,api.example.com
- ALLOWED_CLIENT_HOSTS=localhost:3000,store.example.com
- [email protected]
depends_on:
- db
- redis
command: >
sh -c "python manage.py migrate &&
python manage.py collectstatic --no-input &&
gunicorn saleor.wsgi:application --bind 0.0.0.0:8000 --workers 4 --threads 2"
worker:
image: ghcr.io/saleor/saleor:3.20
environment:
- DATABASE_URL=postgresql://saleor:saleor@db/saleor
- CELERY_BROKER_URL=redis://redis:6379/0
depends_on:
- db
- redis
command: celery -A saleor worker --app=saleor.celeryconf:app -l info --concurrency=4
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: saleor
POSTGRES_USER: saleor
POSTGRES_DB: saleor
volumes:
- saleor-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U saleor"]
interval: 5s
redis:
image: redis:7-alpine
volumes:
- saleor-redis:/data
volumes:
saleor-db:
saleor-redis:
Installation from Source (Without Docker)
git clone https://github.com/saleor/saleor.git && cd saleor
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
# Environment configuration
cp .env.example .env
# Edit .env: DATABASE_URL, SECRET_KEY, CELERY_BROKER_URL
# Database migrations
python manage.py migrate
# Initial data (channels, warehouses, shipping types)
python manage.py populatedb
# Create superuser
python manage.py createsuperuser
# Run dev server
python manage.py runserver 0.0.0.0:8000
# In a separate terminal — Celery worker
celery -A saleor worker --app=saleor.celeryconf:app -l info
Production Environment Configuration
Key variables in settings.py for production:
# saleor/settings.py — override via environment variables
import os
from pathlib import Path
SECRET_KEY = os.environ["SECRET_KEY"]
DEBUG = os.getenv("DEBUG", "False") == "True"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
ALLOWED_CLIENT_HOSTS = os.environ.get("ALLOWED_CLIENT_HOSTS", "").split(",")
# Database
import dj_database_url
DATABASES = {
"default": dj_database_url.config(
default=os.environ["DATABASE_URL"],
conn_max_age=600,
conn_health_checks=True,
)
}
# S3 for media files
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
AWS_S3_REGION_NAME = os.environ.get("AWS_S3_REGION_NAME", "us-east-1")
AWS_S3_CUSTOM_DOMAIN = os.environ.get("AWS_S3_CUSTOM_DOMAIN") # CDN URL
# Email via SMTP
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = os.environ.get("EMAIL_HOST", "smtp.sendgrid.net")
EMAIL_PORT = int(os.environ.get("EMAIL_PORT", "587"))
EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD")
EMAIL_USE_TLS = True
Nginx + Gunicorn Configuration
upstream saleor_api {
server 127.0.0.1:8000;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name api.example.com;
location /graphql/ {
proxy_pass http://saleor_api;
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_read_timeout 120s;
client_max_body_size 50M;
}
location /static/ {
alias /var/www/saleor/static/;
expires 30d;
}
}
Initial Configuration via Dashboard
After installation via Dashboard (localhost:9000 or /dashboard/):
- Channels — create a channel, specify currency and countries
- Warehouses — create a warehouse, bind to a channel
- Shipping Zones — shipping zones by country
- Tax Configuration — tax classes
- Payment Apps — connect via Apps → Explore → Install
Updating Saleor
# Check breaking changes in CHANGELOG.md before updating
git fetch && git log HEAD..origin/main --oneline
# Update
git pull origin main
pip install -r requirements.txt
python manage.py migrate --run-syncdb
# Restart
sudo systemctl restart gunicorn celery
Timeframes
- Docker Compose development setup: 2–4 hours
- Production setup with PostgreSQL, Redis, S3, Nginx, SSL: 1–2 days
- Complete configuration: channels, warehouses, shipping zones, payments, Dashboard + Storefront: 3–5 days







