<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Web-Development on paradigmatic.systems</title>
    <link>https://paradigmatic.systems/tags/web-development/</link>
    <description>Recent content in Web-Development on paradigmatic.systems</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 27 Jul 2025 14:30:00 +0000</lastBuildDate><atom:link href="https://paradigmatic.systems/tags/web-development/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Deploying Hugo in NixOS</title>
      <link>https://paradigmatic.systems/posts/getting-started-with-hugo/</link>
      <pubDate>Sun, 27 Jul 2025 14:30:00 +0000</pubDate>
      
      <guid>https://paradigmatic.systems/posts/getting-started-with-hugo/</guid>
      <description>&lt;p&gt;While my instinct is to use Phoenix for &lt;em&gt;everything&lt;/em&gt;, I had to admit it&amp;rsquo;s overkill for a personal website. I&amp;rsquo;m not here to flex complex backend integrations or live features. I&amp;rsquo;ve heard good things about Hugo, so maybe it&amp;rsquo;s time to try it. I will describe how &lt;code&gt;Nix&lt;/code&gt; and &lt;code&gt;deploy-rs&lt;/code&gt; allowed me to get framed out and deployed in one short and painless sitting!&lt;/p&gt;
&lt;p&gt;A quick google search yielded a serviceable &lt;a href=&#34;https://www.chrisportela.com/posts/this-site-is-a-flake/&#34;&gt;flake&lt;/a&gt; for a Hugo dev environment. So I just ran &lt;code&gt;nix develop&lt;/code&gt;, &lt;code&gt;hugo new site&lt;/code&gt; and then had a Claude agent throw in some placeholder content. 5 minutes later I had something serving on localhost.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>While my instinct is to use Phoenix for <em>everything</em>, I had to admit it&rsquo;s overkill for a personal website. I&rsquo;m not here to flex complex backend integrations or live features. I&rsquo;ve heard good things about Hugo, so maybe it&rsquo;s time to try it. I will describe how <code>Nix</code> and <code>deploy-rs</code> allowed me to get framed out and deployed in one short and painless sitting!</p>
<p>A quick google search yielded a serviceable <a href="https://www.chrisportela.com/posts/this-site-is-a-flake/">flake</a> for a Hugo dev environment. So I just ran <code>nix develop</code>, <code>hugo new site</code> and then had a Claude agent throw in some placeholder content. 5 minutes later I had something serving on localhost.</p>
<p>It&rsquo;s placeholder slop but I decided to complete the loop and ship it. The nice thing is this flake also exports the built site as a package. Excellent! I verified that <code>nix build</code> succeeds.</p>
<p>Then I popped into my deployment repo that has the configuration for my NixOS VPS. The top-level flake gets a new input attribute that pulls in the Hugo repo from local storage: <code>inputs.paradigmatic.url = &quot;path:/path/to/paradigmatic.systems&quot;;</code>. Then my <code>nginx</code> config gets a new entry:</p>
<pre tabindex="0"><code>virtualHosts.&#34;paradigmatic.systems&#34; = {
  enableACME = true;
  forceSSL = true;
  root = &#34;${paradigmatic.packages.${system}.website}&#34;;
};
</code></pre><p>Just like that, I&rsquo;ve got a new reverse proxy serving this static site. Since I already have <code>deploy-rs</code> set up, a simple <code>deploy</code> command kicks of the Nix magic which does the build and sends up the new system. Deployment failed the first time because the Acme certificates hadn&rsquo;t gone through. But thanks to magic rollbacks, the system was uninterrupted.</p>
<p>At time of writing my NixOS flake has 4 different projects coexisting. The flake basically does the job of pulling in different repos that each contain their own packaging instructions. For a more complex (Phoenix) application there is also a module definition that lets me enable and configure the service. So in addition to the input and <code>nginx</code> config we&rsquo;d have something like:</p>
<pre tabindex="0"><code>services.phoenix-app = {
  enable = true;
  port = 4002;
  host = &#34;phoenix-app.com&#34;;
  secretKeyBase = &#34;&#34;;
};
</code></pre><p>I have some lingering curiosity that I&rsquo;d like to state and follow up on.</p>
<blockquote>
<p>When I run <code>nix flake update</code> it pulls all the input repos into the nix store and updates the lock file. Are those store paths immune from garbage collection? What if I was in some silly situation where the nix store has the actual valid copy of what I&rsquo;m deploying, but the source is corrupted?</p></blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>Provisioning a NixOS node in DigitalOcean</title>
      <link>https://paradigmatic.systems/posts/provisioning-nixos-node-digital-ocean/</link>
      <pubDate>Tue, 28 Jan 2025 14:30:00 +0000</pubDate>
      
      <guid>https://paradigmatic.systems/posts/provisioning-nixos-node-digital-ocean/</guid>
      <description>&lt;p&gt;Here&amp;rsquo;s an easy way to get a NixOS node spun up using &lt;a href=&#34;https://github.com/elitak/nixos-infect&#34;&gt;nixos-infect&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;1-set-up-a-new-droplet&#34;&gt;1) Set up a new droplet&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Choose Ubuntu 22.04&lt;/li&gt;
&lt;li&gt;Add SSH keys for something you have a local IdentityFile for.&lt;/li&gt;
&lt;li&gt;Under &amp;ldquo;Advanced Options&amp;rdquo; -&amp;gt; &amp;ldquo;Add initialization scripts&amp;rdquo; paste&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#cloud-config
write_files:
- path: /etc/nixos/host.nix
  permissions: &amp;#39;0644&amp;#39;
  content: |
    {pkgs, ...}:
    {
      environment.systemPackages = with pkgs; [ vim ];
    }
runcmd:
  - curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=digitalocean NIXOS_IMPORT=./host.nix NIX_CHANNEL=nixos-25.05 bash 2&amp;gt;&amp;amp;1 | tee /tmp/infect.log
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;2-ssh-in-and-copy-config-down&#34;&gt;2) SSH in and copy config down&lt;/h3&gt;
&lt;p&gt;Add the node&amp;rsquo;s SSH config to ~/.ssh/config&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Here&rsquo;s an easy way to get a NixOS node spun up using <a href="https://github.com/elitak/nixos-infect">nixos-infect</a>.</p>
<h3 id="1-set-up-a-new-droplet">1) Set up a new droplet</h3>
<ul>
<li>Choose Ubuntu 22.04</li>
<li>Add SSH keys for something you have a local IdentityFile for.</li>
<li>Under &ldquo;Advanced Options&rdquo; -&gt; &ldquo;Add initialization scripts&rdquo; paste</li>
</ul>
<pre tabindex="0"><code>#cloud-config
write_files:
- path: /etc/nixos/host.nix
  permissions: &#39;0644&#39;
  content: |
    {pkgs, ...}:
    {
      environment.systemPackages = with pkgs; [ vim ];
    }
runcmd:
  - curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=digitalocean NIXOS_IMPORT=./host.nix NIX_CHANNEL=nixos-25.05 bash 2&gt;&amp;1 | tee /tmp/infect.log
</code></pre><h3 id="2-ssh-in-and-copy-config-down">2) SSH in and copy config down</h3>
<p>Add the node&rsquo;s SSH config to ~/.ssh/config</p>
<pre tabindex="0"><code>Host [node-name]
        HostName [IP-address]
        User root
        IdentityFile ~/.ssh/[identity]
</code></pre><p>Now you should be able to <code>ssh [node-name]</code> and <code>cat /etc/nixos/configuration.nix</code> to see your new system.</p>
<p>Start a new directory for containing the node&rsquo;s configuration locally. Maybe call it <code>[node-name]-deployment</code>.</p>
<p>On the server, run
<code>scp [node-name]:/etc/nixos/* .</code>.</p>
<p>Now you&rsquo;ve got the remote configuration in hand. If you wanted to alter the node, the naive way to do it is edit the configuration, push it back over, and run <code>sudo nixos-rebuild switch</code>. But there&rsquo;s a better way to approach this that involves building the system locally. We&rsquo;ll continue in <a href="/posts/setting-up-deploy-rs">setting up deploy-rs</a>.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
