class: center, middle # Nix at Home - Configuration Management for your House! Or... How I use enterprise level tools to have sanity at home! Credit where credit is due: gchristensen and clever helped me with getting this in the state it is now! --- # Why nix is great for home devices * Most of us don't have dedicated test networks to test changes out * Breakage is scary with anything else. With nix, just rollback! * Free and easy CI to notify you when things break before you deploy! --- # Types of configuration management with nix * nixos-rebuild switch from a git repo cloned to /etc/nixos * nixops deploy from a git repo cloned anywhere * OSX remote deployments with prepare/deploy tooling * Linux (non-nixos) remote deployments (incomplete) --- # The laptops managed locally * Want to share some configurations * Want some stuff specific per laptop * Want to be able to rebuild a laptop quickly (or spin up new one) * Usually bleeding edge (nixos-unstable with custom commits cherry picked) * Want to easily test different channels though --- # How I do it `/etc/nixos` is a clone of https://github.com/disassembler/network `/etc/nixos/configuration.nix` is a symlink to `machines/HOSTNAME.nix` `/etc/nixos/harwdarw-configuration.nix` is a symlink to `hardware-configurations/HOSTNAME.nix` --- # Sharing stuff `modules` contains profiles, roles and custom services (more later) Include it with: `custom_modules = import ../modules/modules-list.nix;` `custom_modules` is added to `imports` attribute in configuration.nix. After defining a profile: `profiles.vim.enable = true;` --- # What about public/shared content? Just import `shared.nix`! Defines things like my home CA certificate and public SSH keys --- # Okay, but I don't want my secret stuff in git! Use `.gitignore` for specific nix configs in same format as `shared.nix` Add a layer of misdirection for CI in `load-secrets.nix`! `if builtins.pathExists ./secrets.nix then import ./secrets.nix else { ... }` --- # Home Deployments using NixOps * More stable environments * Pin nixpkgs version * Less frequently updated * Family members get mad when these go down (like your router) --- # Home Deployments using NixOps `infrastructure.nix` let secrets = import ./load-secrets.nix; shared = import ./shared.nix; custom_modules = (import ./modules/modules-list.nix); in { network = { description = "home network"; enableRollback = true; }; portal = { ... }: { deployment = { targetHost = "10.40.33.1"; }; imports = [ (import ./portal ) ] ++ custom_modules; deployment.keys."wg0-private".text = secrets.portal_wg0_private; }; } --- # Home Deployments using NixOps Create the deployment: nixops create -d home -I \ nixpkgs=https://github.com/nixos/nixpkgs/archive/dab31f2a9e6e1b05371849cd2b859736f2b16310.tar.gz \ infrastructure.nix Deploy! nixops deploy -d home Update nixpkgs nixops modify -d home \ -I nixpkgs=https://github.com/nixos/nixpkgs/archive/dab31f2a9e6e1b05371849cd2b859736f2b16310.tar.gz \ infrastructure.nix nixops deploy -d home --- # Remote OSX Deployments I don't use OSX very often, but I do have a laptop I want to manage nix-darwin on remotely. `nix-darwin` doesn't support this natively... but *haskell* to the rescue! Credit goes to @rvl with IOHK for the initial design of this! I won't go into the code here, as this talk isn't about haskell but nix. --- # Remote OSX Deployments The premise to to build two tools, one called prepare and one called deploy. These two tools remotely ssh into the host and handle the nix-darwin stuff Prepare installs nix in multi-user and deploy deploys new changes Caveat: nix-darwin and nixos modules don't always have the same design, so some breakage may occur if you share configurations. Code is in `nix-darwin-tools`. Prepare script is slightly outdated, so if you want to do this, I recommend using the code in https://github.com/input-output-hk/iohk-ops/nix-darwin It requires an OSX build slave to build the tool. WARNING: Running prepare will nuke all traces of nix from remote system!!! --- # Remote OSX Deployments nix-build -A tools ./result/bin/prepare-mac 10.40.33.170 ./result/bin/deploy --role ohrid/default.nix 10.40.33.170 --- # Remote Linux Deployments This project was abandoned, as everything I have is NixOS now! Initial premise was to setup prometheus-node-exporter to run on non-nixos linux systems. --- # Remote Linux Deployments with import
{ configuration = { config, lib, pkgs, ... }: { services.prometheus.exporters.node.enable = true; services.prometheus.enable = true; services.prometheus.alertmanager = { enable = true; listenAddress = "127.0.0.1"; }; services.grafana.enable = true; system.build.systemd-lib = import
{ inherit config lib pkgs; }; }; }; rec { fn = x : config.system.build.systemd-lib.makeUnit x config.systemd.units.${x}; allUnits = config._module.args.pkgs.buildEnv { name = "centosmonitor"; paths = map fn [ "prometheus-node-exporter.service" "prometheus.service" "alertmanager.service" "grafana.service" ]; }; inherit config; } --- # Remote Linux Deployments Build locally and make sure it looks right: nix-build centos-monitor.nix && find ./result copy centos-monitor.nix to remote system with nix installed on remote system run: nix-env -p /nix/var/nix/profiles/per-user/root/centosmonitor -f \ centos-monitor.nix -A allUnits --set ln -s /nix/var/nix/profiles/per-user/root/centosmonitor \ /etc/systemd/system/centosmonitor systemctl daemon-reload systemctl start prometheus-node-exporter --- # Remote Linux Deployments * This works (I tested it before I wiped my last non-nixos system) * New runs of `nix-env` create a new generation, so you can rollback! * Really you just need `prometheus-node-exporter`, but I included others to make it scalable * To use in production, I'd use a tool like python fabric or roll your own tool in your favorite programming language like the nix-darwin deploy tool above! --- # custom modules - profiles/roles * I first used the profiles/roles design pattern with puppet in a previous job. * When used properly, each system should only have one role. A role should only define profiles. My repo does not follow this. * The initial code came from a repo by @offlinehacker but it's pretty different from his implementation * In essence, both profiles and roles are just nixos modules with a different prefix. * I don't use roles a lot at all. In my repo, I have a base role that doesn't have an enable option for things I want on any system. * Profiles are glue around nixos configuration. For example, something like `profiles.vim.enable = true` abstracts away lots of vim configuration setup. * Most profiles have an `enable` option to enable/disable. If you forget this, any system importing custom modules will have the profile enabled! * My *goal* is to clean up `legacy` and move everything into separate profiles with some default options. Then `nixconfigs` would only contain profiles. * These are all shared across all linux/OSX systems, which has some tricky challenges to maintain if you're using OSX for more than build slaves! --- # Hydra to test everything! `release.nix` let nixosFuncStable = (import
); nixosFuncUnstable = (import
); nixDarwinFuncUnstable = (import
); nix-darwin-tools = import ./.; in { inherit nix-darwin-tools; optina = (nixosFuncStable { configuration = ./optina; }).system; portal = (nixosFuncStable { configuration = ./portal; }).system; sarov = (nixosFuncUnstable { configuration = ./machines/sarov.nix; }).system; ohrid = (nixDarwinFuncUnstable { configuration = ./ohrid; }).system; } --- # Some other cool features about my network repo * nixos ipxe network booting!!! (Thanks @clever) * Full IPV6 compatibility * Wireguard VPN tunnels * OpenVPN tunnels * Prometheus Monitoring * ELK stack for central logging (disabled currently because of lack of resources on my server)