This procedure targets Ubuntu 24.04 LTS, Docker 28.1.1 and PostgreSQL 17.5, and installs Shuup 3.1.0 by hand instead of through its own Dockerfile. The blocker is a dependency pin: setup.py holds Django to >=1.11,<2.3, a ceiling that predates official support for anything past Python 3.9, so the system’s default Python 3.12.3 has to be routed around entirely. Past that first fix, expect manual work wiring in PostgreSQL, a Docker build that fails outright, and a storefront that is single-vendor unless a separate Multivendor licence is in hand.
Shuup’s install requires Python 3.8 and Django 2.2, not Ubuntu 24.04’s defaults
Shuup 3.1.0’s setup.py (opens in a new tab) pins its web framework dependency to django>=1.11,<2.3, verified against the master branch of shuup/shuup. That ceiling caps the newest allowed Django release at 2.2 — and Django 2.2 only gained official Python 3.9 support in the 2.2.17 patch, per the Django 2.2 release notes (opens in a new tab). It never supported Python 3.10, 3.11 or 3.12.
Shuup’s own PyPI page (opens in a new tab) lists trove classifiers only up to Python 3.8, even though the python_requires string in setup.py just says >=3.6. Classifiers are metadata, not enforcement — pip will not stop you installing Shuup under a newer interpreter. Ubuntu 24.04 LTS’s python3 package (opens in a new tab) resolves to Python 3.12.3 by default, three minor versions past anything Django 2.2 was ever built to run on.
The decision for this install: provision a dedicated Python 3.8 interpreter for Shuup’s virtualenv, and leave the system Python alone. Confirm both numbers before running anything else.
flowchart TD
A["Check python3 --version"] --> B{"3.9 or older?"}
B -->|Yes| C["Use system python3 for the venv"]
B -->|No — e.g. 3.12.3 on Ubuntu 24.04| D["Install python3.8 via deadsnakes or pyenv"]
D --> E["python3.8 -m venv venv"]
E --> F["pip install shuup==3.1.0"]
C --> F
python3 --version
curl -fsSL https://raw.githubusercontent.com/shuup/shuup/master/setup.py | grep -i "django\|python_requires"Expected output:
Python 3.12.3
"django>=1.11,<2.3",
python_requires=">=3.6",You should now see: the system Python at 3.12.3, well past Django 2.2’s supported ceiling — the justification for building a separate Python 3.8 virtualenv in the next section.
Reproduce the migration failure Shuup hits under Ubuntu 24.04’s default Python 3.12
Installing Shuup with the system interpreter does not fail loudly. pip install shuup==3.1.0 inside a plain python3.12 -m venv resolves cleanly and pulls in a Django 2.2.x release — pip’s resolver checks version ranges, not runtime compatibility with the interpreter it happens to be running under. The failure shows up one step later.
Run python manage.py migrate (or Shuup’s own shuup_init management command) against that same environment and it fails with a traceback rooted in a Python stdlib module that Python 3.12 removed. This is not a missing pip package — installing anything more will not fix it. The problem sits inside Django 2.2’s own source, which predates the stdlib deprecations Python 3.10 and later began enforcing.
Root cause: every Django release inside Shuup’s <2.3 pin — 1.11 through 2.2 — was built and tested against Python versions that stopped receiving updates before Python 3.10’s build tooling changes landed. None were ever patched against later CPython removals, because Django’s own support window for the 2.2 series closed in April 2022.
Reproducing this failure matters because it turns an abstract version-pin warning into a traceback the reader will actually recognize if they skip ahead and try the obvious path first.
sequenceDiagram
participant R as Reader
participant Pip as pip resolver
participant Py as Python 3.12 interpreter
participant Dj as Django 2.2 via Shuup's pin
R->>Pip: pip install shuup==3.1.0
Pip->>Dj: resolve django>=1.11,<2.3
Dj-->>Pip: Django 2.2.x installed, no error
R->>Py: python manage.py migrate
Py->>Dj: import Django internals
Dj->>Py: reference a stdlib API removed in 3.12
Py-->>R: Traceback, stdlib module missing
python3.12 -m venv shuup-venv-312
source shuup-venv-312/bin/activate
pip install shuup==3.1.0
django-admin startproject shuupdemo .
python manage.py migrateExpected output:
You should now see: the install step succeed silently, then migrate fail with a stdlib-related traceback — the signal that the default-Python path is a dead end, not a local misconfiguration.
Build a Python 3.8 virtualenv and install Shuup 3.1.0 correctly
Ubuntu 24.04 does not carry Python 3.8 in its default repositories, so you need a separate source for it — the deadsnakes PPA is the common option, though any Python 3.8 build works, including pyenv. Install python3.8 and python3.8-venv from whichever source you choose, then confirm the interpreter resolves before doing anything else.
Shuup depends on packages that compile C extensions during install: Pillow needs JPEG headers, and the PostgreSQL driver installed in the next section needs libpq’s headers. Install build-essential, libjpeg-dev and libpq-dev up front so those builds don’t fail partway through pip install.
Create the virtualenv with python3.8 -m venv, not the system python3, and activate it before installing anything into it. Inside that venv, pip install shuup==3.1.0 resolves Django to the newest 2.2.x release the pin allows, along with the rest of Shuup’s dependency tree. Run pip freeze immediately afterward and keep the output — it is the only record of exactly what got installed, since Shuup itself ships no lockfile.
sudo apt-get update
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y python3.8 python3.8-venv python3.8-dev
sudo apt-get install -y build-essential libjpeg-dev libpq-dev
python3.8 -m venv ~/shuup-venv
source ~/shuup-venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install shuup==3.1.0
pip freeze > shuup-requirements.txt
pip show shuup
python -c "import django; print(django.get_version())"Expected output:
You should now see: pip show shuup reporting version 3.1.0, and Django resolved somewhere in the 2.2.x line — the newest release the <2.3 pin permits.
Skip the reference Dockerfile — it’s pinned to a dead Debian Buster image
Shuup’s own Dockerfile (opens in a new tab) builds FROM node:12.21.0-buster-slim. Buster was Debian 10, and its package repositories moved to Debian’s archive server once the release went end-of-life — the live mirrors no longer serve it. Node.js 12 itself reached end-of-life (opens in a new tab) in April 2022, so the base image is unsupported on two fronts at once.
Run docker build . against the stock Dockerfile and the build fails during apt-get update, before any of Shuup’s own install steps run. Every package URL the container tries to reach returns a 404, because the Buster suite no longer exists at the locations Debian’s package manager expects by default. Docker 28.1.1 does not change this outcome — the failure is upstream repository retirement, not anything specific to the Docker Engine version.
The practical fix for this install: skip the Dockerfile entirely and use the manual venv install from the previous section. If containerising Shuup is a hard requirement, rebasing the image onto a maintained Debian or Ubuntu base and re-pointing every apt-get step is real work, not a one-line patch — budget for it separately from the rest of this install.
git clone https://github.com/shuup/shuup.git
cd shuup
docker build -t shuup-test .Expected output:
You should now see: the build fail with 404s against archived Buster repositories — an expected, unfixable-as-shipped outcome, not a local Docker misconfiguration.
Wire PostgreSQL 17.5 into Shuup’s SQLite-only default settings
Shuup’s reference settings module, shuup_workbench/settings/base_settings.py (opens in a new tab), hardcodes DATABASES to django.db.backends.sqlite3. Nothing in setup.py’s install_requires (opens in a new tab) list installs a PostgreSQL driver — neither psycopg2 nor psycopg2-binary appears anywhere in it, so pip install shuup==3.1.0 alone never gives you a way to talk to Postgres.
Install the driver by hand inside the same venv: pip install psycopg2-binary. The -binary build skips compiling against libpq-dev at install time, though having libpq-dev installed from the earlier section means either build path works.
Provision a PostgreSQL 17.5 database and role with psql, then override DATABASES in a local settings module rather than editing base_settings.py directly — that keeps the change out of Shuup’s tracked files and easy to redo after an upgrade. Point ENGINE at django.db.backends.postgresql and fill in the name, user, password and host just created.
Re-run python manage.py migrate against the new settings module. A successful run against Postgres looks the same from the terminal as a successful SQLite run — no dramatic output — so confirm the switch took effect by checking inside Postgres itself, not by reading the migrate log alone.
pip install psycopg2-binary
sudo -u postgres psql -c "CREATE ROLE shuup_user WITH LOGIN PASSWORD 'changeme-in-production';"
sudo -u postgres psql -c "CREATE DATABASE shuup_db OWNER shuup_user;"DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "shuup_db",
"USER": "shuup_user",
"PASSWORD": "changeme-in-production",
"HOST": "localhost",
"PORT": "5432",
}
}DJANGO_SETTINGS_MODULE=local_settings python manage.py migrate
sudo -u postgres psql -d shuup_db -c "\dt"Expected output:
You should now see: migrate complete without error, and \dt inside shuup_db listing Shuup’s tables — confirmation that the switch off SQLite took effect, instead of a db.sqlite3 file appearing on disk.
Run shuup_init, create a shop, and place one test order
shuup_init is Shuup’s own management command for first-run setup — it walks through creating the first shop, its default currency, and an admin user interactively. Run it against the same settings module used for the Postgres migration, and answer its prompts before starting the server.
Start the app with python manage.py runserver, then load the admin at /sa and the storefront at /. Both should come up without further configuration, since shuup_init already created the shop record that migrate alone does not provide.
Out of the box, what loads is a single-supplier storefront and admin — there is no vendor sign-up flow anywhere in the UI, and no obvious place to add one. Multivendor marketplace features are a paid add-on covers why.
Add one product through the admin, then complete a checkout as a test customer against the storefront. Shuup ships default payment and shipping methods that work without any external gateway configured, which is enough to place one order end to end. Confirm the order appears in the admin’s order list afterward.
The storefront’s default theme is functional rather than polished: it renders correctly and completes a checkout, but reads as a reference implementation rather than something to ship unstyled. That is consistent with a project whose last tagged release predates most of the last several years of front-end tooling updates.
python manage.py shuup_init
python manage.py runserver 0.0.0.0:8000Expected output:
You should now see: one order in the Shuup admin’s order list — confirmation of a working end-to-end storefront on a single-vendor basis.
Measure the install time and resource footprint
Quick-start documentation rarely puts a number on how long an install actually takes, or what it costs in disk and memory once everything is running. Time each phase separately — system and Python 3.8 provisioning, pip install, migrate, shuup_init, and the first completed checkout — with time, rather than eyeballing a stopwatch across the whole session.
Check disk usage of the venv plus its resolved dependencies with du, and check memory use while runserver is active with ps. Both numbers matter for sizing a VM or container before committing resources to an evaluation.
The table below is a template, not a result. This article states what to run and how to read it; it does not report numbers, because no host-specific run has been captured for this piece yet. Fill in the cells on your own machine before treating any of it as a time budget.
{ time bash -c '
sudo apt-get install -y python3.8 python3.8-venv python3.8-dev build-essential libjpeg-dev libpq-dev
'; } 2> phase-provision.log
{ time bash -c '
source ~/shuup-venv/bin/activate
pip install shuup==3.1.0 psycopg2-binary
'; } 2> phase-install.log
{ time python manage.py migrate; } 2> phase-migrate.log
{ time python manage.py shuup_init; } 2> phase-init.log
du -sh ~/shuup-venv
ps -o rss,cmd -C runserverExpected output:
| Phase | Wall-clock time |
|---|---|
| System + Python 3.8 provisioning | [measurement pending] |
| pip install (shuup + psycopg2-binary) | [measurement pending] |
| migrate against PostgreSQL | [measurement pending] |
| shuup_init | [measurement pending] |
| First completed checkout | [measurement pending] |
| Total, clean host to first order | [measurement pending] |
| Resource | Value |
|---|---|
| venv + dependencies disk usage | [measurement pending] |
| runserver peak memory (RSS) | [measurement pending] |
You should now see: every log file populated with a real real/user/sys line once you run this on your own host — replace the pending cells with those numbers before using this as a time budget.
Multivendor marketplace features are a paid add-on, not part of the open-source core
shuup.core ships a single-supplier data model — the Supplier model — not a vendor marketplace. That model is what backs the storefront and admin from the earlier section: one shop, one supplier by default, with no concept of independent vendors managing their own catalogues.
Vendor self-registration, an approval workflow and per-vendor dashboards ship as a separately licensed Multivendor add-on (opens in a new tab), not as a setting inside the open-source package. Shuup’s own guide documentation directs interested users to contact support@shuup.com rather than enable multivendor from anything in the shuup/shuup repository.
That is why nothing resembling a vendor sign-up flow appeared during the install in the previous section — it was never there to find. If a proof of concept depends on vendors self-registering and managing their own listings, that requirement sits outside what pip install shuup gives you. Scope any evaluation around single-vendor use unless a Multivendor licence is already in hand.
flowchart LR
subgraph OSS["shuup.core — open source, OSL-3.0"]
A["Supplier model"]
B["Single shop, single-supplier storefront"]
C["Admin, checkout, order management"]
end
subgraph ADDON["Multivendor add-on — separately licensed"]
D["Vendor self-registration"]
E["Vendor approval workflow"]
F["Per-vendor dashboards"]
end
OSS -. "contact support@shuup.com" .-> ADDON
What the install reveals about Shuup’s project activity in 2026
No commit has landed on shuup/shuup’s master branch (opens in a new tab) since 18 August 2021, and the latest tagged release (opens in a new tab), v3.1.0, shipped the same month. Every pin this article worked around — the Django ceiling, the Buster base image, the missing Postgres driver — traces back to that same stopping point.
The issue tracker (opens in a new tab) currently carries roughly 150 open items, including a stored XSS and an open-redirect report filed as recently as July 2026, neither with a visible maintainer response. That gap matters more for a project with no recent commits than it would for an actively maintained one — there is no scheduled release to fold a fix into.
Shuup ships under the Open Software License v3.0 (opens in a new tab), whose External Deployment clause treats running a modified version as a network service the same way it treats distributing the code — the same source-disclosure obligation applies either way, not only when you hand someone a copy of the software itself.
Budget for dormant-project risk — Python and Django end-of-life exposure, unpatched security reports — alongside the setup work covered above. This article did not test production-scale performance, an upgrade path off Django 2.2, or the paid Multivendor add-on itself; treat all three as open questions for a separate evaluation pass.
Limitations
This procedure covers a single install path on a clean Ubuntu 24.04 host: manual venv, manual Postgres wiring, default theme, one test order. It does not cover production load, horizontal scaling, or any upgrade path off Django 2.2 — none was attempted.
The Docker section identifies why the reference Dockerfile fails and the direction of a fix; it does not walk through rebasing the image onto a maintained Debian or Ubuntu base end to end. The Multivendor add-on was not licensed, installed or tested — everything said about it comes from Shuup’s own public documentation, not from running it.
The timing and resource figures in the measurement section are a template, not results — they were not captured on any host for this piece and must be filled in independently. The open security issues referenced in the final section were confirmed open and unanswered as of the dates given, but were not independently triaged for exploitability or severity.