From c4dcb6e38b7d23d1c647a736e4578faf70e9a163 Mon Sep 17 00:00:00 2001 From: ryfrd Date: Mon, 11 Aug 2025 22:31:45 +0100 Subject: [PATCH] . --- config.toml | 6 +- content/info/index.md | 2 + .../nixos-remote-auto-static-site-deploy.md | 115 +++++++++++++++++ public/categories/index.html | 4 +- public/categories/index.xml | 94 ++++++++++++++ .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- public/image/self-hosting.png | Bin 0 -> 72327 bytes public/index.html | 8 +- public/index.xml | 96 +++++++++++++- public/info/index.html | 7 +- .../index.html | 4 +- public/lowkey-emacs-setup/index.html | 4 +- .../index.html | 4 +- public/multi-user-qtile-fiddling/index.html | 4 +- .../index.html | 119 ++++++++++++++++++ .../index.html | 119 ++++++++++++++++++ .../index.html | 4 +- public/posts/index.html | 8 +- public/posts/index.xml | 96 +++++++++++++- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- public/sitemap.xml | 19 +-- .../index.html | 4 +- public/tags/bash/index.html | 4 +- public/tags/bash/index.xml | 94 ++++++++++++++ public/tags/caddy/index.html | 4 +- public/tags/caddy/index.xml | 94 ++++++++++++++ public/tags/chess/index.html | 4 +- public/tags/chess/index.xml | 94 ++++++++++++++ public/tags/cooking/index.html | 4 +- public/tags/cooking/index.xml | 94 ++++++++++++++ public/tags/css/index.html | 4 +- public/tags/css/index.xml | 94 ++++++++++++++ public/tags/docker/index.html | 4 +- public/tags/docker/index.xml | 94 ++++++++++++++ public/tags/emacs/index.html | 4 +- public/tags/emacs/index.xml | 94 ++++++++++++++ public/tags/home-manager/index.html | 4 +- public/tags/home-manager/index.xml | 94 ++++++++++++++ public/tags/hugo/index.html | 4 +- public/tags/hugo/index.xml | 94 ++++++++++++++ public/tags/index.html | 12 +- public/tags/index.xml | 96 +++++++++++++- public/tags/javascript/index.html | 4 +- public/tags/javascript/index.xml | 94 ++++++++++++++ public/tags/lua/index.html | 4 +- public/tags/lua/index.xml | 94 ++++++++++++++ public/tags/music/index.html | 4 +- public/tags/music/index.xml | 94 ++++++++++++++ public/tags/neovim/index.html | 4 +- public/tags/neovim/index.xml | 94 ++++++++++++++ public/tags/nix-colors/index.html | 4 +- public/tags/nix-colors/index.xml | 94 ++++++++++++++ public/tags/nixos/index.html | 8 +- public/tags/nixos/index.xml | 96 +++++++++++++- public/tags/podman/index.html | 4 +- public/tags/podman/index.xml | 94 ++++++++++++++ public/tags/python/index.html | 4 +- public/tags/python/index.xml | 94 ++++++++++++++ public/tags/qtile/index.html | 4 +- public/tags/qtile/index.xml | 94 ++++++++++++++ public/tags/self-hosting/index.html | 4 +- public/tags/self-hosting/index.xml | 94 ++++++++++++++ public/tags/tailscale/index.html | 4 +- public/tags/tailscale/index.xml | 94 ++++++++++++++ .../index.html | 4 +- .../teeny-tiny-bash-fetch-script/index.html | 4 +- public/theming-nirvana/index.html | 4 +- public/translating-docker-to-nix/index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- static/image/self-hosting.png | Bin 0 -> 72327 bytes themes/etch/layouts/partials/footer.html | 2 +- 78 files changed, 2739 insertions(+), 110 deletions(-) create mode 100644 content/posts/nixos-remote-auto-static-site-deploy.md create mode 100644 public/image/self-hosting.png create mode 100644 public/over-engieered-nixos-blog-deployment-setup/index.html create mode 100644 public/over-engineered-nixos-blog-deployment-setup/index.html create mode 100644 static/image/self-hosting.png diff --git a/config.toml b/config.toml index 68177db..01e2389 100644 --- a/config.toml +++ b/config.toml @@ -12,9 +12,9 @@ pygmentsUseClasses = true [menu] [[menu.main]] - identifier = "info" - name = "info" - title = "info" + identifier = "--help" + name = "--help" + title = "--help" url = "/info/" weight = 20 diff --git a/content/info/index.md b/content/info/index.md index f094293..f49b687 100644 --- a/content/info/index.md +++ b/content/info/index.md @@ -1,3 +1,5 @@ This is a place to document bits and bobs I've been up to that have interested me. Expect linux and self-hosting tinkering, some novice programming, and maybe the occasional recipe. I tend to be a fool so take anything written here with a pinch of salt :) + +- [rss HERE!!](../index.xml) diff --git a/content/posts/nixos-remote-auto-static-site-deploy.md b/content/posts/nixos-remote-auto-static-site-deploy.md new file mode 100644 index 0000000..582c18b --- /dev/null +++ b/content/posts/nixos-remote-auto-static-site-deploy.md @@ -0,0 +1,115 @@ +--- +title: over-engineered (?) nixos blog deployment setup +date: 2025-08-11 +tags: + - nixos +draft: false +--- + +As is traditional with people hosting their own blog I'm going to do a post detailing EXACTLY how I'm hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?). + +![self-hosting](/image/self-hosting.png) + +I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I'd spend a couple of hours sorting the problem so I'd maybe save a minute once a year when I write a blog post. + +### Remote Rebuilds + +First, I'll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it [here](https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines). + +This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine. + +```nix +users.users.blog-king.openssh.authorizedKeys.keys = [ + # ssh public key on computer you're deploying from + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa" +]; + +nix.settings.trusted-users = [ "blog-king" ]; + +# ssh daemon +services.openssh = { + enable = true; + openFirewall = true; + settings = { + PasswordAuthentication = false; + PermitRootLogin = "no"; + }; +}; + +``` + +Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with `nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch`. +The `--ask-sudo-password` is not required if you ssh in as root though that would be a touch gauche. + +### Caddy + +You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at `/etc/blog`. + +```nix +networking.firewall.allowedTCPPorts = [ + 80 + 443 +]; + +services.caddy = { + enable = true; + extraConfig = '' + blog.example.org { + root * /etc/blog + file_server + } + ''; +}; +``` + +### Getting the files from git + +We have a web server pointing at `/etc/blog`. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory. + +I'm using the `fetchFromGitea` helper here which works for gitea and forgejo instances. +The `fetchFromGitHub` helper would look very similar. + +You can get the `rev` and `sha256` of the commit using `nix-prefetch-git`. + +Also note the little `/public` at the end of the `source` string. +That's the directory of the git repo that the website source lives. + +```nix +environment.etc."blog" = { + enable = true; + target = "blog"; + source = "${ + pkgs.fetchFromGitea { + domain = "git.example.org"; + owner = "james"; + repo = "blog"; + rev = "32d81f01388c88a259eed2ba52f4545dbcb1eb07"; + sha256 = "173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8"; + } + }/public"; + user = "caddy"; + group = "caddy"; +}; +``` + +So now with all that setup the blog post work flow is: + +- Commit rebuilt website to repo +- Update the `rev` and `sha256` to the new commit (this is annoying and I'm trying to work out a good way to automate it) +- Rebuild vps from laptop + +Not necessarily faster than the old rsync method but it's pretty damn declarative, that's for sure. diff --git a/public/categories/index.html b/public/categories/index.html index 7da7204..2665ac9 100644 --- a/public/categories/index.html +++ b/public/categories/index.html @@ -16,7 +16,7 @@ @@ -27,7 +27,7 @@ diff --git a/public/categories/index.xml b/public/categories/index.xml index e288b0c..e7fd74d 100644 --- a/public/categories/index.xml +++ b/public/categories/index.xml @@ -11,6 +11,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/chess.com-api-and-the-continuing-search-for-en-passant-checkmate/index.html b/public/chess.com-api-and-the-continuing-search-for-en-passant-checkmate/index.html index a931498..99c1e5e 100644 --- a/public/chess.com-api-and-the-continuing-search-for-en-passant-checkmate/index.html +++ b/public/chess.com-api-and-the-continuing-search-for-en-passant-checkmate/index.html @@ -15,7 +15,7 @@ @@ -74,7 +74,7 @@ diff --git a/public/chess.com-api-and-the-search-for-en-passant-checkmate/index.html b/public/chess.com-api-and-the-search-for-en-passant-checkmate/index.html index 7a6b73d..57f791a 100644 --- a/public/chess.com-api-and-the-search-for-en-passant-checkmate/index.html +++ b/public/chess.com-api-and-the-search-for-en-passant-checkmate/index.html @@ -15,7 +15,7 @@ @@ -65,7 +65,7 @@ diff --git a/public/declarative-firefox-config-with-home-manager-on-nixos/index.html b/public/declarative-firefox-config-with-home-manager-on-nixos/index.html index 284b7e4..22e7061 100644 --- a/public/declarative-firefox-config-with-home-manager-on-nixos/index.html +++ b/public/declarative-firefox-config-with-home-manager-on-nixos/index.html @@ -15,7 +15,7 @@ @@ -85,7 +85,7 @@ diff --git a/public/elite-bread-dough-for-lazy-boys/index.html b/public/elite-bread-dough-for-lazy-boys/index.html index 69d8608..c741ed5 100644 --- a/public/elite-bread-dough-for-lazy-boys/index.html +++ b/public/elite-bread-dough-for-lazy-boys/index.html @@ -15,7 +15,7 @@ @@ -65,7 +65,7 @@ diff --git a/public/get-the-thoughts-out-of-your-head-and-into-a-digital-format-with-this-python-journal-script/index.html b/public/get-the-thoughts-out-of-your-head-and-into-a-digital-format-with-this-python-journal-script/index.html index 91dca20..a1764e3 100644 --- a/public/get-the-thoughts-out-of-your-head-and-into-a-digital-format-with-this-python-journal-script/index.html +++ b/public/get-the-thoughts-out-of-your-head-and-into-a-digital-format-with-this-python-journal-script/index.html @@ -15,7 +15,7 @@ @@ -83,7 +83,7 @@ diff --git a/public/image/self-hosting.png b/public/image/self-hosting.png new file mode 100644 index 0000000000000000000000000000000000000000..7b190feaa6f5cec9f286ae4dad7ae188f95f9229 GIT binary patch literal 72327 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 @@ -25,6 +25,10 @@
diff --git a/public/index.xml b/public/index.xml index 6941e59..8a0d9e8 100644 --- a/public/index.xml +++ b/public/index.xml @@ -6,12 +6,106 @@ Recent content on James' Blog :-) Hugo -- gohugo.io en-GB - Tue, 25 Jun 2024 00:00:00 +0000 + Mon, 11 Aug 2025 00:00:00 +0000 + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/info/index.html b/public/info/index.html index ce49634..89e8008 100644 --- a/public/info/index.html +++ b/public/info/index.html @@ -15,7 +15,7 @@ @@ -28,10 +28,13 @@

