Manual · Chapter 2
Getting started
Ultralab is one file. There is no installer, no runtime to fetch first, and no account. The only real decision is which machine runs the containers.
Decide the shape first #
There are two computers in this story and they are often the same one:
- The operator machine, where you sit and click things.
- The lab host, which actually runs the containers and holds the disks.
Pick the row that matches you:
| What you have | Do this |
|---|---|
| A Linux machine that will be the lab | Run the Linux binary on it. Everything works end to end. |
| A Windows PC, and a separate Linux lab | Run the Linux binary on the lab. Use the Windows one only if you want a window on your desk as well — it will render compose files and hand you commands rather than starting anything. |
| Only a Windows PC | Use the WSL script. It builds you a real Linux lab host inside Windows and puts Ultralab on it. |
Why Windows cannot finish the job. Containers are a Linux thing.
Ultralab on Windows does everything except the final docker compose up: it
renders the exact file, shows you the exact command, and stops. That is deliberate — it
would rather hand you a command you can read than pretend to have done something it
has not.
Install on Windows #
- Download Ultralab-<version>-win-x64.exe from the download page.
- Check the hash. In PowerShell, in the folder you downloaded to:
Compare it with the one on the download page.Get-FileHash .\Ultralab-0.9.0-win-x64.exe -Algorithm SHA256 - Put it somewhere sensible —
C:\Ultralab\or your desktop. It is self-contained; it does not care where it lives. - Run it. Windows will say it does not recognise the program, because it is not code-signed. More info → Run anyway.
Install on Linux #
On the machine that will run the containers:
# Fetch it (or copy it across however you like)
curl -LO https://downloads.jjultralab.uk/0.9.0/Ultralab-0.9.0-linux-x64
# Check it against the hash on the download page
sha256sum Ultralab-0.9.0-linux-x64
sudo mkdir -p /opt/ultralab
sudo mv Ultralab-0.9.0-linux-x64 /opt/ultralab/Ultralab
sudo chmod +x /opt/ultralab/Ultralab
# Does it work at all?
/opt/ultralab/Ultralab --smoke # prints: ok
If the machine has a screen, just run /opt/ultralab/Ultralab and the window
opens. If it does not:
# Create the first login without a display
sudo ULTRALAB_LOGIN=jj ULTRALAB_NAME=Jamie /opt/ultralab/Ultralab --provision
# Serve the household page (loopback only unless you say otherwise)
sudo /opt/ultralab/Ultralab --serve
The password is never a command-line argument. --provision
asks for it on the terminal, or reads ULTRALAB_PASSWORD from the environment.
Arguments end up in your shell history and in the process list where every other account on
the machine can read them.
You also need Docker
Ultralab does not bundle a container runtime. On the Apps page, step 1 checks for Docker or Podman; if it is missing on a Debian, Ubuntu, Fedora, RHEL or Arch host, Ultralab will write your distribution's own documented package steps to a file and offer to run it. Nothing is piped from the internet into a shell — you can read the file first, and you should.
Windows as the lab host #
If Windows is all you have, the scripts archive on the download page contains
setup-wsl-lab-host.ps1. It builds a genuine Linux lab host inside Windows:
WSL2, a distribution, systemd turned on, Docker installed and running, the Linux binary in
/opt/ultralab, and the lab provisioned.
# In an elevated PowerShell, with the Linux binary on your Desktop
.\setup-wsl-lab-host.ps1
It asks for the steward's password when the lab actually needs creating, and passes it to the binary through the environment rather than through a shell, so a password with a quote or a semicolon in it is just a password. Every step that changes the host fails loudly rather than reporting success it has not earned. Run it again any time; it picks up where it stopped.
WSL is a real trade-off. It is genuinely convenient and genuinely worse than a separate machine: it stops when Windows stops, disk performance across the Windows boundary is poor, and a Windows update can reboot your lab. Good for learning and for trying things. For photographs you care about, use a machine that stays on.
The first run #
The first time it opens, Ultralab asks you to create the steward — the first admin. Ten characters minimum, hashed with PBKDF2, never logged and never written to a compose file. Five failed sign-ins locks that login out.
There is no password reset, because there is nobody to prove who you are to. If you lose it, you lose the Ultralab database — the catalogue and the settings. Your files are untouched; you would provision a new lab and scan them again.
Then it drops you on Overview. Before you touch anything, click How this page works in the top right. Every page has one. It says what the page is for, the moves in the order they happen, and — the useful half — what the page will refuse to do.
The words it uses #
Ultralab is fussy about vocabulary, because most confusion in this hobby is two things sharing a word. These are worth five minutes.
| Word | Means | Not |
|---|---|---|
| Dataset | A named folder under the data root with a purpose: media, photos, mail, backups, share. | A partition, a ZFS dataset, a disk. |
| Member | A person with a login here. admin, member or guest. | A user of Jellyfin — those are separate. |
| App | A packaged service Ultralab can install, with whatever companions it cannot boot without. | A plugin. Ultralab never reimplements the application. |
| Plane | One compose project. Live is the household's; Sandbox is the trial one. | A mode or a profile. It is a real boundary. |
| Chosen | A ticked box. Intent, and nothing else. | Running. Ultralab never blurs these two. |
| Running | A container the runtime reports as up. | Chosen. |
| Pin | The exact image digest Ultralab resolved and now writes. | The tag. A tag is how the pin was found; it can move, a digest cannot. |
| Value | A setting the compose file needs. Passwords are generated; a few things only you have are asked for by name. | A secret, unless it is one. |
| Peer | A WireGuard device enrolled to reach the lab. | A forwarded port. There are none. |
| Edge | The policy for what may cross the boundary of your network. Default deny. | A firewall product, a SIEM, an intrusion detector. |
| Build | A saved setup: the Apps chosen, the schedules, your own compose. Swappable and shareable. | A backup. It saves the shape of a lab, never the files. |
| Librarian | The local catalogue of media: scan, exact duplicates, shelve, recycle spares. | A scraper. Nothing is identified, tagged or sent anywhere. |
Where everything lives #
Everything Ultralab writes is under one directory, the data root:
| Windows | %LocalAppData%\Ultralab |
| Linux | ~/.local/share/Ultralab |
| Either, overridden | $ULTRALAB_DATA |
Inside it:
<data root>/
ultralab.sqlite the catalogue, members, settings, audit
incoming/ drop new files here; Scan picks them up
media/
Movies/ TV/ Music/ Books/ Podcasts/
photos/ Immich and the like
backups/
recycle/ where spare copies go, never deleted outright
share/ general file sharing
compose/
docker-compose.yml the file Ultralab renders and applies
.env generated passwords — kept private, never in the YAML
custom/ compose files you wrote yourself
builds/ saved setups (.ultralab.json)
sandbox/ the entire trial world, in miniature
To put the lab on a bigger disk, mount that disk on the host and point
ULTRALAB_DATA at it. Ultralab will not move or mount anything itself.
Notice sandbox/. It has its own incoming, its
own media, its own database — a whole second lab, nested inside the first. That
is what makes the Sandbox real rather than a label: a trial application is pointed at
that folder and has no path to anything above it.
Your first hour #
If you want a route through rather than a tour, do this:
- Plans. Let it profile your machine. It will tell you which suggested labs fit and which are beyond it. Do not adopt one yet — just read.
- Apps → step 1. Check the runtime. If Docker is missing and you are on Linux, let it write the install steps, read the file, run it.
- Apps → aisles. Click Where households start. Read three cards. Click What will this do? on one of them and read the whole thing once, so you know what the panel tells you.
- Sandbox something. Pick anything in Safe to try now and press Sandbox. It cannot touch your files. Open it, poke it, then Empty it.
- Storage. Look at your Datasets. Put a film or a few photographs into
incoming/. - Librarian → Scan. Watch it find them. Then Shelve and
see them land in
media/Movies. - Install Jellyfin properly, point it at those folders, and watch something.
- Health. Turn on the backup schedule before you have anything to lose.
- Builds. Save what you have as first setup, so you can always get back to a lab that worked.