Saleor на Ubuntu 24.04: пошаговая установка
Saleor — не «ещё один WooCommerce», а GraphQL-first e-commerce платформа с раздельным бэкендом (Python/Django + Celery) и фронтендом (React Dashboard, storefront на Next.js), рассчитанная на нагруженные проекты с кастомной логикой. Ставится она не одним apt install, а связкой из нескольких сервисов, и именно на этом моменте новички теряют время: пробуют завести всё вручную, путаются в переменных окружения и очередях Celery. Ниже — рабочий путь через Docker Compose с нуля до открытого GraphQL Playground и панели администратора.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что понадобится и почему без Docker тут не обойтись
Saleor Core сам по себе — Django-приложение, но продакшен-инсталляция требует минимум пяти компонентов: PostgreSQL (основная БД), Redis (брокер для Celery и кеш), сам API-контейнер, воркер Celery для фоновых задач (отправка писем, обработка вебхуков, пересчёт цен) и Dashboard — отдельное SPA-приложение, которое общается с API только по GraphQL. Собирать это вручную из исходников имеет смысл, если вы разработчик Saleor и правите ядро; для запуска магазина куда практичнее использовать официальные Docker-образы и Docker Compose — так вы получаете воспроизводимую конфигурацию и не тащите в систему весь Python/Node toolchain.
Понадобится:
- VPS с Ubuntu 24.04, минимум 2 vCPU / 4 ГБ RAM для теста; для продакшена с реальным трафиком ориентируйтесь на 4 vCPU / 8 ГБ и выше — точную цифру даст только нагрузочное тестирование под ваш каталог и трафик;
- домен (лучше сразу два поддомена:
api.example.comпод GraphQL-эндпоинт иadmin.example.comпод Dashboard), A-записи указывают на IP сервера; - root-доступ или пользователь с sudo;
- открытые порты 80/443 наружу.
Если сервер вы ещё выбираете — под Saleor подходит обычный VPS с NVMe и запасом по памяти под Celery-воркеры и Postgres.
Устанавливаем Docker и Docker Compose
Подключаемся по SSH и обновляем систему:
apt update && apt upgrade -y
apt install -y ca-certificates curl gnupg git
Ставим Docker Engine из официального репозитория Docker (пакет docker.io из Ubuntu-репов часто отстаёт по версии Compose-плагина):
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Проверяем:
docker --version
docker compose version
Если хотите развернуть Docker с нуля более подробно и разобраться с правами непривилегированного пользователя, есть отдельный разбор — пошаговая установка Docker Compose для продакшена.
Не забудьте про фаервол — открываем только необходимое:
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверРазворачиваем Saleor через Docker Compose
Создаём рабочую директорию и структуру проекта:
mkdir -p /opt/saleor && cd /opt/saleor
Собираем docker-compose.yml с ключевыми сервисами Saleor: базой, Redis, API, воркером Celery и Dashboard. Версии образов проверьте перед запуском в официальном реестре ghcr.io/saleor — платформа развивается быстро, и на момент вашего чтения актуальным может быть более свежий тег, чем указанный ниже для примера.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: saleor
POSTGRES_PASSWORD: change_me_strong_password
POSTGRES_DB: saleor
volumes:
- saleor-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U saleor"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- saleor-redis:/data
api:
image: ghcr.io/saleor/saleor:3.20
restart: unless-stopped
command: gunicorn saleor.wsgi:application --bind 0.0.0.0:8000 --workers 3
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
ports:
- "127.0.0.1:8000:8000"
volumes:
- saleor-media:/app/media
- saleor-static:/app/static
env_file: .env
worker:
image: ghcr.io/saleor/saleor:3.20
restart: unless-stopped
command: celery -A saleor worker --loglevel=info -B
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- saleor-media:/app/media
env_file: .env
dashboard:
image: ghcr.io/saleor/saleor-dashboard:latest
restart: unless-stopped
ports:
- "127.0.0.1:9000:80"
volumes:
saleor-db:
saleor-redis:
saleor-media:
saleor-static:
Файл .env рядом с compose-файлом — сюда выносим секреты и адреса:
cat > /opt/saleor/.env << 'EOF'
SECRET_KEY=сгенерируйте_длинную_случайную_строку
DEBUG=False
ALLOWED_HOSTS=api.example.com,localhost
DATABASE_URL=psql://saleor:change_me_strong_password@db:5432/saleor
CELERY_BROKER_URL=redis://redis:6379/1
DEFAULT_FROM_EMAIL=shop@example.com
DASHBOARD_URL=https://admin.example.com/
ALLOWED_CLIENT_HOSTS=admin.example.com
EOF
SECRET_KEY сгенерируйте, например, командой openssl rand -base64 48 — не оставляйте значение из примера. Пароль базы в docker-compose.yml и DATABASE_URL должны совпадать; в реальном проекте вынесите пароль тоже в .env и подставьте переменной.
Поднимаем стек и применяем миграции:
cd /opt/saleor
docker compose up -d db redis
sleep 10
docker compose up -d api worker dashboard
docker compose exec api python3 manage.py migrate
docker compose exec api python3 manage.py collectstatic --noinput
Проверяем, что все контейнеры живы:
docker compose ps
docker compose logs -f api
Если api падает в рестарт-луп — почти всегда дело в неверном DATABASE_URL или в том, что db ещё не успел подняться при первом старте; команда docker compose restart api после готовности базы обычно решает проблему.
Nginx как reverse-proxy и SSL для API и Dashboard
Контейнеры слушают только 127.0.0.1, наружу их отдаёт Nginx. Ставим:
apt install -y nginx
Конфиг для API (/etc/nginx/sites-available/saleor-api):
server {
listen 80;
server_name api.example.com;
client_max_body_size 20m;
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;
}
}
И для Dashboard (/etc/nginx/sites-available/saleor-dashboard):
server {
listen 80;
server_name admin.example.com;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Активируем и перезагружаем:
ln -s /etc/nginx/sites-available/saleor-api /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/saleor-dashboard /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Общие принципы настройки reverse-proxy на Nginx (буферы, тайм-ауты, вебсокеты) подробно разобраны в статье Nginx как reverse-proxy: пошаговая установка — Saleor это касается напрямую, GraphQL-запросы на загрузку каталога бывают увесистыми.
SSL получаем через Certbot:
apt install -y certbot python3-certbot-nginx
certbot --nginx -d api.example.com -d admin.example.com
Certbot сам пропишет listen 443 ssl и настроит редирект с 80 на 443. Если хотите разобраться в альтернативах и нюансах продления сертификатов — есть отдельный гайд про установку Let's Encrypt SSL.
Первый запуск: суперпользователь, Dashboard, GraphQL Playground
Создаём администратора:
docker compose exec api python3 manage.py createsuperuser
Введите email и пароль — под ними вы войдёте в Dashboard.
Открываем https://admin.example.com — это React-приложение, которое ходит на API по адресу, указанному в API_URI при сборке образа dashboard (обычно он берётся из переменной окружения API_URL в самом контейнере dashboard — добавьте её в compose-сервис dashboard, если панель не находит бэкенд):
dashboard:
image: ghcr.io/saleor/saleor-dashboard:latest
environment:
API_URL: "https://api.example.com/graphql/"
После логина проверьте GraphQL-эндпоинт напрямую: https://api.example.com/graphql/ в браузере откроет GraphiQL/Playground (при DEBUG=False playground по умолчанию отключён — это ожидаемо; для отладки временно включите PLAYGROUND_ENABLED=True в .env, но на проде держать его открытым не стоит).
Базовая проверка — создать тестовый товар через Dashboard (Catalog → Products → Create), убедиться, что он появляется в GraphQL-запросе:
query {
products(first: 5, channel: "default-channel") {
edges {
node {
name
pricing {
priceRange {
start { gross { amount currency } }
}
}
}
}
}
}
Если запрос возвращает пустой список — проверьте, что товар опубликован в нужном канале (channel) и указана цена, это частая причина «товар есть, а в API его нет».
Продакшен-нюансы: почта, медиафайлы, бэкапы
Почта. Без настроенного SMTP Saleor не отправит письма о заказе и восстановлении пароля. В .env добавьте:
EMAIL_URL=smtp://user:password@smtp.yourprovider.com:587/?tls=True
и перезапустите api и worker — письма шлёт именно воркер через Celery-задачи.
Медиафайлы. По умолчанию изображения товаров лежат в volume saleor-media на локальном диске — нормально для старта, но не масштабируется на несколько инстансов API и не переживает миграцию без ручного переноса volume. Для продакшена логичнее вынести хранилище во внешний S3-совместимый сервис (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_STORAGE_BUCKET_NAME, AWS_S3_ENDPOINT_URL в .env) — например, поднять свой MinIO рядом, как описано в статье MinIO в Docker Compose: готовый файл.
Бэкапы БД. Всё, что реально критично в Saleor, лежит в Postgres — каталог, заказы, клиенты. Простейший вариант с cron:
docker compose exec -T db pg_dump -U saleor saleor | gzip > /opt/backups/saleor-$(date +%F).sql.gz
Добавьте это в /etc/cron.d/saleor-backup с ежедневным запуском и ротацией старых архивов (find /opt/backups -mtime +14 -delete), и храните копию не только на этом же сервере — если диск умрёт, локальный бэкап не поможет.
Мониторинг ресурсов. Celery-воркер под нагрузкой (много вебхуков, синхронизация с внешними системами) съедает память рывками — держите на сервере запас RAM сверх расчётного минимума и следите за docker stats в первые недели после запуска, чтобы понять реальный профиль потребления именно вашего магазина.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужен ли отдельно storefront (витрина для покупателей)?
Да, Saleor Core и Dashboard — это API и админка. Витрину для покупателей вы либо берёте из официального Next.js Storefront (тоже разворачивается контейнером), либо пишете свою на GraphQL-клиенте — Saleor это допускает изначально.
Можно ли обойтись без Docker и поставить Saleor Core напрямую через pip/poetry?
Технически да, для разработки так и делают, но для продакшена вам всё равно придётся вручную поднимать Postgres, Redis, Celery worker и beat-планировщик отдельными процессами — Docker Compose просто избавляет от этой рутины и рассинхронизации версий.
Почему Dashboard открывается, но пишет ошибку соединения с API?
Чаще всего не совпадает API_URL в переменных окружения контейнера dashboard и реальный публичный адрес API, либо в ALLOWED_CLIENT_HOSTS/CORS-настройках API не добавлен домен админки.
Хватит ли 4 ГБ RAM для боевого магазина?
Для небольшого каталога и низкого трафика — как правило да, но с ростом числа воркеров Celery и параллельных GraphQL-запросов это становится узким местом одним из первых; проще сразу закладывать 8 ГБ, чем потом переезжать под нагрузкой.
Как обновлять Saleor до новой версии?
Меняете тег образа в docker-compose.yml для api, worker и dashboard, делаете docker compose pull, docker compose up -d, затем docker compose exec api python3 manage.py migrate — и обязательно смотрите changelog на breaking changes перед мажорным апгрейдом.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →