I am trying to get ssh access with initrd so I can remotely unlock luks if away from my machine and a reboot is required. I am following this guide Early boot remote decryption on NixOS and below is my configuration
boot.loader = {
systemd-boot = {
enable = true;
configurationLimit = 10;
editor = false; # Disable editing boot entries for security
};
efi.canTouchEfiVariables = true; # Usually true for most systems
};
SSH for initrd
boot.initrd = {
network.ssh = {
enable = true;
# You can use a different port if desired. I would advise against using 22 as this will conflict with your normal SSH access.
port = 2222;
# Remember this is stored in plaintext on the boot partition do not re-use existing keys!!!
hostKeys = [ "/etc/ssh/initrd_ssh_host_ed25519_key" ];
# Paste the Public Key we generated earler.
authorizedKeys = [ "ssh-ed25519 [myactualkey] root@nixos" ];
};
# Set up a shell prompt that will ask for the LUKS passphrase
network.postCommands = let
# Replace this with your LUKS device path !!!
# See previous step
disk = "/dev/disk/by-uuid/luks-f49ab22c-ce52-4505-a24b-b29a0c373dd6";
in ''
echo 'cryptsetup open ${disk} root --type luks && echo > /tmp/unlocked' >> /root/.profile
echo 'Starting SSH server for remote LUKS decryption...'
'';
# Block boot until the LUKS device is unlocked
postDeviceCommands = ''
echo 'Waiting for root device to be unlocked...'
mkfifo /tmp/unlocked
cat /tmp/unlocked
'';
};
I have added luks support for initrd boot.initrd.luks.forceLuksSupportInInitrd = true;
Have added kernel modules:
boot.initrd.availableKernelModules = [
"uhci_hcd" # USB 1.1 Host Controller Interface driver
"ehci_pci" # USB 2.0 PCI-based Host Controller Interface driver
"ahci" # Advanced Host Controller Interface for SATA devices
"virtio_pci" # PCI bus support for virtio
"virtio_scsi" # SCSI device support for virtualized environments
"sd_mod" # SCSI disk driver for most storage devices
"sr_mod" # SCSI CD-ROM/DVD driver
"virtio_net" # Primary network driver
"virtio" # Base virtualization support
"net_failover" # Network failover capability
"failover" # Base failover functionality
];
boot.initrd.kernelModules = [
"virtio_net" # VirtIO network driver for paravirtualized environments
"e1000" # Intel Gigabit Ethernet driver for emulated network interfaces
];
Host rebuilt fine, however there is no ssh server running on 2222 as expected, I have ran an NMAP scan and it’s not present. If I manually jump into the console and enter my LUKS password it hangs on this stage, which is expected as it’s waiting for the unlock signal from the script…I think.
Hi this was massively helpful and I managed to get it resolved by incorporating what you shared with some other elements.
boot.initrd = {
# Enable systemd in the initial ramdisk environment
systemd = {
enable = true;
# Specify which programs need to be available during early boot
initrdBin = with pkgs; [
cryptsetup # Tool needed for unlocking LUKS encrypted drives
];
# Configure networking using systemd's network manager
network = {
networks = {
"enp6s18" = {
matchConfig = {
Name = "enp6s18"; # Matches the network interface by name
};
networkConfig = {
DHCP = "yes"; # Enable DHCP to automatically get an IP address
};
};
};
};
# Define the service that will handle LUKS unlocking
services = {
unlock-luks = {
description = "Unlock LUKS encrypted root device";
# Make sure this service runs during boot
wantedBy = [ "initrd.target" ];
# Wait for network to be ready before trying to unlock
after = [ "network-online.target" ];
# Must unlock before trying to mount the root filesystem
before = [ "sysroot.mount" ];
# Ensure necessary tools are available
path = [ "/bin" ];
# Configure how the service behaves
serviceConfig = {
Type = "oneshot"; # Service runs once and exits
RemainAfterExit = true; # Consider service active even after it exits
SuccessExitStatus = [ 0 1 ]; # Both 0 and 1 are considered success
};
# The actual commands to unlock the drive
script = ''
echo "Waiting for LUKS unlock..."
# Try to unlock the encrypted drive
# The || true ensures the script doesn't fail if first attempt fails
cryptsetup open /dev/disk/by-uuid/[UUIDofLUKS] root --type luks || true
'';
};
};
};
# Configure SSH access during early boot
network = {
enable = true;
ssh = {
enable = true;
port = 2222; # Use a non-standard port for security
# Only allow running the unlock service when connecting via SSH
authorizedKeys = [
''command="systemctl start unlock-luks.service" [SSHKey]'
];
# Location of the SSH host key
hostKeys = [ "/etc/ssh/initrd_ssh_host_ed25519_key" ];
};
};
};
Btw, you don’t need to create that custom unlock-luks.service unit. You can just use the boot.initrd.luks.devices definition you had before and then the command to unlock it from the SSH client would be systemd-tty-ask-password-agent, or I prefer just doing systemctl default (which implicitly spawns the agent until the default target is reached) because then I get informed if boot fails for some other reason.