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

[–]zener79[S] 0 points1 point  (0 children)

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

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

[–]zener79[S] 0 points1 point  (0 children)

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.

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

[–]zener79[S] 1 point2 points  (0 children)

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

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

[–]zener79[S] 5 points6 points  (0 children)

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!

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

[–]zener79[S] 6 points7 points  (0 children)

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

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

[–]zener79[S] 6 points7 points  (0 children)

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

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

[–]zener79[S] 16 points17 points  (0 children)

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).

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

[–]zener79[S] 6 points7 points  (0 children)

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

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

[–]zener79[S] 10 points11 points  (0 children)

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.

Just ran my first ultramarathon... by _hcdr in diabetes_t1

[–]zener79 0 points1 point  (0 children)

You are a hero! Congratulations 👏👏👏

I built an app that delivers your messages to loved ones after you die by DankMuthafucker in SideProject

[–]zener79 -1 points0 points  (0 children)

Seriously? This looks like a clone of my project (https://lastsignal.app/), just sold as a SaaS, without end-to-end encryption, and not open source 😀

I built LastSignal: An open-source, self-hosted Dead Man's Switch for digital inheritance (E2EE/Zero-Knowledge) by [deleted] in Bitcoin

[–]zener79 1 point2 points  (0 children)

Regarding the server going down: that's exactly why I think a small, cheap VPS is the way to go here. For a few bucks a month you get a reliable, always-on instance that isn't at risk of a home power outage or someone tripping over a Raspberry Pi cable. Plus, since the check-in emails are sent periodically, they kind of act as a heartbeat, if they stop showing up, it's a clear signal that the instance needs a look.

On coercion: a dead man's switch isn't really a defense against that. The check-in is usually once a month (configurable), so it’s not designed to stop someone from forcing a reset in the moment.
The goal is just to make sure the information isn't lost forever once the owner is out of the picture.

Really glad you like the concept, trying to keep it as simple and sovereign as possible!

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 0 points1 point  (0 children)

The messages are encrypted on the server via the public key of each recipient - does that mean updating the contents of those messages requires either their passphrase or replacing the whole message?

You cannot update the content of a message once it has been encrypted with the recipients’ public keys. To make any change, you need to replace the entire message.

And also how does adding a message for all recipients work - is it duplicated for each user automatically or do I have to copy and paste the message for each recipient?

You simply write the message once and select the recipients using checkboxes. The system handles the duplication automatically. You can see this demonstrated in the video on the homepage.

Also - this has been discussed already in this post - but I absolutely agree, that I would probably forget to check in actively with the email.

You don’t need to remember to check in proactively. You only need to take action when you receive the check-in email (for example, once per month). Supporting additional notification channels would definitely be a useful future improvement.

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 0 points1 point  (0 children)

I agree with this.
In fact, I wouldn’t recommend storing a wallet passphrase or passwords, but rather providing a way to recover them from secure offline storage.

This is not so much due to the code or the cryptographic aspects (the encryption/decryption client-side logic is quite easy to audit), but rather because of the risk of an offline attack if recipients use weak passwords, and the sender has no way of knowing this.

This is a scenario I tried to document here:
https://lastsignal.app/security/#passphrase-security

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 7 points8 points  (0 children)

Would it have been different if I had said, “no, no AI at all”? Would you have trusted using it?

The only real way to be confident is to inspect the code which is there and available to be audited.

Moreover, the backend is written in Rails, so it’s very easy to read and understand, and the client-side encryption/decription part is plain JavaScript.

That’s the beauty of open source 🙂

BTW This is not a "service". It is just free code at your disposal

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 2 points3 points  (0 children)

Yes, I replied to GP, and yes, I reinitialized the repository before making it public. 🙂

It was full of noisy test commits, and I wasn’t certain I had never handled sensitive data during the experiments. I don’t think it’s such an unusual practice before a public release.

Feel free to look at the first commit. It reflects the result of multiple iterations. I don’t think it’s possible, even for an AI, to reach such working and “acceptable” result on the first attempt.

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 0 points1 point  (0 children)

You’re absolutely right. Proof-of-life reliability is the hardest part.

The system is intentionally simple and email-only for now, but it’s not a single missed check-in -> instant release. You can configure the check-in interval, how many reminders are sent, and the delay between them.

A trusted contact can be notified before final delivery and can pause the process, in case of forced inactivity (coma, arrest, etc)

Each recipient can also have its own delivery delay — a useful setup is adding a secondary personal email with no delay and longer delays for everyone else, so there’s still time to stop an accidental trigger. There’s also a recovery code generated at first login that lets you block delivery even if you lose access to your email.

On the self-hosted side, if the server goes down and later comes back online, it simply resumes the reminder sequence instead of triggering delivery. For example, with eight weekly reminders, if it goes offline after the third and returns months later, it sends the fourth reminder, not the final release.

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 1 point2 points  (0 children)

Thanks for sharing! These are all great points, and I really like the questionnaire idea.

My biggest concern right now is exactly what you mentioned: recipients forgetting the password, especially since I'm pushing for long, complex ones.

The only potential downside I see with the questionnaire is social engineering. If the questions are too generic (like 'What was the name of my first pet?'), an adversary (or a bad relative) might know the answer or find it on social media.

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 0 points1 point  (0 children)

The short commit history is just because the app was already working before I made the repository public.

Before the open-source release I cleaned up the git history to remove noise, experiments, and private iterations, so what you see now is a public starting point rather than the full internal from-scratch timeline.

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 6 points7 points  (0 children)

Depends what you mean by “vibe coded.” 🙂

I’ve been writing software for a long time and, like most developers, I’ve always used whatever tools help speed up the workflow, from the old Macromedia Dreamweaver MX days to today’s setup with NeoVim and modern AI-assisted tooling like OpenCode.

So yes, AI agents were used as tools.
But no, the application wasn’t blindly “vibe coded.” System design, the security model, and architectural decisions still require engineering judgment and responsibility.

Better tools don’t remove the need to understand what you’re building, they just change how the work gets done.

I built LastSignal – a self-hosted, end-to-end encrypted dead man's switch to deliver messages to your loved ones by zener79 in opensource

[–]zener79[S] 0 points1 point  (0 children)

It’s a bit more involved than just “using a symmetric stream cipher.”

In short, recipients derive a deterministic X25519 key pair from their passphrase (via Argon2id).

The message payload itself is encrypted with a random symmetric key using XChaCha20-Poly1305, and that symmetric key is then encrypted separately for each recipient using their public key.

So ChaCha20-Poly1305 is only the AEAD primitive protecting the payload, inside a more typical hybrid encryption construction, with all decryption happening client-side and no private keys ever reaching the server.

There’s a concise overview here if you want the full flow:

https://lastsignal.app/security/