Installation — Linux
Install on Linux (generic)
InstallationHow to take a fresh Linux box from clean install to a running SorterOS UI in your browser. One script, two flags, then the in-app Setup Wizard takes over.
Supported platforms
The installer is written against a freshly installed Debian 12 or Ubuntu 24.04 system (amd64 or aarch64). It also works on Raspberry Pi OS Bookworm on a Pi 5, which is the canonical target.
Prerequisites
- a sudo-capable user account
- a working internet connection
- ~3 GB free disk (Python interpreter,
node_modules, model artifacts)
The one-command install
git clone https://github.com/basicallysource/sorter-v2.git
cd sorter-v2/software
./install.sh
That's it. The installer is idempotent — re-running it on a partially-installed machine just confirms the steps it can skip.
What install.sh actually does, in order:
apt installthe system packages:git,curl,build-essential,libgl1,libglib2.0-0,lsof,v4l-utils.libgl1is what OpenCV needs at import time.- Install a udev rule for Raspberry Pi Pico boards (
/etc/udev/rules.d/99-sorter-pico.rules), so Pico USB access belongs to theplugdevgroup plus the active desktop seat user. The installer adds your user toplugdev; a headless or SSH session needs a logout and login before that takes effect. - Install
uv, the Python toolchain, if it is not already on the box.uvthen fetches the exact Python version the project pins, so you do not needapt python3. - Install Node.js 20.x and
pnpmvia NodeSource.pnpmis what the dev runner invokes, sonpmandyarndo not substitute. - Write
software/.envif there is not one already. - Copy
machine.example.tomltosoftware/machine.tomlif there is not one already. That copy is the machine's own config, and settings you save in the UI are written to it. The example itself is never used directly, so a setting you save never lands in a file git tracks. uv syncinsoftware/sorter/backend/. This is the slow step on a first install, because uv downloads the Python interpreter and resolves the backend dependencies, OpenCV and ONNX Runtime among them.pnpm install --frozen-lockfileinsoftware/sorter/frontend/, which resolves the UI toolchain.
An existing .env or machine.toml is left alone, which is what makes a re-run safe.
Verify the install
When the installer finishes you can start the dev runner:
./dev.sh
./dev.sh starts the Python backend on :8000 and the Vite dev server on :5173, prefixes both log streams, and restarts either one if it crashes. Stop with Ctrl-C.
Then open http://localhost:5173/ (or http://<machine-ip>:5173/ from another device on the same network). You should see the SorterOS UI.
If the UI does not come up, see SorterOS troubleshooting.
The finished result
The SorterOS UI open in a browser, with nothing set up on the machine yet.
Next
Flash the control board before you open the setup wizard. The wizard only lists boards that already answer on USB serial, so a board with no firmware on it does not appear and the wizard says No MCU buses found. Software setup step 2 has the route.
Then First setup in the UI takes the setup wizard step by step.
Installer flags
./install.sh --help
./install.sh # default — install everything in dev mode
./install.sh --as-service # also build the UI and run the Sorter as a systemd service
./install.sh --skip-apt # skip the apt step (useful when packages are already installed)
Running as a systemd service
For an "appliance" install on the Pi 5 that should boot straight into a running SorterOS without anyone touching ./dev.sh:
./install.sh --as-service
In addition to all the steps above, this also:
- runs
pnpm build, which writes the UI as static files tosoftware/sorter/frontend/build/; - substitutes the actual user, paths, and binary locations into the unit templates under
software/systemd/; - writes two units into
/etc/systemd/system/:sorter-backend.serviceand its-devvariant; - runs
systemctl daemon-reload, thensystemctl enable --now sorter-backend-dev.service, so it starts immediately and on every subsequent boot.
It is the -dev unit that gets enabled. The two differ only in how quickly systemd restarts them; enable sorter-backend.service instead if you prefer.
The backend's supervisor serves the UI on port 80, so a service install answers at http://<machine name>/ with no port on the end. It serves the build, so there is no Node process running on the machine, and the page still loads while the backend itself restarts. The :5173 address is the dev runner's, and only applies when you start ./dev.sh by hand. After changing UI code, run pnpm build in software/sorter/frontend/ again; the next page load picks it up.
View the logs with:
sudo journalctl -u sorter-backend-dev -f
Verifying the installer in Docker
The whole install path is reproducibly tested against a fresh Debian 12 container so we catch regressions before they hit a real machine. From the repo root:
software/scripts/test_install_in_docker.sh
This script:
- builds a minimal
debian:12-slimimage whose only pre-installed packages aresudo,curl,ca-certificatesandgit, so everything else has to come frominstall.shitself; - copies the working tree into the container, strips any host-side dev state (
.env,.venv,node_modules), and runs./install.sh; - smoke-tests the backend by importing the trickiest Python dependencies (
fastapi,cv2,onnxruntime,uvicorn,numpy) inside the freshly builtuvenvironment; - runs
pnpm exec vite --versionto confirm the UI toolchain is callable; - runs
systemd-analyze verifyagainst the unit files to catch syntax regressions.
What the Docker test deliberately does not cover: USB serial discovery of Pico boards, camera enumeration, Hailo / RKNN runtimes, anything else that needs physical hardware. Those are exercised on real devices, not in CI.