This is a place to document bits and bobs I’ve been up to that have interested me. Expect linux and self-hosting tinkering, some novice programming, and maybe the occasional recipe. I tend to be a fool so take anything written here with a pinch of salt :)

+ diff --git a/public/learning-about-qtile-widgets-via-the-medium-of-cricket/index.html b/public/learning-about-qtile-widgets-via-the-medium-of-cricket/index.html index 71f4004..846d4fa 100644 --- a/public/learning-about-qtile-widgets-via-the-medium-of-cricket/index.html +++ b/public/learning-about-qtile-widgets-via-the-medium-of-cricket/index.html @@ -15,7 +15,7 @@ @@ -131,7 +131,7 @@ diff --git a/public/lowkey-emacs-setup/index.html b/public/lowkey-emacs-setup/index.html index 0a8b92a..046e8bd 100644 --- a/public/lowkey-emacs-setup/index.html +++ b/public/lowkey-emacs-setup/index.html @@ -15,7 +15,7 @@ @@ -103,7 +103,7 @@ diff --git a/public/making-nix-colors-talk-to-neovim/index.html b/public/making-nix-colors-talk-to-neovim/index.html index 977aaac..534c87e 100644 --- a/public/making-nix-colors-talk-to-neovim/index.html +++ b/public/making-nix-colors-talk-to-neovim/index.html @@ -15,7 +15,7 @@ @@ -73,7 +73,7 @@ After moving across most of my stuff I came across the problem of how to hook th diff --git a/public/multi-user-qtile-fiddling/index.html b/public/multi-user-qtile-fiddling/index.html index 2b757e2..00ba6f7 100644 --- a/public/multi-user-qtile-fiddling/index.html +++ b/public/multi-user-qtile-fiddling/index.html @@ -15,7 +15,7 @@ @@ -99,7 +99,7 @@ diff --git a/public/over-engieered-nixos-blog-deployment-setup/index.html b/public/over-engieered-nixos-blog-deployment-setup/index.html new file mode 100644 index 0000000..00d9d8e --- /dev/null +++ b/public/over-engieered-nixos-blog-deployment-setup/index.html @@ -0,0 +1,119 @@ + + + + + + + + + + + Over-engieered nixos blog deployment setup + + +
+
+
+

