This repository contains my personal NixOS configuration files for system and service management. Configurations are fully declarative and managed via Nix Flakes.
Primary workstation for daily use, development, and gaming. With a customized Plasma desktop environment.
Central homelab node running 24/7 with high uptime. Provides centralized storage, self-hosted services, and automated backups. Operates as a low-power HTPC capable of directing input to TVs and handling light gaming. Hosts containerized services while maintaining remote accessibility.
A publicly accessible server hosting self-managed services like Jellyfin and other web applications.
This is the canonical guide for deploying this repository to a machine. It is split into a general, machine-agnostic section and a VPS-specific section. Follow the checklist before any remote work.
- The flake defines a
nixosConfigurations.<hostname>output for the host you want to deploy. - Secrets are managed with agenix and age public keys are in
secrets/secrets.nixor equivalent. - Keep private keys off the repo.
- When working on remote machines, ensure you have a rescue/console path in case networking breaks.
- Confirm the host entry exists in the flake outputs and the hostname matches the target.
- Update flake inputs locally if you want the latest packages:
nix flake update. Commit the updatedflake.lockif reproducible installs are desired. - Ensure secrets are present locally and encrypted with agenix. Do not commit plaintext secrets.
- Have an SSH key usable on the target. Keep a root or console access backup.
- Back up any critical data on the target before doing major system changes.
Clone the repo on the target:
# HTTPS
sudo nix-shell -p git --run "git clone https://github.com/exil0867/nixcfg /etc/nixos"
# SSH
sudo nix-shell -p git --run "git clone git@github.com:exil0867/nixcfg /etc/nixos"Apply configuration for the current machine:
sudo nixos-rebuild switch --flake path:.#$(hostname)
# or explicitly:
sudo nixos-rebuild switch --flake path:.#kairosFresh install from live medium:
sudo nixos-install --flake path:/mnt/etc/nixos/flake#<hostname>Copying encrypted secrets securely:
tar -czf - -C /home/you/nixcfg secrets \
| ssh nixos@TARGET_IP "sudo tar -xzf - -C /mnt/etc/nixos/flake/"Fixing git safe.directory issues when running as root:
sudo git config --global --add safe.directory /home/<user>/Develop/nixcfg-
Prepare the repo locally:
- Keep
flake.lockup to date. - Ensure
hosts/<hostname>exists andnixosConfigurations.<hostname>is defined. - Encrypt secrets with agenix; store only public keys in
secrets/secrets.nix.
- Keep
-
Make secrets available on the target:
- Preferred: send secrets temporarily with a secure tar+ssh pipeline.
- Alternative: scp/rsync to a user-owned path, then move/extract with sudo.
-
Ensure repo ownership and permissions are correct on the target.
-
Run the build:
- Existing host:
cd /path/to/repo && sudo nixos-rebuild switch --flake path:.#<hostname> - Fresh install: mount root at
/mnt, place repo at/mnt/etc/nixos/flake, thensudo nixos-install --flake path:/mnt/etc/nixos/flake#<hostname>
- Existing host:
-
Post-install:
- Reboot if needed.
- Verify services/logs:
journalctl -b -p errandsystemctl status <service>. - Edit configs and rebuild:
sudo nano /etc/nixos/flake/hosts/<hostname>/...thensudo nixos-rebuild switch --flake path:/etc/nixos/flake#<hostname>.
- Avoid destructive restarts without remote console.
- Use tar+ssh for installing repo into
/mnt/etc/nixos/flakeon VPS. - You can work in
/home/<user>/Develop/nixcfginstead, but fixsafe.directoryif git complains. - When transferring secrets, do not leave plaintext in home. Example safe transfer:
tar -czf - -C /home/you/nixcfg secrets \
| ssh nixos@IP "sudo tar -xzf - -C /mnt/etc/nixos/flake/ && sudo chown -R root:root /mnt/etc/nixos/flake/secrets && sudo chmod -R 600 /mnt/etc/nixos/flake/secrets/*"- Keep private keys local; only public keys in
secrets/secrets.nix. - Encrypt files before committing:
agenix -e secrets/my-secret-file
git add secrets/my-secret-file.age- On target, encrypted files and flake logic are enough to write them at build time.
- Rekey/rotate keys:
agenix --rekeylocally and updatesecrets.nix.
- Repository unsafe when run as root: add safe.directory or run from root-owned path.
- Secrets unreadable: ensure copied under
/mnt/etc/nixos/flake/secrets. nixos-installflake errors: verify path and hostname match; debug withnixos-rebuild switch.- Flake inputs differ on installer vs host: keep
flake.lockcommitted. - Service fails:
journalctl -u <service> -band rollback if needed.
# Local prep
git clone git@github.com:exil0867/nixcfg
cd nixcfg
nix flake update
agenix -e secrets/deluge/auth
git add secrets/*.age
git commit -m "update secrets and flake"
# Push secrets to remote installer
tar -czf - -C "$(pwd)" secrets \
| ssh nixos@37.120.187.211 "sudo tar -xzf - -C /mnt/etc/nixos/flake/"
# On remote live installer
sudo nixos-install --flake path:/mnt/etc/nixos/flake#sky
# After reboot, on host
cd /home/exil0681/Develop/nixcfg
sudo git config --global --add safe.directory /home/exil0681/Develop/nixcfg
sudo nixos-rebuild switch --flake path:.#sky- Never commit raw secrets; always use agenix.
- Prefer ephemeral secret transfer during install.
- Keep
flake.lockunder version control. - Test locally with
nixos-rebuild buildornixos-rebuild testbefore production.
- Apply configuration changes:
sudo nixos-rebuild switch --flake path:.#$(hostname)- Update flake inputs:
nix flake updategraph TD
A[Make changes] --> B{Test locally?}
B -->|Yes| C[nixos-rebuild test]
B -->|No| D[nixos-rebuild switch]
C --> E[Verify functionality]
E --> F[Commit changes]
F --> G[Push to repo]
- Secrets management via
agenix - Automatic service-specific firewall rules
- Full disk encryption by default
- SSH key-based remote access
- Create host directory:
mkdir -p hosts/new-host- Generate hardware configuration:
nixos-generate-config --dir hosts/new-host- Add to flake outputs:
nixosConfigurations.new-host = lib.nixosSystem { /* configuration */ };- Rollback to previous configuration:
sudo nixos-rebuild switch --rollback- Investigate service failures:
journalctl -u failed-service -b