Airgap (Skíðblaðnir) — for idiots
Class:
idiot. Every step, nothing assumed. Goal: from a cold shell, seal nornir + one product on a connected computer, carry it across an air gap, and get nornir running on a computer with no internet. If you already know your way around a terminal, readairgap-guide.mdinstead — this one spells out every keystroke. The why is inairgap-reasoning.md.
What you need first
- Two computers. Call them BUILD (has internet) and TARGET (no internet — the air-gapped one).
- A USB stick (or any way to copy a file from BUILD to TARGET).
- A terminal on each (the black window where you type commands). You press Enter after every command.
nornirinstalled on BUILD. Check it — type and press Enter:
nornir --version
If that prints a version, you are good. TARGET does not need internet, but it does need the nornir binary — you will carry that over too (it can ride inside the bundle).
PART A — on BUILD (the computer with internet)
Step 1 — open a shell and make a workspace folder
Type each line, pressing Enter after each:
cd ~
mkdir -p airgap-demo
cd airgap-demo
Step 2 — lay out the "staging tree"
The staging tree is just a folder whose shape becomes the bundle. Make the folders:
mkdir -p stage/linux-x86_64
mkdir -p stage/manifests
Now copy the program(s) you want to ship into stage/linux-x86_64/. For example, if your built nornir-server binary is at target/release/nornir-server:
cp target/release/nornir-server stage/linux-x86_64/nornir-server
Copy any other product the same way (e.g. holger). One file per program. If you do not have a real binary yet, make a fake one just to see the flow:
echo "pretend-binary" > stage/linux-x86_64/nornir-server
Step 3 — seal it into ONE bundle file
Type and press Enter (pick today's date as the version, 8 digits YYYYMMDD):
nornir airgap pack ./stage --out lake-20250505.tar.zst --version 20250505
You should see a line like:
✓ packed 1 entries → lake-20250505.tar.zst (root sha256 abc123… , VERSION beside)
That created three things in the folder:
lake-20250505.tar.zst— the sealed bundle (this is the important one).lake-20250505.tar.zst.manifest.json— its "packing list" with a hash of every file.VERSION— a tiny text file with20250505in it.
Write down the root sha256 value it printed (the first 16 characters are fine) on a sticky note. You will check it on the other side.
Step 4 — copy the bundle onto the USB stick
Plug in the USB stick. Find where it mounted (often under /media/<you>/... or /run/media/<you>/...). Copy both the bundle and its manifest:
cp lake-20250505.tar.zst /run/media/$USER/USB/
cp lake-20250505.tar.zst.manifest.json /run/media/$USER/USB/
Then eject it safely (use your file manager's eject button), unplug it, and walk it over to TARGET.
PART B — on TARGET (the air-gapped computer, no internet)
Step 5 — plug in the USB and copy the bundle onto TARGET
Open a terminal on TARGET. Make a folder and copy both files off the USB stick:
cd ~
mkdir -p airgap-in
cd airgap-in
cp /run/media/$USER/USB/lake-20250505.tar.zst .
cp /run/media/$USER/USB/lake-20250505.tar.zst.manifest.json .
Step 6 — VERIFY the bundle before trusting it
This checks that nothing got corrupted or tampered with on the way over. Type and press Enter (paste the full sha you wrote down after --sha256, or leave that part off to just check the internal packing list):
nornir airgap fetch lake-20250505.tar.zst
- Green / "ok" → good, keep going.
- Red / a non-zero error → STOP. The file is broken or was changed. Re-copy it from BUILD and try again. nornir will refuse to install a bad bundle on purpose.
Step 7 — install a component (this needs admin/root)
Installing creates a system user, writes a service, and unpacks the program. That needs sudo (admin). Type and press Enter:
sudo nornir airgap component add nornir-server --bundle lake-20250505.tar.zst
Not sure what the name should be? Ask nornir to list what it knows:
nornir airgap component status
That prints the components it can install (like nornir-server, holger, tunnr). Use one of those names.
Want to see what it WOULD do without touching anything? Add --dry-run (no sudo needed):
nornir airgap component add nornir-server --bundle lake-20250505.tar.zst --dry-run
That just prints the service file it would write.
Step 8 — start everything in the right order
If you shipped more than one product, they might depend on each other. Make a small lake.json describing them (copy the example from airgap-guide.md and edit the names), then type and press Enter:
nornir airgap start lake.json
It prints the "waves" — which product starts first, which waits for it — and records what happened. Read the record back any time:
nornir airgap events
Step 9 — check it is actually running
Ask nornir whether the service is up:
nornir airgap component status nornir-server
An active service means you did it: nornir is running on a computer with no internet, installed entirely from the one file you carried over.
If something goes wrong
- "verify FAILED" on Step 6 → the copy got corrupted. Re-copy the bundle from BUILD. Do not force past it.
- "needs root" / "permission denied" on Step 7 → you forgot
sudo. Putsudoat the front. - "unknown component" → run
nornir airgap component statusand use exactly one of the names it lists. - You have no internet on TARGET and something tries to download → it should not. The whole point is that everything is inside the bundle. If nornir asks for the network on TARGET, you are missing a file from the bundle — go back to BUILD and add it to the staging tree in Step 2, then repack.
That is the whole journey: seal one file on BUILD → carry it → verify → install → start on TARGET. No internet on the far side, ever.