Over-engieered nixos blog deployment setup

+
+ +
+

As is traditional with people hosting their own blog I’m going to do a post detailing EXACTLY how I’m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).

+

self-hosting

+

I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engieered. +So in true nixos fashion I decided I’d spend a couple of hours sorting the problem so I’d maybe save a minute once a year when I write a blog post.

+

Remote Rebuilds

+

First, I’ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it here.

+

This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.

+
users.users.blog-king.openssh.authorizedKeys.keys = [ 
+  # ssh public key on computer you're deploying from
+  "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa"
+];
+
+nix.settings.trusted-users = [ "blog-king" ];
+
+# ssh daemon
+services.openssh = {
+  enable = true;
+  openFirewall = true;
+  settings = {
+    PasswordAuthentication = false;
+    PermitRootLogin = "no";
+  };
+};
+

Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch. +The --ask-sudo-password is not required if you ssh in as root though that would be a touch gauche.

+

Caddy

+

You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at /etc/blog.

+
networking.firewall.allowedTCPPorts = [
+  80
+  443
+];
+
+services.caddy = {
+  enable = true;
+  extraConfig = ''
+    blog.example.org {
+      root * /etc/blog
+      file_server
+    }
+  '';
+};
+

Getting the files from git

+

We have a web server pointing at /etc/blog. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.

+

I’m using the fetchFromGitea helper here which works for gitea and forgejo instances. +The fetchFromGitHub helper would look very similar.

+

You can get the rev and sha256 of the commit using nix-prefetch-git. +Also note the little /public at the end of the source string. +That’s the directory of the git repo that the wesite source lives.

+
environment.etc."blog" = {
+  enable = true;
+  target = "blog";
+  source = "${
+    pkgs.fetchFromGitea {
+      domain = "git.dymc.win";
+      owner = "james";
+      repo = "blog";
+      rev = "32d81f01388c88a259eed2ba52f4545dbcb1eb07";
+      sha256 = "173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8";
+    }
+  }/public";
+  user = "caddy";
+  group = "caddy";
+};
+

So now with all that setup the blog post work flow is:

