Configuring NBDE on Fedora with Clevis and Tang: Automatic LUKS Unlocking on Your Local Network

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

Running a Fedora server with LUKS-encrypted drives is something I set up from day one. Protecting data against physical theft is a baseline requirement — non-negotiable. But a problem surfaces at reboot time: you have to manually enter the passphrase via console or SSH with dropbear, which is a real pain when no one is around. After some research, I discovered that NBDE with Clevis + Tang solves exactly this problem — automatically unlocking the drive when the machine boots within a secure local network.

I ran this setup on my homelab for 6 months, then rolled it out to 2 production servers. This article documents exactly what I did, including the spots where I stumbled.

How NBDE Works

NBDE (Network-Bound Disk Encryption) is a “network-bound” disk encryption model — the drive can only unlock itself when the machine is connected to a local network that has a Tang server. Take the machine off the network, or unplug the cable — the drive remains fully protected.

Three main components:

  • Tang: A simple HTTP server that provides key material for unlocking the drive. Tang stores no client secrets — designed around the McCallum-Relyea protocol.
  • Clevis: A client-side tool that integrates with LUKS. Clevis “pins” the drive to a Tang server (or TPM, or a combination of both) and handles automatic unlocking at boot.
  • LUKS: Linux’s disk encryption mechanism, supporting multiple keyslots — Clevis adds a new keyslot without touching the original passphrase.

An important point to understand: Tang doesn’t know your LUKS passphrase. The unlock process uses ECDH (Elliptic Curve Diffie-Hellman) — Tang only needs to “exist and respond” on the network. No secrets stored, no centralized point of leakage.

Setting Up the Environment

I’m using 2 machines on the same LAN:

  • Tang server: Fedora Server, IP 192.168.1.10 — can be a Raspberry Pi, VM, or an old machine sitting on the local network.
  • Client: Fedora Workstation/Server with a LUKS-encrypted drive, IP 192.168.1.20.

Requirements: Fedora 36+ (I’m using Fedora 40), a pre-existing LUKS-encrypted drive, 2 machines on the same subnet.

Installing the Tang Server

On the Tang server machine (192.168.1.10):

sudo dnf install tang -y
sudo systemctl enable --now tangd.socket

Tang runs via socket activation — no persistent service needed, it only “wakes up” when a request comes in. Listens on port 7500 by default.

Open the firewall for Tang:

sudo firewall-cmd --add-service=tangd --permanent
sudo firewall-cmd --reload

From the client machine, quickly test that Tang is alive:

curl http://192.168.1.10:7500/adv

Getting a JSON response with a payload field means Tang is running correctly. This is the advertisement — the Tang server’s public key that Clevis uses for binding.

Getting Tang’s Thumbprint

The thumbprint is used to verify the Tang server during binding, preventing man-in-the-middle attacks. Run on the Tang machine:

sudo tang-show-keys

Output is a base64 string, something like: 3DqH5h1TxhJGRD9pZm.... Save it — you’ll need it at the bind step.

Installing Clevis on the Client

On the client machine (192.168.1.20), install Clevis and the dracut module to integrate into initramfs:

sudo dnf install clevis clevis-luks clevis-dracut -y

Binding the LUKS Drive to Tang

Identify the LUKS partition:

lsblk -f | grep crypto_LUKS

Assuming the partition is /dev/sda2. Bind it to Tang, replacing the thumbprint with the value from the previous step:

sudo clevis luks bind -d /dev/sda2 tang '{"url":"http://192.168.1.10:7500","thp":"3DqH5h1TxhJGRD9pZm"}'

Clevis will ask for the LUKS passphrase to add a new keyslot — enter it and you’re done. The original passphrase remains intact — Clevis only adds a new slot, it doesn’t remove the old one.

Check the keyslot after binding:

sudo cryptsetup luksDump /dev/sda2 | grep -E "Keyslot|ENABLED"

Regenerate initramfs — The Step Most Often Forgotten

After binding, regenerate initramfs immediately — skip this step and Clevis won’t run at boot:

