- Goals
- Setup
- Extra setup: First time only (If you didn't restore from a backup)
- Other: Python per project setup
- File structure
- Common pahts
- Configuring programs (Stow)
- Installing programs
- Updating packages broadly
- Upgrading/downgrading an specific package or pinning it to an specific version
- Updating secrets
- Backups
- Todo
- For reference, things I tried before this
- Simple: Minimize cognitive load, minimize configuration.
- Effective: Get close to the best developer experience available.
- Reliable: Favor well stablished technologies, favor software with less dependencies, favor lightweight, favor UNIX philosophy.
- Reproducible: Be able to set up the environment quickly.
- Low maintance: Do the configuration effort upfront.
- 1 spare laptop that is not apple. (Apple setup differs, and I don't use their devices.)
- 1 usb.
- (Optional) Openrouter api key for aichat.
- (Optional) Claude pro subscription for claude-code.
- Download the official nixos graphical iso image..
- Flash it to the usb:
sudo fdisk -l # Find the usb disk mount, e.g. /dev/sdb
# NOTE: It must be the whole disk and not a partition, e.g. /dev/sdb instead of /dev/sdb1
sudo umount /dev/sdb*
sudo dd bs=4M conv=fsync oflag=direct status=progress if=/home/nixos/Downloads/nixos-graphical-25.05.810859.20c4598c84a6-x86_64-linux.iso of=/dev/sdbOne alternative: https://etcher.balena.io/
- Plug the usb into the spare laptop, boot it from the image. To display the option to do so, press F12 repeteadly after pressing the powerup button.
During the wizard:
- For desktop environment choose
minimal. - For
usernameandnameusenixos. - For partitioning I've always used
erase all, but other options might work.
- Connect to wifi:
nmtui # Activate a connection -> Select the network -> Enter the password- Copy the config:
Option A) If it is the first time, clone this repo into ~/.config/nixos:
export NIX_CONFIG="experimental-features = nix-command flakes"
nix run nixpkgs#git -- clone "https://github.com/PbVrCt/dotfiles" "$HOME/.config/nixos"Option B) If you have a backup from a previous setup, then restore it.
Plug the usb into the laptop and mount it:
export NIX_CONFIG="experimental-features = nix-command flakes"
nix run nixpkgs#bashmount # mount to /home/nixos/mnt/usbRestore the backup:
REPO=/home/nixos/mnt/usb/restic-repo
RESTORE_PATH="$HOME/restic-restored/"
nix run nixpkgs#restic -- restore latest -r "$REPO" --target "$RESTORE_PATH"
# config
mkdir /home/nixos/.config
cp $RESTORE_PATH/home/nixos/.config/nixos /home/nixos/.config/nixos -r
# other stuff: projects, notes, secrets key, the backup itself
cp $RESTORE_PATH/home/nixos/projects /home/nixos/projects -r
cp $RESTORE_PATH/home/nixos/notes /home/nixos/notes -r
cp $RESTORE_PATH/home/nixos/.config/secretkey/sops_private_key.txt /home/nixos/.config/secretkey/sops_private_key.txt
cp $REPO /home/nixos/restic-repo -r
sudo rm $RESTORE_PATH -r- Make scripts executable:
chmod +x /home/nixos/.config/nixos/scripts/**
chmod +x /home/nixos/.config/nixos/scripts_as_dotfiles/**- Symlink dotfiles:
nix-shell -p stow
/home/nixos/.config/nixos/scripts/stow.sh
exit- Add a new host at
host/$HOST/following the existing examples.
HOST=vesuvio # Insert laptop brand / volcano name / battleship name etc.
mkdir /home/nixos/.config/nixos/hosts/$HOST -pCopy whatever files your host might use, .e.g., intel.nix, amd.nix, nvidia.nix.
# For example: cp $HOME/.config/nixos/hosts/thinkpad/** $HOME/.config/nixos/hosts/$HOST/**- Copy the autogenerated hardware-configuration.nix file to the configuration folder.
sudo cp /etc/nixos/hardware-configuration.nix /home/nixos/.config/nixos/hosts/$HOST/hardware-configuration.nix The hardware file changes after partitioning even if on the same machine. Don't skip this after a fresh reinstall.
- Reference the host from the previous steps in
flake.nix.
nix run nixpkgs#helix /home/nixos/.config/nixos/flake.nixFor example:
vesuvio = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
{networking.hostName = "vesuvio";}
./configuration.nix
./base.nix
inputs.sops-nix.nixosModules.sops
inputs.schizofox.nixosModules.default
./hosts/vesuvio/hardware-configuration.nix
./hosts/vesuvio/intel.nix
];
};- Change the timezone. In
base.nix:
config.time.timeZone = "Asia/Tokyo";nix run nixpkgs#helix /home/nixos/.config/nixos/base.nix- Rebuild the system.
WARNING: This will download the programs the config specifies (~15GB):
nix-shell -p git
HOST=vesuvio
sudo nixos-rebuild switch --flake "/home/nixos/.config/nixos#$HOST"- Reboot:
rebootSuper+h should show you the keybind helper.
- Install browser extensions: Vimium, etc.
- Secrets
- RSS feed
- Generate a .sops.yaml file, a public key and a private key:
|
fish set PUBLIC_KEY (age-keygen -o ~/.config/secretkey/sops_private_key.txt 2>&1 | sed 's/Public key: //')
echo "keys:
- &personal $PUBLIC_KEY
creation_rules:
- path_regex: secrets.yaml\$
key_groups:
- age:
- *personal" > ~/.config/nixos/secrets/.sops.yaml
cd ~/.config/nixos/secrets
rm secrets.yaml |
bash export PUBLIC_KEY=$(age-keygen -o ~/.config/secretkey/sops_private_key.txt 2>&1 | sed 's/Public key: //')
cat > ~/.config/nixos/secrets/.sops.yaml << EOF
keys:
- &personal $PUBLIC_KEY
creation_rules:
- path_regex: secrets.yaml\$
key_groups:
- age:
- *personal
EOF
cd ~/.config/nixos/secrets
rm secrets.yaml |
- Place your secrets in the
secrets.yamlfile:
~/.config/nixos/secrets/sops.shWhen you exit the file becomes encrypted.
Here is how mine looks while editing:
OPENROUTER_API_KEY: sk-or-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
USUAL_USBS_SERIALS: |
xxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxx
git:
USER_EMAIL: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
USER_NAME: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMake sure your .nix files using config.sops.secrets, including ~/.config/nixos/secrets/sopsnix.nix, only references secrets you have set in secrets.yaml
- Rebuild:
sudo nixos-rebuild switch --flake "/home/nixos/.config/nixos#$hostname"cp ~/.config/nixos/dotfiles/newsraft/feeds.example ~/.config/nixos/dotfiles/newsraft/feedsPython can be troublesome on NixOs because of the way it manages dependencies and NixOs's non-FHS filesystem.
My preferred soulution is to run the code entrypoint from an Ubuntu shell using distrobox
Also, install pretty_errors.
source .venv/bin/activate.fish
uv pip install pretty_errors
python -m pretty_errors # Enter to accept the setup wizard defaultsflake.nix: Entrypoint for the config. Eachoutputs.nixosConfiguration.*defines a configuration for a different machine / virtual machine.configuration.nix: Specifies programs,.nixconfig files, environment variables, and not much more.base.nix: Things I don't put inconfiguration.nixbecause they rarely change, like battery or audio settings.dotfiles/: Both regular program configuration files, that I symlink using GNU stow, as well as.nixfiles.scripts_as_dotfiles/: Scripts that programs rely on, or that I effectively use as configuration.hosts/: Contains configuration specific the different machines / virtual machines; referenced fromflake.nix.secrets/: Configuration to set up secrets and encrypted secrets file. The private key is somewhere else.
~/projects/~/.config/nixos/: Where the config in this repo lives locally. It didn't necessarily have to be here but I chose this location.~/.config/secretkey/sops_private_key.txt: Decrypts sops secrets.~/notes/~/restic-repo/: Where I backup the above paths to.
Set up a new dotfile:
- Add the dotfile in
~/.config/nixos/dotfiles/*/* - Reference it in
~/.config/nixos/scripts/stow.sh, and run the script, to symlink it where the program expects it.
Update a dotfile::
- Edit it.
- Reload the program. Depends on the program:
| Program | Reload options (not necessarily all) |
|---|---|
| River | Log out (Super+Shift+E) and back in. |
riverctl COMMAND (avoids logging out) |
|
| Kanata | sudo nixos-rebuild switch --flake "/home/nixos/.config/nixos#$hostname" |
systemctl stop kanata-default; kanata -c ~/.config/nixos/dotfiles/kanata/kanata.kbd |
|
| Helix | :config-reload |
| Ghostty | Press ctrl+shift+, (default for reload_config) |
| Mako | makoctl reload |
| Tmux | tmux source ~/.tmux.conf |
| Fish | source ~/.config/fish/config.fish |
| Lazygit | Open a new instance |
| Yazi | Open a new instance |
| Aichat | Open a new instance |
| Claude-code | Open a new instance |
- Specify the package in
config.environment.systemPackages; Seeconfiguration.nix. - Rebuild
sudo nixos-rebuild switch --flake "/home/nixos/.config/nixos#$hostname"
- (Optional) Change
inputs.nixpkgs.urlinflake.nix - Run
nix flake updateornix flake update nixkpgs - Rebuild
sudo nixos-rebuild switch --flake "/home/nixos/.config/nixos#$hostname"
I avoid doing that. If a program doesn't work on my nixpkgs version, I pass on it until it does. (When authoring and releasing software I might consider using flakes for that, but not as a consumer)
I use sops-nix with secrets that I am comfortable exposing to anyone having access to my machine.
sops-nix enables referencing the secrets from the nixos config.
The file containing the secrets is encrypted, so it can be commited with the rest of the configuration.
- To edit/add a secret to the secrets file:
- Run sops
~/.config/nixos/scripts/sops.sh. This unencrypts the file and opens it in $EDITOR, where you add/edit secrets. - Save and exit; The file becomes encrypted again.
- To access a secret from the nixos config (and also expose it at
/run/secrets/$SECRET, depending on who you set as the owner):
- Reference it in
~/.config/nixos/secrets/sopsnix.nix - Reference it wherever you want to use it in the config with
config.sops.secrets.SECRET.path - Rebuild
sudo nixos-rebuild switch --flake "/home/nixos/.config/nixos#$hostname"
- To access a secret from the shell prompt, or a script:
cat /run/secrets/$SECRETWARNING:
- It might be better to have the secrets referencej in
sopsnix.nixbe owned by systemd services and not the user. - Access through /run/secrets/$SECRET might be problematic if a program keeps a history of the outputs of shell commands.
- I might remove the access through /run/secrets/$SECRET.
Aside from sops/sopsnix, I use a password manager.
I made scripts for my usual backup sceneraios. They are just thin wrappers around the restic CLI:
~/.config/nixos/scripts/restic_backup.sh: Do a backup.~/.config/nixos/scripts/restic_copy.sh: Copy the backup to drives.~/.config/nixos/scripts/restic__backup_and_copy.sh: Call the above two sequentially.
- Remote development, convenience, and running AI workloads: Setup
tailscale+rustdesk. Ifrustdeskturns out problematic on Wayland then considerwayvnc. - Developping with LLMs in parallel: Investigate on how are people using worktrees with LLMs, try things,
and ponder on how developping with models might look in the future.
Adopt a system that seems in the right direction, and allows
for operating 2
claude-codeinstances in parallel. - Security: Disk encryption.
- Security: Acquire a better understanding of how security works on linux, of networking and of tailscale.
For reference, things I have already tried:
-
For automating program installation:
- No automation, download from a website on
Windowsor usewget. Ansiblescripts (too unreliable) onPopOs (Ubuntu)NixOs
- No automation, download from a website on
-
For managing dotfiles:
- Save them 1 by 1 to an usb/cloud and copy them over to a new machine.
Chezmoi(too bothersome for a one machine setup)NixOs home-manager(same as chezmoi, and also I felt like it does too many things under the 'home-manager' umbrella)Gnu Stow