+
    +
  • Commit rebuilt website to repo
  • +
  • Update the rev and sha256 to the new commit (this is annoying and I’m trying to work out a good way to automate it)
  • +
  • Rebuild vps from laptop
  • +
+

Not necessarily faster than the old rsync method but it’s pretty damn declarative.

+
+ +
+ + diff --git a/public/over-engineered-nixos-blog-deployment-setup/index.html b/public/over-engineered-nixos-blog-deployment-setup/index.html new file mode 100644 index 0000000..695d792 --- /dev/null +++ b/public/over-engineered-nixos-blog-deployment-setup/index.html @@ -0,0 +1,119 @@ + + + + + + + + + + + over-engineered (?) nixos blog deployment setup + + +
+
+
+

over-engineered (?) nixos blog deployment setup

+
+ +
+

As is traditional with people hosting their own blog I’m going to do a post detailing EXACTLY how I’m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).

+

self-hosting

+

I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I’d spend a couple of hours sorting the problem so I’d maybe save a minute once a year when I write a blog post.

+

Remote Rebuilds

+

First, I’ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it here.

+

This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.

+
users.users.blog-king.openssh.authorizedKeys.keys = [ 
+  # ssh public key on computer you're deploying from
+  "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa"
+];
+
+nix.settings.trusted-users = [ "blog-king" ];
+
+# ssh daemon
+services.openssh = {
+  enable = true;
+  openFirewall = true;
+  settings = {
+    PasswordAuthentication = false;
+    PermitRootLogin = "no";
+  };
+};
+

Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch. +The --ask-sudo-password is not required if you ssh in as root though that would be a touch gauche.

+

Caddy

+

You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at /etc/blog.

+
networking.firewall.allowedTCPPorts = [
+  80
+  443
+];
+
+services.caddy = {
+  enable = true;
+  extraConfig = ''
+    blog.example.org {
+      root * /etc/blog
+      file_server
+    }
+  '';
+};
+

Getting the files from git

+

We have a web server pointing at /etc/blog. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.

+

I’m using the fetchFromGitea helper here which works for gitea and forgejo instances. +The fetchFromGitHub helper would look very similar.

+

You can get the rev and sha256 of the commit using nix-prefetch-git.

+

Also note the little /public at the end of the source string. +That’s the directory of the git repo that the website source lives.

+
environment.etc."blog" = {
+  enable = true;
+  target = "blog";
+  source = "${
+    pkgs.fetchFromGitea {
+      domain = "git.example.org";
+      owner = "james";
+      repo = "blog";
+      rev = "32d81f01388c88a259eed2ba52f4545dbcb1eb07";
+      sha256 = "173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8";
+    }
+  }/public";
+  user = "caddy";
+  group = "caddy";
+};
+

So now with all that setup the blog post work flow is:

+
    +
  • Commit rebuilt website to repo
  • +
  • Update the rev and sha256 to the new commit (this is annoying and I’m trying to work out a good way to automate it)
  • +
  • Rebuild vps from laptop
  • +
+

Not necessarily faster than the old rsync method but it’s pretty damn declarative, that’s for sure.

