Ultralab

Manual · Chapter 5

Builds

Get the lab working the way you want. Save it. Then go and build the same job a completely different way, knowing you can have the first one back in a click.

The problem it solves #

You spend an evening getting media and mail working exactly right. A fortnight later you wonder whether a different set of applications would do it better — so you tear the first arrangement down to find out. And now the good setup is gone, and it is gone in the way that matters: not the files, the knowledge. Which applications, on which ports, with which schedules, with that one compose file you wrote at midnight.

A Build is that knowledge, in a file. Save it before you go and play. Put it back when the new idea disappoints. Or keep three of them and switch depending on what you are doing this month.

It is also the honest way to share a working lab. Not "here is my screenshot, good luck" — an actual file that sets somebody else's lab up the same way.

What a Build carries #

  • Every application chosen in each plane — Live and Sandbox, kept separate.
  • The standing jobs and their intervals: scans, backups, verifications.
  • Whether the Sandbox is lending the real library.
  • Any compose files you wrote yourself, with your machine's paths replaced by a token.
  • Settings that are preferences rather than secrets — the timezone, a VPN exit country.
  • A name, a description, and a free-text note about the machine it suits.
  • The Ultralab version that wrote it, and what the whole set costs in memory.

What it never carries #

This is the important half, because a Build is meant to be published. One leaked value is not a bug in a feature — it is your VPN key on the internet.

Never in a BuildWhat happens instead
Generated passwords, database passwords, admin tokens The receiving lab generates its own. They would be worse than useless elsewhere.
A VPN provider's key, a tunnel token, anything only you have The Build names it under "it will ask you for", and carries none of it.
Members, logins, password hashes Nothing. Identity is not part of a setup.
VPN peers and their keys Nothing. Those belong to the devices they were issued to.
Your files, your catalogue, your mail Nothing. A Build is the shape of a lab, not its contents.

The import side does not trust the file either. A hand-edited Build with a key written into it has that key refused and reported, not applied. A Build off the internet is a document off the internet, and it is treated as one.

Saving one #

  1. Get the lab the way you want it. A Build is a photograph, so take it once it works.
  2. Go to Builds and fill in three fields. Name it for what it does — "media and mail" beats "setup 2" the third time you read the list. Say what it is for, and what machine it suits.
  3. Save this setup. The file lands in builds/ under your data root as <name>.ultralab.json.

That file is the deliverable. Copy it, email it, put it on a website.

Putting one back on #

Load makes the lab mean that setup: it chooses everything the Build names and un-chooses everything it does not. That last part is what makes a Build a setup rather than a shopping list.

Untick "Loading un-chooses anything this setup does not include" to merge instead — useful when you want to add somebody else's media stack on top of what you have.

Loading starts nothing and stops nothing. It changes what the lab means to run. Anything currently up that the new setup does not include is named and left running — Ultralab will not tear down a container behind your back. Go to Apps and uninstall it when you mean to.

Equally, the applications the Build just chose are not running yet. Install them from Apps when you are ready.

Things that get skipped, and are always reported rather than silently dropped:

  • An application this catalogue no longer has — renamed or removed since the Build was written. The rest of the setup still lands.
  • Anything the Sandbox will not take, when you are loading into the Sandbox.
  • A value the Build should never have carried.
  • A custom compose file that fails this lab's guard.

Trying one in the Sandbox #

Try in Sandbox queues the whole setup in the trial plane, beside whatever is already running. Live comes out completely untouched.

This is the question you actually have — does this new arrangement work? — asked without giving up the arrangement that does. Run both. Compare them. Then either promote the trial or empty it.

Both planes want memory at the same time, so on a small host expect it to be tight. The Sandbox runs under a ceiling for exactly this reason.

Sharing and receiving #

Giving one away

Take the .ultralab.json out of your builds/ folder and send it. Open it in a text editor first if you like — it is readable, and you should be able to satisfy yourself that nothing of yours is in it.

Taking somebody else's

Two ways, and they end up in the same place:

  • Drop the file into builds/ under your data root and press Refresh.
  • Paste its contents into the box on the Builds page and press Read it and keep it.

There is no fetch-from-a-URL. Nothing about reading a Build reaches the network, and a stranger's file goes through exactly the code that reads your own.

Keeping a Build does not choose anything. It sits in the list until you load it, and the card tells you first: how many applications, what it costs in memory, and anything this lab cannot honour.

The file itself #

Plain JSON, readable, versioned. Roughly:

{
  "Name": "Media and mail",
  "Summary": "Jellyfin with the request page, local mailboxes.",
  "Machine": "N100, 16 GB, one 4 TB disk",
  "Ultralab": "0.9.0",
  "CreatedAt": "2026-09-01",
  "LiveApps": ["jellyfin", "jellyseerr", "samba", "duplicati"],
  "SandboxApps": [],
  "Values": { "ULTRALAB_TZ": "Europe/London" },
  "Needs": [],
  "Schedules": [ { "Task": "Backup", "Enabled": true, "EveryHours": 24 } ],
  "Custom": [],
  "SandboxSeesLiveMedia": false,
  "Format": 1
}

Needs is the honest bit: the names of values this Build will make you supply, carried without any of the values. Somebody reading a Build on a web page can see what it will want of them before downloading anything.

A Build written by a newer Ultralab is read anyway, with a warning that anything this version has never heard of will be ignored.

A Build is not a backup #

A Build describes the shape of a lab: which applications, which schedules, which of your own compose files. It contains none of your photographs, none of your films, none of your documents and none of your mail.

If your disk dies, a Build will rebuild the arrangement in about a minute and will not bring back a single file. The copy that matters is the one you made with Duplicati, on a disk this machine cannot reach — see chapter 6.


← Chapter 4 · Chapter 6 · Keeping it alive →