Minimal LUKS Encrypted Install with Btrfs Subvolumes
Follow this guide to set up a minimal NixOS install with LUKS, Btrfs, and encrypted secrets. This guide aims for a manually entered LUKS passphrase at boot and uses SOPS for other system/user secrets.
- Prepare the Minimal ISO and Networking
sudo systemctl start wpa_supplicant.service # Ensure wpa_supplicant is running
sudo wpa_cli
> add_network
0
> set_network 0 ssid "myhomenetwork"
OK
> set_network 0 psk "mypassword"
OK
> enable_network 0
OK
> quit
Test your connection: Bash
ping google.com
- Enable Experimental Nix Features Bash
export NIX_CONFIG='experimental-features = nix-command flakes'
- Install Initial Essential Tools & Clone Repo
These tools are needed for the initial configuration and running disko. Bash
sudo nix-env -iA nixos.{git,helix,yazi} # Install globally for the installer environment
export EDITOR='hx' # Set your preferred editor for this session
git config --global user.name "YourUsername"
git config --global user.email "YourGitEmail"
Clone the Starter Repo
git clone https://github.com/saylesss88/my-flake.git
- Customize Configuration Files (Pre-Disko)
- Navigate into your cloned flake:
cd ~/my-flake
-
Modify
flake.nix
,users.nix
, andconfiguration.nix
to set your desired hostname and username. -
Check your disk device with
lsblk
and updatedisk-config2.nix
accordingly (i.e., the device needs to match your actual disk device, e.g.,/dev/nvme0n1
or/dev/sda
).
- Apply Initial Configuration & Prepare Disko
This step builds a temporary NixOS system in the installer's RAM disk that includes your disko configuration.
- Generate your
hardware-configuration.nix
based on the installer's view of your hardware.
sudo nixos-generate-config --no-filesystems --root /mnt
sudo mv /mnt/etc/nixos/hardware-configuration.nix ~/my-flake/hardware-configuration.nix
Run Disko to wipe, partition, and format your disk (WARNING: This destroys ALL data on the target disk!) Bash
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount ~/my-flake/disk-config2.nix
- Crucial: You will be prompted for your LUKS passphrase. This is the password you will use to unlock your disk every time you boot. Choose a strong, memorable passphrase.
Verify your partitions are mounted to /mnt
:
mount | grep /mnt
- Install SOPS-Related Tools & Generate Secrets (Post-Disko)
Now that your disk is formatted and mounted to /mnt
, we can generate and
encrypt your secrets directly onto the target filesystem. This ensures the Age
key is located where the installed system can always find it.
Change into the mounted flake directory:
sudo mv ~/my-flake /mnt/etc/nixos/
cd /mnt/etc/nixos/my-flake
Install SOPS-related tools:
sudo nix-env -iA nixos.{age,sops,mkpasswd} # Install these into the installer environment
6.1. Set Up Age Key for SOPS
This generates your Age private key directly on the target root partition.
Create the directory for your Age key and generate the key pair:
sudo mkdir -p /mnt/root/.config/sops/age
sudo age-keygen -o /mnt/root/.config/sops/age/keys.txt
The above location will persist after the install and reboot.
Display your Public Key and Manually Transcribe:
sudo age-keygen -y /mnt/root/.config/sops/age/keys.txt
Carefully read and manually type the age1...
public key string into your
.sops.yaml
file within your flake directory
(/mnt/etc/nixos/my-flake/.sops.yaml
).
Example .sops.yaml
(after editing):
keys:
- &personal_age_key age1yuvx83vtxr8rf6t8vmwjeymt9u83h4cwktnqvmn49rhy36chj3tqlgunhz # <-- Your public key goes here
creation_rules:
- path_regex: "secrets/.*\\.yaml$"
key_groups:
- age:
- *personal_age_key
Add .sops.yaml
to Git
git add .sops.yaml
-
Note: If you forget to add the
.sops.yaml
to Git, sops won't be able to decrypt your secrets after reboot.6.2. Generate SSH Key & Add to SOPS
-
Generate your SSH key and save the private key to a temporary file:
ssh-keygen -t ed25519 -C "your_email@example.com" -f /tmp/ssh_key
- Encrypt the private key into
secrets/github-deploy-key.yaml
using SOPS:
sops secrets/github-deploy-key.yaml
Inside the editor (e.g., helix
, vim
, nano
):
-
Add the YAML key:
github_deploy_key_ed25519: |
-
Move your cursor to the line below, indented by 2 spaces.
-
To read the content from
/tmp/ssh_key
:
-
For vim: In Normal mode, type
:r /tmp/ssh_key
and press Enter. -
For nano: Press
Ctrl+R
, type/tmp/ssh_key
, and press Enter.
- Save and exit the editor.
- Securely delete the temporary file:
shred -u /tmp/ssh_key
6.3. Add Hashed Password to SOPS
- Generate your hashed password for the user and save it to a temporary file:
mkpasswd -m SHA-512 -s > /tmp/user_hashed_pass.txt
- Encrypt the hashed password into
secrets/password-hash.yaml
using SOPS:
sops secrets/password-hash.yaml
Inside the editor:
-
Add the YAML key: password_hash:
-
Move your cursor to the end of that line (or the line below, if your editor prefers).
-
To read the content from
/tmp/user_hashed_pass.txt
:
-
For vim: In Normal mode, type
:r /tmp/user_hashed_pass.txt
and press Enter. (You may need to join the lines using Shift+J and add 2 spaces of indentation if it pastes on a new line). -
For nano: Press
Ctrl+R
, type/tmp/user_hashed_pass.txt
, and press Enter. Save and exit the editor.
Securely delete the temporary file:
shred -u /tmp/user_hashed_pass.txt
- Configure SOPS in Nix (sops.nix)
Ensure your sops.nix
looks like this, adjusting age.keyFile
to the new path
(which is on your root filesystem).
{ config, ... }: { sops = { defaultSopsFile = ./sops.yaml; # If your host's SSH key is Ed25519 and you want SOPS to use it for decryption, # you can add:
age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
age.keyFile = "/root/.config/sops/age/keys.txt"; # Crucial: This path is now on your installed system's root
secrets = {
"password_hash" = {
sopsFile = ./secrets/password-hash.yaml;
owner = "root";
group = "root";
mode = "0400";
neededForUsers = true; # Ensures it's available for user creation/login
};
"github_deploy_key_ed25519" = {
sopsFile = ./secrets/github-deploy-key.yaml;
key = "github_deploy_key_ed25519"; # Specifies the key within the YAML file
owner = "root";
group = "root";
mode = "0400";
};
};
}; }
- Final Configuration & Apply
- Update
configuration.nix
: Review and update yourconfiguration.nix
with your hostname, desired packages, services, etc.
Final rebuild to apply all changes:
sudo nixos-rebuild switch --flake .#your-hostname # Use . since you are in the flake directory
- Install NixOS
Execute the installation command:
sudo nixos-install --flake /mnt/etc/nixos/my-flake#your-hostname
- You will be prompted to set a new password. This is for the root user on your newly installed system.
- Post-Installation
First Boot: After reboot, your system will pause to ask for your encryption password (the LUKS passphrase you set during the Disko command in Step 5). Enter it to proceed with booting. Move your flake to your user's home directory (if desired) and fix permissions:
sudo mv /etc/nixos/my-flake ~ sudo chown -R $USER:users ~/my-flake
Optional: It is possible to use sops to auto-decrypt your LUKS partition, but this guide focuses on manual entry for enhanced security awareness at boot. If you're interested, you could explore that option, but it negates some of the benefits of manually entering your passphrase. I'm currently working on an impermanence guide for this setup, which has presented some challenges. I'm open to suggestions!