Ultralab

Manual · Chapter 3

Every page

Apps and Builds have chapters of their own. This is everything else, in the order the navigation lists it.

Every page in the app has a How this page works button that says the same things in shorter form, including the refusals. It is off by default because a manual that is always showing is one nobody reads.

Overview #

What this lab is, and what it currently holds.

The front page answers "is the lab fine?" without a second click: catalogue counts, spare copies, missing files, free disk, applications chosen versus running, enrolled devices, unread mail, when the last scan and backup were.

There is one search box. It searches the catalogue — filenames and titles — and starts no model, contacts nothing, and sends nothing anywhere.

Read the data root path. Everything Ultralab writes is under it, and nothing escapes it.

Librarian #

The local catalogue of what media you have, and where each copy is.

The Librarian is deliberately narrow: it reads filenames and computes checksums. There is no scraper, no perceptual hashing, no model, and nothing leaves the machine. Jellyfin does the identifying, once files are shelved.

  1. Scan. Walks incoming/ and the media Datasets and records what it finds. Catalogue only — nothing moves.
  2. Join identical bytes. Hashes files and folds byte-identical copies into one entry with several locations. This is exact: same bytes, same file.
  3. Variants. The other kind of duplicate — one film sitting there as a 4K remux, a 1080p rip and a phone copy. Different bytes, so the hash join cannot see them. Ultralab groups them by the names you already wrote and reads the picture size out of the container header. That is reading a file, not analysing a work. It shows you a plan; it does not act.
  4. Shelve for Jellyfin. Moves files into media/Movies, TV and Music by filename, in the layout Jellyfin expects.
  5. Recycle extras. Moves spare copies to backups/recycle. It will not take the last remaining copy of anything, and it shows you what it refused to move and why.
  6. Back up the catalogue, and verify it. A copy nobody has read back is not a backup, so Verify opens one and says whether it would actually restore.

Also here: Forget removes the catalogue entry and leaves the file — the two are deliberately separate. Relink reattaches an entry to a file that moved. Collections group things and move nothing.

The Librarian is not a backup. It is an index. Losing it costs you a rescan; losing your files costs you your files.

Storage #

The disks this host actually has, and the Datasets Ultralab keeps on them.

Every mounted volume with its size, free space and filesystem, and the one holding the lab marked. This is read from the host. Ultralab reports storage and does not manage it — no formatting, no partitioning, no mounting, no ZFS.

A Dataset is a named folder under the data root with a purpose. Create one with a name and a purpose and it becomes a directory applications can be pointed at.

Deleting a Dataset from outside Ultralab does not ask first, and the Librarian will then report those files as missing — which is correct, and is how you find out.

Shares #

Publishing a Dataset over SMB, so other machines on the network can open it.

  1. Publish a Dataset. Ultralab records the grant and exports an smb.conf.
  2. Install Samba from the catalogue. It mounts each published Dataset at its own host path, so one configuration file is true inside the container and out.
  3. Apply on the Linux host, where smbd actually runs. On Windows, Ultralab records the intent and stops.

Only published Datasets reach Samba. An unpublished one is not in the export at all. Ultralab records who may see what; it does not implement SMB.

Health #

Whether the lab is in a state you would want to find it in.

Disk, catalogue, whether incoming exists, when the last scan and backup were, and what the container runtime reports. Each check names its own fix.

The storage truth goes further than free bytes: how much of the disk each Dataset is using, what the host says about the drives, and what would be lost if one died. Reading storage is not managing it.

Standing jobs are the cure for what Health diagnoses. Backups, scans and checks on an interval. They run when Ultralab is open and something is due — there is no daemon, and nothing on the host runs as root waiting for a timer. A schedule that has not run because the app was closed says so rather than pretending. On a Linux lab host you can export a systemd timer that calls the binary directly.

Health reports. It does not repair, and it will never delete anything to free space.

Mail #

Mailboxes between the members of this household — and the question of the internet.

Local mail between members always works and needs nothing from outside. Write to a member; it lands in their mailbox in this lab.

