r/NixOS • • Mar 11 '26

I built a reproducible NixOS deployment system for a multi-PC school lab with no client internet access

Hi everyone,

I’m a teacher, and I’m responsible for a school computer lab with 30 student PCs.

In this kind of environment, reproducibility matters a lot. If even a few machines drift over time, maintenance becomes messy very quickly. Reinstalling systems by hand is slow, error-prone, and hard to repeat consistently even with Ansible.

So over the last month, I built this:

https://github.com/giovantenne/nixos-lab

I’m still a Nix beginner, so this was also a big learning project for me. A lot of the heavy lifting in the early phase came from working with Claude, which helped me get from “I kind of understand the pieces” to a setup that I can actually use and maintain in the real world.

The main challenge was this:

the lab PCs do not have internet access until a user logs into the school network.

That constraint made installation, updates, and recovery much harder than they should have been. So I built a local-first NixOS workflow centered around one master machine (pc99) that acts as the controller for the whole lab.

The setup is built around 31 machines: 1 controller (pc99) + 30 student workstations (pc01–pc30).

It currently uses:

  • Nix flakes as the source of truth
  • UEFI PXE/netboot for the initial installation only (I didn't want to boot every single PC from USB)
  • Harmonia as a local binary cache
  • Colmena for multi-machine orchestration
  • Disko for declarative partitioning
  • Btrfs for snapshots on the student machines

One networking detail that mattered a lot in my case is that the computers have both a DHCP address and a static lab IP. The DHCP address is used to integrate with the school network, while the static IP is used for the internal lab network.

The practical result is that I can now reinstall the whole lab in less than 20 minutes.

What I like most is not just the reinstall speed, but the fact that maintenance is now much more predictable:

  • one declarative source of truth
  • consistent configuration across all machines
  • offline-friendly installation via a local cache
  • easier recovery when a machine needs to be rebuilt

I also added two features that are especially useful in a school lab:

  • student home directories are reset to a clean state
  • snapshots are preserved for recovery

This means the machines stay clean for the next class, while still keeping a recovery path when needed.

The UEFI PXE boot — which was by far the hardest part to build and test — is only used for the initial installation of the workstations. After that, the machines are maintained declaratively through the NixOS configuration, the local binary cache, and multi-machine deployment tools (Colmena).

For experienced NixOS users this may not be especially advanced, but for me it was a big milestone: turning a difficult-to-maintain school lab into something reproducible, recoverable, fun and much less stressful to manage.

I’m sharing it in case it’s useful to anyone managing classrooms, training rooms, public labs, libraries, or other multi-PC environments.

Feedback, criticism, and suggestions are very welcome.

Repo: https://github.com/giovantenne/nixos-lab

251 Upvotes

34 comments sorted by

51

u/_zonni Mar 11 '26

Good job, nix definitely serves this purpose the best

One question, have you considered applying impermanence to don't have unnecessary files on the PCs?

9

u/Nico_Weio Mar 11 '26

Assuming the students don't have privileged access, doesn't resetting their home directories (as mentioned in the post) have the exact same effect?

8

u/VisualSome9977 Mar 11 '26

Not 100% necessarily. It will prevent them from writing arbitrary files but there are still ways an unprivileged user can interact with daemons and such that will modify certain parts of the system state. Not a big issue since usually these files are created to fit a highly specific format, but they can still be created nonetheless. It is for these certain edge cases that I use impermanence at all

2

u/pcs3rd Mar 12 '26

Nix makes it so easy to do that it doesn’t make sense to not to when using disko imo

3

u/VisualSome9977 Mar 12 '26

I don't see what you really lose by doing it without disko except a slightly more annoying install

2

u/VisualSome9977 Mar 12 '26

oh my god I totally misread this LOL ignore my other comment. You are right

11

u/zener79 Mar 11 '26

Thanks!

Yes, I did consider impermanence, and I think it would have been a reasonable option.

For this lab, though, I wanted to keep the system easier to reason about operationally. Right now, student home directories are reset to a clean state, and snapshots are kept for recovery. That already solves most of the “unnecessary files accumulating on lab PCs” problem, while keeping the setup simpler than a fully ephemeral system with selectively persisted state.

45

u/jerrygreenest1 Mar 11 '26

Giving your students linux is already a saints work, but giving them nix is god-like

27

u/mister2d Mar 11 '26

You're a teacher? 🏆

You provision NixOS for your students? ❤️

15

u/VisualSome9977 Mar 11 '26

is there any infrastructure in place for the students to upload contents of their home directory somewhere permanent? You say the home directories get wiped, but I assume students have some things they want to preserve, right? So I am just curious if/how that exists. Really really cool idea though, I wish that the people managing my old school lab had something like this!

17

u/zener79 Mar 11 '26

They are required to use Git for programming, which is a win-win:
they learn a solid workflow, and the PC stays clean :-)
For other types of documents, they use Google Drive (the school uses Google for Education, and each student has an account).

