Labtris
Install

One line on Ubuntu. One compose file anywhere else.

Three ways in, and one fact about your host picks it. The shell installer wants Ubuntu 24.04 or 26.04 and the ISO brings its own; Docker runs on any distribution, which is also the answer on Ubuntu 26.04 — resolute ships Python 3.14 and does not package Guacamole, so the native install has nothing to build against. No signup, no key, nothing to register.

Pick your host

Whichever you pick: the RDMA lab alone wants Linux 7.1+ on the host, where rdma_rxe gained its per-namespace UDP 4791 socket. Below that it starts and moves no data, and says so on first run. Detail and the check.

On 26.04 there is no RDP console. Ubuntu stopped packaging Guacamole after 24.04, so Labtris builds guacd from source there, and 1.6.0 does not compile against FreeRDP 3 — the only FreeRDP 26.04 ships. VNC, SSH and telnet consoles all work, and QEMU consoles are VNC. It only bites if you connect to a Windows guest over RDP, in which case use 24.04 or the compose install, which pulls a prebuilt guacd with RDP in it.

On a fresh Ubuntu 24.04 or 26.04 host

Runs about five minutes and finishes with the URL to open, where the config lives, and where the generated database password sits. Idempotent — re-run to upgrade.

curl -fsSL https://labtris.com/install | sudo LABTRIS_TOKEN=github_pat_… bash
The token
The repository is private. LABTRIS_TOKEN is the GitHub token from your access invitation; the installer sends it as a header on the clone and writes it nowhere on the host, so the upgrade command needs it again. GH_TOKEN and GITHUB_TOKEN are read as well.
What it does
  1. Refuses to run on anything but Ubuntu 24.04 or 26.04 x86_64 (override with LABTRIS_FORCE_OS=1).
  2. Installs git, curl, ca-certificates.
  3. Clones the repository to /opt/labtris, using the token for that one request.
  4. Hands off to packaging/install-labtris.sh, which sets up Postgres, the service user, systemd units, nginx, everything.
  5. Prints a summary block and writes /root/labtris-install-summary.txt.
Read the script first — recommended
Piping a shell script into sudo bash is a trust exercise. The installer at /install is get.sh from the repository, served here unchanged — kept tiny and readable on purpose. The real installer, packaging/install-labtris.sh, is in the clone it makes; read it there before the hand-off if you want to.
Upgrading

One command, with a backup taken first.

Goes to the latest release, dumps the database before it migrates anything, and tells you whether the result is actually serving. Your labs, pods, images and database are carried across, not replaced.

curl -fsSL https://labtris.com/upgrade | sudo LABTRIS_TOKEN=github_pat_… bash

A specific release instead: … | sudo bash -s -- --to v0.12.0. To see what it would do and change nothing: … | sudo bash -s -- --check. The -s -- matters — without it bash takes the flags for itself rather than passing them on.

What it does, in order
Resolves the newest release tag from the GitHub API, because a --depth 1 clone has no tags locally and sorting them as text puts v0.9.0 above v0.12.0. Then pg_dump to /var/backups/labtris — always, with no flag to skip, because alembic upgrade head is not reversible. Then fetch, check out, reinstall dependencies, migrate, restart. Then it verifies labtris-api and labtris-netd are active and the interface answers, and on failure prints the journal command, the previous commit and the path to the dump.
Verified on a real 0.11.0 install: upgraded to 0.12.0 with its two existing labs still present afterwards, and a restorable 7.5 KB dump on disk.
Docker installs do not use this
A compose deployment is a tag bump. From the directory holding your compose file:
docker compose pull && docker compose up -d
Volumes are untouched, and the API container runs the same migrations on start.
After install

Where to look when something breaks.

Shell installer or ISODocker
Web UIhttps://<host>/ (also :8081, plain HTTP)http://<host>:8080
Config/etc/labtris/labtris.envenvironment: in docker-compose.yml
DB password/etc/labtris/db-passwordset in docker-compose.yml
Health checklabtris system doctordocker compose exec api labtris system doctor
Logsjournalctl -u labtris-api -u labtris-netd -fdocker compose logs -f api netd
Restartsystemctl restart labtris-api labtris-netddocker compose restart

The full handbook lives at docs.labtris.com.