+
+ +
+ + diff --git a/public/podcast-setup-for-broke-boys-whose-trash-phone-cant-hack-modern-apps/index.html b/public/podcast-setup-for-broke-boys-whose-trash-phone-cant-hack-modern-apps/index.html index 9b8f151..55b2d33 100644 --- a/public/podcast-setup-for-broke-boys-whose-trash-phone-cant-hack-modern-apps/index.html +++ b/public/podcast-setup-for-broke-boys-whose-trash-phone-cant-hack-modern-apps/index.html @@ -15,7 +15,7 @@ @@ -111,7 +111,7 @@ diff --git a/public/posts/index.html b/public/posts/index.html index c556a6a..8601287 100644 --- a/public/posts/index.html +++ b/public/posts/index.html @@ -16,12 +16,16 @@
diff --git a/public/posts/index.xml b/public/posts/index.xml index e7fb5fc..2e8efd7 100644 --- a/public/posts/index.xml +++ b/public/posts/index.xml @@ -6,12 +6,106 @@ Recent content in Posts on James' Blog :-) Hugo -- gohugo.io en-GB - Tue, 25 Jun 2024 00:00:00 +0000 + Mon, 11 Aug 2025 00:00:00 +0000 + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/rudimentary-local-scrobbling-with-bash/index.html b/public/rudimentary-local-scrobbling-with-bash/index.html index 3dfe7b3..2ad7475 100644 --- a/public/rudimentary-local-scrobbling-with-bash/index.html +++ b/public/rudimentary-local-scrobbling-with-bash/index.html @@ -15,7 +15,7 @@ @@ -53,7 +53,7 @@ diff --git a/public/setting-up-a-lean-mean-hugo-blogging-theme/index.html b/public/setting-up-a-lean-mean-hugo-blogging-theme/index.html index 3827d3f..db4720a 100644 --- a/public/setting-up-a-lean-mean-hugo-blogging-theme/index.html +++ b/public/setting-up-a-lean-mean-hugo-blogging-theme/index.html @@ -15,7 +15,7 @@ @@ -105,7 +105,7 @@ diff --git a/public/simple-nixos-config-for-vps-static-site/index.html b/public/simple-nixos-config-for-vps-static-site/index.html index cd9a45a..ed259d2 100644 --- a/public/simple-nixos-config-for-vps-static-site/index.html +++ b/public/simple-nixos-config-for-vps-static-site/index.html @@ -15,7 +15,7 @@ @@ -79,7 +79,7 @@ diff --git a/public/sitemap.xml b/public/sitemap.xml index 72a6b52..2101e50 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -3,10 +3,19 @@ xmlns:xhtml="http://www.w3.org/1999/xhtml"> https://nonsense.dymc.win/ - 2024-06-25T00:00:00+00:00 + 2025-08-11T00:00:00+00:00 + + https://nonsense.dymc.win/tags/nixos/ + 2025-08-11T00:00:00+00:00 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + 2025-08-11T00:00:00+00:00 https://nonsense.dymc.win/posts/ - 2024-06-25T00:00:00+00:00 + 2025-08-11T00:00:00+00:00 + + https://nonsense.dymc.win/tags/ + 2025-08-11T00:00:00+00:00 https://nonsense.dymc.win/tags/lua/ 2024-04-06T00:00:00+00:00 @@ -16,9 +25,6 @@ https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ 2024-04-06T00:00:00+00:00 - - https://nonsense.dymc.win/tags/ - 2024-04-06T00:00:00+00:00 https://nonsense.dymc.win/tags/home-manager/ 2023-08-18T00:00:00+00:00 @@ -28,9 +34,6 @@ https://nonsense.dymc.win/tags/nix-colors/ 2023-08-18T00:00:00+00:00 - - https://nonsense.dymc.win/tags/nixos/ - 2023-08-18T00:00:00+00:00 https://nonsense.dymc.win/tags/css/ 2023-06-26T00:00:00+00:00 diff --git a/public/so-you-want-to-write-a-neovim-plugin-with-lua/index.html b/public/so-you-want-to-write-a-neovim-plugin-with-lua/index.html index f28e661..89396cd 100644 --- a/public/so-you-want-to-write-a-neovim-plugin-with-lua/index.html +++ b/public/so-you-want-to-write-a-neovim-plugin-with-lua/index.html @@ -15,7 +15,7 @@ @@ -96,7 +96,7 @@ As a little coda, this is how you can use your fancy new plugin using -

~~~ made with hugo and my bastardised version of this nice theme ~~~

+

made with hugo and my bastardised version of this nice theme

diff --git a/public/tags/bash/index.html b/public/tags/bash/index.html index af67343..7cd78a9 100644 --- a/public/tags/bash/index.html +++ b/public/tags/bash/index.html @@ -16,7 +16,7 @@ @@ -35,7 +35,7 @@ diff --git a/public/tags/bash/index.xml b/public/tags/bash/index.xml index 70cd1ab..769bfcd 100644 --- a/public/tags/bash/index.xml +++ b/public/tags/bash/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/caddy/index.html b/public/tags/caddy/index.html index bdc063e..00b27d4 100644 --- a/public/tags/caddy/index.html +++ b/public/tags/caddy/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/caddy/index.xml b/public/tags/caddy/index.xml index e44309d..20d0e96 100644 --- a/public/tags/caddy/index.xml +++ b/public/tags/caddy/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/chess/index.html b/public/tags/chess/index.html index 60cdd97..085bd95 100644 --- a/public/tags/chess/index.html +++ b/public/tags/chess/index.html @@ -16,7 +16,7 @@ @@ -35,7 +35,7 @@ diff --git a/public/tags/chess/index.xml b/public/tags/chess/index.xml index 0b91b1b..3fe3425 100644 --- a/public/tags/chess/index.xml +++ b/public/tags/chess/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/cooking/index.html b/public/tags/cooking/index.html index acb2d06..667953e 100644 --- a/public/tags/cooking/index.html +++ b/public/tags/cooking/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/cooking/index.xml b/public/tags/cooking/index.xml index e095db4..82553a1 100644 --- a/public/tags/cooking/index.xml +++ b/public/tags/cooking/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/css/index.html b/public/tags/css/index.html index b26eb60..a537f0e 100644 --- a/public/tags/css/index.html +++ b/public/tags/css/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/css/index.xml b/public/tags/css/index.xml index 442ffbc..5bff4c2 100644 --- a/public/tags/css/index.xml +++ b/public/tags/css/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/docker/index.html b/public/tags/docker/index.html index e9845fd..2281beb 100644 --- a/public/tags/docker/index.html +++ b/public/tags/docker/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/docker/index.xml b/public/tags/docker/index.xml index 38c6531..65d9edb 100644 --- a/public/tags/docker/index.xml +++ b/public/tags/docker/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/emacs/index.html b/public/tags/emacs/index.html index 21ce3f8..c68479f 100644 --- a/public/tags/emacs/index.html +++ b/public/tags/emacs/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/emacs/index.xml b/public/tags/emacs/index.xml index ee429d3..81a9db2 100644 --- a/public/tags/emacs/index.xml +++ b/public/tags/emacs/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/home-manager/index.html b/public/tags/home-manager/index.html index be53f05..a46c6b2 100644 --- a/public/tags/home-manager/index.html +++ b/public/tags/home-manager/index.html @@ -16,7 +16,7 @@ @@ -43,7 +43,7 @@ diff --git a/public/tags/home-manager/index.xml b/public/tags/home-manager/index.xml index 33ae1b8..8c0ae3e 100644 --- a/public/tags/home-manager/index.xml +++ b/public/tags/home-manager/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/hugo/index.html b/public/tags/hugo/index.html index 94a88d4..a16ee59 100644 --- a/public/tags/hugo/index.html +++ b/public/tags/hugo/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/hugo/index.xml b/public/tags/hugo/index.xml index fb7f0e2..6538ba9 100644 --- a/public/tags/hugo/index.xml +++ b/public/tags/hugo/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/index.html b/public/tags/index.html index f893249..90bf9aa 100644 --- a/public/tags/index.html +++ b/public/tags/index.html @@ -16,7 +16,7 @@ @@ -24,6 +24,10 @@

