diff --git a/blog.nix b/blog.nix
index f22b0cd..0fe0b07 100644
--- a/blog.nix
+++ b/blog.nix
@@ -12,10 +12,14 @@
path = "index.html";
title = "Home";
- head = ''
-
+ body.markdown = ''
+ Webster's dictionary defines "blog" as "a website that contains online personal reflections, comments, and often hyperlinks, videos, and photographs provided by the writer".
+ This is mine.
+
+ You will find mostly longform technical writing here.
+
+
'';
- body.html = "";
}
];
}
diff --git a/posts/hello/body.md b/posts/hello/body.md
index 2e157df..0949ba7 100644
--- a/posts/hello/body.md
+++ b/posts/hello/body.md
@@ -1,3 +1,119 @@
-Hello world! This is a test post.
+As you know if you're part of my life, I have been going pretty hard on nixing my workstations and servers lately.
+This post is to commemorate the creation of this blog being run through nix, but also the workflow I've established to get here.
-There will be a real post here soon.
+Since the year is 2025 and attention span is in short supply, here's the punchline:
+
+- I ran `nix run .#sunflower.deploy` to update my server, including deploying this blog
+- I will run `nix run .#sunflower.deploy.blog-rhelmot-io` to update the blog without updating the system profile
+- ...but I can still roll the blog forward and back without rolling the system forward and back, because the blog is its own nix profile!
+
+Let's break it down.
+
+# Part 1: Static Site Generation
+
+What a hotly contentious topic. I could probably stand to care a little bit less, but the caring I do care isn't much.
+I started this journey trying to use Jekyll, but quickly found that the Ruby-isms were too much for me.
+I did at one point succeed at getting [a flake output which could build a whole Jekyll site](https://git.lain.faith/rhelmot/blog.rhelmot.io/commit/5e24401e67b613c7d81abcec8aed14fdf04a4159), but it was too much of a hack for me to deign to put it upon my domain.
+
+I eventually found [Coricamu](https://github.com/danth/coricamu), which is exactly what I want, though it seems to be abandoned.
+It's small enough that I feel comfortable carrying it on my shoulders, so I forked it and did the one small fix necessary to get it to work with current nixpkgs.
+I may mess around with theming later, but it provides exactly what I want and not much more.
+
+The source for this blog can be found [here](https://git.lain.faith/rhelmot/blog.rhelmot.io).
+
+Coricamu lets you build a site through a NixOS-style module system.
+I constructed my flake.nix such that it runs module evaluation with two modules:
+
+- the `blog.nix` file, defining the site metadata
+- a module constructed automatically by slapping each entry of `/posts/*/post.nix` into a post directive
+
+```nix
+let
+ posts = let
+ listingMap = builtins.readDir ./posts;
+ listing = builtins.attrNames listingMap;
+ getPostFile = post: (import ./posts/${post}/post.nix) // { slug = post; };
+ in builtins.map getPostFile listing;
+ in
+ coricamu.lib.generateFlakeOutputs {
+ outputName = "blog";
+ modules = [ ./blog.nix { inherit posts; }];
+ };
+```
+
+Then I just write some posts in markdown, put some quick metadata into a .nix file which references the markdown file, and build: `nix build .#blog`.
+I can also `nix run .#blog-preview` if I want a fancy server.
+Truly, we stand on the shoulders of giants.
+
+# Part 2: Managing Multiple Machines
+
+I have several machines I manage with a [central NixOS configuration repository](https://git.lain.faith/rhelmot/nixos-config) - some workstations and some servers.
+This flake.nix also does a directory scan in order to populate its outputs, this time scanning `sites` in order to populate `packages.${buildSystem}.nixosConfigurations.${site}`.
+
+Yes, `nixos-rebuild` will automatically search `packages.${buildSystem}` in order to build a system, allowing for cross compilation.
+This fact is particularly useful seeing as I work on [NixBSD](https://github.com/nixos-bsd/nixbsd) and am constantly cross compiling entire systems.
+There are various accoutrements in this repository which make it reasonable for me to use it for both NixOS and NixBSD systems, but that's a story for another time.
+
+Now, I can deploy any of these systems with `nixos-rebuild .#$HOST --remote-target $HOST --use-remote-sudo switch`, ideally with `--use-substitutes` since my home internet uplink is dogshit.
+
+There is a problem though - if I want to have my blog as a nix derivation, this means that I have to run a full system rebuild every time I publish a new post.
+It is very easy to simply drop the derivation output into the nginx configuration, but suddenly rollbacks are tied together with both the system and blog. Can we do better?
+
+# Part 3: Profiles and Deployment
+
+Yes, we can, with the power of [Nix Profiles](https://nix.dev/manual/nix/2.24/command-ref/files/profiles)!
+We won't be linking the typical kind of derivation output you would usually be putting in a user profile, with the system path and applications and such.
+Instead, our profile will simply be the static site build output derivation!
+
+I may in the future decide to standardize some sort of "nginx site derivation" layout so I can link non-static sites this way, but for now I just point the root of the site at `/nix/var/nix/profiles/blog-rhelmot-io`, and deploy as follows:
+
+```shell
+nix-copy-closure --to $SITE $DRV
+ssh $SITE sudo nix-env --set -p /nix/var/nix/profiles/blog-rhelmot-io $DRV
+```
+
+This can be automated! Check [deploy.nix](https://git.lain.faith/rhelmot/nixos-config/src/branch/main/deploy.nix) in my NixOS configuration for the final product.
+I define a list of deployments, each of which sets a profile name, a site to deploy on, and the package to deploy:
+
+```nix
+deployments = builtins.map mkDeploy [
+ {
+ profileName = "blog-rhelmot-io";
+ site = "sunflower";
+ targetPkg = flakeInputs."blog-rhelmot-io".packages.${platform}.blog;
+ }
+];
+```
+
+`mkDeploy` simply templates the previously-mentioned script with these parameters.
+We can then combine each script for a given site into a unified deploy script, along with a system profile rebuild for good measure:
+
+```nix
+filteredDeployments = builtins.filter (deployment: deployment.site == site) deployments;
+targetSystem = flakeInputs.self.packages.${platform}.${site}.system;
+deployAll = pkgs.writeShellScriptBin "deploy-all-${site}" (''
+ set -ex
+ # TODO take advantage of the nixos-rebuild infrastructure
+ nix-copy-closure --to ${site} ${targetSystem}
+ ssh ${site} 'sudo nix-env --set -p /nix/var/nix/profiles/system ${targetSystem} && sudo ${targetSystem}/bin/switch-to-configuration switch'
+ set +e
+'' + lib.concatStringsSep "\n" filteredDeployments);
+```
+
+It is annoying that `nixos-rebuild` proper doesn't support this use-case - that is, deploying a pre-built system profile.
+I have made the requisite change to enable this behavior in the [NixBSD fork of nixos-rebuild](https://github.com/nixos-bsd/nixbsd/blob/main/modules/installer/tools/nixos-rebuild.sh), but this script is obviously only appropriate for building BSD targets.
+
+Finally, we can deploy just the blog with a sub-attribute, `nix run .#sunflower.deploy.blog-rhelmot-io`:
+
+```nix
+filteredDeploymentsAttrs = builtins.listToAttrs (builtins.map (value: { name = value.profileName; inherit value; }) filteredDeployments);
+final = deployAll // filteredDeploymentsAttrs;
+```
+
+I believe this is the best of both worlds.
+
+# Conclusion
+
+Yippee woo hoo ya ha ha
+
+You too can take control of your systems like this. Go forth and nixify!
diff --git a/posts/hello/post.nix b/posts/hello/post.nix
index 30bcc3f..9d61aef 100644
--- a/posts/hello/post.nix
+++ b/posts/hello/post.nix
@@ -1,6 +1,6 @@
{
authors = [ "Audrey Dutcher" ];
- datetime = "2025-04-20 03:20-0700";
- title = "First post!!1!";
+ datetime = "2025-04-20 00:00-0700";
+ title = "Hello Blog - How I streamlined my application management with Nix";
body.markdownFile = ./body.md;
}