6

u/VisualSome9977 Mar 11 '26

I see, that's nice. Do you manage your own centralised git server for them, or do they upload to GitHub or some other alternative?

9

u/zener79 Mar 11 '26

They can choose whichever server they prefer, but almost everyone uses GitHub.

5

u/philosophical_lens Mar 11 '26

Thanks for sharing! I'm curious to learn more about your snapshot and recovery implementation with btrfs please.

8

u/zener79 Mar 11 '26

Thanks!
The Btrfs part is actually pretty simple in this project.

The disk layout is declared with Disko, and on the student machines (put also on PC99) I create three Btrfs subvolumes:

The interesting part is modules/home-reset.nix. At activation time, I generate a clean template for the informatica user under /var/lib/home-template/informatica, including Git config, XDG dirs, and preloaded VS Code extensions. Then, on every boot, a oneshot systemd service called home-reset runs before the display manager and resets /home/informatica from that template.

Before replacing the home, that reset flow keeps snapshots of the previous state in /var/lib/home-snapshots, and the repo currently keeps the last 5 versions there. The idea is: every class starts from a clean student environment, but I still have a practical recovery path if I need to recover files from a previous session.

If you want to look at the code, the main places are:

  • disko-uefi.nix for the Btrfs subvolumes
  • modules/home-reset.nix for the template creation + boot-time reset service
  • scripts/home-reset.sh for the actual reset/snapshot logic

7

u/artnoi43 Mar 11 '26

Awesome. But damn I’d have made the control machine pc0 and not pc99 lol

8

u/zener79 Mar 11 '26

Yes, you're right! It bothers me too 😂

But the PC number will become the last octet of the static IP address, and it can’t be 10.22.9.0.

So I used the last available two-digit number (for simplicity) 10.22.9.99
Terrible choice!

3

u/landonr99 Mar 11 '26

What do students do on NixOS? Also curious what DE you have them using

9

u/zener79 Mar 11 '26

They mostly use VS Code, Chromium, Docker, and Git. I chose GNOME as the desktop environment since they are already familiar with it

2

u/4DBug Mar 11 '26

may I ask what grade(s) you teach?

3

u/zener79 Mar 11 '26

I teach students in the final year of high school in Italy, so they’re usually around 18–19 years old.

2

u/Pixelgordo Mar 12 '26

Nice! You got your "Centro Di Gravità Permanente" for the lab. Bravissimo!

1

u/Tiny_Cow_3971 Mar 11 '26

Exactly what I will need sometime in the future. Great!

1

u/4DBug Mar 11 '26

This is wonderful I would love to be able to manage something like that.. I love nix

2

u/pookieboss Mar 11 '26

Incredible use case of NixOS. Bravo

1

u/TDR-Java Mar 13 '26

Legendary work my man

1

u/LippyGrips Mar 14 '26

You're already using btrfs. Can't you just keep one machine up to date and send fresh snapshots to the rest? It's been a while since I used btrfs, but that's how I'd do it with zfs.

1

u/zener79 Mar 14 '26

Thanks for the suggestion! btrfs send/receive is great, but since I'm already using Harmonia as a local binary cache and Colmena for deployment, it's actually redundant.

My current stack already avoids downloading from the internet (only the master node does) and handles the activation of new generations and bootloader updates atomically on all 30 machines. Using Btrfs for the /nix/store would be a bit more manual and rigid if I have slight hardware variations.

I still use Btrfs snapshots, though! I use them to 'reset' the students' /home at every reboot. It's the perfect combo.

1

u/LippyGrips Mar 14 '26

I actually meant deploying the entire system this way, not just the Nix store. But it sounds like you already have a good setup that works, which is the important thing.

1

u/zener79 Mar 14 '26 edited Mar 14 '26

I totally get it. That's basically a modern, incremental version of disk imaging, similar to what I used to do with Clonezilla (and then Ansible to manage the lab) in the past.

However, with Nix/Colmena approach I'm basically trading the raw speed of block transfers for the surgical precision of Nix deployments

1

u/freekarl408 Mar 11 '26

that’s fkn awesome 👏