Tags

    +
  • + Nixos - +
  • +
  • Lua -
  • @@ -40,10 +44,6 @@ Nix-Colors - -
  • - Nixos - -
  • -
  • Css -
  • @@ -107,7 +107,7 @@
diff --git a/public/tags/index.xml b/public/tags/index.xml index 4d0a742..a3b0527 100644 --- a/public/tags/index.xml +++ b/public/tags/index.xml @@ -6,12 +6,106 @@ Recent content in Tags on James' Blog :-) Hugo -- gohugo.io en-GB - Sat, 06 Apr 2024 00:00:00 +0000 + Mon, 11 Aug 2025 00:00:00 +0000 + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/javascript/index.html b/public/tags/javascript/index.html index a6f946e..a5ddc4e 100644 --- a/public/tags/javascript/index.html +++ b/public/tags/javascript/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/javascript/index.xml b/public/tags/javascript/index.xml index 0cb74d5..4bcfecf 100644 --- a/public/tags/javascript/index.xml +++ b/public/tags/javascript/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/lua/index.html b/public/tags/lua/index.html index 4304673..f517467 100644 --- a/public/tags/lua/index.html +++ b/public/tags/lua/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/lua/index.xml b/public/tags/lua/index.xml index ced128c..58e2a4e 100644 --- a/public/tags/lua/index.xml +++ b/public/tags/lua/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/music/index.html b/public/tags/music/index.html index 70f8601..d4203ac 100644 --- a/public/tags/music/index.html +++ b/public/tags/music/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/music/index.xml b/public/tags/music/index.xml index 9064777..b18b13d 100644 --- a/public/tags/music/index.xml +++ b/public/tags/music/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/neovim/index.html b/public/tags/neovim/index.html index cfb597f..0dbe89a 100644 --- a/public/tags/neovim/index.html +++ b/public/tags/neovim/index.html @@ -16,7 +16,7 @@ @@ -35,7 +35,7 @@ diff --git a/public/tags/neovim/index.xml b/public/tags/neovim/index.xml index a840dd4..09091fe 100644 --- a/public/tags/neovim/index.xml +++ b/public/tags/neovim/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/nix-colors/index.html b/public/tags/nix-colors/index.html index 40f3773..fa969cb 100644 --- a/public/tags/nix-colors/index.html +++ b/public/tags/nix-colors/index.html @@ -16,7 +16,7 @@ @@ -35,7 +35,7 @@ diff --git a/public/tags/nix-colors/index.xml b/public/tags/nix-colors/index.xml index 7782cdc..1141ac4 100644 --- a/public/tags/nix-colors/index.xml +++ b/public/tags/nix-colors/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/nixos/index.html b/public/tags/nixos/index.html index 26b37b6..549d575 100644 --- a/public/tags/nixos/index.html +++ b/public/tags/nixos/index.html @@ -16,7 +16,7 @@ @@ -24,6 +24,10 @@

Nixos

