From 4663c1f746ef5a50311ca1445913e5b94712cc3e Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Sun, 25 Apr 2021 18:38:54 -0400 Subject: [PATCH] blog: add morph tutorial Signed-off-by: Christine Dodrill --- blog/morph-setup-2021-04-25.markdown | 334 +++++++++++++++++++++++++++ src/app/markdown.rs | 3 +- templates/mara.rs.html | 15 +- 3 files changed, 337 insertions(+), 15 deletions(-) create mode 100644 blog/morph-setup-2021-04-25.markdown diff --git a/blog/morph-setup-2021-04-25.markdown b/blog/morph-setup-2021-04-25.markdown new file mode 100644 index 0000000..dcadc4a --- /dev/null +++ b/blog/morph-setup-2021-04-25.markdown @@ -0,0 +1,334 @@ +--- +title: Using Morph for Deploying to NixOS +date: 2021-04-25 +series: nixos +tags: + - morph +--- + +# Using Morph for Deploying to NixOS + +Managing a single NixOS host is easy. Any time you want to edit any settings, +you can just change options in `/etc/nixos/configuration.nix` and then do +whatever you want from there. Managing multiple NixOS machines can be +complicated. [Morph](https://github.com/DBCDK/morph) is a tool that makes it +easy to manage multiple NixOS machines as if they were one single machine. In +this post we're gonna start a new NixOS configuration for a network of servers +from scratch and explain each step in the way. + +## `nixos-configs` Repo + +NixOS configs usually need a home. Let's make a home for this in a Git +repository named `nixos-configs`. You can make a nixos configs repo like this: + +```console +$ mkdir -p ~/code/nixos-configs +$ cd ~/code/nixos-configs +$ git init +``` + +[You can see a copy of the repo that we're describing in this post here. That repo is licensed +as Creative Commons Zero and no attribution or credit is required if you want to +use it as the basis for your NixOS configuration repo for any setup, home or +professional.](conversation://Mara/hacker) + +From here you could associate it with a Git forge if you want, but that is an +exercise left to the reader. + +Now that we have the nixos-configs repository, let's create a few folders that +will be used to help organize things: + +- `common` -> base system configuration and options +- `common/users` -> user account configuration +- `hosts` -> host-specific configuration for named servers +- `ops` -> operations data such as deployment configuration +- `ops/home` -> configuration for a home network + +You can make them with a command like this: + +```console +$ mkdir -p common/users hosts ops/home +``` + +Now that we have the base layout, let's start with adding a few files into the +`common` folder: + +- `common/default.nix` -> the "parent" file that will import all of the other + files in the `common` directory, as well as define basic settings that + everything else will inherit from +- `common/generic-libvirtd.nix` -> a bunch of settings to configure libvirtd + virtual machines (omit this if you aren't running VMs in libvirtd) +- `common/users/default.nix` -> the list of all the user accounts we are going + to configure in this system + +Here's what you should put in `common/default.nix`: + +```nix +# common/default.nix + +# Mara\ inputs to this NixOS module. We don't use any here +# so we can ignore them all. +{ ... }: + +{ + imports = [ + # Mara\ User account definitions + ./users + ]; + + # Mara\ Clean /tmp on boot. + boot.cleanTmpDir = true; + + # Mara\ Automatically optimize the Nix store to save space + # by hard-linking identical files together. These savings + # add up. + nix.autoOptimiseStore = true; + + # Mara\ Limit the systemd journal to 100 MB of disk or the + # last 7 days of logs, whichever happens first. + services.journald.extraConfig = '' + SystemMaxUse=100M + MaxFileSec=7day + ''; + + # Mara\ Use systemd-resolved for DNS lookups, but disable + # its dnssec support because it is kinda broken in + # surprising ways. + services.resolved = { + enable = true; + dnssec = "false"; + }; +} +``` + +This will give you a base system config with sensible defaults that you can +build on top of. + +[Is now when I get my account? :D](conversation://Mara/happy) + +[Yep! We define that in `common/users/default.nix`:](conversation://Cadey/enby) + +```nix +# common/users/default.nix + +# Mara\ Inputs to this NixOS module, in this case we are +# using `pkgs` so I can configure my favorite shell fish +# and `config` so we can make my SSH key also work with +# the root user. +{ config, pkgs, ... }: + +{ + # Mara\ The block that specifies my user account. + users.users.mara = { + # Mara\ This account is intended for a non-system user. + isNormalUser = true; + + # Mara\ The shell that the user will default to. This + # can be any NixOS package, even PowerShell! + shell = pkgs.fish; + + # Mara\ My SSH keys. + openssh.authorizedKeys.keys = [ + # Mara\ Replace this with your SSH key! + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPg9gYKVglnO2HQodSJt4z4mNrUSUiyJQ7b+J798bwD9" + ]; + }; + + # Mara\ Use my SSH keys for logging in as root. + users.users.root.openssh.authorizedKeys.keys = + config.users.users.mara.openssh.authorizedKeys.keys; +} +``` + +In case you are using libvirtd to test this blogpost like I am, put the +following in `common/generic-libvirtd.nix`: + +```nix +# common/generic-libvirtd.nix + +# Mara\ This time all we need is the `modulesPath` +# to grab an optional module out of the default +# set of modules that ships in nixpkgs. +{ modulesPath, ... }: + +{ + # Mara\ Set a bunch of QEMU-specific options that + # aren't set by default. + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + # Mara\ Enable SSH daemon support. + services.openssh.enable = true; + + # Mara\ Make sure the virtual machine can boot + # and attach to its disk. + boot.initrd.availableKernelModules = + [ "ata_piix" "uhci_hcd" "virtio_pci" "sr_mod" "virtio_blk" ]; + + # Mara\ Other boot settings that we're leaving + # to the defaults. + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + # Mara\ This VM boots with grub. + boot.loader.grub.enable = true; + boot.loader.grub.version = 2; + boot.loader.grub.device = "/dev/vda"; + + # Mara\ Mount /dev/vda1 as the root filesystem. + fileSystems."/" = { + device = "/dev/vda1"; + fsType = "ext4"; + }; +} +``` + +Now that we have the basic modules defined, we can create a `network.nix` file +that will tell Morph where to deploy to. In this case we are going to create a +network with a single host called `ryuko`. Put the following in +`ops/home/network.nix`: + +```nix +# ops/home/network.nix + +{ + # Mara\ Configuration for the network in general. + network = { + # Mara\ A human-readable description. + description = "My awesome home network"; + }; + + # Mara\ This specifies the configuration for + # `ryuko` as a NixOS module. + "ryuko" = { config, pkgs, lib, ... }: { + # Mara\ Import the VM-specific config as + # well as all of the settings in + # `common/default.nix`, including my user + # details. + imports = [ + ../../common/generic-libvirtd.nix + ../../common + ]; + + # Mara\ The user you will SSH into the + # machine as. This defaults to your current + # username, however for this example we will + # just SSH in as root. + deployment.targetUser = "root"; + + # Mara\ The target IP address or hostname + # of the server we are deploying to. This is + # the IP address of a libvirtd virtual + # machine on my machine. + deployment.targetHost = "192.168.122.251"; + }; +} +``` + +Now that we finally have all of this set up, let's write a little script that we +can use to push this config to the server that will do the following: + +- Build the NixOS configuration for `ryuko` +- Push the NixOS configuration for `ryuko` to the virtual machine +- Activate the configuration on `ryuko` + +Put the following in `ops/home/push`: + +```shell +#!/usr/bin/env nix-shell +# Mara\ The above shebang line will use `nix-shell` +# to create the environment of this shell script. + +# Mara\ Specify the packages we are using in this +# script as well as the fact that we are running it +# in bash. +#! nix-shell -p morph -i bash + +# Mara\ Explode on any error. +set -e + +# Mara\ Build the system configurations for every +# machine in this network and register them as +# garbage collector roots so `nix-collect-garbage` +# doesn't sweep them away. +morph build --keep-result ./network.nix + +# Mara\ Push the config to the hosts. +morph push ./network.nix + +# Mara\ Activate the NixOS configuration on the +# network. +morph deploy ./network.nix switch +``` + +Now mark that script as executable: + +```console +$ cd ./ops/home +$ chmod +x ./push +``` + +And then let's try it out: + +```console +$ ./push +``` + +And finally let's SSH into the machine to be sure that everything works: + +```console +$ ssh mara@192.168.122.251 -- id +uid=1000(mara) gid=100(users) groups=100(users) +``` + +From here you can do just about anything you want with `ryuko`. + +If you want to add a non-VM NixOS host to this, make a folder in `hosts` for +that machine's hostname and then copy the contents of `/etc/nixos` to that +folder. For example let's say you have a server named `mako` with the IP address +`192.168.122.147`. You would do something like this: + +```console +$ mkdir hosts/mako -p +$ scp root@192.168.122.147:/etc/nixos/configuration.nix ./hosts/mako +$ scp root@192.168.122.147:/etc/nixos/hardware-configuration.nix ./hosts/mako +``` + +And then you can register it in your `network.nix` like this: + +```nix +"mako" = { config, pkgs, lib, ... }: { + deployment.targetUser = "root"; + deployment.targetHost = "192.168.122.147"; + + # Mara\ Import mako's configuration.nix + imports = [ ../../hosts/mako/configuration.nix ]; +}; +``` + +This should help you get your servers wrangled into a somewhat consistent state. +From here the following articles may be useful to give you ideas: + +- [Borg Backup Config](https://christine.website/blog/borg-backup-2021-01-09) +- [Nixops Services On Your Home + Network](https://christine.website/blog/nixops-services-2020-11-09) (just be + sure to ignore the part where it mentions `deployment.keys`, you can replace + it with the semantically identical + [`deployment.secrets`](https://github.com/DBCDK/morph/blob/master/examples/secrets.nix) + as described in the morph documentation) +- [Prometheus and + Aegis](https://christine.website/blog/aegis-prometheus-2021-04-05) +- [My Automagic NixOS Wireguard + Setup](https://christine.website/blog/my-wireguard-setup-2021-02-06) +- [Encrypted Secrets with + NixOS](https://christine.website/blog/nixos-encrypted-secrets-2021-01-20) + +Also feel free to dig around [the `common` folder of my `nixos-configs` +repo](https://github.com/Xe/nixos-configs/tree/master/common). There's a bunch +of examples of things in there that I haven't gotten around to documenting in +this blog yet. Another useful thing you may want to look into is +[home-manager](https://github.com/nix-community/home-manager), which is a tool +that lets you manage your dotfiles across machines. With home-manager I'm able +to set up all of my configurations for everything on a new machine in less than +30 minutes (starting from a blank NixOS server). diff --git a/src/app/markdown.rs b/src/app/markdown.rs index 0b5f096..dbc5ecf 100644 --- a/src/app/markdown.rs +++ b/src/app/markdown.rs @@ -29,7 +29,6 @@ pub fn render(inp: &str) -> Result { if u.scheme() != "conversation" { return Ok(()); } - let smol = u.query().unwrap_or("").contains("smol"); let parent = node.parent().unwrap(); node.detach(); let mut message = vec![]; @@ -44,7 +43,7 @@ pub fn render(inp: &str) -> Result { let name = u.host_str().unwrap_or("Mara"); let mut html = vec![]; - crate::templates::mara(&mut html, mood, name, Html(message.trim().into()), smol)?; + crate::templates::mara(&mut html, mood, name, Html(message.trim().into()))?; let new_node = arena.alloc(AstNode::new(RefCell::new(Ast::new( NodeValue::HtmlInline(html), diff --git a/templates/mara.rs.html b/templates/mara.rs.html index f892c1e..ad86b1c 100644 --- a/templates/mara.rs.html +++ b/templates/mara.rs.html @@ -1,22 +1,11 @@ -@(mood: &str, character: &str, message: Html, smol: bool) +@(mood: &str, character: &str, message: Html)
-
+
@character is @mood
- @if smol {
<@character> @message
- } else { -
-

- @character -

-
- @message -
-
- }