Tailscale VPN with Dracut Initrd

November 16, 2025

Debian 13 (Trixie) still ships with initramfs-tools by default – the traditional initrd system that prepares your system for boot. But times are changing. With systemd becoming the standard, the boot process is evolving: GRUB is gradually being replaced by systemd-boot, and more and more systems are moving from initramfs-tools to dracut.

So, what makes Dracut special? Unlike traditional initrd systems, Dracut provides a systemd-based early boot environment, making it easier to handle complex setups like networking or disk encryption right from the start.

In this post, I’ll walk you through my setup for getting Tailscale VPN running inside Dracut’s initramfs. The idea is simple: you can unlock your system remotely over a secure VPN connection during boot. This is a game-changer for headless servers, remote machines, or anyone who wants extra flexibility and security during system startup.

This tutorial was tested with Debian 13 (trixie), dracut(108-3) and systemd-boot(257.8).

1. Install the Latest Dracut Version

First, enable the Debian Unstable repositories. If you haven’t done so yet, follow this guide.

Once the repositorie is enabled, install Dracut along with the network module:

sudo apt-get install -t unstable dracut dracut-network

2. Install Required Packages for Initramfs

We need a few essential packages to enable networking and remote access during early boot. These packages will be included in the initramfs:

$ sudo apt-get install systemd-resolved openssh-server

Install Tailscale following the official docs: https://tailscale.com/kb/1031/install-linux

(Optional) 3. Add the Dracut OpenSSH Module

To start a clasical OpenSSH-Server during early boot, we need the Dracut SSH module. Otherwise you can use the tailscale SSH server aswell. Download and install it:

$ wget https://github.com/gsauthof/dracut-sshd/archive/refs/heads/master.zip
$ sudo unzip -j master.zip "dracut-sshd-master/46sshd/**" -d /usr/lib/dracut/modules.d/46sshd

This will place the module in the proper directory so Dracut can include it in the initramfs.

4. Configure Dracut for Tailscale

Now, create a configuration file for Dracut to include the necessary drivers, modules, and items:

/etc/dracut.conf.d/10-tailscale.conf

add_drivers+=" "
omit_dracutmodules+=" network-manager "
add_dracutmodules+=" systemd-networkd sshd systemd-resolved tailscale "
#add_dracutmodules+=" systemd-networkd sshd "
install_items+=" /usr/bin/ping "
kernel_cmdline+=" rd.KEYMAP=de "

5. Create Tailscale Files

/usr/lib/dracut/modules.d/40tailscale/tailscale-up.service

[Unit]
Description=Tailscale Up Service
After=tailscaled.service
Wants=tailscaled.service
DefaultDependencies=no
Before=cryptsetup.target

[Service]
Type=oneshot
EnvironmentFile=/etc/tailscale-initrd
ExecStart=/usr/bin/tailscale up --login-server $TAILSCALE_SERVER --auth-key $TAILSCALE_AUTHKEY --hostname=${TAILSCALE_HOSTNAME} --accept-dns=false --accept-routes=false 
RemainAfterExit=yes

[Install]
WantedBy=sysinit.target

/usr/lib/dracut/modules.d/40tailscale/tailscaled.service

[Unit]
Description=Tailscale node agent
Documentation=https://tailscale.com/kb/
DefaultDependencies=no
Before=cryptsetup.target

[Service]
Type=notify
ExecStart=/usr/sbin/tailscaled --state=mem: --socket=/run/tailscale/tailscaled.sock
ExecStopPost=/usr/sbin/tailscaled --cleanup

Restart=on-failure

RuntimeDirectory=tailscale
RuntimeDirectoryMode=0755
CacheDirectory=tailscale
CacheDirectoryMode=0750

[Install]
WantedBy=sysinit.target

/usr/lib/dracut/modules.d/40tailscale/module-setup.sh

#!/bin/bash

# 2025, Thomas Weigold

# called by dracut
check() {
    require_binaries tailscaled || return 1
    # 0 enables by default, 255 only on request
    return 0
}

# called by dracut
depends() {
    return 0
}

# called by dracut
install() {

    mkdir -p -m 0700 /var/lib/tailscale
    inst_simple /var/lib/tailscale/tailscaled.state /var/lib/tailscale/tailscaled.state
    inst_simple /etc/tailscale-initrd /etc/tailscale-initrd
    inst_simple "${moddir}/start-tailscale.sh" /start-tailscale.sh

    inst_binary /usr/bin/tailscale
    inst_binary /usr/sbin/tailscaled
    inst_binary /usr/sbin/iptables
    inst_binary /usr/sbin/ip6tables
    inst_binary /usr/sbin/nft

    instmods nf_tables nfnetlink nft_chain_net nft_nat nft_ct nft_set_hash nft_counter nft_log nf_defrag_ipv4 nf_defrag_ipv6

    inst_simple "${moddir}/tailscaled.service" "$systemdsystemunitdir/tailscaled.service"
    inst_simple "${moddir}/tailscale-up.service" "$systemdsystemunitdir/tailscale-up.service"
    systemctl -q --root "$initdir" enable tailscaled
    systemctl -q --root "$initdir" enable tailscale-up
    return 0
}

6. Regenerate Initramfs

After configuring Dracut, regenerate the initramfs so your changes take effect:

$ update-initramfs -u -k all

Now, your system is ready to boot with Tailscale and SSH enabled in the initramfs, allowing remote unlocking and secure access even before the main system starts.