How to Install Saleor on Ubuntu 24.04 VPS: Self-Hosted GraphQL Commerce Platform
Saleor is a modern, headless, GraphQL-first commerce platform used by brands like Lush, Breitling, FarFetch Sandbox, and Volvo. Unlike monolithic platforms like Magento or WooCommerce, Saleor separates the backend API, admin dashboard, and storefront into independently deployable services — giving you control over every pixel while keeping a solid Python/Django backend behind the scenes.
This guide walks you through installing a production-grade Saleor stack on Ubuntu 24.04 with Docker Compose — GraphQL API, React Dashboard, Next.js storefront, Celery workers, PostgreSQL, Redis, Mailpit, and Jaeger.
Want a headless commerce platform that scales with your business? Deploy on our CloudCore Business VPS with 8 vCPU, 24 GB RAM, and 400 GB NVMe — Saleor's API, workers, Dashboard, storefront, and Postgres all fit comfortably on a single node.
Table of Contents
What is Saleor?
Saleor is an open-source, enterprise-grade e-commerce platform written in Python/Django with a GraphQL-only API. Released under the permissive BSD-3-Clause license, it has been in active development since 2012 and is maintained by Saleor Commerce (Wrocław, Poland). Today it powers commerce for brands like Lush Cosmetics, Breitling, FarFetch, and Volvo, alongside thousands of smaller merchants.
Saleor splits into independent services that communicate over HTTP and Redis:
- Saleor API — Django/GraphQL backend exposing products, orders, checkouts, payments, shipping, promotions, customers, and taxes at a single
/graphql/endpoint. - Saleor Dashboard — React SPA admin UI for catalog, orders, channels, attributes, and apps.
- Saleor Storefront — reference Next.js storefront you fork, customise, or replace entirely.
- Celery workers — background jobs for webhooks, email, thumbnails, and scheduled tasks.
- PostgreSQL, Redis, Mailpit, Jaeger — data store, cache/broker, dev SMTP catcher, and tracing backend.
Why Self-Host Saleor on Your VPS?
Running Saleor on your own VPS instead of a SaaS platform gives you meaningful advantages:
- No per-transaction fees — SaaS platforms like Shopify charge 0.5–2% on every sale. Your VPS cost is flat regardless of GMV.
- Complete data ownership — Customer records, orders, and payment tokens stay on hardware you control. Critical for GDPR and PCI scope reduction.
- Unlimited customization — Fork the Dashboard, replace the storefront, add GraphQL fields via plugins and apps. BSD licence imposes virtually no restrictions.
- Headless by design — Web, mobile, POS, and kiosk frontends all hit the same API with identical data models.
- No catalog limits — 10 SKUs or 500,000 SKUs; your hardware is the only constraint.
- EU data residency — Self-hosting on an EU VPS gives clean GDPR compliance without a vendor DPA.
Cost Comparison: Self-Hosted Saleor vs. SaaS Commerce Platforms
| Scenario | Shopify Advanced | BigCommerce Enterprise | Self-Hosted Saleor (VPS) |
|---|---|---|---|
| Monthly base cost | $399/mo | Custom quote ($1,000+/mo typical) | EUR 39.99/mo (CloudCore Business) |
| Transaction fees | 0.5% + payment fees | 0% (enterprise) | None (pay your payment processor only) |
| Storefront customization | Liquid templates, theme limits | Stencil templates | Unlimited (any frontend framework) |
| API rate limits | Yes | Yes | None (your server) |
| Multi-store / multi-channel | Extra cost | Extra cost | Native channels feature |
| Source code access | No | No | Yes (BSD license) |
| Data export freedom | Limited | Limited | Full pg_dump, full media volume |
| Typical annual cost at $1M GMV | $10,000+/yr | $25,000+/yr | EUR 480/yr (flat) |
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- At least 4 GB of RAM (8 GB+ recommended — Saleor runs eight services via Docker Compose and Postgres benefits from more memory)
- At least 40 GB of free disk space for Docker images, Postgres data, and product media
- A domain name with DNS pointed at the server (for TLS in Step 9)
- Basic Linux command-line familiarity
Recommended Plan: CloudCore Business>
Saleor's full Docker Compose stack runs eight containers plus Postgres working data. For a comfortable production deployment we recommend CloudCore Business:>
- 8 vCPU cores
- 24 GB RAM
- 400 GB NVMe SSD
- Unmetered bandwidth
- EUR 39.99/month>
This fits the API, Dashboard, storefront, two Celery workers, Postgres, Redis, Mailpit, and Jaeger with headroom for traffic spikes and a growing product catalog. For smaller catalogs and lower traffic you can start on CloudCore Professional and scale up later.
Connect to your server via SSH:
ssh root@your-server-ipStep 1: Update System Packages
Start by updating your package index and upgrading installed packages so dependency resolution is clean and you have current security patches.
sudo apt update && sudo apt upgrade -yExpected output (abbreviated):
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists... Done
Building dependency tree... Done
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.Install a few helpful utilities we'll use later:
sudo apt install -y git curl ca-certificates ufwIf your kernel was updated, reboot before continuing:
sudo rebootStep 2: Install Docker and Docker Compose
Saleor's official deployment path is a Docker Compose stack, so we need a working Docker installation. If you already have Docker Engine and the Compose plugin on this server, skip ahead.
Install Docker Engine following the official convenience script, which works well on Ubuntu 24.04:
curl -fsSL https://get.docker.com | sudo shAdd your user to the docker group so you don't need sudo for every command:
sudo usermod -aG docker $USER
newgrp dockerVerify Docker and the Compose plugin are working:
docker --version
docker compose versionExpected output:
Docker version 27.3.1, build ce12230
Docker Compose version v2.29.7For a deeper walkthrough of the Docker install (including rootless mode, log rotation, and overlay2 tuning), see our How to Install Docker on Ubuntu 24.04 guide. For Compose-specific configuration patterns, see How to Install Docker Compose on Ubuntu 24.04.
Step 3: Clone the saleor-platform Repository
Saleor publishes an official meta-repository called saleor-platform that wires the API, Dashboard, storefront, workers, Postgres, Redis, Mailpit, and Jaeger into a single Docker Compose file. This is the easiest path to a working local stack and a solid starting point for production.
Clone it into /opt:
cd /opt
sudo git clone https://github.com/saleor/saleor-platform.git
sudo chown -R $USER:$USER saleor-platform
cd saleor-platformList the important files:
ls -laExpected output:
drwxr-xr-x common-assets
drwxr-xr-x apps
-rw-r--r-- docker-compose.yml
-rw-r--r-- README.md
-rw-r--r-- LICENSEQuickly inspect the services that docker-compose.yml will bring up:
grep -E '^\s{2}[a-z-]+:' docker-compose.ymlExpected output:
api:
dashboard:
db:
redis:
worker:
celery-beat:
mailpit:
jaeger:That's the full Saleor stack in one file — the API (Django + GraphQL), the React Dashboard, a Postgres database, Redis, a Celery worker, a Celery beat scheduler for periodic tasks, Mailpit for email capture, and Jaeger for tracing. We'll add a Next.js example storefront shortly.
Step 4: Configure Environment Variables
Saleor's API container reads configuration from environment variables. The repo ships with a common.env file that holds shared defaults. For production you'll want to override several values.
Create a .env file in the project root:
tee /opt/saleor-platform/.env > /dev/null <<'EOF'
--- Core secrets ---
SECRET_KEY=replace-with-a-long-random-string-at-least-50-chars
RSA_PRIVATE_KEY=--- Host and URL config ---
ALLOWED_HOSTS=localhost,api.example.com
ALLOWED_CLIENT_HOSTS=example.com,dashboard.example.com,storefront.example.com
[email protected]--- Database ---
DATABASE_URL=postgres://saleor:saleor@db:5432/saleor--- Cache and message broker ---
REDIS_URL=redis://redis:6379/1
CELERY_BROKER_URL=redis://redis:6379/2--- Email (dev only — replace with real SMTP in production) ---
EMAIL_URL=smtp://mailpit:1025--- Debug and telemetry ---
DEBUG=False
JAEGER_AGENT_HOST=jaeger--- Storefront / Dashboard URLs (used in emails and webhooks) ---
DASHBOARD_URL=https://dashboard.example.com/
STOREFRONT_URL=https://example.com/
PUBLIC_URL=https://api.example.com
EOFGenerate a strong secret key:
python3 -c "import secrets; print(secrets.token_urlsafe(60))"Paste the output into SECRET_KEY= in .env. Replace example.com with your real domain throughout.
Key variables:
ALLOWED_HOSTS— Django's Host-header safeguard. Must list every hostname the API answers on.ALLOWED_CLIENT_HOSTS— storefront/dashboard domains allowed in CORS/CSRF checks.DATABASE_URL— points at thedbCompose service. Swap for a managed Postgres URL if preferred. See How to Install PostgreSQL on Ubuntu 24.04.REDIS_URL/CELERY_BROKER_URL— cache and broker on separate Redis DB numbers. See How to Install Redis on Ubuntu 24.04.EMAIL_URL— Mailpit by default. For production, use e.g.smtp://apikey:<key>@smtp.sendgrid.net:587/?tls=True.DEBUG=False— essential. Never run Saleor withDEBUG=Truepublicly.
Step 5: Start the Stack with Docker Compose
Bring up the stack in detached mode:
cd /opt/saleor-platform
docker compose up -dDocker pulls the images (ghcr.io/saleor/saleor, ghcr.io/saleor/saleor-dashboard, postgres:15-alpine, redis:7-alpine, axllent/mailpit, jaegertracing/all-in-one). First pull takes 3–8 minutes.
Expected output (abbreviated):
[+] Running 8/8
✔ Network saleor-platform_saleor-backend-tier Created
✔ Container saleor-platform-db-1 Started
✔ Container saleor-platform-redis-1 Started
✔ Container saleor-platform-jaeger-1 Started
✔ Container saleor-platform-mailpit-1 Started
✔ Container saleor-platform-api-1 Started
✔ Container saleor-platform-worker-1 Started
✔ Container saleor-platform-celery-beat-1 Started
✔ Container saleor-platform-dashboard-1 StartedCheck that every container is up:
docker compose psExpected output:
NAME IMAGE STATUS
saleor-platform-api-1 ghcr.io/saleor/saleor:latest Up (healthy)
saleor-platform-celery-beat-1 ghcr.io/saleor/saleor:latest Up
saleor-platform-dashboard-1 ghcr.io/saleor/saleor-dashboard Up
saleor-platform-db-1 postgres:15-alpine Up (healthy)
saleor-platform-jaeger-1 jaegertracing/all-in-one Up
saleor-platform-mailpit-1 axllent/mailpit Up
saleor-platform-redis-1 redis:7-alpine Up
saleor-platform-worker-1 ghcr.io/saleor/saleor:latest UpAt this point Postgres is empty — the API container is waiting for a schema. That's what the next step takes care of.
Step 6: Run Database Migrations
Saleor uses Django's ORM, so schema creation is done through manage.py migrate. Run it inside a fresh one-off API container:
docker compose run --rm api python3 manage.py migrateExpected output (abbreviated):
Operations to perform:
Apply all migrations: account, app, attribute, auth, channel, checkout, ...
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying account.0001_initial... OK
...
Applying warehouse.0027_auto... OK
Migrations complete.This creates ~200 tables covering accounts, channels, products, variants, attributes, orders, checkouts, payments, shipping, taxes, warehouses, discounts, apps, and webhooks. First run takes 1–3 minutes.
Collect static files for the API (GraphQL Playground, admin assets):
docker compose run --rm api python3 manage.py collectstatic --noinputStep 7: Create a Superuser and Populate Example Data
You'll need at least one admin user to sign into the Dashboard. Create one interactively:
docker compose run --rm api python3 manage.py createsuperuserYou'll be prompted for email and password:
Email: [email protected]
Password:
Password (again):
Superuser created successfully.Optional — populate example data. The populatedb command loads a sample catalog (categories, products, variants, attributes, channels, shipping, orders) — fastest way to explore the Dashboard:
docker compose run --rm api python3 manage.py populatedb --createsuperuserExpected output (abbreviated):
Creating channels
Creating shipping zones
Creating warehouses
Creating products
Creating categories
Creating attributes
Creating collections
Creating pages
Creating orders
Creating menus
Superuser - [email protected]/adminSkip this on a production deployment — the sample data is only for exploration.
Step 8: Access the Dashboard, API, and Storefront
The stack is fully functional. Open a browser:
- GraphQL API →
http://your-server-ip:8000/graphql/
{
shop {
name
description
}
}- Saleor Dashboard →
http://your-server-ip:9000— sign in with the superuser from Step 7. - Mailpit (SMTP catcher) →
http://your-server-ip:8025— captures all outbound dev email. - Jaeger tracing →
http://your-server-ip:16686— GraphQL and Celery traces.
cd /opt
git clone https://github.com/saleor/storefront.git saleor-storefront
cd saleor-storefront
cp .env.example .env
Edit NEXT_PUBLIC_SALEOR_API_URL to http://your-server-ip:8000/graphql/
docker run -d --name saleor-storefront \
-p 3000:3000 \
--env-file .env \
--network saleor-platform_saleor-backend-tier \
node:20-alpine sh -c "cd /app && npm install && npm run build && npm start"Open http://your-server-ip:3000 to see the example storefront fetching live products.
You now have a working Saleor installation. The remaining steps harden it for production.
Step 9: Configure Nginx Reverse Proxy with TLS
Exposing raw ports 8000 / 9000 / 3000 publicly is fine for testing but not for production. Put Nginx in front, terminate TLS, and route by hostname.
Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxFor a deeper look at Nginx tuning (gzip, caching, rate limiting), see How to Install Nginx on Ubuntu 24.04.
Create three DNS A records pointed at your VPS:
api.example.comdashboard.example.comexample.com(orstorefront.example.com)
sudo tee /etc/nginx/sites-available/saleor > /dev/null <<'EOF'Saleor API (GraphQL + subscriptions)
server { listen 80; server_name api.example.com;client_max_body_size 100m;
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 for GraphQL subscriptions proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
proxy_read_timeout 600s; proxy_send_timeout 600s; } }
Saleor Dashboard (React SPA)
server { listen 80; server_name dashboard.example.com;location / { proxy_pass http://127.0.0.1:9000; 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; } }
Saleor Storefront (Next.js)
server { listen 80; server_name example.com www.example.com;location / { proxy_pass http://127.0.0.1:3000; 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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } EOF
sudo ln -s /etc/nginx/sites-available/saleor /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx
Obtain TLS certificates for all three hostnames in one shot:
sudo certbot --nginx \
-d api.example.com \
-d dashboard.example.com \
-d example.com \
-d www.example.com \
--redirect --agree-tos -m [email protected]Certbot will insert listen 443 ssl; blocks and set up automatic renewal. The WebSocket Upgrade / Connection headers are essential — without them GraphQL subscriptions (used by the Dashboard's real-time notifications and order updates) will not work.
Lock down the firewall:
sudo ufw allow OpenSSH
sudo ufw allow "Nginx Full"
sudo ufw enableStep 10: Configure CORS, ALLOWED_HOSTS, and Production Settings
Now that TLS is live, update .env to reflect the real public URLs and re-harden Django:
cd /opt/saleor-platform
sed -i \
-e 's|ALLOWED_HOSTS=.*|ALLOWED_HOSTS=api.example.com|' \
-e 's|ALLOWED_CLIENT_HOSTS=.*|ALLOWED_CLIENT_HOSTS=example.com,www.example.com,dashboard.example.com|' \
-e 's|DASHBOARD_URL=.*|DASHBOARD_URL=https://dashboard.example.com/|' \
-e 's|STOREFRONT_URL=.*|STOREFRONT_URL=https://example.com/|' \
-e 's|PUBLIC_URL=.*|PUBLIC_URL=https://api.example.com|' \
.envAlso update the Dashboard so it knows where the API lives. The Dashboard container reads API_URL and APP_MOUNT_URI at build time — pass them through the Compose file. Edit docker-compose.yml:
dashboard:
image: ghcr.io/saleor/saleor-dashboard:latest
ports:
- 9000:80
environment:
- API_URL=https://api.example.com/graphql/
- APP_MOUNT_URI=/
- STATIC_URL=/Restart the stack so the new environment takes effect:
docker compose up -d --force-recreate api dashboard worker celery-beatPoint your browser at https://dashboard.example.com and sign in. The Dashboard should now talk to your public API over HTTPS without any CORS errors.
If you see CORS header 'Access-Control-Allow-Origin' missing in the browser console, double-check that the Dashboard's domain is listed in ALLOWED_CLIENT_HOSTS and that PUBLIC_URL uses https://, not http://.
Step 11: Tune Celery Workers for Async Tasks
Saleor offloads slow or periodic work to Celery: email, webhooks, thumbnails, promotion calculations, scheduled exports, search indexing. The default Compose file starts a single worker — production usually wants more concurrency.
Edit docker-compose.yml and bump the worker concurrency:
worker:
image: ghcr.io/saleor/saleor:latest
command: celery -A saleor --app=saleor.celeryconf:app worker \
--loglevel=info --concurrency=4
env_file: common.env
environment:
- CELERY_BROKER_URL=redis://redis:6379/2
depends_on:
- redis
- apiRule of thumb: concurrency equal to (or slightly above) your vCPU count for CPU-bound tasks; higher for IO-bound workloads like webhook delivery. On CloudCore Business (8 vCPU), --concurrency=4 leaves headroom for the API, Dashboard, Postgres, and Redis.
For high-throughput shops, run a second worker on a dedicated queue:
worker-webhooks:
image: ghcr.io/saleor/saleor:latest
command: celery -A saleor worker -Q webhooks --loglevel=info --concurrency=8
env_file: common.env
depends_on: [redis, api]Apply the changes:
docker compose up -d worker worker-webhooksMonitor Celery live:
docker compose logs -f workerPost-Install: Payment Apps, Channels, and Warehouses
A running stack is only the beginning. Every Saleor store needs a few core pieces of configuration before it can take a real order.
Channels represent sales channels ("Default Channel", "EU Wholesale", "US Retail"). Each has its own currency, country, enabled products, prices, and warehouses. Create one under Configuration → Channels.
Warehouses are inventory locations. Every variant must be stocked in at least one warehouse linked to an enabled channel. Configure under Configuration → Warehouses.
Payment apps handle cards, refunds, and 3DS. Saleor's Stripe integration is the most common — clone https://github.com/saleor/saleor-app-payment-stripe, run it as a separate Docker service, and register it under Configuration → Apps → Install app with its manifest URL. Adyen, Authorize.Net, and Mollie templates also exist.
Attributes define structured product data (color, size, material, voltage) and are queryable via GraphQL. Set them up under Configuration → Attributes before bulk-importing a catalog.
Webhooks and Apps extend Saleor without forking. Order-created, product-updated, or checkout-completed events trigger HTTP webhooks; apps can mutate Saleor through the same GraphQL API. Browse apps.saleor.io or build your own with the App SDK.
Backups and Upgrades
Saleor stores state in two places: the Postgres database and the media volume (uploaded product images, variant thumbnails, etc.). A complete backup covers both.
Daily Postgres Dump
sudo tee /usr/local/bin/saleor-backup.sh > /dev/null <<'EOF' #!/bin/bash set -e STAMP=$(date +%Y%m%d-%H%M%S) BACKUP_DIR=/var/backups/saleor mkdir -p "$BACKUP_DIR"Database dump
docker compose -f /opt/saleor-platform/docker-compose.yml exec -T db \ pg_dump -U saleor saleor | gzip > "$BACKUP_DIR/saleor-db-$STAMP.sql.gz"Media volume snapshot
docker run --rm \ -v saleor-platform_saleor-media:/media \ -v "$BACKUP_DIR":/backup \ alpine tar czf "/backup/saleor-media-$STAMP.tar.gz" -C / mediaRetention: keep last 14 days
find "$BACKUP_DIR" -name 'saleor-*' -mtime +14 -delete EOF
sudo chmod +x /usr/local/bin/saleor-backup.sh
Schedule it via cron:
(sudo crontab -l 2>/dev/null; echo "15 3 * /usr/local/bin/saleor-backup.sh") | sudo crontab -For off-site backups, rclone sync the /var/backups/saleor directory to S3, Backblaze B2, or any S3-compatible bucket.
Upgrading to a New Saleor Version
Saleor follows a predictable quarterly release cycle (3.20, 3.21, 3.22...). Upgrades are straightforward:
cd /opt/saleor-platform
git pull
Optional: pin to a specific tag inside docker-compose.yml (image: ghcr.io/saleor/saleor:3.22)
docker compose pull
docker compose up -d
docker compose run --rm api python3 manage.py migrateAlways take a fresh backup before upgrading. Read the Saleor changelog for any breaking changes between your current version and the target.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
django.db.utils.OperationalError: could not connect to server on API start | Postgres not ready yet or credentials mismatch | Wait 30s and retry, or check docker compose logs db. Verify DATABASE_URL in .env matches the Postgres env in docker-compose.yml. |
relation "account_user" does not exist | Migrations never ran | Run docker compose run --rm api python3 manage.py migrate. |
| Dashboard shows 401 Unauthorized on login | API URL misconfigured or cookies blocked across domains | Verify the Dashboard's API_URL points at https://api.example.com/graphql/ and both are on HTTPS. Check browser devtools for CORS errors. |
CORS header 'Access-Control-Allow-Origin' missing in browser | Storefront/dashboard domain not in ALLOWED_CLIENT_HOSTS | Add the exact domain (no trailing slash) to ALLOWED_CLIENT_HOSTS in .env and restart api. |
| GraphQL subscriptions stop working after Nginx install | Missing WebSocket upgrade headers | Confirm proxy_http_version 1.1, Upgrade, and Connection "upgrade" directives are present in the API server block. |
| Celery worker stuck, tasks never complete | Redis unreachable, deadlock, or OOM | Check docker compose logs worker. Verify Redis is up (docker compose ps redis). Restart worker: docker compose restart worker. Bump RAM if the host is swapping. |
SECRET_KEY warning in API logs | Default/dev key in use | Generate with python3 -c "import secrets; print(secrets.token_urlsafe(60))" and set in .env. |
413 Request Entity Too Large on product image upload | Nginx default client_max_body_size too low | Set client_max_body_size 100m; in the API server block (already in Step 9's config). |
disk I/O error or slow Postgres queries | Host IO saturated or low RAM | Upgrade plan, mount Postgres volume on NVMe, or tune shared_buffers. See How to Install PostgreSQL on Ubuntu 24.04. |
| Emails not sending in production | Still pointed at Mailpit | Replace EMAIL_URL=smtp://mailpit:1025 with a real SMTP provider URL, restart api and worker. |
Viewing Logs
Tail the API logs:
docker compose logs -f apiAll services at once:
docker compose logs -f --tail=100Jaeger at http://your-server-ip:16686 (or behind Nginx with basic auth) visualises per-query latency and makes it obvious when a slow GraphQL resolver or an N+1 query is dragging down checkout.
FAQ
What are Saleor's minimum hardware requirements?
A dev sandbox runs on 2 vCPU and 4 GB RAM. For production, plan for at least 4 vCPU and 8 GB RAM — Postgres benefits from RAM, and Celery workers spike CPU during webhook floods or email sends. A mid-sized catalog (10,000 SKUs, 100 orders/day) runs comfortably on CloudCore Business with 8 vCPU and 24 GB RAM.
Do I need a separate frontend, or can I use the Dashboard?
The Dashboard is a merchant admin tool, not a storefront. You need a separate frontend — Saleor's reference Next.js storefront, a fork, or a custom frontend in any GraphQL-capable framework (Remix, Nuxt, SvelteKit, Astro, React Native, Flutter).
How does Saleor compare to Magento, WooCommerce, and Medusa?
Magento is the enterprise monolith — huge feature set, huge complexity, expensive. WooCommerce is the easiest start but tightly coupled to WordPress. Medusa is the closest peer — headless Node.js/TypeScript, simpler admin, younger community. Saleor sits in the mature, GraphQL-native, Python/Django niche — used by brands you've heard of, free under BSD, richer feature set (channels, attributes, App framework) than Medusa.
Can I migrate from Shopify or WooCommerce to Saleor?
Yes, with work. The GraphQL API exposes productBulkCreate, productVariantBulkCreate, and similar mutations that make bulk imports straightforward. Export from your source store, map categories and attributes, script the import, then redirect old URLs. Budget 1–3 weeks for a clean mid-sized migration.
Is Saleor PCI compliant?
Saleor itself never touches raw card data when you use a tokenised payment app like Stripe — cards are tokenised in the browser by Stripe.js, and only the token reaches your server. This keeps you in PCI DSS SAQ A scope (the easiest). A custom app that handles raw PANs moves you into SAQ D territory.
Next Steps
Now that Saleor is running on your VPS, here are high-value follow-ups:
- Install the Stripe payment app — fastest path to real card payments. Follow the Saleor App Stripe README.
- Fork and deploy the Next.js storefront — the reference at github.com/saleor/storefront is production-ready and designed to be customised.
- Set up search with Algolia or Meilisearch — install saleor-app-search for sub-50ms faceted search.
- Add CrowdSec for runtime protection — see How to Install CrowdSec on Ubuntu 24.04.
- Wire up a monitoring stack — Prometheus + Grafana + Loki for API latency, Celery queue depth, and Postgres connections. See How to Build a Self-Hosted Monitoring Stack on Ubuntu.
- Read the official docs — docs.saleor.io covers architecture, apps, webhooks, and GraphQL patterns in depth.
Ready to launch your headless commerce store?>
Our CloudCore Business plan fits Saleor's full Docker Compose stack comfortably on a single node — API, Dashboard, storefront, Celery workers, Postgres, and Redis, with headroom for traffic and a growing catalog.>
- 8 vCPU cores
- 24 GB RAM
- 400 GB NVMe SSD
- Unmetered 1 Gbps bandwidth
- EU and North American datacenter locations
- 24/7 support and 99.9% uptime SLA>
Deploy Saleor on CloudCore Business — EUR 39.99/month, cancel anytime.