Internet mail is a different thing entirely, and Ultralab checks rather than refuses. It looks up what a receiving server would look up — the reverse DNS of your address, SPF, whether you are in a range providers treat as residential — and tells you what Gmail would make of a message from here.

A home connection is almost certainly not a mail host. Large providers refuse consumer IP ranges without a clean PTR record, and no setting in this or any other program changes that. Internet mail belongs on a VPS with a real reverse-DNS record. The check tells you the truth in advance instead of leaving you to discover it as mail that silently bounces days later.

Network #

Names and routes inside the lab.

Set the hostname and domain — these are what application URLs and every exported configuration use. Add a route to record a host and port you want reachable on the network.

A route is a record and a convenience. It is not a port forward and does not touch your router.

VPN #

How you get back into the lab from outside it.

  1. Enrol a Peer. Name the device. Ultralab generates the key pair and hands you the configuration.
  2. Take the configuration to the device. The server's private key never leaves this machine and is not in the file you are given.
  3. Connect. Your phone is then on your home network, and the applications are reachable exactly where they always were.

Revoking a Peer keeps the record. You need to be able to see that a phone once had access and no longer does; an audit trail whose rows vanish is worthless.

This is the front door. Forwarding an application's admin port instead is the usual way households get breached. Headscale and Tailscale are in the catalogue and sit alongside Peers rather than replacing them.

Identity #

Who has a login here, and what they may do with it.

Three roles. admin installs applications, publishes shares, restores backups and reads the audit. member uses the lab. guest sees less. Passwords are ten characters minimum, hashed, never logged.

Five failed attempts locks that login out. Keep the admin list short.

These logins are local to Ultralab. Jellyfin has its own users; so does Immich. authentik in the catalogue is single sign-on for the other applications and does not replace these until you wire it up.

Edge #

What is allowed to cross the boundary of your network.

Default is deny. Enabling or installing an application does not publish it to the internet, and nothing on the Apps page can change this page.

Add an allow rule only if you mean it: source, protocol, port, and a comment saying why. The comment is the part you will want in a year when you have forgotten.

Export the nftables ruleset and apply it on the Linux host or router yourself. Ultralab writes an export file; it never quietly applies a live ruleset, and on Windows applying is a no-op while the policy still exists and is still exported.

Edge is your household's rule about its own boundary. It is not an intrusion detector.

Plans #

Which of these labs this particular machine can carry.

Ultralab probes the host — memory, cores, disk, whether a container runtime answers, whether there is a hardware video device — and scores each suggested lab against it: Fits, Tight, or Beyond. Memory decides, because memory is what actually kills home servers. Disk, runtime and devices become notes you read.

Measure running Apps asks the runtime what your containers are really using and scores from that instead of the table. Every line then says measured rather than estimated, and the difference is never blurred: if a number does not say measured, nobody has checked it on your machine.

Adopt records intent — each application becomes chosen. Nothing starts. Queue for Sandbox does the same in the trial plane, skipping anything the Sandbox will not take.

A plan is a suggestion. Nothing about adopting one stops you choosing the other fifty.

Audit #

An append-only record of who did what.

Setup, sign-ins, installs and uninstalls, share grants, plan adoptions, Build saves and loads, restores and Sandbox resets — all with the login that did them. Read it after anything surprising.

Append-only within Ultralab. Anybody with the disk can still edit the database: this is a household record, not tamper-proof evidence, and it says so rather than implying otherwise.

The household page #

Not a page in the app — a separate surface for everybody else in the house.

The people who live with the lab are not operators. They want to know whether a film is on the shelf, read a message somebody left them, see that Jellyfin is up, and change their own password — from a phone, in a kitchen, without a desktop session on the lab host.

The same binary serves it:

/opt/ultralab/Ultralab --serve

Loopback only by default. Putting it on your network takes an environment variable and prints a warning naming the edge policy first. It is server-rendered HTML with one stylesheet and no script.

It has no operator half at all. Every control that could change the lab is in the desktop window, not on that page. That is the line, and it is drawn in the code rather than in a convention.


← Chapter 2 · Chapter 4 · Apps and the Sandbox →