diff --git a/public/tags/nixos/index.xml b/public/tags/nixos/index.xml index f403965..13eb9f2 100644 --- a/public/tags/nixos/index.xml +++ b/public/tags/nixos/index.xml @@ -6,12 +6,106 @@ Recent content in Nixos on James' Blog :-) Hugo -- gohugo.io en-GB - Fri, 18 Aug 2023 00:00:00 +0000 + Mon, 11 Aug 2025 00:00:00 +0000 + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/podman/index.html b/public/tags/podman/index.html index ee82a9d..a2b7666 100644 --- a/public/tags/podman/index.html +++ b/public/tags/podman/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/podman/index.xml b/public/tags/podman/index.xml index 1440607..d1bc9d0 100644 --- a/public/tags/podman/index.xml +++ b/public/tags/podman/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/python/index.html b/public/tags/python/index.html index d85449b..cf857c6 100644 --- a/public/tags/python/index.html +++ b/public/tags/python/index.html @@ -16,7 +16,7 @@ @@ -55,7 +55,7 @@ diff --git a/public/tags/python/index.xml b/public/tags/python/index.xml index bd85ff0..a1bae67 100644 --- a/public/tags/python/index.xml +++ b/public/tags/python/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/qtile/index.html b/public/tags/qtile/index.html index c926b6a..5827774 100644 --- a/public/tags/qtile/index.html +++ b/public/tags/qtile/index.html @@ -16,7 +16,7 @@ @@ -39,7 +39,7 @@ diff --git a/public/tags/qtile/index.xml b/public/tags/qtile/index.xml index 92d1a8a..e8240b4 100644 --- a/public/tags/qtile/index.xml +++ b/public/tags/qtile/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/self-hosting/index.html b/public/tags/self-hosting/index.html index a3aeab5..58d1cc2 100644 --- a/public/tags/self-hosting/index.html +++ b/public/tags/self-hosting/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/self-hosting/index.xml b/public/tags/self-hosting/index.xml index 1d69522..d6b9014 100644 --- a/public/tags/self-hosting/index.xml +++ b/public/tags/self-hosting/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tags/tailscale/index.html b/public/tags/tailscale/index.html index 3c180e5..43e489c 100644 --- a/public/tags/tailscale/index.html +++ b/public/tags/tailscale/index.html @@ -16,7 +16,7 @@ @@ -31,7 +31,7 @@ diff --git a/public/tags/tailscale/index.xml b/public/tags/tailscale/index.xml index 72da0b2..f5a5ab2 100644 --- a/public/tags/tailscale/index.xml +++ b/public/tags/tailscale/index.xml @@ -12,6 +12,100 @@ + + over-engineered (?) nixos blog deployment setup + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + Mon, 11 Aug 2025 00:00:00 +0000 + + https://nonsense.dymc.win/over-engineered-nixos-blog-deployment-setup/ + <p>As is traditional with people hosting their own blog I&rsquo;m going to do a post detailing EXACTLY how I&rsquo;m hosting my blog. +Down to the last dirty detail. +I have nothing better to talk about. +Here is a diagram I edited to illustrate (credit to xkcd I think?).</p> +<p><img src="https://nonsense.dymc.win/image/self-hosting.png" alt="self-hosting"></p> +<p>I host my site on a hetzner vps running nixos. +I also have a git repo where all the static files for my blog live. +I had previously been manually rsyncing the website up to my vps from my laptop. +Qute an easy, efficient solution; it worked well. +But not very nixos; far too simple, not sufficiently over-engineered. +So in true nixos fashion I decided I&rsquo;d spend a couple of hours sorting the problem so I&rsquo;d maybe save a minute once a year when I write a blog post.</p> +<h3 id="remote-rebuilds">Remote Rebuilds</h3> +<p>First, I&rsquo;ll show the fancy way to rebuild your remote nixos systems via ssh. +In my case, this means I can rebuild my hetzner box from my laptop. +You can read the wiki about it <a href="https://wiki.nixos.org/wiki/Nixos-rebuild#Deploying_on_other_machines">here</a>.</p> +<p>This sets up ssh with key-based authentication and lets our local user in. +This config belongs on the remote machine.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">blog-king</span><span class="o">.</span><span class="n">openssh</span><span class="o">.</span><span class="n">authorizedKeys</span><span class="o">.</span><span class="n">keys</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="c1"># ssh public key on computer you&#39;re deploying from</span> +</span></span><span class="line"><span class="cl"> <span class="s2">&#34;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPzFa1hmmmmmPL5HvJZhXVEaWiZIMi34oR6AOcaaaaaaa&#34;</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">nix</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">trusted-users</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;blog-king&#34;</span> <span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="c1"># ssh daemon</span> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">openssh</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">openFirewall</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">PasswordAuthentication</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">PermitRootLogin</span> <span class="o">=</span> <span class="s2">&#34;no&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">};</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>Once you have this going on your remote machine (in my case the hetzner vps) you should be able to rebuild the remote machine with <code>nixos-rebuild --target-host blog-king@remote-ip-here --ask-sudo-password switch</code>. +The <code>--ask-sudo-password</code> is not required if you ssh in as root though that would be a touch gauche.</p> +<h3 id="caddy">Caddy</h3> +<p>You can do this with whatever your preferred webserver is. +I am a caddy stan. +This opens the necessary ports in the firewall and sets up caddy in file server mode pointing at <code>/etc/blog</code>.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">networking</span><span class="o">.</span><span class="n">firewall</span><span class="o">.</span><span class="n">allowedTCPPorts</span> <span class="o">=</span> <span class="p">[</span> +</span></span><span class="line"><span class="cl"> <span class="mi">80</span> +</span></span><span class="line"><span class="cl"> <span class="mi">443</span> +</span></span><span class="line"><span class="cl"><span class="p">];</span> +</span></span><span class="line"><span class="cl"> +</span></span><span class="line"><span class="cl"><span class="n">services</span><span class="o">.</span><span class="n">caddy</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">extraConfig</span> <span class="o">=</span> <span class="s1">&#39;&#39; +</span></span></span><span class="line"><span class="cl"><span class="s1"> blog.example.org { +</span></span></span><span class="line"><span class="cl"><span class="s1"> root * /etc/blog +</span></span></span><span class="line"><span class="cl"><span class="s1"> file_server +</span></span></span><span class="line"><span class="cl"><span class="s1"> } +</span></span></span><span class="line"><span class="cl"><span class="s1"> &#39;&#39;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><h3 id="getting-the-files-from-git">Getting the files from git</h3> +<p>We have a web server pointing at <code>/etc/blog</code>. +The last piece of the puzzle is to get the static files from our git repo and spit them out in that directory.</p> +<p>I&rsquo;m using the <code>fetchFromGitea</code> helper here which works for gitea and forgejo instances. +The <code>fetchFromGitHub</code> helper would look very similar.</p> +<p>You can get the <code>rev</code> and <code>sha256</code> of the commit using <code>nix-prefetch-git</code>.</p> +<p>Also note the little <code>/public</code> at the end of the <code>source</code> string. +That&rsquo;s the directory of the git repo that the website source lives.</p> +<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">environment</span><span class="o">.</span><span class="n">etc</span><span class="o">.</span><span class="s2">&#34;blog&#34;</span> <span class="o">=</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">source</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">${</span> +</span></span><span class="line"><span class="cl"> <span class="n">pkgs</span><span class="o">.</span><span class="n">fetchFromGitea</span> <span class="p">{</span> +</span></span><span class="line"><span class="cl"> <span class="n">domain</span> <span class="o">=</span> <span class="s2">&#34;git.example.org&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">owner</span> <span class="o">=</span> <span class="s2">&#34;james&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">repo</span> <span class="o">=</span> <span class="s2">&#34;blog&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">rev</span> <span class="o">=</span> <span class="s2">&#34;32d81f01388c88a259eed2ba52f4545dbcb1eb07&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">sha256</span> <span class="o">=</span> <span class="s2">&#34;173g99dj8y4sw1v7f1s5f7zgcrrlr6dly9n6ysr2i4jg095lkxw8&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="p">}</span> +</span></span><span class="line"><span class="cl"> <span class="si">}</span><span class="s2">/public&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">user</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"> <span class="n">group</span> <span class="o">=</span> <span class="s2">&#34;caddy&#34;</span><span class="p">;</span> +</span></span><span class="line"><span class="cl"><span class="p">};</span> +</span></span></code></pre></div><p>So now with all that setup the blog post work flow is:</p> +<ul> +<li>Commit rebuilt website to repo</li> +<li>Update the <code>rev</code> and <code>sha256</code> to the new commit (this is annoying and I&rsquo;m trying to work out a good way to automate it)</li> +<li>Rebuild vps from laptop</li> +</ul> +<p>Not necessarily faster than the old rsync method but it&rsquo;s pretty damn declarative, that&rsquo;s for sure.</p> + + + + + so you want to write a neovim plugin with lua https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/ diff --git a/public/tailscale-caddy-and-nixos-containers-a-match-made-in-heaven/index.html b/public/tailscale-caddy-and-nixos-containers-a-match-made-in-heaven/index.html index 312042a..ff1440b 100644 --- a/public/tailscale-caddy-and-nixos-containers-a-match-made-in-heaven/index.html +++ b/public/tailscale-caddy-and-nixos-containers-a-match-made-in-heaven/index.html @@ -15,7 +15,7 @@ @@ -88,7 +88,7 @@ diff --git a/public/teeny-tiny-bash-fetch-script/index.html b/public/teeny-tiny-bash-fetch-script/index.html index 850a4f1..566ac16 100644 --- a/public/teeny-tiny-bash-fetch-script/index.html +++ b/public/teeny-tiny-bash-fetch-script/index.html @@ -15,7 +15,7 @@ @@ -99,7 +99,7 @@ diff --git a/public/theming-nirvana/index.html b/public/theming-nirvana/index.html index 798071d..10e7572 100644 --- a/public/theming-nirvana/index.html +++ b/public/theming-nirvana/index.html @@ -15,7 +15,7 @@ @@ -118,7 +118,7 @@ diff --git a/public/translating-docker-to-nix/index.html b/public/translating-docker-to-nix/index.html index 3b335c3..c68f6a1 100644 --- a/public/translating-docker-to-nix/index.html +++ b/public/translating-docker-to-nix/index.html @@ -15,7 +15,7 @@ @@ -73,7 +73,7 @@ diff --git a/public/upgrade-your-qtile-setup-with-a-cute-dropdown-terminal/index.html b/public/upgrade-your-qtile-setup-with-a-cute-dropdown-terminal/index.html index 82963ab..e0475c8 100644 --- a/public/upgrade-your-qtile-setup-with-a-cute-dropdown-terminal/index.html +++ b/public/upgrade-your-qtile-setup-with-a-cute-dropdown-terminal/index.html @@ -15,7 +15,7 @@ @@ -71,7 +71,7 @@ diff --git a/public/vanilla-javascript-theme-toggle-for-simpletons/index.html b/public/vanilla-javascript-theme-toggle-for-simpletons/index.html index 5fde248..c126992 100644 --- a/public/vanilla-javascript-theme-toggle-for-simpletons/index.html +++ b/public/vanilla-javascript-theme-toggle-for-simpletons/index.html @@ -15,7 +15,7 @@ @@ -106,7 +106,7 @@ diff --git a/static/image/self-hosting.png b/static/image/self-hosting.png new file mode 100644 index 0000000000000000000000000000000000000000..7b190feaa6f5cec9f286ae4dad7ae188f95f9229 GIT binary patch literal 72327 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 -

~~~ made with hugo and my bastardised version of this nice theme ~~~

+

made with hugo and my bastardised version of this nice theme