6 minutes
Debian with Encrypted Root and Automatic Unlock via Tang + Clevis
A recipe for installing Debian with a LUKS-encrypted root filesystem and configuring it to unlock automatically at boot using Tang and Clevis (Network-Bound Disk Encryption).
Disclaimer: This process will nuke all data on the drives you target. Back up anything you want to keep before you start.
This works on plain ext4 on LUKS (Part 1 below) and on ZFS on LUKS equally – Clevis binds to the LUKS layer regardless of what is on top.
Why Tang + Clevis?
LUKS encryption normally means typing a password at every reboot. On a headless server that’s a problem. Tang provides key-derivation as a service on your LAN. Clevis binds your LUKS volume to Tang so the server can unlock itself at boot as long as the Tang server is reachable.
With two Tang servers and Shamir’s Secret Sharing (SSS), both must be available for the key to reconstruct – you can lose one without losing the ability to boot.
Part 1: Install Debian with encrypted root
This section uses the standard Debian installer with ext4 on LUKS. If you prefer ZFS on the same LUKS layer (snapshots, compression), follow the ZFS on LUKS article instead, then come back to Part 3 for Tang + Clevis.
Step 1.1: Boot and partition
Boot from the Debian 13 netinst ISO and go through the installer normally until you reach the partitioning step.
Choose Manual partitioning and create three partitions:
| Partition | Size | Use |
|---|---|---|
| 1st | 1024 MiB | EFI (FAT32, mounted at /boot/efi) |
| 2nd | 1024 MiB | ext4, mounted at /boot |
| 3rd | rest of disk | Physical Volume for Encryption |
Step 1.2: Configure encryption
- Select Configure encrypted volumes from the partitioner menu.
- Write changes, then Create encrypted volumes.
- Select the 3rd partition and confirm.
- Set your LUKS passphrase.
Step 1.3: Use the encrypted volume
- Back in the partitioner, navigate into the encrypted volume.
- Select the partition inside it and edit it.
- Set mount point to
/(root). - Finish partitioning and write changes.
When the installer asks about a swap partition, select No if you prefer a swap file (you can add one later).
Step 1.4: Finish the install
Complete the installation normally. Reboot into your new system.
After first boot, check your apt sources:
sudo nano /etc/apt/sources.list
It should look something like this. Adjust as needed:
deb http://deb.debian.org/debian/ trixie main contrib non-free-firmware
deb http://deb.debian.org/debian/ trixie-updates main non-free-firmware
deb http://deb.debian.org/debian/ trixie-backports main non-free-firmware
Part 2: Set up Tang server(s)
Tang is lightweight. It runs as a service on a container or VM on your LAN, or even on a remote VPS.
Step 2.1: Install Tang
On the machine that will host the Tang service:
sudo apt install tang jose
That is it. Tang is a simple HTTP-based service that listens on port 80 by default.
Step 2.2: Verify Tang is working
From another machine on the same network, fetch the advertising key:
curl http://192.168.13.51/adv
You should get a large JSON payload. That means Tang is running.
Step 2.3: Plan your Tang layout
I recommend running at least two Tang servers:
- One on your LAN (e.g. a container on another encrypted server)
- One off-site (a friend’s machine, a cheap VPS, or a Raspberry Pi elsewhere)
Both are used together with Shamir’s Secret Sharing, so if either one
is down, the other still allows unlocking. Adjust port with e.g.
http://203.0.113.42:7500/adv if your remote Tang listens on a
non-default port.
Part 3: Configure Clevis on the encrypted server
Step 3.1: Install Clevis
On your encrypted Debian server:
sudo apt install clevis clevis-luks clevis-initramfs
Step 3.2: Bind LUKS to your Tang servers
Find your LUKS partition:
lsblk
Look for the crypt device or the partition under it. On the example
setup from Part 1, the raw LUKS partition might be /dev/nvme0n1p3 or
/dev/sda3. In this example I use /dev/nvme0n1p3 – change to match
your setup.
Bind against two Tang servers with Shamir Secret Sharing (threshold 2):
sudo clevis luks bind -d /dev/nvme0n1p3 sss \
'{"t":2,"pins":{"tang":[
{"url":"http://192.168.13.51"},
{"url":"http://203.0.113.42:7500"}
]}}'
Clevis will ask for your LUKS passphrase, verify both Tang servers, and ask you to trust them. After confirming, a new LUKS keyslot is created.
Your existing LUKS passphrase still works. The Tang keyslot is an addition, not a replacement.
Threshold explained:
"t":2with two Tang servers means both must be reachable to unlock. If you want either Tang to suffice, use"t":1instead. I prefert:2for security.
Part 4: Network during boot
For Clevis to unlock at boot, the initramfs needs networking. This is the most fiddly part.
Step 4.1: Configure initramfs networking
Edit the initramfs config:
sudo nano /etc/initramfs-tools/initramfs.conf
At the end of the file, add a line like this (adjust for your network):
IP=192.168.13.15::192.168.13.1:255.255.255.0::enp5s0:off:192.168.13.1
Breaking it down:
| Part | Example | Meaning |
|---|---|---|
| Client IP | 192.168.13.15 | Static IP for this server at boot |
| Server IP | (empty) | NFS root server (blank for local boot) |
| Gateway | 192.168.13.1 | Default gateway |
| Netmask | 255.255.255.0 | Subnet mask |
| Hostname | (empty) | Optional |
| Interface | enp5s0 | Your network interface name |
| Autoconf | off | Static IP (use dhcp for DHCP) |
| DNS | 192.168.13.1 | Name server (needed if Tang uses hostnames) |
The double colons are intentional – server-ip and hostname are
left blank in this example.
Find your interface name:
ip a
Step 4.2: CURL hook for remote Tang (optional)
If your Tang server uses a hostname or HTTPS, add a CURL hook so the initramfs can resolve names and fetch over HTTPS.
Create the hook file:
sudo nano /usr/share/initramfs-tools/hooks/curl
Paste this:
#!/bin/sh -e
PREREQS=""
case $1 in
prereqs) echo "${PREREQS}"; exit 0;;
esac
. /usr/share/initramfs-tools/hook-functions
# Copy curl binary
copy_exec /usr/bin/curl /bin
# Fix DNS lib
cp -a /usr/lib/x86_64-linux-gnu/libnss_dns* $DESTDIR/usr/lib/x86_64-linux-gnu/
# Fix DNS resolver
echo "nameserver 1.1.1.1" > ${DESTDIR}/etc/resolv.conf
# Copy CA certificates for HTTPS
mkdir -p $DESTDIR/usr/share
cp -ar /usr/share/ca-certificates $DESTDIR/usr/share/
cp -ar /etc/ssl $DESTDIR/etc/
Make it executable and update initramfs:
sudo chmod 755 /usr/share/initramfs-tools/hooks/curl
sudo update-initramfs -u -k all
Step 4.3: Reboot
sudo reboot
Watch the boot messages. The initramfs will:
- Ask for the LUKS passphrase (fallback if Tang fails).
- Bring up networking.
- Contact the Tang servers.
- Unlock the root partition automatically.
If it works, you have password-less encrypted boot – a server that unlocks itself on your LAN but is useless if stolen.
Notes
- Your original LUKS passphrase is in a separate keyslot. If the Tang servers are unreachable at boot and the initramfs times out, it will fall back to the passphrase prompt. You are never locked out as long as you remember it.
- If you need to rebind after changing Tang keys, use
clevis luks regen -d /dev/nvme0n1p3 -s 1. - Stopping a Tang server prevents any Clevis-bound server from auto-unlocking. Useful as a remote kill switch – if a server is stolen and the Tang server is stopped, the drive stays locked even if booted elsewhere.
Credits and sources
- Debian install on encrypted root: reddit.com/r/debian
- Tang + Clevis for a LUKS encrypted Debian server: OG Self-Hosting
- CURL hook for HTTPS Tang: tqdev.com