sudo dracut --force

I hit exactly this snag the first time — bound the drive but forgot to run dracut, rebooted and still had to manually type the passphrase as before. Took 30 minutes of debugging to figure it out.

Configuring Network in initramfs

There’s a subtle issue here: the client needs network to contact the Tang server, but the root filesystem is locked by LUKS — it needs to be unlocked first. Classic chicken-and-egg. Clevis-dracut solves this by embedding the network stack directly into initramfs.

Add kernel parameters to enable networking in initramfs (DHCP):

sudo grubby --update-kernel=ALL --args="rd.neednet=1 ip=dhcp"

If using a static IP (common with servers):

sudo grubby --update-kernel=ALL --args="rd.neednet=1 ip=192.168.1.20::192.168.1.1:255.255.255.0:myhostname:eth0:none"

Regenerate initramfs once more to pick up the new configuration:

sudo dracut --force

Testing Before the Real Reboot

Manually unlock to confirm binding — no passphrase needed if Tang is running:

sudo clevis luks unlock -d /dev/sda2

If it doesn’t ask for a passphrase, the setup is correct. At this point it’s safe to do a real reboot.

Handling Tang Server Unavailability

The question I worried about most before production deployment: if the Tang server goes down, can the client still boot?

The answer: yes, but you’ll need to manually enter the passphrase. Clevis tries to contact Tang during initramfs, times out after ~30 seconds, then falls back to a LUKS passphrase prompt. The original passphrase still works normally.

Waiting 30 seconds staring at a black screen when Tang is down is pretty annoying. Shorten the timeout:

sudo grubby --update-kernel=ALL --args="rd.clevis.tang.timeout=10"
sudo dracut --force

Rotating Tang Keys Periodically

After about 6 months, you should rotate the Tang keys to reduce risk if a key is ever compromised. Fedora 40 uses Tang 14+ — the tangd-keygen command no longer exists. Keys are automatically generated when the service first starts and stored at /var/db/tang/.

Add a new exchange key using jose (bundled with the tang package), then reload the service:

# View current keys
ls /var/db/tang/
sudo tang-show-keys

# Generate new exchange key
sudo jose jwk gen -i '{"alg":"EC","crv":"P-521","key_ops":["deriveKey"]}' \
  | sudo tee /var/db/tang/rotate-exc.jwk > /dev/null
sudo systemctl reload tangd.socket

On each client, re-bind with the new key (replace SLOT with the keyslot number Clevis is using):

# Check which slot Clevis is using
sudo clevis luks list -d /dev/sda2

# Re-bind that slot
sudo clevis luks regen -d /dev/sda2 -s SLOT
sudo dracut --force

The old key remains in /var/db/tang/ until you manually delete it — a safety net so clients that haven’t re-bound yet continue to work.

What I Learned After 6 Months

The beauty of NBDE is that you stop thinking about it once the setup is done — the server reboots after kernel updates without needing to stay up until midnight to type a passphrase. This is what I’m most satisfied with operationally.

A few takeaways from real-world experience:

  • Tang server must boot before the client: If both reboot simultaneously after a power outage, the client will timeout and need a manual passphrase. A UPS for the Tang machine is a worthwhile investment.
  • Monitor Tang uptime separately: I added a simple HTTP check in Uptime Kuma — if Tang goes down I get an immediate alert, so no client server reboots at that moment.
  • Tang must be a separate machine: Seems obvious but people still ask. Tang and the client on the same machine completely defeats the purpose of encryption.
  • Test the fallback periodically: Every quarter I shut down the Tang server and reboot the client to confirm the fallback passphrase still works. Don’t wait until you actually need it to discover you’ve forgotten the passphrase.

Conclusion

NBDE with Clevis + Tang lets you have both at once: strong disk encryption and no passphrase typing on every reboot. The tradeoff is dependence on Tang server availability — but the fallback passphrase still works, so this risk is manageable.

The entire stack lives in Fedora’s official repos — no third-party repos needed, unlike many DIY alternatives.

Share: