<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Lenny's Blog!</title>
    <link href="https://blog.lenny.ninja/atom.xml" rel="self" />
    <link href="https://blog.lenny.ninja" />
    <id>https://blog.lenny.ninja/atom.xml</id>
    <author>
        <name>Lenny.</name>
        
        <email>test@example.com</email>
        
    </author>
    <updated>2023-04-16T00:00:00Z</updated>
    <entry>
    <title>Part 2: Quickly packaging services using Nix flakes</title>
    <link href="https://blog.lenny.ninja/posts/2023-04-16-packaging-nix-services-2.html" />
    <id>https://blog.lenny.ninja/posts/2023-04-16-packaging-nix-services-2.html</id>
    <published>2023-04-16T00:00:00Z</published>
    <updated>2023-04-16T00:00:00Z</updated>
    <summary type="html"><![CDATA[<article>
    <section class="header">
        Posted on April 16, 2023
        
    </section>
    <section>
        <p>In the <a href="/part-1-quickly-packaging-services-using-nix-flakes.html">first part</a> of this series, we learned how to package a small Go application into a Nix flake. In this second part, we will add a service definition and corresponding NixOS module to it, so that we can easily use it on our machines running NixOS!</p>
<p>For reference, the entire Flake is available <a href="https://codeberg.org/Lenny/float">here</a>.</p>
<h2 id="nixos-modules">NixOS modules</h2>
<p>To make our service configurable, we will need to add a NixOS module to our flake. These modules allow us to define familiar things such as <code>service.enable</code>. You can read a detailed explanation about them <a href="https://nixos.wiki/wiki/NixOS_modules">here</a>.</p>
<p>For now we only need to know that it’s just a Nix function returning this set of attributes:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">options</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="co"># option declarations</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="va">config</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="co"># option definitions</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 id="adding-a-module-to-a-flake">Adding a module to a flake</h3>
<p>To add such a module to our flake, we need to use the <code>nixosModule</code> attribute of our flake output.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">outputs</span> <span class="op">=</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="va">config</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="va">self</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="va">nixpkgs</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>:</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>      <span class="co">#System types to support.</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>      <span class="va">supportedSystems</span> <span class="op">=</span> <span class="op">[</span> <span class="st">&quot;x86_64-linux&quot;</span> <span class="st">&quot;x86_64-darwin&quot;</span> <span class="st">&quot;aarch64-linux&quot;</span> <span class="st">&quot;aarch64-darwin&quot;</span> <span class="op">];</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>      <span class="co"># Helper function to generate an attrset &#39;{ x86_64-linux = f &quot;x86_64-linux&quot;; ... }&#39;.</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>      <span class="va">forAllSystems</span> <span class="op">=</span> nixpkgs<span class="op">.</span>lib<span class="op">.</span>genAttrs supportedSystems<span class="op">;</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>      <span class="co"># Nixpkgs instantiated for supported system types.</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>      <span class="va">nixpkgsFor</span> <span class="op">=</span> forAllSystems <span class="op">(</span><span class="va">system</span><span class="op">:</span> nixpkgs<span class="op">.</span>legacyPackages<span class="op">.</span><span class="sc">${</span>system<span class="sc">}</span><span class="op">);</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>      <span class="va">version</span> <span class="op">=</span> <span class="st">&quot;0.0.3&quot;</span><span class="op">;</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>      <span class="va">pname</span> <span class="op">=</span> <span class="st">&quot;float&quot;</span><span class="op">;</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>      <span class="va">nixosModule</span> <span class="op">=</span> forAllSystems <span class="op">(</span><span class="va">system</span><span class="op">:</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>          <span class="va">pkgs</span> <span class="op">=</span> nixpkgsFor<span class="op">.</span><span class="sc">${</span>system<span class="sc">}</span><span class="op">;</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>        <span class="kw">in</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> <span class="va">config</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="va">lib</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="va">pkgs</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="op">...</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>: <span class="op">{</span> </span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>          <span class="co"># ...</span></span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a>        <span class="op">});</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Note the use of some helper functions to define the <code>nixosModule</code> for every platform.</p>
<h2 id="options">Options</h2>
<p>Let’s define our first one, a simple option whether this service should be enabled or not:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>options<span class="op">.</span>services<span class="op">.</span>float = <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="va">enable</span> <span class="op">=</span> lib<span class="op">.</span>mkEnableOption <span class="st">&quot;enable the float homepage service&quot;</span><span class="op">;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Here we use the helper function <code>mkEnableOption</code> to create the boolean option. You can read more about all the available option functions <a href="https://ryantm.github.io/nixpkgs/functions/library/options/">here</a>.</p>
<p>Likewise, we can define some more simple options that float specifically will need:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>package = mkOption <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">type</span> <span class="op">=</span> types<span class="op">.</span>package<span class="op">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="va">default</span> <span class="op">=</span> self<span class="op">.</span>packages<span class="op">.</span><span class="sc">${</span>system<span class="sc">}</span><span class="op">.</span>float<span class="op">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;float package to use&quot;</span><span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>port = mkOption <span class="op">{</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="va">type</span> <span class="op">=</span> types<span class="op">.</span>port<span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="va">default</span> <span class="op">=</span> <span class="dv">8051</span><span class="op">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;port to serve float on&quot;</span><span class="op">;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>title = mkOption <span class="op">{</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>  <span class="va">type</span> <span class="op">=</span> types<span class="op">.</span>str<span class="op">;</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>  <span class="va">default</span> <span class="op">=</span> <span class="st">&quot;float&quot;</span><span class="op">;</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>  <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;title of the homepage&quot;</span><span class="op">;</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>You can find all the types defined <a href="https://github.com/NixOS/nixpkgs/blob/master/lib/types.nix">here</a>.</p>
<h3 id="advanced-options">Advanced options</h3>
<p>Until now, we only used very basic options. However, sometimes we might need to allow users of our module to supply more complex, nested options. A good example of this is the pages we want float to display. It’s a list of links with pretty names for display that we will need to supply as a YAML configuration file.
Let’s create a custom “page” option type that represents a single float page.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>page = types<span class="op">.</span>submodule <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">options</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="va">name</span> <span class="op">=</span> mkOption <span class="op">{</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>      <span class="va">type</span> <span class="op">=</span> types<span class="op">.</span>str<span class="op">;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>      <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;name of the page&quot;</span><span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="va">url</span> <span class="op">=</span> mkOption <span class="op">{</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>      <span class="va">type</span> <span class="op">=</span> types<span class="op">.</span>str<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>      <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;url of the page&quot;</span><span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>pageToYMAL = <span class="va">page</span><span class="op">:</span> <span class="op">{</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>  <span class="va">name</span> <span class="op">=</span> page<span class="op">.</span>name<span class="op">;</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>  <span class="va">url</span> <span class="op">=</span> page<span class="op">.</span>url<span class="op">;</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>configToYAML = <span class="va">input</span><span class="op">:</span> <span class="op">{</span></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>  <span class="va">title</span> <span class="op">=</span> input<span class="op">.</span>title<span class="op">;</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>  <span class="va">page_data</span> <span class="op">=</span> <span class="bu">map</span> pageToYMAL input<span class="op">.</span>pages<span class="op">;</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Just insert this into a let definition before the body of the module.
We can then use the custom type like so:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>pages = mkOption <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">type</span> <span class="op">=</span> types<span class="op">.</span>listOf page<span class="op">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="va">default</span> <span class="op">=</span> <span class="op">[</span> <span class="op">];</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;list of sites to be displayed&quot;</span><span class="op">;</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 id="generating-the-nixos-config">Generating the NixOS config</h2>
<p>Now with our options defined, we can finally define the <code>config</code> part of our module. This will be applied to the NixOS config of the system using this module. Note that we get the state of the NixOS config before our module is applied, passed as the <code>config</code> parameter to our module function.
We will use that to access the options we created and the user may have chosen to use!</p>
<p>Our goal here is to create a systemd service that will properly configure and start the float package we created in Part 1!</p>
<p>First, let’s create a small helper variable to point to our service options in the config:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>cfg = config<span class="op">.</span>services<span class="op">.</span>float;</span></code></pre></div>
<p>Then we can use the <code>mkIf</code> helper function to only generate our config if the enable option is on:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>config = lib<span class="op">.</span>mkIf cfg<span class="op">.</span>enable <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">systemd</span>.<span class="va">services</span>.<span class="va">float</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="co"># ...</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Finally, we can populate the body of the systemd service itself!</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>config = mkIf cfg<span class="op">.</span>enable <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">systemd</span>.<span class="va">services</span>.<span class="va">float</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;float home page&quot;</span><span class="op">;</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="va">wantedBy</span> <span class="op">=</span> <span class="op">[</span> <span class="st">&quot;multi-user.target&quot;</span> <span class="op">];</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    <span class="va">serviceConfig</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>      <span class="va">ExecStart</span> <span class="op">=</span> <span class="st">&quot;</span><span class="sc">${</span>cfg<span class="op">.</span>package<span class="sc">}</span><span class="st">/bin/cmd -port </span><span class="sc">${</span><span class="bu">toString</span> cfg<span class="op">.</span>port<span class="sc">}</span><span class="st"> -file </span><span class="sc">${</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>      <span class="bu">builtins</span><span class="op">.</span>toFile <span class="st">&quot;config.yml&quot;</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>      <span class="op">(</span>lib<span class="op">.</span>generators<span class="op">.</span>toYAML <span class="op">{}</span> <span class="op">(</span>configToYAML cfg<span class="op">))</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    <span class="sc">}</span><span class="st">&quot;</span><span class="op">;</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>      <span class="va">ProtectHome</span> <span class="op">=</span> <span class="st">&quot;read-only&quot;</span><span class="op">;</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>      <span class="va">Restart</span> <span class="op">=</span> <span class="st">&quot;on-failure&quot;</span><span class="op">;</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>      <span class="va">Type</span> <span class="op">=</span> <span class="st">&quot;exec&quot;</span><span class="op">;</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>      <span class="va">DynamicUser</span> <span class="op">=</span> <span class="cn">true</span><span class="op">;</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Note: I’m not that well-versed in systemd services myself, we could probably do more things to harden it.</p>
<p>Pay particular attention to how we referenced the package to locate the float binary and generated a <code>config.yml</code> using our custom functions!</p>
<h2 id="wrap-up">Wrap Up</h2>
<p>So now you vaguely know how to create a flake that will build a Go application and use it to actually run it inside of your NixOS system. If I made any mistakes in this series, please let me know on <a href="https://chaos.social/@lenny_">mastodon</a>!</p>
    </section>
</article>
]]></summary>
</entry>
<entry>
    <title>Part 1: Quickly packaging services using Nix flakes</title>
    <link href="https://blog.lenny.ninja/posts/2022-11-06-packaing-nix-services.html" />
    <id>https://blog.lenny.ninja/posts/2022-11-06-packaing-nix-services.html</id>
    <published>2022-11-06T00:00:00Z</published>
    <updated>2022-11-06T00:00:00Z</updated>
    <summary type="html"><![CDATA[<article>
    <section class="header">
        Posted on November  6, 2022
        
    </section>
    <section>
        <p>Even though Nix has the <a href="https://repology.org/repositories/statistics/total">most</a> and <a href="https://repology.org/repositories/statistics/newest">most up-to-date</a> packages, there is always some software you use that is not included yet. You could of course just download a binary, but if you are reading this you probably would like a more declarative way of dealing with the software you use. Thankfully, Nix flakes make it quite easy and quick to package most software. You can even add a NixOS module in the same flake to tell the OS how to configure the service and run it as a systemd service.</p>
<p>The rest of this article assumes that you have a basic understanding of <a href="https://nixos.wiki/wiki/Flakes">Nix flakes</a> and, for example, already used a flake as a NixOS or home-manager configuration. It’s basically the tutorial I wish I had after setting up my own systems as flakes and needed to run some unpackaged software.</p>
<p>Below we will make a Nix flake for <a href="https://github.com/aaqaishtyaq/float">float</a>. It’s a small web service written in golang that you can use to set up a homepage for your homeserver. I chose this as an example because its repo is out of my control, which probably is the case for the software you want to package as well. It’s also configured via a small <code>.yaml</code> file, which is a common case we should cover. Finally, its whole purpose is to run as a service and serve a web page, a good excuse to learn how to do that.</p>
<p>It’s probably a good idea to skim over the float’s <a href="https://github.com/aaqaishtyaq/float/blob/trunk/README.md">readme</a> before continuing - it’ll only take a minute!</p>
<p>For reference later, the code used in this example is residing <a href="https://codeberg.org/Lenny/float-nix-flake-package-example">here</a>.</p>
<h2 id="packaging-non-go-application">Packaging non-go application</h2>
<p>While we will focus on a go package, almost all of what is written below still applies for rust, node or even haskell packages. See the further reading section below for pointers after you’ve gotten the basics from the float example.</p>
<h2 id="packaging-a-go-application">Packaging a go application</h2>
<p>These days, most go programs are quite simple. They consist of a <code>main.go</code> with the entry point of the application and accompanying <code>go.mod</code> and <code>go.sum</code> files defining and locking dependencies (analagous to node’s <code>package.json</code> and <code>package-lock.json</code>). Nixpkgs includes a helper function (<code>pkgs.buildGoModule</code>) that takes all of these and just spits out a compiled app we can use in the rest of Nix. Let’s use it to make a package for float!</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;minimalist Configurable Homelab Start Page&quot;</span><span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">inputs</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="va">nixpkgs</span>.<span class="va">url</span> <span class="op">=</span> <span class="st">&quot;nixpkgs/nixos-22.05&quot;</span><span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="va">outputs</span> <span class="op">=</span> <span class="op">{</span><span class="va">nixpkgs</span><span class="op">,</span> <span class="op">...}</span>: <span class="kw">let</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="co"># you can also put any architecture you want to support here</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="co"># i.e. aarch64-darwin for never M1/2 macbooks</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="va">system</span> <span class="op">=</span> <span class="st">&quot;x86_64-linux&quot;</span><span class="op">;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="va">pname</span> <span class="op">=</span> <span class="st">&quot;float&quot;</span><span class="op">;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span> <span class="op">{</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="va">packages</span>.<span class="sc">${</span>system<span class="sc">}</span> <span class="op">=</span> <span class="kw">let</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>      <span class="va">pkgs</span> <span class="op">=</span> nixpkgs<span class="op">.</span>legacyPackages<span class="op">.</span><span class="sc">${</span>system<span class="sc">}</span><span class="op">;</span> <span class="co"># this gives us access to nixpkgs as we are used to</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span> <span class="op">{</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>      <span class="va">default</span> <span class="op">=</span> pkgs<span class="op">.</span>buildGoModule <span class="op">{</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>        <span class="va">name</span> <span class="op">=</span> pname<span class="op">;</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>        <span class="va">src</span> <span class="op">=</span> pkgs<span class="op">.</span>fetchFromGitHub <span class="op">{</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>          <span class="va">owner</span> <span class="op">=</span> <span class="st">&quot;aaqaishtyaq&quot;</span><span class="op">;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>          <span class="va">repo</span> <span class="op">=</span> pname<span class="op">;</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>          <span class="va">rev</span> <span class="op">=</span> <span class="st">&quot;v0.0.3&quot;</span><span class="op">;</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>          <span class="va">sha256</span> <span class="op">=</span> pkgs<span class="op">.</span>lib<span class="op">.</span>fakeSha256<span class="op">;</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>        <span class="op">};</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>        <span class="va">vendorSha256</span> <span class="op">=</span> pkgs<span class="op">.</span>lib<span class="op">.</span>fakeSha256<span class="op">;</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>      <span class="op">};</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Now that’s quite a lot, let’s take it step by step.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;minimalist Configurable Homelab Start Page&quot;</span><span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">inputs</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="va">nixpkgs</span>.<span class="va">url</span> <span class="op">=</span> <span class="st">&quot;nixpkgs/nixos-22.05&quot;</span><span class="op">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">};</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  ...</span></code></pre></div>
<p>Here we set a small description of our flake, and define our inputs. In this case we only need nixpkgs for some helper functions.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>  outputs = <span class="op">{</span><span class="va">nixpkgs</span><span class="op">,</span> <span class="op">...}</span>: <span class="kw">let</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># you can also put any architecture you want to support here</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="co"># i.e. aarch64-darwin for never M1/2 macbooks</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="va">system</span> <span class="op">=</span> <span class="st">&quot;x86_64-linux&quot;</span><span class="op">;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="va">pname</span> <span class="op">=</span> <span class="st">&quot;float&quot;</span><span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span> <span class="op">{</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Here we define our output function that gets passed the inputs as an arg, and set some variables we will refernce later. Note that there are ways to easily make a package for all systems at once, but I left that out to keep it simple. I will leave some further reading material at the end of the post.</p>
<p>Finally, we are getting to the meaty part of actually describing our package!</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>    packages<span class="op">.</span><span class="sc">${</span>system<span class="sc">}</span> = <span class="kw">let</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>      <span class="va">pkgs</span> <span class="op">=</span> <span class="bu">import</span> nixpkgs <span class="op">{</span><span class="kw">inherit</span> <span class="va">system</span><span class="op">;};</span> <span class="co"># this gives us access to nixpkgs as we are used to</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span> <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>      <span class="va">default</span> <span class="op">=</span> <span class="op">.</span>..;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    };</span></code></pre></div>
<p>Here we set the outputs of our flake, namely the <code>packages</code> attribute set. This name is convention and specifies what packages for what system this flake provides. <code>default</code> is also a convention, it’s the package that will get build when you run just <code>nix build .</code> without specifying anything else.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>  pkgs<span class="op">.</span>buildGoModule <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="va">name</span> <span class="op">=</span> pname<span class="op">;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="va">src</span> <span class="op">=</span> pkgs<span class="op">.</span>fetchFromGitHub <span class="op">{</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>      <span class="va">owner</span> <span class="op">=</span> <span class="st">&quot;aaqaishtyaq&quot;</span><span class="op">;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>      <span class="va">repo</span> <span class="op">=</span> pname<span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>      <span class="va">rev</span> <span class="op">=</span> <span class="st">&quot;v0.0.3&quot;</span><span class="op">;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>      <span class="va">sha256</span> <span class="op">=</span> pkgs<span class="op">.</span>lib<span class="op">.</span>fakeSha256<span class="op">;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    <span class="va">vendorSha256</span> <span class="op">=</span> pkgs<span class="op">.</span>lib<span class="op">.</span>fakeSha256<span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span></code></pre></div>
<p>Here we call the <code>pkgs.buildGoModule</code> helper function to actually build float. We have to specify some mandatory arguments: the <code>name</code> of our package, where to get the source from and the sha256 of the packages’ dependencies. We can handily fetch the source directly from GitHub with the <code>pkgs.fetchFromGitHub</code> function.</p>
<p>Now, you might be rightly wondering about all these hashes and the reference to <code>pkgs.lib.fakeSha256</code>. The environment in which Nix evaluates our expressions does not really have access to the internet, except when we provide the hash of what we download <em>before</em>. This makes sure that all our builds are reproducible, and we never have to worry about it resulting in something we didn’t want. More info at the of end of the post!</p>
<p>But where do we get these hashes from? Isn’t that tedious to calculate? Here the fake hashes come to the rescue. Just run <code>nix build .</code>. Now, you will see an error message like:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode txt"><code class="sourceCode default"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>&gt; nix build .</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>error: hash mismatch in fixed-output derivation &#39;/nix/store/4kq7wvibcdc10nxcw991cf5yp13y1862-source.drv&#39;:</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>         specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>            got:    sha256-3gMP9VjC8+u41gvzT45LflqZ4uk5+tObBtlJO5SCjwQ=</span></code></pre></div>
<p>This is nix telling us: Hey, you wanted to download something, but it didn’t match the hash you provided. The helpful part is that it actually gives us the hash it actually downloaded, so we can copy it and substitute it for the <code>sha256</code> field in <code>fetchFromGitHub</code>. Repeat this step one more time afterwards to get the hash for <code>vendorSha256</code> as well.</p>
<p><em>Note</em>: You probably want to verify these hashes match what they should be (i.e. by checking the commit hash on GitHub itself) to make sure nothing funky got introduced somehow.</p>
<p>Now you can run <code>nix build .</code> build one last time and everything succeed. Congrats! You now have the build float binary in <code>./result/bin/float</code>. Go ahead and try to execute it.</p>
<h2 id="using-this-package-directly">Using this package directly</h2>
<p>Now that we defined this package, we probably want to use it in our NixOS or home-manager configuration.
…</p>
<h2 id="adding-a-nixos-module-for-float">Adding a NixOS module for float</h2>
<p>This is covered in part 2 of this series. Click <a href="/part-2-quickly-packaging-services-using-nix-flakes.html">here</a> to get there!</p>
<h2 id="further-reading">Further reading</h2>
<ol type="1">
<li>Helper functions to build packages in other languages are nicely covered in this version of the nix manual. Here is rust for example: https://ryantm.github.io/nixpkgs/languages-frameworks/rust/#rust</li>
<li>The <code>flake-utils</code> repo provides some helper functions to generate package definitions for all systems: https://github.com/numtide/flake-utils</li>
<li>More info on Nix hashes: https://nixos.wiki/wiki/Nix_Hash</li>
</ol>
    </section>
</article>
]]></summary>
</entry>
<entry>
    <title>zrepl on rsync.net</title>
    <link href="https://blog.lenny.ninja/posts/2022-01-25-zrepl-rsync-net.html" />
    <id>https://blog.lenny.ninja/posts/2022-01-25-zrepl-rsync-net.html</id>
    <published>2022-01-25T00:00:00Z</published>
    <updated>2022-01-25T00:00:00Z</updated>
    <summary type="html"><![CDATA[<article>
    <section class="header">
        Posted on January 25, 2022
        
    </section>
    <section>
        <p>A while ago I got a testing account on <a href="https://rsync.net">rsync.net</a> to try out the experience of using it with <a href="https://zrepl.github.io/">zrepl</a>. The experience I has been quite wonderful, and I want to share what I learned with you.</p>
<h2 id="what-is-zrepl">What is zrepl?</h2>
<p>If you use zfs on your NAS, you inevitably think about doing an offsite backup for your data. For this you might use off the shelf tools like <a href="https://www.duplicati.com/">Duplicati</a> or <a href="https://borgbackup.readthedocs.io">borg</a>. As a zfs user you might also be aware of the option to use the <code>zfs send</code> command to send a byte for byte copy of a zfs snapshot to another system running zfs. Writing some shell scripts around this and using it as a backup has <a href="https://utcc.utoronto.ca/~cks/space/blog/solaris/ZFSSendNotABackup">numerous drawbacks</a> however.</p>
<p>This is where zrepl comes in, it’s a “one-stop, integrated solution for ZFS replication”. It runs as a daemon on your local nas and your remote system making sure the replication of your datasets proceeds reliably (for example by recovering from network outages) and transparently (by exposing various tools for monitoring).</p>
<p>It it also manages the creation and cleanup of periodic snapshots of your datasets. You could for example keep 24 hourly snapshots on your local nas to quickly recover deleted files while on the other hand keeping 6 monthly snapshots on your remote in case you need to recover something older.</p>
<p>Zrepl is an awesome tool if you want your data to be in two places at the same time while using many native zfs features.</p>
<h2 id="what-is-rsync.net">What is <a href="https://rsync.net">rsync.net</a>?</h2>
<p>Rsync.net is basically a cloud storage provider without all the fuss. Originally they would just provide you a vm to <code>rsync</code> your files to (hence the name) and make sure they stay there. You can also use various other tools to send them your data like <code>sftp</code>, <code>borg</code>, <code>rclone</code>, <code>git-annex</code> or just good old <code>scp</code>.</p>
<p>The happy coincidence is that their system is based on zfs, just like ours. You even get full access to your own zpool if you sign up for a zfs-send enabled account <a href="https://rsync.net/products/zfs.html">here</a>. You can simply treat your rsync.net vm as a remote zpool under your control.</p>
<h2 id="setting-up-zrepl-on-rsync.net">Setting up zrepl on rsync.net</h2>
<p>As it turns out all this allows us to run zrepl on our remote vm, the rest of this post is about how to set that up. I will skip the setup on your local nas as that is nicely explained by the <a href="https://zrepl.github.io/installation.html">zrepl docs</a>.</p>
<p>When you sign up for your account you will get a user, password and a host to ssh into. You then want to do basic setup steps like adding a ssh key for your user, but I will skip this part as they have <a href="https://www.rsync.net/resources/howto/ssh_keys.html">their own guides</a> on how to get started with that. The vms are running on FreeBSD, so some things are a little different. (At least they were for me as a Linux user)</p>
<p>To install zrepl simply run <code>pkg add zrepl</code>.</p>
<p>The next step is making sure that our local NAS’ zrepl daemon can access the rsync.net vm. Zrepl has various <a href="https://zrepl.github.io/configuration/transports.html">transports</a> to make that work. For this guide we will use the simple <code>ssh+stdinserver</code> transport (be aware that this has some throughput limitations however). You should generate a fresh ssh keypair for that on your local machine, putting the private key somewhere your local zrepl daemon can access it. The public counterpart goes into the familiar <code>.ssh/authorized_keys</code> file in addition to some preamble that restrict incoming connections using that key to running zrepl.</p>
<pre><code>command=&quot;zrepl stdinserver client1&quot;,restrict ssh-ed25519 AAAAC3N...</code></pre>
<p>Simply replace the <code>ssh-ed25519 AAAAC3N...</code> here with the public key you generated.</p>
<p>The next step is to configure zrepl by editing the config file at <code>/usr/local/etc/zrepl/zrepl.yml</code>, however we will go into detail on that in the next section.</p>
<p>To enable the zrepl service on your remote simple create the file <code>/etc/rc.conf.d/zrepl</code> and add a line containing <code>zrepl_enable="YES"</code> to it. Then start zrepl by running <code>service zrepl start</code>.</p>
<h2 id="simple-zrepl-config">Simple zrepl config</h2>
<p>I’ll pride you with a very simple zrepl config for your local nas and remote here. Be sure to read the <a href="https://zrepl.github.io/configuration.html">zrepl docs</a> to tune it for your use case.</p>
<p>Local: <code>/etc/zrepl/zrepl.yml</code></p>
<div class="sourceCode" id="cb2"><pre class="sourceCode yml"><code class="sourceCode yaml"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">global</span><span class="kw">:</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">logging</span><span class="kw">:</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> </span><span class="fu">format</span><span class="kw">:</span><span class="at"> human</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">level</span><span class="kw">:</span><span class="at"> warn</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">type</span><span class="kw">:</span><span class="at"> syslog</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="fu">jobs</span><span class="kw">:</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> </span><span class="fu">connect</span><span class="kw">:</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">host</span><span class="kw">:</span><span class="at"> &lt;your rsync.net vm name&gt;.rsync.net</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">identity_file</span><span class="kw">:</span><span class="at"> &lt;path to the private key you crated&gt;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">port</span><span class="kw">:</span><span class="at"> </span><span class="dv">22</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">type</span><span class="kw">:</span><span class="at"> ssh+stdinserver</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">user</span><span class="kw">:</span><span class="at"> root</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">filesystems</span><span class="kw">:</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">&lt;datasets you want to replicate&gt;</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">pruning</span><span class="kw">:</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">keep_receiver</span><span class="kw">:</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> </span><span class="fu">grid</span><span class="kw">:</span><span class="at"> 1x1h(keep=all) | 24x1h | 30x1d | 6x30d</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">regex</span><span class="kw">:</span><span class="at"> ^zrepl_</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">type</span><span class="kw">:</span><span class="at"> grid</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">keep_sender</span><span class="kw">:</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> </span><span class="fu">type</span><span class="kw">:</span><span class="at"> not_replicated</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> </span><span class="fu">count</span><span class="kw">:</span><span class="at"> </span><span class="dv">10</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">type</span><span class="kw">:</span><span class="at"> last_n</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">snapshotting</span><span class="kw">:</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">interval</span><span class="kw">:</span><span class="at"> 10m</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">prefix</span><span class="kw">:</span><span class="at"> zrepl_</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">type</span><span class="kw">:</span><span class="at"> periodic</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">type</span><span class="kw">:</span><span class="at"> push</span></span></code></pre></div>
<p>Remote: <code>/usr/local/etc/zrepl/zrepl.yml</code></p>
<div class="sourceCode" id="cb3"><pre class="sourceCode yml"><code class="sourceCode yaml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">global</span><span class="kw">:</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">logging</span><span class="kw">:</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> </span><span class="fu">type</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;stdout&quot;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">level</span><span class="kw">:</span><span class="at">  </span><span class="st">&quot;error&quot;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">format</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;human&quot;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> </span><span class="fu">type</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;syslog&quot;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">level</span><span class="kw">:</span><span class="at">  </span><span class="st">&quot;info&quot;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">format</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;logfmt&quot;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="fu">jobs</span><span class="kw">:</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> </span><span class="fu">name</span><span class="kw">:</span><span class="at"> sink</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">type</span><span class="kw">:</span><span class="at"> sink</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">serve</span><span class="kw">:</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">type</span><span class="kw">:</span><span class="at"> stdinserver</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">client_identities</span><span class="kw">:</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> </span><span class="st">&quot;client1&quot;</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">root_fs</span><span class="kw">:</span><span class="at"> </span><span class="st">&quot;data1&quot;</span></span></code></pre></div>
<p>This will make zrepl push snapshots to your rsync.net vm with some snapshotting and pruning. Specifically it takes a snapshot every 10 minutes on your local nas, but only keeps the 10 most recent ones around. Your remote will keep 1 snapshot of each of the last 24h, 1 snapshots for each of the last 30 days and 1 snapshot for each of the last 6 months.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Using zrepl on rsync.net provides us with a fairly straight forward way to replicate our zpool off site, with the added benefit not having to convert our data into other backup formats (such as borg) while keeping most of their benefits. It’s a unique offering that I have not seen anywhere else and hopefully fits your use case as well as it does mine.</p>
<p>Disclaimer: I’m continueing to receive a discounted access to rsync.net.</p>
    </section>
</article>
]]></summary>
</entry>

</feed>
