<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>Ivan Petkov</title>
	<link href="https://ipetkov.dev/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://ipetkov.dev"/>
	<icon>https://ipetkov.dev/favicon.png</icon>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2025-04-27T00:00:00+00:00</updated>
	<id>https://ipetkov.dev/atom.xml</id>
	<entry xml:lang="en">
		<title>The Markdown to PDF pipeline I wish someone told me about</title>
		<published>2025-04-26T00:00:00+00:00</published>
		<updated>2025-04-27T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/markdown-to-pdf-pipeline/" type="text/html"/>
		<id>https://ipetkov.dev/blog/markdown-to-pdf-pipeline/</id>
		<content type="html">&lt;p&gt;I recently found myself in a situation where I needed to write up a document
intended to be updated once or twice per year and otherwise kept printed out as
a hard copy in a safe location. The only requirement I have is that I want to be
able to write in Markdown (I write a lot of Markdown and find it to be minimal
enough fuss that I can focus on getting content on to a page) and be able to
render to something that can easily be printed out (like PDF!).&lt;&#x2F;p&gt;
&lt;p&gt;Although there are resources online on doing this, I had to read through and
cobble together information from various places, so hopefully this ends up being
a nicer quick start for someone else!&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;In the end I settled on the moral equivalent (not to scale) of&lt;br&gt;
&lt;code&gt;cat *.md | pandoc | typst &amp;gt;out.pdf&lt;&#x2F;code&gt;, modulo some minor configuration which is
easy to set and forget once it fits your liking.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pandoc.org&#x2F;&quot;&gt;Pandoc&lt;&#x2F;a&gt; is basically a Swiss Army knife for converting between different
markup formats, and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;typst.app&#x2F;docs&#x2F;&quot;&gt;Typst&lt;&#x2F;a&gt; is a modern typesetting system (in the same vein as
LaTeX but way easier to use and get running). Thus, Typst knows how to take some
layout markup and some content and spit out a PDF, while Pandoc knows how to
convert Markdown to whatever inputs Typst is used to parsing.&lt;&#x2F;p&gt;
&lt;p&gt;The final missing piece is giving Pandoc a little bit of metadata and a template
file which will set up the Typst preamble and default styling. Pandoc has &lt;em&gt;a
lot&lt;&#x2F;em&gt; of flags and functionality it supports and I got lost in the docs for a
while trying to make sense of how to inject my own styles as overrides into
Pandoc&#x27;s default Typst template, so I gave up and adapted a template I found
online and made it my own (which in hindsight ended up being way simpler).&lt;&#x2F;p&gt;
&lt;p&gt;Save the following (and tweak it to your liking) under &lt;code&gt;metadata.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;Hello world!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;subtitle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;A simple Markdown to PDF pipeline
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then save the following (and tweak it to your liking) under &lt;code&gt;my.template&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;perl&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-perl &quot;&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;Loosely based on
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;https&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;web&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;archive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;org&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;web&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;20250427030050&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;https&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;imaginarytext&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ca&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;posts&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pandoc&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;typst&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;tutorial&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;#let conf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  title: none,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  subtitle: none,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  date: datetime&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;today&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;display&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  lang: &amp;quot;en&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  paper: &amp;quot;a4&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  body,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;= {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  set page&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    paper: paper,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    footer: context &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;      #set text(style: &amp;quot;italic&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;      Last updated: #date #h(1fr) #counter(page).display(&amp;quot;1 of 1&amp;quot;, both: true)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;BASIC BODY PARAGRAPH FORMATTING
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  set par&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    first-line-indent: 0em,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    justify: true,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  set text&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    lang: lang,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    alternates: false,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;Block quotations
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  set quote&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;block: true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  show quote: set pad&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;x: 2em&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;L&amp;amp;R margins
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  show quote: set text&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;style: &amp;quot;italic&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;HEADINGS
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  show heading: it =&amp;gt; {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    if it&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;depth == 1 {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;      pagebreak&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;weak: true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    set text&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;hyphenate: true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    it
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;Title page and TOC
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  align&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;horizon &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;center, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    #text(size: 2.5em)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;#title&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    #text(size: 1em, style: &amp;quot;italic&amp;quot;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;#subtitle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    #v(25%)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  pagebreak&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  set heading&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;numbering: &amp;quot;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  outline&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    title: auto,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;    indent: auto,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  pagebreak&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;THIS IS THE ACTUAL BODY:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  body
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;BOILERPLATE PANDOC TEMPLATE:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;#show: body =&amp;gt; conf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  title: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;$title$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;endif&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;subtitle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  subtitle: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;$subtitle$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;endif&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  date: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;$date$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;endif&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;lang&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  lang: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;lang&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;endif&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;papersize&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  paper: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;papersize&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;endif&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;  body,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;include-after&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;)$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;include-after&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;endfor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Lastly invoke the whole thing via:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;pandoc &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --pdf-engine&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;typst &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o&lt;&#x2F;span&gt;&lt;span&gt; out.pdf &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --template&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;my.template &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --metadata-file&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;metadata.yaml &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.md
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;As an added bonus, if you ever want to inject some one-off Typst specific
markdown but not apply it to the entire template, you can use Pandoc&#x27;s
&lt;code&gt;raw_attribute&lt;&#x2F;code&gt; syntax like so:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;```{=typst}
&lt;&#x2F;span&gt;&lt;span&gt;#lorem(30)
&lt;&#x2F;span&gt;&lt;span&gt;```
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Configuring Gitea&#x2F;Forgejo to Sign Merge Commits</title>
		<published>2024-05-05T00:00:00+00:00</published>
		<updated>2025-04-26T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/configuring-gitea-to-sign-merge-commits/" type="text/html"/>
		<id>https://ipetkov.dev/blog/configuring-gitea-to-sign-merge-commits/</id>
		<content type="html">&lt;p&gt;Gitea supports &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20240420145934&#x2F;https:&#x2F;&#x2F;docs.gitea.com&#x2F;administration&#x2F;signing#automatic-signing&quot;&gt;automatically signing commits&lt;&#x2F;a&gt; it generates (such as when
merging pull requests, or editing files through the web editor). Sadly there is
no documentation on how to actually configure this, besides vague references
that it is left up to the server administrator to achieve.&lt;&#x2F;p&gt;
&lt;p&gt;Secure key management is a topic fraught with complexity and trade off
decisions, and the Gitea development team holds a (sensible) position that it is
preferable to give no advice than it is to give &lt;em&gt;bad&lt;&#x2F;em&gt; advice.&lt;&#x2F;p&gt;
&lt;p&gt;A position that I, as an internet rando, am absolutely not bound by, so here&#x27;s
what I did!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Edit 2024-08-19: these exact steps also work for Forgejo! Just use
&lt;code&gt;&#x2F;var&#x2F;lib&#x2F;forgejo&lt;&#x2F;code&gt; instead of &lt;code&gt;&#x2F;var&#x2F;lib&#x2F;gitea&lt;&#x2F;code&gt; for all instructions below&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;blockquote&gt;
&lt;p&gt;Seriously though, take a close look at your own threat model and security
posture before you apply any of the following instructions, which are,
frankly, provided for free, as in &lt;em&gt;used mattress&lt;&#x2F;em&gt;. These are educational
instructions, and you bear all responsibility for the consequences of
following them.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;&#x2F;h1&gt;
&lt;p&gt;Under the hood, Gitea basically has its own &lt;code&gt;.gitconfig&lt;&#x2F;code&gt; which is applied to all
git operations that it performs. At the end of the day, all we need to do is
ensure a GPG signing key is available inside Gitea&#x27;s &quot;home&quot; directory and make
sure that Gitea can interact with it unattended.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Which is easier said than done as GPG strongly insists on passphrase prompts
and is otherwise hostile to unattended interaction. Perhaps it is possible to
achieve this by starting and priming a &lt;code&gt;gpg-agent&lt;&#x2F;code&gt; instance to be used by
Gitea, but I did not bother investigating it as it adds more complexity, and
still requires automating entering the passphrase to it. At that rate, a
secret of one form or another needs to be available.&lt;&#x2F;p&gt;
&lt;p&gt;I also have not (yet) tried using SSH signing. Since git already supports it
with some config changes, it might be possible that it &quot;just works&quot;, but I
don&#x27;t know if there might be other GPG-assumptions baked into Gitea (like the
&lt;code&gt;&#x2F;api&#x2F;v1&#x2F;signing-key.gpg&lt;&#x2F;code&gt; endpoint.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;generating-a-new-key&quot;&gt;Generating a new key&lt;&#x2F;h1&gt;
&lt;p&gt;First we want to create a brand new GPG key for this Gitea instance. Note that
this key only needs to be configured &lt;em&gt;for signing&lt;&#x2F;em&gt; as we&#x27;ll only use it to
generate a &lt;em&gt;second&lt;&#x2F;em&gt; signing subkey that will be used by Gitea.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --full-generate-key
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Follow the wizard and fill in the values as appropriate. Note that GPG
will ask for a passphrase. Generate a strong password and save it in your
password manager (as we&#x27;ll need it in a bit).&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
&lt;&#x2F;span&gt;&lt;span&gt;This is free software: you are free to change and redistribute it.
&lt;&#x2F;span&gt;&lt;span&gt;There is NO WARRANTY, to the extent permitted by law.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Please select what kind of key you want:
&lt;&#x2F;span&gt;&lt;span&gt;   (1) RSA and RSA
&lt;&#x2F;span&gt;&lt;span&gt;   (2) DSA and Elgamal
&lt;&#x2F;span&gt;&lt;span&gt;   (3) DSA (sign only)
&lt;&#x2F;span&gt;&lt;span&gt;   (4) RSA (sign only)
&lt;&#x2F;span&gt;&lt;span&gt;   (9) ECC (sign and encrypt) *default*
&lt;&#x2F;span&gt;&lt;span&gt;  (10) ECC (sign only)
&lt;&#x2F;span&gt;&lt;span&gt;  (14) Existing key from card
&lt;&#x2F;span&gt;&lt;span&gt;Your selection? 10
&lt;&#x2F;span&gt;&lt;span&gt;Please select which elliptic curve you want:
&lt;&#x2F;span&gt;&lt;span&gt;   (1) Curve 25519 *default*
&lt;&#x2F;span&gt;&lt;span&gt;   (4) NIST P-384
&lt;&#x2F;span&gt;&lt;span&gt;   (6) Brainpool P-256
&lt;&#x2F;span&gt;&lt;span&gt;Your selection? 1
&lt;&#x2F;span&gt;&lt;span&gt;Please specify how long the key should be valid.
&lt;&#x2F;span&gt;&lt;span&gt;         0 = key does not expire
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;  = key expires in n days
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;w = key expires in n weeks
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;m = key expires in n months
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;y = key expires in n years
&lt;&#x2F;span&gt;&lt;span&gt;Key is valid for? (0) 0
&lt;&#x2F;span&gt;&lt;span&gt;Key does not expire at all
&lt;&#x2F;span&gt;&lt;span&gt;Is this correct? (y&#x2F;N) y
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;GnuPG needs to construct a user ID to identify your key.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Real name: Example Gitea
&lt;&#x2F;span&gt;&lt;span&gt;Email address: gitea@git.example.com
&lt;&#x2F;span&gt;&lt;span&gt;Comment:
&lt;&#x2F;span&gt;&lt;span&gt;You selected this USER-ID:
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;Example Gitea &amp;lt;gitea@git.example.com&amp;gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Change (N)ame, (C)omment, (E)mail or (O)kay&#x2F;(Q)uit? o
&lt;&#x2F;span&gt;&lt;span&gt;We need to generate a lot of random bytes. It is a good idea to perform
&lt;&#x2F;span&gt;&lt;span&gt;some other action (type on the keyboard, move the mouse, utilize the
&lt;&#x2F;span&gt;&lt;span&gt;disks) during the prime generation; this gives the random number
&lt;&#x2F;span&gt;&lt;span&gt;generator a better chance to gain enough entropy.
&lt;&#x2F;span&gt;&lt;span&gt;gpg: revocation certificate stored as
&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&#x2F;home&#x2F;ivan&#x2F;.gnupg&#x2F;openpgp-revocs.d&#x2F;F41E36D6735FD9BE1B53518EA1596EF2CE56B350.rev&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;public and secret key created and signed.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;pub   ed25519&#x2F;0xA1596EF2CE56B350 2024-05-05 [SC]
&lt;&#x2F;span&gt;&lt;span&gt;      Key fingerprint = F41E 36D6 735F D9BE 1B53  518E A159 6EF2 CE56 B350
&lt;&#x2F;span&gt;&lt;span&gt;uid                              Example Gitea &amp;lt;gitea@git.example.com&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note the line about &lt;code&gt;gpg: revocation certificate stored as &#x27;&#x2F;home&#x2F;ivan&#x2F;.gnupg&#x2F;openpgp-revocs.d&#x2F;F41E36D6735FD9BE1B53518EA1596EF2CE56B350.rev&#x27;&lt;&#x2F;code&gt;.
This is a revocation certificate for the new key, generated here in case the
key needs to be revoked in the future (but the secret part of the key is somehow
lost or destroyed). Save this somewhere safe (like a password manager) and
destroy this copy when done (and optionally ensure it is scrubbed from your ZFS
snapshots if you care to).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;generating-a-signing-subkey&quot;&gt;Generating a signing subkey&lt;&#x2F;h1&gt;
&lt;p&gt;Now it&#x27;s time to generate a signing subkey that will be used by Gitea directly.
The idea is that this subkey can be rotated at will while the main key remains
offline&#x2F;in cold storage (so it can be trusted for longer periods of time). Note
that GPG will ask for the password we set earlier.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --edit-key&lt;&#x2F;span&gt;&lt;span&gt; 0xA1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
&lt;&#x2F;span&gt;&lt;span&gt;This is free software: you are free to change and redistribute it.
&lt;&#x2F;span&gt;&lt;span&gt;There is NO WARRANTY, to the extent permitted by law.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Secret key is available.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;sec  ed25519&#x2F;0xA1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: SC
&lt;&#x2F;span&gt;&lt;span&gt;     trust: ultimate      validity: ultimate
&lt;&#x2F;span&gt;&lt;span&gt;[ultimate] (1). Example Gitea &amp;lt;gitea@git.example.com&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;gpg&amp;gt; addkey
&lt;&#x2F;span&gt;&lt;span&gt;Please select what kind of key you want:
&lt;&#x2F;span&gt;&lt;span&gt;   (3) DSA (sign only)
&lt;&#x2F;span&gt;&lt;span&gt;   (4) RSA (sign only)
&lt;&#x2F;span&gt;&lt;span&gt;   (5) Elgamal (encrypt only)
&lt;&#x2F;span&gt;&lt;span&gt;   (6) RSA (encrypt only)
&lt;&#x2F;span&gt;&lt;span&gt;  (10) ECC (sign only)
&lt;&#x2F;span&gt;&lt;span&gt;  (12) ECC (encrypt only)
&lt;&#x2F;span&gt;&lt;span&gt;  (14) Existing key from card
&lt;&#x2F;span&gt;&lt;span&gt;Your selection? 10
&lt;&#x2F;span&gt;&lt;span&gt;Please select which elliptic curve you want:
&lt;&#x2F;span&gt;&lt;span&gt;   (1) Curve 25519 *default*
&lt;&#x2F;span&gt;&lt;span&gt;   (4) NIST P-384
&lt;&#x2F;span&gt;&lt;span&gt;   (6) Brainpool P-256
&lt;&#x2F;span&gt;&lt;span&gt;Your selection? 1
&lt;&#x2F;span&gt;&lt;span&gt;Please specify how long the key should be valid.
&lt;&#x2F;span&gt;&lt;span&gt;         0 = key does not expire
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;  = key expires in n days
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;w = key expires in n weeks
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;m = key expires in n months
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;n&amp;gt;y = key expires in n years
&lt;&#x2F;span&gt;&lt;span&gt;Key is valid for? (0) 0
&lt;&#x2F;span&gt;&lt;span&gt;Key does not expire at all
&lt;&#x2F;span&gt;&lt;span&gt;Is this correct? (y&#x2F;N) y
&lt;&#x2F;span&gt;&lt;span&gt;Really create? (y&#x2F;N) y
&lt;&#x2F;span&gt;&lt;span&gt;We need to generate a lot of random bytes. It is a good idea to perform
&lt;&#x2F;span&gt;&lt;span&gt;some other action (type on the keyboard, move the mouse, utilize the
&lt;&#x2F;span&gt;&lt;span&gt;disks) during the prime generation; this gives the random number
&lt;&#x2F;span&gt;&lt;span&gt;generator a better chance to gain enough entropy.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;sec  ed25519&#x2F;0xA1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: SC
&lt;&#x2F;span&gt;&lt;span&gt;     trust: ultimate      validity: ultimate
&lt;&#x2F;span&gt;&lt;span&gt;ssb  ed25519&#x2F;0xA36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: S
&lt;&#x2F;span&gt;&lt;span&gt;[ultimate] (1). Example Gitea &amp;lt;gitea@git.example.com&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;gpg&amp;gt; save
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;backing-up-the-newly-generated-keys&quot;&gt;Backing up the newly generated keys&lt;&#x2F;h1&gt;
&lt;p&gt;Now is a good time to store a secure copy of the key&#x27;s we&#x27;ve just generated
(e.g. storing the output somewhere in your password manager). Once again GPG
will ask for the password we created earlier.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --export-secret-keys --armor --export-options&lt;&#x2F;span&gt;&lt;span&gt; export-backup 0xA1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;transferring-the-signing-subkey&quot;&gt;Transferring the signing subkey&lt;&#x2F;h1&gt;
&lt;p&gt;Next we&#x27;ll need to transfer the signing subkey to the Gitea host itself. Running
the following will print out the secret portion which we&#x27;ll copy&#x2F;paste
afterwards. There are other ways to achieve this without leaving traces (either
on disk or through the system clipboard) but that is left as an exercise to the
(sufficiently paranoid) reader.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --export-secret-subkeys --armor&lt;&#x2F;span&gt;&lt;span&gt; 0xA36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, we need to ssh to the Gitea host and temporarily take on the &lt;code&gt;gitea&lt;&#x2F;code&gt; user.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;span&gt; giteahost.example.com
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; su gitea
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On NixOS, Gitea will use &lt;code&gt;&#x2F;var&#x2F;lib&#x2F;gitea&lt;&#x2F;code&gt; as its root directory, and &lt;code&gt;data&#x2F;home&lt;&#x2F;code&gt;
for it&#x27;s &lt;code&gt;$HOME&lt;&#x2F;code&gt; equivalent (though both of these are configurable so consult
your distro docs and replace the values as appropriate).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# NB: using --batch here will suppress password prompts, meaning the key will
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# be imported without any (password) protection. Make sure Gitea&amp;#39;s root
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# directory is fully sandboxed away from other users
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --homedir&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;.gnupg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --batch --import
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Paste the output from the previous command here.
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Hit Enter then Ctrl+D to finish
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note: if importing fails, kill all instances of `gpg-agent` and try again.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that the (subkey) is imported, we need to update its trust level:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --homedir&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;.gnupg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --edit-key&lt;&#x2F;span&gt;&lt;span&gt; 0xA36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
&lt;&#x2F;span&gt;&lt;span&gt;This is free software: you are free to change and redistribute it.
&lt;&#x2F;span&gt;&lt;span&gt;There is NO WARRANTY, to the extent permitted by law.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Secret subkeys are available.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;gpg: &#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;.gnupg&#x2F;trustdb.gpg: trustdb created
&lt;&#x2F;span&gt;&lt;span&gt;pub  ed25519&#x2F;A1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: SC
&lt;&#x2F;span&gt;&lt;span&gt;     trust: unknown       validity: unknown
&lt;&#x2F;span&gt;&lt;span&gt;ssb  ed25519&#x2F;A36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: S
&lt;&#x2F;span&gt;&lt;span&gt;[ unknown] (1). Example Gitea &amp;lt;gitea@git.example.com&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;gpg&amp;gt; trust
&lt;&#x2F;span&gt;&lt;span&gt;pub  ed25519&#x2F;A1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: SC
&lt;&#x2F;span&gt;&lt;span&gt;     trust: unknown       validity: unknown
&lt;&#x2F;span&gt;&lt;span&gt;ssb  ed25519&#x2F;A36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: S
&lt;&#x2F;span&gt;&lt;span&gt;[ unknown] (1). Example Gitea &amp;lt;gitea@git.example.com&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Please decide how far you trust this user to correctly verify other users&amp;#39; keys
&lt;&#x2F;span&gt;&lt;span&gt;(by looking at passports, checking fingerprints from different sources, etc.)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  1 = I don&amp;#39;t know or won&amp;#39;t say
&lt;&#x2F;span&gt;&lt;span&gt;  2 = I do NOT trust
&lt;&#x2F;span&gt;&lt;span&gt;  3 = I trust marginally
&lt;&#x2F;span&gt;&lt;span&gt;  4 = I trust fully
&lt;&#x2F;span&gt;&lt;span&gt;  5 = I trust ultimately
&lt;&#x2F;span&gt;&lt;span&gt;  m = back to the main menu
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Your decision? 5
&lt;&#x2F;span&gt;&lt;span&gt;Do you really want to set this key to ultimate trust? (y&#x2F;N) y
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;pub  ed25519&#x2F;A1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: SC
&lt;&#x2F;span&gt;&lt;span&gt;     trust: ultimate      validity: unknown
&lt;&#x2F;span&gt;&lt;span&gt;ssb  ed25519&#x2F;A36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;span&gt;     created: 2024-05-05  expires: never       usage: S
&lt;&#x2F;span&gt;&lt;span&gt;[ unknown] (1). Example Gitea &amp;lt;gitea@git.example.com&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Please note that the shown key validity is not necessarily correct
&lt;&#x2F;span&gt;&lt;span&gt;unless you restart the program.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;gpg&amp;gt; quit
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Lastly, we need to configure Gitea to not even attempt to open a pinentry prompt
since there isn&#x27;t going to be anyone around to answer it. We can achieve this by
configuring git to call a wrapper program which invokes GPG with &lt;code&gt;--batch&lt;&#x2F;code&gt;
(which will disable these prompts)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# On NixOS, system-wide packages show up in &#x2F;run&#x2F;current-system&#x2F;sw&#x2F;bin&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# swap it out with the appropriate location on your system
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;gpg-nopinentry &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;exec &#x2F;run&#x2F;current-system&#x2F;sw&#x2F;bin&#x2F;gpg --batch &amp;quot;$@&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;span&gt; +x &#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;gpg-nopinentry
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;.gitconfig &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;[gpg]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;	program = &amp;quot;&#x2F;var&#x2F;lib&#x2F;gitea&#x2F;data&#x2F;home&#x2F;gpg-nopinentry&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;telling-gitea-about-the-new-key&quot;&gt;Telling Gitea about the new key&lt;&#x2F;h1&gt;
&lt;p&gt;Gitea still needs to be instructed to use the key. There are a number of
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20240405224925&#x2F;https:&#x2F;&#x2F;docs.gitea.com&#x2F;administration&#x2F;config-cheat-sheet#repository---signing-repositorysigning&quot;&gt;configuration options&lt;&#x2F;a&gt; to consider but here are the most important ones to set.
Make sure they match the values that were originally set when generating the
root key.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ini&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-ini &quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;[repository.signing]
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;SIGNING_KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;0xA36F2B11E12C310D
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;SIGNING_NAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;Example Gitea
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;SIGNING_EMAIL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;gitea&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;@git&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;example&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;clean-up&quot;&gt;Clean up&lt;&#x2F;h1&gt;
&lt;p&gt;Back on the original host we can now purge the secret keys (assuming they have
been backed up securely) to minimize them getting compromised:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gpg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --delete-secret-keys&lt;&#x2F;span&gt;&lt;span&gt; 0xA1596EF2CE56B350
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Happy self-hosting!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Open Source is a Gift, Relicensing is a Grift</title>
		<published>2023-08-11T00:00:00+00:00</published>
		<updated>2023-08-11T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/open-source-is-a-gift-relicensing-is-a-grift/" type="text/html"/>
		<id>https://ipetkov.dev/blog/open-source-is-a-gift-relicensing-is-a-grift/</id>
		<content type="html">&lt;p&gt;Open Source is a Gift. But a gift that comes with strings attached is a shitty
one.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;HashiCorp &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230811143814&#x2F;https:&#x2F;&#x2F;www.hashicorp.com&#x2F;blog&#x2F;hashicorp-adopts-business-source-license&quot;&gt;recently announced its decision to relicense their
software&lt;&#x2F;a&gt;.
I&#x27;ve never used, nor contributed to their software so I don&#x27;t particularly care,
but since there&#x27;s a lot of takes flying around in &lt;em&gt;the discourse&lt;&#x2F;em&gt; I wanted to
express my own thoughts on the general pattern of companies trying to relicense
and lock down the past permissiveness of the software they have created.&lt;&#x2F;p&gt;
&lt;p&gt;Different folks will ascribe different definitions (or even &quot;requirements&quot;) to
whether something actually is Open Source or not. To me, Open Source is software
given away to others to do with it as they will. In other words, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230811144941&#x2F;https:&#x2F;&#x2F;apenwarr.ca&#x2F;log&#x2F;20211229&quot;&gt;a
Gift&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Open Source as a Gift&lt;&#x2F;em&gt; is what happens when someone truly gives away software
they&#x27;ve created because they want to share the value it brings with no strings
attached. Someone who makes a contribution to that work (technical or otherwise) is
also giving a Gift in return under the same terms.&lt;&#x2F;p&gt;
&lt;p&gt;What frustrates and annoys me is when people try to defend &lt;strong&gt;Open Source as a
Grift&lt;&#x2F;strong&gt; as if it&#x27;s the same thing. &lt;strong&gt;Open Source as a Grift&lt;&#x2F;strong&gt; is what happens
when a corporation adopts Open Source as a business &lt;em&gt;strategy&lt;&#x2F;em&gt;. They start out
giving software away under a permissive license to garner adoption and extract
free-as-in-labor contributions from others. Sooner or later the corporation
decides it wants to extract rent from its products (or it decides it isn&#x27;t able
to extract &lt;em&gt;enough&lt;&#x2F;em&gt; rent) and tries to claw back control over their software and
make it so that &lt;em&gt;only they&lt;&#x2F;em&gt; can (monetarily) profit directly from that work.&lt;&#x2F;p&gt;
&lt;p&gt;I have no sympathy for situations like &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230811152832&#x2F;https:&#x2F;&#x2F;www.zdnet.com&#x2F;article&#x2F;elastic-changes-open-source-license-to-monetize-cloud-service-use&#x2F;&quot;&gt;Elastic bemoaning
AWS&lt;&#x2F;a&gt;
&quot;unfairly&quot; profiting by hosting their software. AWS&#x27;s business model is to rent
servers and software to customers. Elastic&#x27;s business model is (was?) developing
software and giving it away under terms that permits others to build on top of
it. Their sudden regret in not being able to extract the same rent with their
existing business model does not change the fact that &lt;em&gt;they chose to build
permissive, free-as-in-beer software knowing that someone like AWS could, and
would, come along and make money with it&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now, don&#x27;t get me wrong: I think everyone should be fairly compensated for their
labor, we all have to put food on the table in this world of capitalism. But &lt;em&gt;if
you cannot economically sustain yourself by giving Gifts away&lt;&#x2F;em&gt; &lt;strong&gt;then you have
no business in doing so&lt;&#x2F;strong&gt;. And you most certainly do not get to come back after
the fact, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=-zRN7XLCRhc&amp;amp;t=2483s&quot;&gt;break the social
contract&lt;&#x2F;a&gt;, and demand
everyone adopt new terms on how they use the very thing you voluntarily chose to
give away.&lt;&#x2F;p&gt;
&lt;p&gt;Of course the tension here is that if those who engage in &lt;strong&gt;Open Source as a
Grift&lt;&#x2F;strong&gt; kept their software proprietary from the start, it would not have seen
the same level of adoption or been able to extract contributions from others.&lt;&#x2F;p&gt;
&lt;p&gt;You can&#x27;t have it both ways.&lt;&#x2F;p&gt;
&lt;p&gt;Attempting to relicense to less permissive terms is, and always has been,
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230811151446&#x2F;https:&#x2F;&#x2F;pluralistic.net&#x2F;2023&#x2F;01&#x2F;21&#x2F;potemkin-ai&#x2F;&quot;&gt;enshittification&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>NixOS on the PiBox</title>
		<published>2023-02-19T00:00:00+00:00</published>
		<updated>2023-06-04T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/nixos-on-the-pibox/" type="text/html"/>
		<id>https://ipetkov.dev/blog/nixos-on-the-pibox/</id>
		<content type="html">&lt;p&gt;The &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219020959&#x2F;https:&#x2F;&#x2F;pibox.io&#x2F;&quot;&gt;PiBox&lt;&#x2F;a&gt; is a small personal server powered by a Raspberry Pi CM4. It comes
in a nice enclosure which has a fan, an LCD screen, and has two bays for SATA
SSDs. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219021025&#x2F;https:&#x2F;&#x2F;kubesail.com&#x2F;homepage&quot;&gt;KubeSail&lt;&#x2F;a&gt;, the company behind it, offers backup storage and proxy traffic
as a service. They also support a bunch of templates for easily self hosting
apps like Jellyfin or NextCloud.&lt;&#x2F;p&gt;
&lt;p&gt;But, since I&#x27;m already very comfortable with NixOS and deploy a bunch of custom
workloads with it, I wanted to try using it instead of the OS that ships with
the PiBox.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how I went about it, and how you can too!&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h1 id=&quot;preparing-the-cm4-for-boot&quot;&gt;Preparing the CM4 for boot&lt;&#x2F;h1&gt;
&lt;p&gt;Although the CM4 (technically) supports booting from a variety of different
targets besides its EEPROM (like an NVMe drive, a USB stick, and even the
network!), it doesn&#x27;t actually support booting from a SATA drive. I guess most
people either boot from a USB drive or go all in with an NVMe drive, so for
whatever reason direct boot from SATA was never designed into the firmware. The
good thing is we can still boot from the EEPROM itself but keep the OS and all
other data on the SSD drive, so that&#x27;s what we&#x27;ll do here.&lt;&#x2F;p&gt;
&lt;p&gt;The first step is to optionally update the board&#x27;s firmware and change the boot
order. The default configuration tries a whole bunch of boot options which
likely will never be used which means it takes it a while to actually boot.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ll start by &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219020754&#x2F;https:&#x2F;&#x2F;docs.kubesail.com&#x2F;guides&#x2F;pibox&#x2F;rpiboot&#x2F;&quot;&gt;opening up the PiBox and carefully separating the carrier board from
the backplane&lt;&#x2F;a&gt;,
then flip the &quot;boot mode&quot; switch to &lt;code&gt;rpiboot&lt;&#x2F;code&gt; and connect the board with a USB-C
cable to a PC. To change the boot config we&#x27;ll need to use the raspberrypi
&lt;code&gt;usbboot&lt;&#x2F;code&gt; toolkit:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; clone https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;usbboot &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#39bae6;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usbboot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;cd &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#39bae6;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usbboot&#x2F;recovery
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Edit the `boot.conf` file and set the `BOOT_ORDER` variable
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# I noticed that if the &amp;quot;SD&amp;quot; (same as the EEPROM on CM4) option (1) is set to
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# run first the board doesn&amp;#39;t actually boot from it but tries everything else
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# first. Maybe there&amp;#39;s some kind of delay the hardware needs to warm up but I
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# found if I set `BOOT_ORDER=0xf514` then things work pretty smoothly. This
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# configuration basically tries things in the following order:
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# - 4: USB mass storage device: don&amp;#39;t care about this, try anything first
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# - 1: SD card (or the EEPROM for the CM4), where we would normally boot from
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# - 5: BCM-USB: boot from the board hardware headers or something idk
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# - f: Restart if all else fails
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Also note that you can keep `ENABLE_SELF_UPDATE=1` to allow updating the
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# firmware directly from a booted OS in the future without having to reconnect
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# to the board like we are doing here
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;vim&lt;&#x2F;span&gt;&lt;span&gt; boot.conf
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Then apply the changes and flash the firmware, if it went well the lights
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# should start blinking red and green
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;.&#x2F;update-pieeprom.sh
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; shell nixpkgs#rpiboot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --command&lt;&#x2F;span&gt;&lt;span&gt; sudo rpiboot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span&gt; .
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Disconnect and reconnect the board to the PC again. This time we&#x27;ll mount the
CM4&#x27;s EEPROM storage as a generic device we can manipulate from the PC.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; shell nixpkgs#rpiboot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --command&lt;&#x2F;span&gt;&lt;span&gt; sudo rpiboot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -d &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#39bae6;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usbboot&#x2F;mass-storage-gadget
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# The disk should show up as something like &#x2F;dev&#x2F;sda, though if the system
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# already has other disks present it might show up as &#x2F;dev&#x2F;sdb or &#x2F;dev&#x2F;sdc, etc.
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# so DOUBLE CHECK THIS!
&lt;&#x2F;span&gt;&lt;span&gt;SD_DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;sd...&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: I noticed that sometimes the mount would randomly disconnect and
reconnect on its own (usually showing up as a &lt;em&gt;new&lt;&#x2F;em&gt; device like &lt;code&gt;&#x2F;dev&#x2F;sdb&lt;&#x2F;code&gt; if
it was previously &lt;code&gt;&#x2F;dev&#x2F;sda&lt;&#x2F;code&gt;). Not sure if this was due to my cable connection
or something else, so I highly recommend double checking things before doing
any operations on the EEPROM.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Next we&#x27;ll partition the EEPROM and initialize a file system on it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; shell nixpkgs#parted&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --command&lt;&#x2F;span&gt;&lt;span&gt; sudo parted&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --align&lt;&#x2F;span&gt;&lt;span&gt; optimal &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{SD_DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    mklabel gpt \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    mkpart primary fat32 1MiB 100% \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    name 1 &amp;#39;EFI system partition&amp;#39; \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    set 1 esp on \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    print \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    quit
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; shell nixpkgs#dosfstools&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --command&lt;&#x2F;span&gt;&lt;span&gt; sudo mkfs.vfat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{SD_DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;1&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Write down UUIDs for what will become our boot partition
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# and add it to the NixOS config
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;disk&#x2F;by-uuid
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, disconnect the CM4, but don&#x27;t reassemble it quite yet as we&#x27;ll write
some more data to it later!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;preparing-a-builder-vm&quot;&gt;Preparing a builder VM&lt;&#x2F;h1&gt;
&lt;p&gt;I had originally set out to plug the new SSD into my desktop and do the
partitioning and installation from there, in the hope that it would be faster
and save me various reboot and debug cycles. Even though I have binfmt enabled
(let&#x27;s me run aarch64 binaries via QEMU) and I can successfully do remote
aarch64 deployments from my x86 desktop via &lt;code&gt;nixos-rebuild switch&lt;&#x2F;code&gt;, I was not
able to get &lt;code&gt;nixos-install&lt;&#x2F;code&gt; to work despite my best efforts.&lt;&#x2F;p&gt;
&lt;p&gt;I was also unsuccessful in booting the PiBox from a USB stick (though maybe I
made a mistake with the firmware config or my USB image). I briefly considered
flashing the NixOS installer directly on the EEPROM and doing the installation
from there, but I wasn&#x27;t sure if it could cope with doing the installation
directly on the partition it was booted from.&lt;&#x2F;p&gt;
&lt;p&gt;Instead I decided to spin up a quick QEMU VM and trick &lt;code&gt;nixos-install&lt;&#x2F;code&gt; into
working. To save you some effort, copy the config below a &lt;code&gt;flake.nix&lt;&#x2F;code&gt; in a new
directory, then &lt;code&gt;nix build -L &amp;amp;&amp;amp; .&#x2F;result&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:NixOS&#x2F;nixpkgs&#x2F;nixos-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs &lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;DISK &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: &#x2F;dev&#x2F;disk&#x2F;by-id&#x2F;ata-...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sshKey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: ssh-ed25519 ...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;pkgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;x86_64-linux&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;pkgsAarch64 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;aarch64-linux&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;isoConfiguration &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixosSystem &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;aarch64-linux&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;modules &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;          ({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;modulesPath&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, ... &lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;modulesPath&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;installer&#x2F;cd-dvd&#x2F;iso-image.nix&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;isoImage&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;makeEfiBootable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;supportedFilesystems &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostId &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;a7dbd851&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# random value
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;systemPackages &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pkgsAarch64&lt;&#x2F;span&gt;&lt;span&gt;; [
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;coreutils
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;cryptsetup
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;dosfstools
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;gitMinimal
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;htop
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;openssh
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;parted
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;smartmontools
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;unzip
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;util-linux
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;wget
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;zfs
&lt;&#x2F;span&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;authorizedKeys&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;keys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;sshKey &lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          })
&lt;&#x2F;span&gt;&lt;span&gt;        ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;iso &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;isoConfiguration&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;isoImage&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;vmScript &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;writeScript &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;run-nixos-vm&amp;quot; &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;        #!&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;runtimeShell&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;qemu&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;bin&#x2F;qemu-system-aarch64 \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -machine virt,gic-version=max \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -cpu max \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -m 4G \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -smp 4 \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -drive file=$(echo &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;iso&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;iso&#x2F;*.iso),format=raw,readonly=on \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -drive file=&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;DISK&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;,format=raw,readonly=off \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -nic user,hostfwd=tcp::3333-:22 \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -nographic \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;          -bios &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;pkgsAarch64&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;OVMF&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;fd&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;FV&#x2F;QEMU_EFI.fd
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;      &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;packages&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;x86_64-linux&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;default &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;vmScript&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we have a VM running we can connect to it using&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; 3333 root@localhost &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;UserKnownHostsFile=&#x2F;dev&#x2F;null&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;StrictHostKeyChecking=no&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unless specified otherwise, the below commands should be run within this
session.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;partitioning-the-ssd&quot;&gt;Partitioning the SSD&lt;&#x2F;h2&gt;
&lt;p&gt;I like to partition my drives as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;1MiB for the GPT partition metadata&lt;&#x2F;li&gt;
&lt;li&gt;1023MiB for the boot partition
&lt;ul&gt;
&lt;li&gt;Although we&#x27;re going to be booting from the EEPROM, I&#x27;m still going to
reserve a boot partition in case the drive needs to be salvaged and booted
elsewhere. That way it won&#x27;t be necessary to add a partition later and risk
destroying the existing data.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;32MiB for storing LUKS keys and metadata&lt;&#x2F;li&gt;
&lt;li&gt;8GiB for (encrypted) swap (same size as the RAM on the device)&lt;&#x2F;li&gt;
&lt;li&gt;The remainder of the space for the (encrypted) data&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# The disk should show up at &#x2F;dev&#x2F;vdb on the VM, change this if it doesn&amp;#39;t
&lt;&#x2F;span&gt;&lt;span&gt;VDISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;dev&#x2F;vdb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Confirm this we&amp;#39;ve chosen the right disk
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;smartctl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -a &lt;&#x2F;span&gt;&lt;span&gt;${VDISK}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Do the actual partition as described above
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --align&lt;&#x2F;span&gt;&lt;span&gt; optimal ${VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt; -- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    mklabel gpt &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    mkpart primary fat32 1MiB 1024MiB &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    name 1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;EFI system partition&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    set 1 esp on &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    mkpart primary 1024MiB 1056MiB &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    name 2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;luks key&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    mkpart primary 1056MiB 9248MiB &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    name 3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;swap&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    mkpart primary 9248MiB 100% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    name 4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;root&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    print &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    quit
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Lastly, write down the UUIDs for the LUKS, swap, and root partitions
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# and add them to the NixOS config
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;disk&#x2F;by-uuid
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;luks-configuration&quot;&gt;LUKS Configuration&lt;&#x2F;h2&gt;
&lt;p&gt;Encrypting the SSD(&#x27;s non-boot partitions) works just like on any other machine.
To give a concrete example, we&#x27;re going to set up things in the following manner:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cryptkey&lt;&#x2F;code&gt; - this is the second partition we created above, and will be
unlocked with a password we remember. Its contents will be a bunch of random
data which will be used for unlocking the rest of the encrypted partitions&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cryptswap&lt;&#x2F;code&gt; - this is the third partition we created above, and will be
unlocked using the decrypted &lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition. It will be used for the
system&#x27;s swap.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cryptroot&lt;&#x2F;code&gt; - this is the fourth partition we created above, and will be
unlocked using the decrypted &lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition; it will also have a
&lt;em&gt;backup&lt;&#x2F;em&gt; password (which we need not remember, but should store a copy in a
safe place) in case &lt;code&gt;cryptkey&lt;&#x2F;code&gt; is corrupted. It will contain the actual root
filesystem for the device.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: I choose to enable &lt;code&gt;--allow-discards&lt;&#x2F;code&gt; which instructs the mapper to
propagate trim commands issued by the underlying filesystem, allowing the SSD
to better perform wear leveling. This option is disabled by default since
there are some theoretical attack vectors from having it enabled and allowing
an attacker to physically access the disk (namely leaking which blocks are
trimmed, an some potential oracle attacks if the attacker can influence what
data is written to the disk). Consult your threat model if this option is
appropriate for you.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note set the password you will use for &amp;quot;day-to-day&amp;quot; unlocking of the system
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# at boot, and make it a good one!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksFormat&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;2&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; open&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; cryptkey
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Fill the (decrypted) cryptkey partition full of random data
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# This invocation will fail with a &amp;quot;device out of space&amp;quot; error which is expected
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;dd&lt;&#x2F;span&gt;&lt;span&gt; if=&#x2F;dev&#x2F;urandom of=&#x2F;dev&#x2F;mapper&#x2F;cryptkey bs=1024 status=progress
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Create and mount the encrypted swap partition
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksFormat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --key-file&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;3&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; open &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --key-file&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;3&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  cryptswap
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Create and mount the data partition.
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Use a strong backup unlock phrase (e.g. dice ware) and write this down someplace safe!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksFormat&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;4&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksAddKey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --new-keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;4&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &#x2F;dev&#x2F;mapper&#x2F;cryptkey
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; open &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --key-file&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  --allow-discards &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;4&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  cryptroot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, we initialize the (unencrypted) boot partition with an empty FAT32
partition, and initialize and enable the (decrypted) swap partition.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkfs.vfat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;1&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkswap&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptswap
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;swapon&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptswap
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember to update the configuration with a &lt;code&gt;postDeviceCommand&lt;&#x2F;code&gt; to &lt;code&gt;cryptsetup close cryptkey&lt;&#x2F;code&gt; so that the contents of the &lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition don&#x27;t remain
accessible after booting!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;zfs-configuration&quot;&gt;ZFS Configuration&lt;&#x2F;h2&gt;
&lt;p&gt;There&#x27;s nothing specific to this setup which dictates how ZFS must be
configured, but as a complete example I want to describe my approach with the
following dataset hierarchy:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;local&lt;&#x2F;code&gt; - for data which is either ephemeral or does not need to be backed up
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;root&lt;&#x2F;code&gt; - mounted as the system root, reverted to a blank snapshot on every
boot so I can &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230216224910&#x2F;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;erase-your-darlings&quot;&gt;Erase My Darlings&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nix&lt;&#x2F;code&gt; - mounted as &lt;code&gt;&#x2F;nix&#x2F;store&lt;&#x2F;code&gt;, no need to snapshot as it can be trivially
rebuilt if necessary&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;persist&lt;&#x2F;code&gt; - for all data that should be persisted across reboots, snapshotted
by default
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;journal&lt;&#x2F;code&gt; - systemd logs, mounted at &lt;code&gt;&#x2F;var&#x2F;log&#x2F;journal&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lib&lt;&#x2F;code&gt; - catchall for application state, mounted at &lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt;. Normally I
like to split out services into their own datasets (for independent
snapshotting and rollback), though this acts as a good safety to avoid
forgetting to persist a particular service&#x27;s state directories and losing them
on reboot.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;system&lt;&#x2F;code&gt; - miscellaneous system-specific files which should be persisted
across reboots, mounted at &lt;code&gt;&#x2F;persist&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user&lt;&#x2F;code&gt; - parent dataset for users&#x27; data&#x2F;home directories&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;reserved&lt;&#x2F;code&gt; - used for over-provisioning the disk (i.e. no data will be written
here to allow the SSD to move blocks and maintain the health of the
flash storage)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Configure the pool and user names we want to use
&lt;&#x2F;span&gt;&lt;span&gt;POOL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;phlegethon
&lt;&#x2F;span&gt;&lt;span&gt;MY_USER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;ivan
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note: when creating the pool, lower case `-o` is used to configure properties at
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# the _pool_ level, while upper case `-O` is used to configure properties at the
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# _dataset_ level
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note: ashift MUST BE SET or there will be horrible horrible write performance
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# using the default value ZFS selects. If you aren&amp;#39;t sure what to pick and
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# have a modern drive, just take my word for it and set it to 13.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span&gt; create &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o&lt;&#x2F;span&gt;&lt;span&gt; ashift=13 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o&lt;&#x2F;span&gt;&lt;span&gt; autotrim=on &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -O&lt;&#x2F;span&gt;&lt;span&gt; acltype=posixacl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -O&lt;&#x2F;span&gt;&lt;span&gt; atime=off &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -O&lt;&#x2F;span&gt;&lt;span&gt; canmount=off &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -O&lt;&#x2F;span&gt;&lt;span&gt; compression=lz4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -O&lt;&#x2F;span&gt;&lt;span&gt; xattr=sa &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -m&lt;&#x2F;span&gt;&lt;span&gt; legacy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  ${POOL} &#x2F;dev&#x2F;mapper&#x2F;cryptroot
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Reserve (i.e. overprovision) ~10% of the disk (assuming 1TB disk)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;    -o&lt;&#x2F;span&gt;&lt;span&gt; reservation=200G &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;    -o&lt;&#x2F;span&gt;&lt;span&gt; quota=200G &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;    -o&lt;&#x2F;span&gt;&lt;span&gt; canmount=off &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    ${POOL}&#x2F;reserved
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# systemd-remount-fs.service complains if mountpoint not set
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; canmount=off&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; mountpoint=&#x2F; ${POOL}&#x2F;local
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create ${POOL}&#x2F;local&#x2F;nix
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create ${POOL}&#x2F;local&#x2F;root
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Snapshot the root while still empty so we can easily revert it back
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; snapshot ${POOL}&#x2F;local&#x2F;root@blank
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; com.sun:auto-snapshot=true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; canmount=off ${POOL}&#x2F;persist
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create ${POOL}&#x2F;persist&#x2F;system
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create ${POOL}&#x2F;persist&#x2F;lib
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create ${POOL}&#x2F;persist&#x2F;journal
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; canmount=off ${POOL}&#x2F;persist&#x2F;user
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create ${POOL}&#x2F;persist&#x2F;user&#x2F;${MY_USER}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, mount all datasets at their appropriate paths &lt;em&gt;before&lt;&#x2F;em&gt; doing the
installation (lest the data be written in the wrong spot and missing during
boot):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;local&#x2F;root&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;{boot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;home&#x2F;${MY_USER}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;nix&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;persist&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;var&#x2F;{lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;log&#x2F;journal}}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{VDISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;boot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;local&#x2F;nix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;nix
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;user&#x2F;$&lt;&#x2F;span&gt;&lt;span&gt;{MY_USER}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;home&#x2F;${MY_USER}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;system&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;persist
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;lib&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;var&#x2F;lib
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;journal&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;var&#x2F;log&#x2F;journal
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;optional-remote-luks-unlock&quot;&gt;(Optional) Remote LUKS Unlock&lt;&#x2F;h2&gt;
&lt;p&gt;Having to plug in a keyboard and monitor to the PiBox to unlock after a restart
can be a chore, so being able to unlock the drive remotely via SSH can be much
more convenient. First we need to generate a unique host key for the &lt;em&gt;boot&lt;&#x2F;em&gt;
stage.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that although the key itself will be stored on the encrypted partition,
it will be copied to the initrd stored on the &lt;em&gt;unecrypted&lt;&#x2F;em&gt; boot partition
since the CM4 has no TPM that can be used to further encrypt secrets.
Therefore, this needs to be a unique host key that is &lt;em&gt;only&lt;&#x2F;em&gt; used for remote
unlocking and not shared with other hosts. Once the root drive is unlocked,
the machine will use another host key which is protected by the disk
encryption.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# This can be stored anywhere on the host, so long as the path is accessible
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# when the system activation script is run. When doing remote deployments it
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# _need not_ be accessible by the deploying host
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;persist&#x2F;etc&#x2F;ssh
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ssh-keygen&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; ed25519&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -N &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;persist&#x2F;etc&#x2F;ssh&#x2F;initrd_ssh_host_ed25519_key
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note the generated fingerprint here and add it to &lt;code&gt;~&#x2F;.ssh&#x2F;known_hosts&lt;&#x2F;code&gt; (for the
correct address and port) so you can be (more) sure you are connecting to the
correct host before entering the unlock password.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Next, pick a port and update the NixOS configuration with the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;network &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ssh &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;port &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;9999&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;authorizedKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;add an authorized key here&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note this file lives on the host itself,
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# and isn&amp;#39;t passed in by the deployer
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&#x2F;etc&#x2F;ssh&#x2F;initrd_ssh_host_ed25519_key&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Also note that when connecting over SSH during boot you&#x27;ll need to use the port
defined above (to avoid ambiguity with connecting to the default port (22) after
unlocking) and you will need to set the user as &lt;code&gt;root&lt;&#x2F;code&gt;. These can be configured
with a host alias in &lt;code&gt;~&#x2F;.ssh&#x2F;config&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;Host boot-unlock
&lt;&#x2F;span&gt;&lt;span&gt;  Hostname = REPLACE_WITH_IP_FOR_THE_HOST
&lt;&#x2F;span&gt;&lt;span&gt;  User root
&lt;&#x2F;span&gt;&lt;span&gt;  Port 9999
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, to unlock the host, simply run &lt;code&gt;ssh boot-unlock&lt;&#x2F;code&gt; and execute
&lt;code&gt;cryptsetup-askpass&lt;&#x2F;code&gt; to enter the password. You might get a warning about
&quot;Passphrase is not requested now&quot; after 10 seconds, but this is completely
normal. I&#x27;ve noticed that it takes about 15 seconds before the disk and CPU LEDs
start blinking, and about 45 more seconds until the actual boot sequence starts.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Also note that it is probably worth making sure the PiBox has an ethernet
cable plugged in, as it will not be able to connect to WiFi during boot,
unless the SSID password is also stored (unprotected) on the initrd&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;nixos-installation&quot;&gt;NixOS Installation&lt;&#x2F;h2&gt;
&lt;p&gt;To set a password for the root user which persists across unlocks we&#x27;ll need to
use a password file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; mkpasswd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -m&lt;&#x2F;span&gt;&lt;span&gt; sha-512 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;persist&#x2F;root&#x2F;passwordfile
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And update the configuration with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;passwordFile &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&#x2F;root&#x2F;passwordfile&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;fileSystems&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;neededForBoot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we need to get the configuration on to the VM. A quick and dirty solution
is to &lt;code&gt;scp&lt;&#x2F;code&gt; it over:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# In a fresh terminal
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;scp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -P&lt;&#x2F;span&gt;&lt;span&gt; 3333&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -r &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#39bae6;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;dotfiles root@localhost:&#x2F;root &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;UserKnownHostsFile=&#x2F;dev&#x2F;null&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;  -o &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;StrictHostKeyChecking=no&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, back in the VM session we can finally install NixOS on the SSD&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;HOST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;asphodel
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;cd &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#39bae6;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;dotfiles
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixos-install&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --root&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --flake&lt;&#x2F;span&gt;&lt;span&gt; .#${HOST}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --no-channel-copy
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Gracefully detach the disks and exit
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;umount&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;boot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span&gt; export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;halt
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Afterwards, hit &amp;quot;Ctrl-a&amp;quot;, then &amp;quot;x&amp;quot; on the QEMU window to terminate the image
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;firmware-and-bootloader-installation&quot;&gt;Firmware and Bootloader Installation&lt;&#x2F;h1&gt;
&lt;p&gt;The last few things we need to do are installing the firmware needed to boot the
CM4 (as well as inform the kernel about the fan and LCD peripherals) and the
EFI&#x2F;bootloader files generated by the NixOS installation.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve already done the hard part of writing a flake which can prepare the
firmware, as well as enable the fan and display services bundled with the
PiBox OS so checkout &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;nixos-pibox&quot;&gt;the repo&lt;&#x2F;a&gt; for more info!&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;2023-06-04: Hello from the future! If you are updating from 22.11 to 23.05
you may need to build and copy the firmware before updating (but take a backup
of your existing &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; directory first)! There was a kernel update (from
5.15 to 6.1) between the two releases and the device tree definitions need to
be updated or the new kernel may not recognize the fan and display hardware!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build and prepare the raspberrypi firmware and apply the device tree
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# overrides to make the PWM fan and LCD discoverable by the kernel.
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Results will be found in `.&#x2F;result`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; build github:ipetkov&#x2F;nixos-pibox#packages.aarch64-linux.firmware&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -L
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Prepare mount paths for the disks
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt &#x2F;mnt_ssd
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Reconnect the CM4 as a mass storage device
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; shell nixpkgs#rpiboot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --command&lt;&#x2F;span&gt;&lt;span&gt; sudo rpiboot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -d &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#39bae6;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usbboot&#x2F;mass-storage-gadget
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Double check the disks paths here again:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;disk&#x2F;by-id&#x2F;ata-...&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;SD_DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;sd...&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Mount the &amp;quot;boot&amp;quot; partition of the SSD
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; mount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;-part1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt_ssd
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Mount the CM4&amp;#39;s EEPROM
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; mount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{SD_DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Copy the firmware and EFI&#x2F;bootloader
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; cp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;result&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt_ssd&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Cleanup
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; umount &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; umount &#x2F;mnt_ssd
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; rmdir &#x2F;mnt &#x2F;mnt_ssd
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Et voilà, the installation is complete! Flip the &quot;boot mode&quot; switch back to
&lt;code&gt;normal&lt;&#x2F;code&gt;, put the SSD in, and reassemble the PiBox case. If all else has gone
well you should be able to power on, unlock the disk, and boot and into NixOS.&lt;&#x2F;p&gt;
&lt;p&gt;Happy hacking!&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A quick aside on installing the firmware directly instead of using something
like the &lt;code&gt;boot.loader.raspberryPi&lt;&#x2F;code&gt; NixOS module: the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219015849&#x2F;https:&#x2F;&#x2F;discourse.nixos.org&#x2F;t&#x2F;planning-for-a-better-nixos-on-arm&#x2F;15346&quot;&gt;plans for NixOS on ARM&lt;&#x2F;a&gt;
highlight that this module largely exists for legacy reasons and should not be
used going forward. Even though the raspberrypi was designed to have this
firmware written to its boot partition, it&#x27;s more akin to the BIOS of a PC
motherboard: it&#x27;s not something NixOS should be attempting to manage as
without it the hardware can&#x27;t even &lt;em&gt;boot&lt;&#x2F;em&gt;, so getting something wrong means we
can&#x27;t even use a &quot;previous generation&quot;. Hence these files should be installed
once and not touched further (unless you have a backup ready and are willing
to physically restore the files if something goes wrong).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;appendix&quot;&gt;Appendix&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;nixos-pibox&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;nixos-pibox&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubesail&#x2F;pibox-os&#x2F;tree&#x2F;main&#x2F;lcd-display&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;kubesail&#x2F;pibox-os&#x2F;tree&#x2F;main&#x2F;lcd-display&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;usbboot&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;raspberrypi&#x2F;usbboot&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219015339&#x2F;https:&#x2F;&#x2F;carjorvaz.com&#x2F;posts&#x2F;nixos-on-raspberry-pi-4-with-uefi-and-zfs&quot;&gt;https:&#x2F;&#x2F;carjorvaz.com&#x2F;posts&#x2F;nixos-on-raspberry-pi-4-with-uefi-and-zfs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219015443&#x2F;https:&#x2F;&#x2F;mth.st&#x2F;blog&#x2F;nixos-initrd-ssh&quot;&gt;https:&#x2F;&#x2F;mth.st&#x2F;blog&#x2F;nixos-initrd-ssh&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219015738&#x2F;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;nixos-on-raspberry-pi-4&quot;&gt;https:&#x2F;&#x2F;mgdm.net&#x2F;weblog&#x2F;nixos-on-raspberry-pi-4&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219015836&#x2F;https:&#x2F;&#x2F;www.jeffgeerling.com&#x2F;blog&#x2F;2022&#x2F;how-update-raspberry-pi-compute-module-4-bootloader-eeprom&quot;&gt;https:&#x2F;&#x2F;www.jeffgeerling.com&#x2F;blog&#x2F;2022&#x2F;how-update-raspberry-pi-compute-module-4-bootloader-eeprom&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219015849&#x2F;https:&#x2F;&#x2F;discourse.nixos.org&#x2F;t&#x2F;planning-for-a-better-nixos-on-arm&#x2F;15346&quot;&gt;https:&#x2F;&#x2F;discourse.nixos.org&#x2F;t&#x2F;planning-for-a-better-nixos-on-arm&#x2F;15346&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230216224910&#x2F;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;erase-your-darlings&quot;&gt;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;erase-your-darlings&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219020744&#x2F;https:&#x2F;&#x2F;jrs-s.net&#x2F;2018&#x2F;08&#x2F;17&#x2F;zfs-tuning-cheat-sheet&quot;&gt;https:&#x2F;&#x2F;jrs-s.net&#x2F;2018&#x2F;08&#x2F;17&#x2F;zfs-tuning-cheat-sheet&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230219020754&#x2F;https:&#x2F;&#x2F;docs.kubesail.com&#x2F;guides&#x2F;pibox&#x2F;os&quot;&gt;https:&#x2F;&#x2F;docs.kubesail.com&#x2F;guides&#x2F;pibox&#x2F;os&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;sample-configuration&quot;&gt;Sample Configuration&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s a sample NixOS configuration to get you started with everything we&#x27;ve set
up above. This also includes the systemd services required for controlling the
PWM fan and LCD on the PiBox!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&#x2F;nixos-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixos-hardware&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:NixOS&#x2F;nixos-hardware&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixos-pibox &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:ipetkov&#x2F;nixos-pibox&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;@{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, ... &lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Replace all these placeholders with your actual values!
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;deviceBoot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: &#x2F;dev&#x2F;disk&#x2F;by-uuid&#x2F;...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;deviceCryptKey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: &#x2F;dev&#x2F;disk&#x2F;by-uuid&#x2F;...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;deviceCryptRoot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: &#x2F;dev&#x2F;disk&#x2F;by-uuid&#x2F;...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;deviceCryptSwap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: &#x2F;dev&#x2F;disk&#x2F;by-uuid&#x2F;...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostId &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: deadbeef&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostName &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;userSshKey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME: ssh-ed25519 ...&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;user &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zpool &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;REPLACE ME&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixosConfigurations&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;hostName&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixosSystem &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;modules &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;          ({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, ... &lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixos-hardware&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixosModules&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;raspberry-pi-4
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixos-pibox&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixosModules&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;default
&lt;&#x2F;span&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;overlays &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixos-pibox&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;overlays&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;default
&lt;&#x2F;span&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;boot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;extraModulePackages &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#f07178;&quot;&gt;!!!&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt; cryptkey must be done first, and the list seems to be
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# alphabetically sorted, so take care that cryptroot &#x2F; cryptswap,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# whatever you name them, come after cryptkey.
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;initrd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;luks&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;devices &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;deviceCryptKey&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptroot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;allowDiscards &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;deviceCryptRoot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;keyFile &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;mapper&#x2F;cryptkey&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;keyFileSize &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;8192&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptswap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;allowDiscards &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;deviceCryptSwap&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;keyFile &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;mapper&#x2F;cryptkey&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;keyFileSize &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;8192&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;postDeviceCommands &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;mkAfter &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;                  cryptsetup close cryptkey
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;                  zfs rollback -r &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;local&#x2F;root@blank &amp;amp;&amp;amp; echo blanked out root
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;                &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Support remote unlock. Run `cryptsetup-askpass` to unlock
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;network &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ssh &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;authorizedKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;authorizedKeys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;port &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;9999&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;                      &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note this file lives on the host itself, and isn&amp;#39;t passed in by the deployer
&lt;&#x2F;span&gt;&lt;span&gt;                      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&#x2F;etc&#x2F;ssh&#x2F;initrd_ssh_host_ed25519_key&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                    ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;loader &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;efi&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;canTouchEfiVariables &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;generic-extlinux-compatible&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;systemd-boot&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;timeout &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# seconds
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;kernelParams &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;8250.nr_uarts=1&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;console=ttyAMA0,115200&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;console=tty1&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;              ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;supportedFilesystems &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fileSystems &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;local&#x2F;root&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;options &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfsutil&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;boot&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;deviceBoot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;vfat&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;options &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;noatime&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;home&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;user&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;nix&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;local&#x2F;nix&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;system&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;neededForBoot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;var&#x2F;lib&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;lib&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;var&#x2F;log&#x2F;journal&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;persist&#x2F;journal&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;zfs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;neededForBoot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;swapDevices &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;              {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;mapper&#x2F;cryptswap&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }
&lt;&#x2F;span&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;powerManagement&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cpuFreqGovernor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;mkDefault &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;ondemand&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;networking &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostId hostName&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;useDHCP &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;interfaces&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;eth0&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;useDHCP &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;services &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;openssh &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;hostKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;                  {
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;path &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&#x2F;etc&#x2F;ssh&#x2F;ssh_host_ed25519_key&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;ed25519&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  }
&lt;&#x2F;span&gt;&lt;span&gt;                ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;piboxPwmFan&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;piboxFramebuffer&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;autoScrub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;interval &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;monthly&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;autoSnapshot&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;trim&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;passwordFile &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;persist&#x2F;root&#x2F;passwordfile&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;isNormalUser &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;home &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;home&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;authorizedKeys&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;keys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;userSshKey
&lt;&#x2F;span&gt;&lt;span&gt;              ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Other files to persist, e.g. NetworkManager
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# environment.etc.&amp;quot;NetworkManager&#x2F;system-connections&amp;quot; = {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;#   source = &amp;quot;&#x2F;persist&#x2F;etc&#x2F;NetworkManager&#x2F;system-connections&#x2F;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# };
&lt;&#x2F;span&gt;&lt;span&gt;          })
&lt;&#x2F;span&gt;&lt;span&gt;        ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Transparently Exposing Services Over Tailscale and the LAN</title>
		<published>2023-02-07T00:00:00+00:00</published>
		<updated>2023-12-16T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/transparently-exposing-services-over-tailscale-and-the-lan/" type="text/html"/>
		<id>https://ipetkov.dev/blog/transparently-exposing-services-over-tailscale-and-the-lan/</id>
		<content type="html">&lt;p&gt;Suppose we have control of our own domain and a set of services we want to share
with (only) our friends and family. Here&#x27;s how we can make them accessible over
both Tailscale or when connected to the same physical network while using the
&lt;em&gt;exact same domain&lt;&#x2F;em&gt; in each case.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;blockquote&gt;
&lt;p&gt;I personally &lt;em&gt;love&lt;&#x2F;em&gt; Tailscale and it truly makes securely connecting devices
incredibly easy. That said, it&#x27;s not always &lt;em&gt;practical&lt;&#x2F;em&gt; to expect all friends
and family to have Tailscale set up and always connected, so there&#x27;s
definitely a value to being able to access services on the local network
directly.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;&#x2F;h1&gt;
&lt;p&gt;Things we&#x27;ll need and their example values. Remember to substitute these with your
own!&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A domain we control: &lt;code&gt;example.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A subdomain we would like to use for the service: &lt;code&gt;rainbows.example.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A tailnet name: &lt;code&gt;cat-crocodile.ts.net&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A host (on the local network) running the &lt;code&gt;rainbows&lt;&#x2F;code&gt; service
&lt;ul&gt;
&lt;li&gt;A machine name assigned to this host in Tailscale: &lt;code&gt;fido&lt;&#x2F;code&gt; (meaning the
host can be reached via &lt;code&gt;fido.cat-crocodile.ts.net&lt;&#x2F;code&gt; over Tailscale)&lt;&#x2F;li&gt;
&lt;li&gt;A stable local IP address for &lt;code&gt;fido&lt;&#x2F;code&gt;: likely something like &lt;code&gt;192.168.0.42&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;A(n always reachable) host to run a DNS server: &lt;code&gt;dennis&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;A stable local IP address for &lt;code&gt;dennis&lt;&#x2F;code&gt;: likely something like &lt;code&gt;192.168.0.42&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The local network&#x27;s DHCP server (i.e. your router) should assign this
IP as the primary DNS server for the rest of the local network&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;MagicDNS enabled on the tailnet&lt;&#x2F;li&gt;
&lt;li&gt;The appropriate Tailscale ACLs such that &lt;code&gt;dennis&lt;&#x2F;code&gt;&#x27; port 53 is accessible
(and whatever other ports the &lt;code&gt;rainbows&lt;&#x2F;code&gt; service will use on &lt;code&gt;fido&lt;&#x2F;code&gt;, e.g. 443
for HTTPS)&lt;&#x2F;li&gt;
&lt;li&gt;A &quot;base&quot; DNS server:
&lt;ul&gt;
&lt;li&gt;This can be a &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pi-hole.net&#x2F;&quot;&gt;Pi-hole&lt;&#x2F;a&gt;, though if it is going to be
running on &lt;code&gt;dennis&lt;&#x2F;code&gt; you will need to configure it to listen to &lt;em&gt;any port
besides 53&lt;&#x2F;em&gt; (the default DNS port).&lt;&#x2F;li&gt;
&lt;li&gt;Or this can be any public DNS provider like &lt;code&gt;9.9.9.9&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h1 id=&quot;the-approach&quot;&gt;The Approach&lt;&#x2F;h1&gt;
&lt;p&gt;First we need to create a CNAME record pointing &lt;code&gt;rainbows.example.com&lt;&#x2F;code&gt; to
&lt;code&gt;fido.cat-crocodile.ts.net&lt;&#x2F;code&gt;; this should be done on the nameserver for
&lt;code&gt;example.com&lt;&#x2F;code&gt;, likely your domain registrar.&lt;&#x2F;p&gt;
&lt;p&gt;Next, we &lt;em&gt;could&lt;&#x2F;em&gt; configure our local DNS server (i.e. our Pi-hole instance
running on &lt;code&gt;dennis&lt;&#x2F;code&gt;) to hard-code an address record pointing
&lt;code&gt;fido.cat-crocodile.ts.net&lt;&#x2F;code&gt; to &lt;code&gt;192.168.0.42&lt;&#x2F;code&gt; &lt;em&gt;except this will not work&lt;&#x2F;em&gt; if
&lt;code&gt;dennis&lt;&#x2F;code&gt; is set as the global nameserver for your tailnet: if you ever leave the
local network &lt;code&gt;dennis&lt;&#x2F;code&gt; will recursively resolve &lt;code&gt;rainbows.example.net&lt;&#x2F;code&gt; to the
&quot;wrong&quot; address.&lt;&#x2F;p&gt;
&lt;p&gt;Instead &lt;code&gt;dennis&lt;&#x2F;code&gt; needs to run a recursive DNS server &lt;em&gt;which can tailor results
based on the requester&#x27;s address&lt;&#x2F;em&gt;. Namely, if a request comes from a local
address for &lt;code&gt;rainbows.example.com&lt;&#x2F;code&gt; or &lt;code&gt;fido.cat-crocodile.ts.net&lt;&#x2F;code&gt; it would need
to respond with &lt;code&gt;192.168.0.42&lt;&#x2F;code&gt; directly; otherwise it should use MagicDNS to
resolve to the Tailscale IP.&lt;&#x2F;p&gt;
&lt;p&gt;BIND&#x27;s &lt;code&gt;named&lt;&#x2F;code&gt; fulfills our use-case perfectly: it can present different &lt;em&gt;views&lt;&#x2F;em&gt;
of DNS records based on the requester&#x27;s address (among other things).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;&#x2F;h1&gt;
&lt;p&gt;Below is the minimal configuration necessary to get things working with &lt;code&gt;named&lt;&#x2F;code&gt;.
Remember to change the placeholder values with your own, but otherwise feel free
to tailor it further to your needs:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;acl tailnet &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;0&#x2F;10; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;acl mynet &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;localnets&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# bind builtin, automatically represents all interfaces on the device
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;tailnet&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# also include tailscale&amp;#39;s range (which is the Carrier Grade NAT range)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;options &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;directory &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;&amp;quot;&#x2F;run&#x2F;named&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;querylog no&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Change to `yes` to debug queries
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;listen-on &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;listen-on-v6 &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Keep this set to `only` if using Pi-hole. Setting it to `first`
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# will result in `named` trying to resolve results on its own which
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# would defeat Pi-hole&amp;#39;s filtering
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;forward only&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Assuming there is a Pi-hole instance running on this host on port 9053,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# forward requests for any zones not configured here. If you aren&amp;#39;t using
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Pi-hole this can be replaced with any other public DNS (e.g. `9.9.9.9`).
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;forwarders &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;127&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;port &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;9053; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Allow recursive resolution for any LAN&#x2F;Tailscale queries
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;recursion yes&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;allow-query &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mynet&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;allow-recursion &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mynet&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;allow-query-cache &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mynet&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# NB: view order is significant here: views are considered one by one and only
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# the first one to match is used. Specifically, the `catchall` view will
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# effectively be used for non-tailnet clients as they would have otherwise been
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# matched by the `tsnet` view
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;view tsnet &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;match-clients &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;{ tailnet; };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# We forward any queries for our tailnet directly to the MagicDNS server
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# since it should have the results for any hosts on the tailnet (which the
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# upstream DNS likely won&amp;#39;t).
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# NB: be _very_ careful that the tailnet name does not change here
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# and also be careful to ensure that this host was initialized with
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# `tailscale up --accept-dns=false` otherwise we could end up recursively
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# ourselves if the MagicDNS forwards any non-tailnet queries back to us
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;zone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;cat-crocodile.ts.net&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;IN &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;forward;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;forward only&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;forwarders &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;100; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Tailscale&amp;#39;s MagicDNS IP
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# The &amp;quot;catchall&amp;quot; view which will match all clients. Remember
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# that the earlier view will filter out any tailnet clients
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# maning this view represents clients directly on the local network
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;view catchall &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;match-clients &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;{ any; };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;zone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;cat-crocodile.ts.net&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;IN &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;primary;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;file &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;path&#x2F;to&#x2F;file&#x2F;for&#x2F;lan&#x2F;zone&#x2F;cat-crocodile.ts.net&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Where the contents of &lt;code&gt;&#x2F;path&#x2F;to&#x2F;file&#x2F;for&#x2F;lan&#x2F;zone&#x2F;cat-crocodile.ts.net&lt;&#x2F;code&gt; are:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;$TTL 2d
&lt;&#x2F;span&gt;&lt;span&gt;$ORIGIN cat-crocodile.ts.net.
&lt;&#x2F;span&gt;&lt;span&gt;@ IN SOA dns.example.com. hostmaster.example.com. (
&lt;&#x2F;span&gt;&lt;span&gt;                                1          ; serial number
&lt;&#x2F;span&gt;&lt;span&gt;                                12h        ; refresh
&lt;&#x2F;span&gt;&lt;span&gt;                                15m        ; update retry
&lt;&#x2F;span&gt;&lt;span&gt;                                3w         ; expiry
&lt;&#x2F;span&gt;&lt;span&gt;                                2h         ; minimum
&lt;&#x2F;span&gt;&lt;span&gt;                                )
&lt;&#x2F;span&gt;&lt;span&gt;@ IN NS  dns.example.com.
&lt;&#x2F;span&gt;&lt;span&gt;@ IN A   192.168.0.42
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Happy birthday Crane!</title>
		<published>2022-12-26T00:00:00+00:00</published>
		<updated>2022-12-26T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/happy-birthday-crane/" type="text/html"/>
		<id>https://ipetkov.dev/blog/happy-birthday-crane/</id>
		<content type="html">&lt;p&gt;A year ago I found myself with some free time around the holidays which was the
perfect opportunity for tinkering with Nix and cargo. What started out as a
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&quot;&gt;weekend learning project&lt;&#x2F;a&gt; shaped up so nicely
that &lt;a href=&quot;https:&#x2F;&#x2F;ipetkov.dev&#x2F;blog&#x2F;introducing-crane&#x2F;&quot;&gt;I decided to share it with the
world&lt;&#x2F;a&gt;, and here we are a year
later.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Since then we&#x27;ve seen:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;89 pull requests&lt;&#x2F;li&gt;
&lt;li&gt;17 releases&lt;&#x2F;li&gt;
&lt;li&gt;300+ GitHub stars&lt;&#x2F;li&gt;
&lt;li&gt;Support for auditing dependencies via &lt;code&gt;cargo-audit&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Support for running tests via &lt;code&gt;cargo-nextest&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Improved source filtering to maximize artifact caching&lt;&#x2F;li&gt;
&lt;li&gt;Improved performance when removing references to source files&lt;&#x2F;li&gt;
&lt;li&gt;Improved performance when compressing cargo artifacts&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A big thank you to everyone who has taken the time to report issues, offer
suggestions for improvement, and submit pull requests!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Of course no birthday celebration would be complete without presents: I&#x27;m
pleased to announce &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;crane.dev&quot;&gt;crane.dev&lt;&#x2F;a&gt;, the home for all Crane
related documentation! I hope for it to grow over time and become a great
source of comprehensive tips, tricks, and troubleshooting guides.&lt;&#x2F;p&gt;
&lt;p&gt;The documentation can always use more improvement, so please feel free to open a
pull request with improvements!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Bisecting Nix Configurations</title>
		<published>2022-07-29T00:00:00+00:00</published>
		<updated>2022-07-29T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/bisecting-nix-configurations/" type="text/html"/>
		<id>https://ipetkov.dev/blog/bisecting-nix-configurations/</id>
		<content type="html">&lt;p&gt;I live my life dangerously. And by that I mean I like to run &lt;em&gt;unstable&lt;&#x2F;em&gt;
versions of various software that I use daily and prefer to work as I expect
them. Sometimes a change will land and break my workflow, though Nix makes this
tolerable since I can always switch back to an older version of my
configuration.&lt;&#x2F;p&gt;
&lt;p&gt;Except sometimes the breakage isn&#x27;t due to a bug but an intentional change
in upstream defaults, and in those cases the solution is to update my configs
appropriately. The hard part is figuring out &lt;em&gt;how and why&lt;&#x2F;em&gt; they broke especially
since I don&#x27;t always pay close attention to every change landing upstream.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how I used Nix to find out what broke my workflow.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h1 id=&quot;background&quot;&gt;Background&lt;&#x2F;h1&gt;
&lt;p&gt;I run a nightly version of Neovim which I update about once a week. A few days
ago I suddenly noticed a change in behavior which I didn&#x27;t like. The specific
change in question isn&#x27;t so important, the key part is that I had no idea what
led to it or what was to blame, so the technique I&#x27;m about to demonstrate is a
good aid for diagnosing when something previously unnoticed goes wrong.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this case Neovim changed the default behavior of scrolling the mouse.
Previously it would move the cursor, but the new default scrolls the screen
without moving the cursor. I wasn&#x27;t sure what option controls this value, and
neither digging into the help pages, nor stackoverflow, nor glancing at the
recent issues and commits on the Neovim repo answered my question.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately I could have probably trawled through the changelog but a) that did
not cross my mind, and b) I wanted to quickly get to the bottom of the exact
commit which landed the change instead of spending more time guessing.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;bisecting-a-nix-flake&quot;&gt;Bisecting a Nix Flake&lt;&#x2F;h1&gt;
&lt;p&gt;I deploy my &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;dotfiles&quot;&gt;dotfiles&lt;&#x2F;a&gt; through a Nix flake whose git history contains a paper
trail of every change I&#x27;ve ever made on my systems. They use a number of
different inputs (other dependencies) such as &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&quot;&gt;nixpkgs&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&quot;&gt;home-manager&lt;&#x2F;a&gt;, and
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;neovim-nightly-overlay&quot;&gt;neovim-nightly-overlay&lt;&#x2F;a&gt; and sometimes it isn&#x27;t clear if undesired behavior is
due to a bug in a specific package or from a misconfiguration in a Nix module
somewhere. The situation is also exacerbated since I tend to update all inputs
at once meaning there isn&#x27;t one obvious culprit.&lt;&#x2F;p&gt;
&lt;p&gt;Git has a feature to allow &lt;em&gt;bisecting&lt;&#x2F;em&gt; the commit history: basically you mark
some commit known &lt;em&gt;to include&lt;&#x2F;em&gt; the behavior and another commit known &lt;em&gt;to not include&lt;&#x2F;em&gt;
the behavior and git will begin checking commits &quot;halfway&quot; between them
(handling merge commits for you automatically). At each step on the way it asks
&quot;does this commit contain the behavior?&quot; and your response allows it to steer
its search appropriately.&lt;&#x2F;p&gt;
&lt;p&gt;In my case I knew the bad behavior showed up recently, so I randomly picked a
commit of my dotfiles to double check as a &quot;good&quot; commit. The latest commit was
obviously &quot;bad&quot;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; clone https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;dotfiles
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; dotfiles
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Check out a random commit a week or two back
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; checkout e5f21cebb9a4323fcc14397136dac6780a05ec87
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Test out the config to see the behavior
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; nixos-rebuild&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --flake&lt;&#x2F;span&gt;&lt;span&gt; .# test
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Check for offending behavior, looks good
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;vim&lt;&#x2F;span&gt;&lt;span&gt; some_long_file
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Start a git bisect and mark the &amp;quot;good&amp;quot; and &amp;quot;bad&amp;quot; commits
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect start
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect good e5f21cebb9a4323fcc14397136dac6780a05ec87
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# current HEAD
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect bad 09e21eede76234ff66a539079ff14f5b170e56d5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Optional visualize the bisection progress
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect visualize
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then for each commit of my dotfiles I would deploy my configuration and verify
if the undesired behavior is there or not. It was a bit annoying having to wait
for systemd to reload random services, but I pushed through since there weren&#x27;t
that many revisions to test and checking for the offending behavior was very
fast.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# For each commit git 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; nixos-rebuild&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --flake&lt;&#x2F;span&gt;&lt;span&gt; .# test
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Check for offending behavior
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;vim&lt;&#x2F;span&gt;&lt;span&gt; some_long_file
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# If the behavior was gone, mark the commit as good
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect good
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Otherwise mark it as bad
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect bad
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Eventually I landed on this &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;dotfiles&#x2F;commit&#x2F;4e5969ce2a88dc79c81334cc557cfc3e32bfa03b&quot;&gt;bad commit&lt;&#x2F;a&gt; which shows exactly to which commit
each dependency was updated, meaning this gives a finite set of changes to
continue testing which &lt;em&gt;must&lt;&#x2F;em&gt; include the reason for the behavior change.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cleaning up before continuing on is as easy as &lt;code&gt;git bisect reset&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;verifying-inputs&quot;&gt;Verifying Inputs&lt;&#x2F;h1&gt;
&lt;p&gt;The next step was to figure out which input led to the change in behavior. I
started by updating my &lt;code&gt;flake.lock&lt;&#x2F;code&gt; file to use the all the commits from before
the bad update was applied. One by one I updated them to their version found in
the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;dotfiles&#x2F;commit&#x2F;4e5969ce2a88dc79c81334cc557cfc3e32bfa03b&quot;&gt;bad commit&lt;&#x2F;a&gt;, testing each time.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is a way to accomplish this without editing the &lt;code&gt;flake.lock&lt;&#x2F;code&gt; file and
specify commit overrides directly when invoking Nix like: &lt;code&gt;nixos-rebuild --flake .# --override-input nixpkgs github:NixOS&#x2F;nixpkgs&#x2F;$COMMIT_SHA&lt;&#x2F;code&gt;. I
didn&#x27;t bother doing that since editing the &lt;code&gt;flake.lock&lt;&#x2F;code&gt; was faster without
having to juggle multiple input overrides on the command line each time.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;First I changed the &lt;code&gt;nixpkgs-stable&lt;&#x2F;code&gt; input (which I know was not used in the
configuration for the machine I was using, but it was a good sanity check)
and the behavior did not show up (as expected).&lt;&#x2F;li&gt;
&lt;li&gt;Next I changed the &lt;code&gt;nixpkgs&lt;&#x2F;code&gt; input and the behavior did not show up. Clearly
this was not introduced by a change there&lt;&#x2F;li&gt;
&lt;li&gt;Next I changed the &lt;code&gt;home-manager&lt;&#x2F;code&gt; input and the behavior did not show up
either. Clearly the change was not introduced due to a configuration issue
there&lt;&#x2F;li&gt;
&lt;li&gt;Then I changed the &lt;code&gt;neovim-nightly-overlay&lt;&#x2F;code&gt; input and the behavior did not
show up. This input largely exists to keep track of the &lt;code&gt;neovim&lt;&#x2F;code&gt; input, and
since I was manually updating the input hashes it clearly did not result in
the bad behavior showing up.&lt;&#x2F;li&gt;
&lt;li&gt;Lastly I changed the &lt;code&gt;neovim&lt;&#x2F;code&gt; input and &lt;em&gt;bingo&lt;&#x2F;em&gt; the behavior showed up. Now I
knew that the change must have happened somewhere between
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim&#x2F;commit&#x2F;9777907467b29e890556db287b6a9995c0024896&quot;&gt;9777907467b29e890556db287b6a9995c0024896&lt;&#x2F;a&gt;
and
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim&#x2F;commit&#x2F;bb7853a62dc32baafa7416b94c97f985287f39e2&quot;&gt;bb7853a62dc32baafa7416b94c97f985287f39e2&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h1 id=&quot;bisecting-neovim&quot;&gt;Bisecting Neovim&lt;&#x2F;h1&gt;
&lt;p&gt;Knowing the exact range which includes the behavior change means we can run
another git bisect. In this case I directly checked out the Neovim repo since I
could test more quickly that way without having to redeploy my NixOS
configuration.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; clone https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim.git
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; neovim&#x2F;contrib
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect start
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect good 9777907467b29e890556db287b6a9995c0024896
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect bad bb7853a62dc32baafa7416b94c97f985287f39e2
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then for each commit we test for the undesired behavior.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build and run all in one step to check for offending behavior
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt; run .#neovim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt; --&lt;&#x2F;span&gt;&lt;span&gt; some_file
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# If the behavior was gone, mark the commit as good
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect good
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Otherwise mark it as bad
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect bad
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Alternatively skip if a commit can&amp;#39;t build
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; bisect skip
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At last, this process yields the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim&#x2F;commit&#x2F;eb9b93b5e025386ec9431c9d35a4a073d6946d1d&quot;&gt;exact commit&lt;&#x2F;a&gt; which introduced a change in
default behavior. It was pretty easy to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;dotfiles&#x2F;commit&#x2F;353aaa909d384127ff573d3b7d881b249b2295cd&quot;&gt;apply the fix&lt;&#x2F;a&gt; when that was all I had
to review.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;In the end I was able to go from noticing an unexpected behavior to finding &lt;em&gt;a
single commit introducing the behavior&lt;&#x2F;em&gt; in less than an hour. Thanks to git and
Nix I was able to do it without even having to know where to look on my own.&lt;&#x2F;p&gt;
&lt;p&gt;Can your configuration system do that?&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Steam Deck First Impressions</title>
		<published>2022-05-21T00:00:00+00:00</published>
		<updated>2022-05-21T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/steam-deck-first-impressions/" type="text/html"/>
		<id>https://ipetkov.dev/blog/steam-deck-first-impressions/</id>
		<content type="html">&lt;p&gt;It&#x27;s been about two days since I received my Steam Deck, and after a few hours
of playing with it, I wanted to write up my very first impressions and thoughts
on it. There are tons of professional reviews of it online, but I figured it
might be useful if you are impatiently anticipating receiving your own unit and
want to know what to expect (or, if you are Valve and you want to get some data
points from the eyes of a new user).&lt;&#x2F;p&gt;
&lt;p&gt;I have a more detailed conclusion of my thoughts later on, but in a nutshell,
I&#x27;m very excited for what the Deck has to offer.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I might come back and do an update later on my impressions after having had it
for a bit longer. Feel free to ask me anything if you have something specific in
mind or anything you&#x27;d like me to test out!&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&#x27;m going to compare the Deck to the Nintendo Switch from time to time,
&lt;em&gt;not&lt;&#x2F;em&gt; because they are somehow a like-to-like comparison (they are not), but
because a lot of people have a Switch and it can serve as a familiar reference
point.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;what-s-in-the-box&quot;&gt;What&#x27;s in the box?&lt;&#x2F;h1&gt;
&lt;p&gt;The Deck arrives in a slim box which contains the case (with the Deck inside)
and a charging cable. The charging cable isn&#x27;t too exciting, a USB-C cable
attached to a power brick. At first glance I kind of wished the outlet prongs
would fold in for a slightly slimmer travel size (Apple laptop chargers have
spoiled me) but I quickly got over my disappointment.&lt;&#x2F;p&gt;

  &lt;img src=&quot;deck.jpg&quot; alt=&quot;The Steam Deck sitting inside of its case with the top open.&quot; class=&quot;center&quot; &#x2F;&gt;

&lt;p&gt;The case itself is pretty sturdy. I wouldn&#x27;t drop it down the stairs or anything
like that, but the Deck will be safe in a backpack or with your luggage. What I
also found kinda cool was that the case came locked with a Valve branded zipper
lock that I had to cut through. I wasn&#x27;t particularly worried about a
supply-chain attack on my Deck during transit, but feels neat to imagine no one
has seen&#x2F;tampered with my unit since it came off the factory.&lt;&#x2F;p&gt;

  &lt;img src=&quot;zipper_lock.jpg&quot; alt=&quot;A Valve-branded tag which loops through and locks the case&amp;#x27;s zippers.&quot; class=&quot;center&quot; &#x2F;&gt;

&lt;p&gt;The case also has a little recess in the back with an elastic band over it.
Perhaps it&#x27;s a slot to fit the charging cable, because the inside of the case
fits the Deck precisely with no space to spare. I&#x27;m a bit skeptical if the
charger can securely remain held by the elastic band, but I also haven&#x27;t tried
throwing it a backpack to test, so your mileage may vary...&lt;&#x2F;p&gt;

  &lt;img src=&quot;case_back.jpg&quot; alt=&quot;A small recess in the back of the case, an elastic band which covers it has been stretched open&quot; class=&quot;center&quot; &#x2F;&gt;

&lt;h1 id=&quot;size-and-feel&quot;&gt;Size and Feel&lt;&#x2F;h1&gt;
&lt;p&gt;The first thing that struck me about the Deck is just how BIG it is. I knew it
was way bigger than a Switch, but it was something else to see in person. The
case is pretty much the same size as both halves of my ZSA Moonlander next to
each other (without the wrist guards, of course). Despite this first impression
(and my initial skepticism about the button layout), it feels incredibly
comfortable in my hands. Definitely heavier than the Switch (the Deck is about
twice as heavy as the Switch as per their weight specs) but still comfortable to
hold and play in my lap.&lt;&#x2F;p&gt;

  &lt;figure class=&quot;center&quot; &gt;
    &lt;img src=&quot;case_switch.jpg&quot; alt=&quot;A Nintendo Switch sits inside the Deck&amp;#x27;s case with space to spare&quot; &#x2F;&gt;
    
      &lt;figcaption class=&quot;center&quot;&gt;A Switch inside the case for scale.&lt;&#x2F;figcaption&gt;
    
  &lt;&#x2F;figure&gt;

&lt;p&gt;The button layout feels great and is within easy reach from the thumb sticks. I
also found that I &lt;em&gt;really&lt;&#x2F;em&gt; liked the buttons on the back of the Deck, especially
since I haven&#x27;t used or seen any (mainstream) controllers actually support that
layout. Basically you get four extra keys to use with the rest of your fingers
(which usually don&#x27;t do anything on other controllers), which makes it possible
to play games without even lifting your right thumb from the joystick.&lt;&#x2F;p&gt;
&lt;p&gt;I imagine that most adult hands would feel comfortable on the Deck. Even hands
on the smaller size &lt;em&gt;should&lt;&#x2F;em&gt; be able to hold it comfortably. For example, I
position my middle and ring fingers on the back buttons, but I could easily
shift my hand further up (so that my ring and pinkie fingers are on the buttons)
without having to stretch to reach them. Younger children would probably
struggle a bit though, especially since the joystick do have a bit of travel
to them; the Switch controllers might be a better fit for them.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;install&quot;&gt;Install&lt;&#x2F;h1&gt;
&lt;p&gt;I immediately updated the Deck after the initial boot. It took about five
minutes to download and do the update (fun fact, the initial build flashed on
the unit was from November 2021 but after the update it skipped straight to
April 2022). I somehow expected that to just update the Steam client and then
require updating the OS afterwards, but no, that was all of it!&lt;&#x2F;p&gt;
&lt;p&gt;Next was signing into my Steam account, which was a bit painful given that I use
a very long and complicated password stored in my password manager and I clearly
mistyped something on my first attempt. I did not consider going to desktop mode
(and installing my password manager) at this step, so I&#x27;m not sure if the
installer would have prevented me from trying or not.&lt;&#x2F;p&gt;
&lt;p&gt;I did notice during my initial login that the keyboard had an emoji button in
the corner. Tapping on it greeted me with a JavaScript error of all things, and
I couldn&#x27;t help but chuckle to myself. It&#x27;s okay, Valve, fonts on Linux &lt;em&gt;are&lt;&#x2F;em&gt;
hard.&lt;&#x2F;p&gt;

  &lt;figure class=&quot;center&quot; &gt;
    &lt;img src=&quot;emoji_error.jpg&quot; alt=&quot;A JavaScript error is shown on the screen: TypeError: Cannot read property &amp;#x27;GetServerRTime32&amp;#x27; of undefined&quot; &#x2F;&gt;
    
  &lt;&#x2F;figure&gt;

&lt;p&gt;Jokes aside, the problem immediately went away after I manually rebooted (the
installer rebooted on its own when completing, but clearly it wasn&#x27;t enough). My
recommendation is to just manually reboot after the install is done lest other
paper cuts bite you (actually the reason why I switched to using the touch
screen to type in my password was because hitting up on the controller stick
would end up closing the keyboard, another bug which resolved itself after
rebooting).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h2 id=&quot;post-install&quot;&gt;Post Install&lt;&#x2F;h2&gt;
&lt;p&gt;Somehow I found Valve&#x27;s &lt;em&gt;Aperture Desk Job&lt;&#x2F;em&gt; when Steam opened up. It&#x27;s basically
a &lt;em&gt;Portal&lt;&#x2F;em&gt;-universe-themed little tech demo which shows off the Deck&#x27;s inputs
(and has you practice summoning and using the keyboard among other things). It
was a fun way to warm up with the controls so check it out!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;screen-and-disk-size&quot;&gt;Screen and Disk Size&lt;&#x2F;h1&gt;
&lt;p&gt;I got the 256GB SSD model which does not come with the &quot;premium anti-glare
etched glass&quot;. The screen is awesome, given it&#x27;s size, resolution, and color, I
have absolutely no complaints. It is pretty shiny and you can definitely see a
reflection when taking photos of it. But other than that I don&#x27;t plan on playing
in the sun so I don&#x27;t anticipate it would be a huge problem for me.&lt;&#x2F;p&gt;
&lt;p&gt;I partly regret not ordering the biggest model which would double the storage
capacity for another 120 bucks (not to mention I&#x27;ve heard the anti-glare glass
is also great). Especially since games these days tend to average around 10 gigs
meaning as time goes on the hard drive can only fit so many games at a time (and
I&#x27;m not even mentioning the 50+ gig monstrosities some AAA studios are putting
out these days). That said, the Deck&#x27;s SSD is apparently user serviceable, not
to mention the SD card slot can really expand the memory, so I&#x27;m not too
worried. I&#x27;m just happy to have one in hand given all the supply chain shortages
hitting the world right now.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;thermals&quot;&gt;Thermals&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s talk about the thermals and cooling on the Deck. I won&#x27;t sugar coat it,
the fan is audible when it kicks in. If you are sitting in a quiet room trying
to read, for example, you will hear it. That said, the audio speakers are more
than enough to overcome it and I immediately forgot about it after focusing on
the game in front of me. I imagine gaming with headphones would drown the noise
out completely (for me at least).&lt;&#x2F;p&gt;
&lt;p&gt;There &lt;em&gt;is&lt;&#x2F;em&gt; a reason why the fan is so strong, as you can feel the stream of heat
coming straight out of the Deck when playing a game. My first gaming session was
about an hour while I was also charging the battery. By the end of it, the
middle-top of the Deck felt pretty warm (the back surface that is, not just the
air coming out of it) which is where the heat sink must be. The hand grips are
incredibly far away, though, and since it vents upwards I don&#x27;t have any
concerns about temperature related discomfort while playing in my lap.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;battery-life&quot;&gt;Battery Life&lt;&#x2F;h1&gt;
&lt;p&gt;I&#x27;ve yet to drain the battery fully. Based on my own estimates and those of
others, you should be able to get three to four hours of play time from a full
charge, though it will depend on how performance intensive the game is. For what
it&#x27;s worth, I played about an hour of &lt;em&gt;Portal 2&lt;&#x2F;em&gt; and the battery went down to
75% from starting at a full charge. I&#x27;m pretty happy with the prospect of
getting four hours out of the Deck&#x27;s specs. There might be ways to squeeze out
extra battery life (like capping frame rate, turning down graphics and
brightness settings) but I&#x27;m fine traveling with a charger.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is worth mentioning that &lt;em&gt;Portal 2&lt;&#x2F;em&gt; is (at the time of writing) an
11-year-old game, and one which Valve has had plenty of opportunity to
optimize ahead of the Deck&#x27;s launch. So take the comparison for what it&#x27;s
worth...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;controller-customization&quot;&gt;Controller Customization&lt;&#x2F;h1&gt;
&lt;p&gt;I&#x27;m really impressed with the amount of customization you can do of the controls
on the Deck. Anything including the joystick dead zones and sensitivity, along
with binding buttons to arbitrary inputs, as well as specific inputs to enable
gyro controls. For games that don&#x27;t support controller inputs, the Deck can
instead send key codes which achieve the same outcome even without formal
controller support!&lt;&#x2F;p&gt;
&lt;p&gt;What&#x27;s also cool is that it supports &lt;em&gt;layers&lt;&#x2F;em&gt; where the button bindings can be
changed based on having another button pressed or held. It&#x27;s very similar to
layers on programmable keyboards, for those of you who are familiar with them.&lt;&#x2F;p&gt;
&lt;p&gt;Controller layouts can be defined&#x2F;customized per-game, and you can even share
and download configurations with others (I guess Steam has supported this for a
while around their Steam Controller integration, but it was the first time I
came across it).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-gyroscope&quot;&gt;The Gyroscope&lt;&#x2F;h1&gt;
&lt;p&gt;I have very mixed feelings about the gyroscope feature on the Deck.&lt;&#x2F;p&gt;
&lt;p&gt;Basically the way it works is you can tilt the body of the Deck and use that as
an input source. What that is translated to is entirely configurable, it could
be the camera controls, or movement controls, or whatever else the game may
support. The gyro also isn&#x27;t constantly on, you can configure how it is
triggered (by default resting a thumb on the right joystick or right track pad,
but it can also be configured to activate with holding a different button).&lt;&#x2F;p&gt;
&lt;p&gt;The controls also feel &lt;em&gt;unintuitively intuitive&lt;&#x2F;em&gt;: logically it makes sense how
they are implemented but intuitively I struggled for a while. Perhaps I just
need more practice.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&#x27;ll try to explain how it works as best as I can: Imagine you are holding the
Deck at half an arms length away from you, perpendicular to your chest. Now
imagine there is a laser pointer emanating from your chest to the center of
the Deck (think of laser pointer as the cross hairs in the game). If, while
keeping your body completely still, you bend your left arm in and extend your
right arm out, the laser would project closer to the right edge of the screen.
If you extend your left arm out and bend your right arm in, the laser pointer
would then project to the left size of the screen.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Normally I &lt;em&gt;hate&lt;&#x2F;em&gt; gyro controls: I personally find the Switch&#x27;s gyro controls a
gimmick in both &lt;em&gt;Mario Kart 8&lt;&#x2F;em&gt; and &lt;em&gt;Breath of the Wild&lt;&#x2F;em&gt; and disabled them the
first opportunity. On the Deck, however, I find them to work pretty well,
especially since they give really precise control with very minimal movement
(which is a huge achievement given the Deck&#x27;s hefty size). Depending on joy
stick&#x27;s dead zones and how sluggish&#x2F;imprecise the game handles with the joy
stick inputs (like it is the case for &lt;em&gt;Portal 2&lt;&#x2F;em&gt;), I found that I can quickly
and precisely do minor aim correction without over or undershooting as I would
with the joystick (but for macro aim correction the joystick would work fine).&lt;&#x2F;p&gt;
&lt;p&gt;What put me off about actually &lt;em&gt;using&lt;&#x2F;em&gt; the gyro in-game was that nothing
actually stops you from sending &lt;em&gt;both&lt;&#x2F;em&gt; gyro and joystick controls &lt;em&gt;at the same
time&lt;&#x2F;em&gt;. The default settings also have the gyro running when resting a thumb on
the right joystick (i.e. how I imagine most people operate the joystick) which
made me feel very disoriented with unexpected inputs. Perhaps with more training
and the right sensitivity configuration it could make for interesting control
schemes, but I&#x27;m going to avoid it for the time being.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I also ran into an issue where I couldn&#x27;t seem to be able to turn of gyro
controls. It&#x27;s not out of the realm of possibility that I was looking in the
wrong spot, but it certainly felt like a bug in Steam. Basically you can
configure gyro controls per-game, and I had it turned on for &lt;em&gt;Portal 2&lt;&#x2F;em&gt;. I
switched to &lt;em&gt;Half Life 2&lt;&#x2F;em&gt; and even though the control settings clearly showed
the gyro was off, it was definitely on in-game, and I checked twice. After going
back to the &lt;em&gt;Portal 2&lt;&#x2F;em&gt; settings and disabling the gyro, then suddenly &lt;em&gt;Half Life
2&lt;&#x2F;em&gt; started showing that it &lt;em&gt;was&lt;&#x2F;em&gt; on. After more futzing with the settings and a
reboot I finally managed to disable it in &lt;em&gt;Half Life 2&lt;&#x2F;em&gt; without it triggering
in-game. I&#x27;m hoping this is just a UX bug which Valve will get fixed sometime
soon...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;desktop-mode&quot;&gt;Desktop Mode&lt;&#x2F;h1&gt;
&lt;p&gt;Desktop Mode allows you to drop straight into a KDE Plasma session and use it
just like you would on a desktop install. The track pad makes for a good mouse
cursor to click around and launch stuff. The touchscreen also works, but isn&#x27;t
calibrated for use with a finger.&lt;&#x2F;p&gt;
&lt;p&gt;I would drop any delusions about meaningfully using Desktop Mode without having
at least a keyboard attached to it (unless you are &lt;em&gt;really&lt;&#x2F;em&gt; desperate to watch a
YouTube video or something). You can summon the keyboard in a pinch (default
binding is &lt;code&gt;STEAM + X&lt;&#x2F;code&gt;), but it takes up half the screen and locks you out of
mouse inputs on the other half until you close it. Oh and the keyboard has most
of the keys you&#x27;d need to type in some login credentials, but it&#x27;s missing stuff
like &lt;code&gt;Ctrl&lt;&#x2F;code&gt; or &lt;code&gt;Esc&lt;&#x2F;code&gt; so even masochists will have a difficult time trying to get
vim working without a physical keyboard.&lt;&#x2F;p&gt;
&lt;p&gt;Don&#x27;t get me wrong, I&#x27;m glad I have access to the actual desktop if I need to
install something or launch a game outside of Steam. But I&#x27;m not going to fault
Valve for not making &lt;em&gt;operating a Linux desktop environment easy with a
controller&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The only thing I &lt;em&gt;will&lt;&#x2F;em&gt; complain about is a bug where Desktop Mode insists on
rendering the keyboard with a different theme besides the one I&#x27;ve selected. I
prefer the default keyboard theme. Apparently Desktop Mode doesn&#x27;t...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;

  &lt;img src=&quot;desktop_mode.jpg&quot; alt=&quot;A picture of the Deck running in Desktop Mode. A KDE Plasma session is shown, with Firefox and Dolphin (a file manager) opened in two separate windows.&quot; class=&quot;center&quot; &#x2F;&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;Congratulations to Valve on the Deck launch, they&#x27;ve done an awesome job
designing it! Overall I&#x27;m really happy with what it has to offer. I&#x27;m also
really pleased that it lives up to the promise of being a handheld computer
which gives the user power to do with it as they wish.&lt;&#x2F;p&gt;
&lt;p&gt;The few criticisms I have are all temporary: UX glitches will eventually be
fixed, game compatibility will improve with time, and storage expansion is one
SD card purchase away. As for the criticisms which cannot be changed, like
battery life or fan noise, I know I can live with them; I&#x27;m sure the design
choices leading up to them were intentionally picked to improve the end result.&lt;&#x2F;p&gt;
&lt;p&gt;For those still waiting to receive their own Deck: it&#x27;s worth the wait!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Crane Support for Alternative Registries and Git Dependencies</title>
		<published>2022-02-13T00:00:00+00:00</published>
		<updated>2022-02-14T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/crane-support-for-alt-registries-and-git-deps/" type="text/html"/>
		<id>https://ipetkov.dev/blog/crane-support-for-alt-registries-and-git-deps/</id>
		<content type="html">&lt;p&gt;Since the initial release of &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&quot;&gt;Crane&lt;&#x2F;a&gt;, I&#x27;ve been busy hacking on adding support
for building projects which may pull in dependencies from alternative registries
as well as git repositories. I wanted to share how it works, so let&#x27;s dive right
in!&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h1 id=&quot;alternative-registries&quot;&gt;Alternative Registries&lt;&#x2F;h1&gt;
&lt;p&gt;Although crates.io is the default registry for the majority of (public) Rust
projects, cargo &lt;em&gt;does&lt;&#x2F;em&gt; allow for configuring any other crate registry&#x2F;index to
be used for dependencies. So far, the main use-case for alternative registries
seems to be for privately publishing crates (e.g. on an enterprise network)
judging by the lack of other &lt;em&gt;public&lt;&#x2F;em&gt; registries present in the ecosystem (well,
except for &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Hirevo&#x2F;alexandrie&quot;&gt;Alexandrie&lt;&#x2F;a&gt; which was very useful for my testing!).&lt;&#x2F;p&gt;
&lt;p&gt;The workflow for vendoring crates is pretty much the same, regardless if the
crates come from crates.io or some other index:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;We check the project&#x27;s &lt;code&gt;.cargo&#x2F;config.toml&lt;&#x2F;code&gt; file (if it exists) to see what
registries are defined (specifically their unique index URL and the name used
to link them to dependency definitions in &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;We then crawl the &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; file to find out the name, version, checksum,
and (registry) source (i.e. the index URL) for each dependency package&lt;&#x2F;li&gt;
&lt;li&gt;Using this information we can construct the download URL for the crate and
pull down the source to the Nix store. &lt;strong&gt;We&#x27;ll come back to this step in a bit.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The sources are then grouped by the registry they come from, and are unpacked
in a format that cargo can understand
&lt;ul&gt;
&lt;li&gt;The sources are basically tarballs which are extracted into directories
named after the crate&#x27;s name and version, along with some checksum metadata
used by cargo to validate the sources are as expected.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Finally, we write some configuration which can instruct cargo to look at the
directories we&#x27;ve prepared when building the project, instead of trying to
access the network itself (which would fail if running inside of a sandboxed
build).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So how does cargo figure out what the download URL is for a particular crate?&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;cargo&#x2F;reference&#x2F;registries.html#index-format&quot;&gt;specification&lt;&#x2F;a&gt; requires that the index contain a &lt;code&gt;config.json&lt;&#x2F;code&gt; file at its
root which defines the endpoint and path that should be used for downloading
crate sources. This definition can also contain placeholders (like the crate&#x27;s
name and version among other things) which need to be substituted to create the
final URL used for fetching the source.&lt;&#x2F;p&gt;
&lt;p&gt;How does Crane figure out the download configuration for each registry?
Unfortunately, we &lt;em&gt;have to tell it&lt;&#x2F;em&gt;. We can take a look at a &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&#x2F;blob&#x2F;fc7a94f841347c88f2cb44217b2a3faa93e2a0b2&#x2F;examples&#x2F;alt-registry&#x2F;flake.nix#L25-L47&quot;&gt;full example&lt;&#x2F;a&gt; in
context, but in summary, we have two options to take:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The first option is to straight up copy the configuration out of the index&#x27;s
&lt;code&gt;config.json&lt;&#x2F;code&gt; file and tell Crane about it. This is the simplest and most
lightweight option we can employ, especially if the download endpoint and
path virtually never change.&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLibOrig &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLibOrig&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;appendCrateRegistries &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;  (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLibOrig&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;registryFromDownloadUrl &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;indexUrl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;https:&#x2F;&#x2F;github.com&#x2F;Hirevo&#x2F;alexandrie-index&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;dl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;https:&#x2F;&#x2F;crates.polomack.eu&#x2F;api&#x2F;v1&#x2F;crates&#x2F;{crate}&#x2F;{version}&#x2F;download&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The second option is to tell Crane about a particular revision of the index
and let it figure out the download template on its own. This option has the
benefit of having a single canonical source of truth (without copying URLs
around by hand), and, if the download endpoint or path changes from time to
time, it can easily be remedied by updating the index snapshot to a newer
revision (which is especially nice if it needs to be automated). The cost of
this option, however, is needing to check out the &lt;em&gt;entire index&lt;&#x2F;em&gt; at that
revision and put a copy of it in the store before we can evaluate the
derivation. Note that this revision only needs to be updated if the
&lt;code&gt;config.json&lt;&#x2F;code&gt; file changes, so it is safe to pin to a version for as long as
that takes.&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLibOrig &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLibOrig&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;appendCrateRegistries &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;  (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLibOrig&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;registryFromGitIndex &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;indexUrl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;https:&#x2F;&#x2F;github.com&#x2F;Hirevo&#x2F;alexandrie-index&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;rev &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;90df25daf291d402d1ded8c32c23d5e1498c6725&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Technically, we could try to automate this away completely by always fetching
the latest version of the index and looking at the configuration before
downloading any crate sources. Even ignoring issues with requiring impure
evaluations to make this work, this would make for a really bad default from a
performance standpoint.&lt;&#x2F;p&gt;
&lt;p&gt;You see, cargo keeps a checked out version of every registry index that has ever
been used (usually somewhere in your home directory). It used during dependency
resolution (such as what are the latest published&#x2F;yanked version, etc.) and
incrementally fetched as needed.&lt;&#x2F;p&gt;
&lt;p&gt;When we build with Nix, however, we don&#x27;t care about re-resolving dependencies
since the Cargo.lock file already pins everything into place; checking out the
entire index to the store, just to peek at a small configuration file and throw
the results away seems wasteful. Even the store is regularly cleaned out, we
would still need to fetch the index again and again any time the derivation is
evaluated. That&#x27;s a lot of wasted bandwidth, especially as the index accrues
newly published crates. And lets not forget that Nix doesn&#x27;t keep the repository
around such that it can be incrementally fetched, either.&lt;&#x2F;p&gt;
&lt;p&gt;I really wish this paper cut experience of having to manually specify
alternative registries can be improved in the future, but for now, it seems like
the best choice available.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;git-dependencies&quot;&gt;Git Dependencies&lt;&#x2F;h1&gt;
&lt;p&gt;Vendoring crate sources from git repositories is roughly the same as vendoring
from registries:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;We crawl the &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; file to look for any packages originating from git
sources, and find out the repository&#x27;s URL as well as the revision that has
been locked&lt;&#x2F;li&gt;
&lt;li&gt;We then pass the git URL and revision to Nix which will pull down the source
for us
&lt;ul&gt;
&lt;li&gt;Note: this does not pull down the entire repository, we &lt;em&gt;only&lt;&#x2F;em&gt; get a
checkout of the revision.&lt;&#x2F;li&gt;
&lt;li&gt;Fetching a git repository is not reproducible, as any new commit or branch
would add new data which would result in invalidating all of our build
caches&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The one main difference between a git dependency and a registry tarball is
that the tarball always contains a single crate. The git repository could
contain an entire workspace of crates. To handle this, we crawl the source
looking for &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; files as a proxy for identifying what crates are
present.
&lt;ul&gt;
&lt;li&gt;Looking for &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; is a simple heuristic which goes a long way.
Although there can be a false-positive (we vendor a crate not part of the
actual workspace), we cannot have a false-negative (accidentally ignore a
real crate) since you cannot define a crate without a &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; file.&lt;&#x2F;li&gt;
&lt;li&gt;Ultimately, cargo will ignore the crates it does not care about which gives
us some flexibility here.&lt;&#x2F;li&gt;
&lt;li&gt;Why not ask &lt;code&gt;cargo metadata&lt;&#x2F;code&gt; to tell us about the workspace members?
&lt;ul&gt;
&lt;li&gt;Doing so will make cargo try to pull down the sources from the network to
tell us about them. Since this whole exercise is to pull the sources down
&lt;em&gt;for&lt;&#x2F;em&gt; cargo, we need to avoid this chicken-egg problem somehow.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Why not look at the &lt;code&gt;[workspace]&lt;&#x2F;code&gt; definition in the &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; file if it
exists?
&lt;ul&gt;
&lt;li&gt;Cargo supports glob patterns both for including &lt;strong&gt;and&lt;&#x2F;strong&gt; excluding
members. Re-implementing this logic ourselves is way too overkill when a
simple search can get us where we need.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;We then transform the crates into the same vendor directory structure as for
registries (i.e. each crate goes into its own sub-directory using the crate&#x27;s
name and version).&lt;&#x2F;li&gt;
&lt;li&gt;And finally, we generate some configuration that can instruct cargo to look
at these vendored directories as is appropriate.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;One interesting thing to note that whereas the &quot;unique unit of vendoring&quot; for a
registry is the &lt;em&gt;index itself&lt;&#x2F;em&gt;, for git dependencies it is &lt;em&gt;the specific
revision of a particular repository&lt;&#x2F;em&gt;. In other words, all crates coming from the
same registry&#x2F;index are vendored in one directory which is registered as a
single source replacement with cargo. All crates coming from the same git
repository &lt;strong&gt;and&lt;&#x2F;strong&gt; revision are also vendored in one directory and registered as
a single source replacement with cargo, but more git revisions in the dependency
closure will result in more cargo sources behind the scenes.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s several benefits to this approach:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;First and foremost we don&#x27;t have to care (or worry) about whether there is a
name&#x2F;version collision between crates coming from a registry or from a git
repository. Each will get their own unique &quot;vendor space&quot; for which we know
is impossible to have collisions!&lt;&#x2F;li&gt;
&lt;li&gt;Even if we do get a collision, we can avoid the risks of having to establish
which source would take precedence! We simply make the sources &lt;em&gt;available&lt;&#x2F;em&gt; to
cargo, and it is free to use (or ignore them) based on how the project
authors&#x27; have dictated via the &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; and &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; files
&lt;ul&gt;
&lt;li&gt;To illustrate this point a bit further, consider the following: you may
have a workspace which may contain an auxillary crate used for running
tests. Perhaps this crate pins to some ancient git revision of a dependency
crate to perform some compatibility testing.&lt;&#x2F;li&gt;
&lt;li&gt;We wouldn&#x27;t want this dependency to get selected when building our
production binaries as we would likely want to use the latest and greatest
version of that dependency as pinned by the &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; file&lt;&#x2F;li&gt;
&lt;li&gt;At the same time, we wouldn&#x27;t want to ignore the pinned git version as that
could break the tests that we thought were running&lt;&#x2F;li&gt;
&lt;li&gt;All in all, this means that cargo will behave the same when running under
Nix as it does outside of it, without any unexpected surprises!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Oh and the other cool thing about this implementation is there is nothing to
configure! Everything should Just Work™ out of the box :)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;feedback&quot;&gt;Feedback&lt;&#x2F;h1&gt;
&lt;p&gt;As always, if something doesn&#x27;t seem quite right or you have any feedback, feel
free to let me know on the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&quot;&gt;project repo&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Introducing Crane: Composable and Cacheable Builds with Cargo and Nix</title>
		<published>2022-01-22T00:00:00+00:00</published>
		<updated>2022-01-30T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/introducing-crane/" type="text/html"/>
		<id>https://ipetkov.dev/blog/introducing-crane/</id>
		<content type="html">&lt;p&gt;I&#x27;m pleased to announce the initial release of &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&quot;&gt;Crane&lt;&#x2F;a&gt;: a Nix library for
building cargo projects!&lt;&#x2F;p&gt;
&lt;p&gt;In a nutshell it offers:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source fetching&lt;&#x2F;strong&gt;: automatically done using a Cargo.lock file&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Incremental&lt;&#x2F;strong&gt;: build your workspace dependencies just once, then quickly lint,
build, and test changes to your project without slowing down&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Composable configuration&lt;&#x2F;strong&gt;: split builds and tests into granular steps. Gate CI without
burdening downstream consumers building from source.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h1 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;&#x2F;h1&gt;
&lt;p&gt;I want to take a moment to acknowledge and give credit to the impressive work
behind &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;naersk&quot;&gt;Naersk&lt;&#x2F;a&gt;. It has been a huge source of inspiration, especially since it
absolutely nails a number of features like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;automatic dependency handling with out needing to mess with SHAs yourself&lt;&#x2F;li&gt;
&lt;li&gt;dependency artifacts can be built, cached, and reused independently of the
project&#x27;s source, making it a great fit for running in CI&lt;&#x2F;li&gt;
&lt;li&gt;the defaults &quot;just work&quot; out of the box, regardless if a project is building
applications, libraries, or an entire workspace of crates&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;&#x2F;h2&gt;
&lt;p&gt;My biggest motivation for writing Crane was wanting to use an API that allows
for build configurations which feel intuitive to write and easy to reconfigure
without sacrificing the performance of cacheable artifacts.&lt;&#x2F;p&gt;
&lt;p&gt;I find Naersk&#x27;s configuration options work best when you are intimately familiar
with its internals. And if you aren&#x27;t, even a goal like &quot;run clippy on the
project&quot; can leave you having to face evaluation errors, build errors,
accidental cache invalidation, or the acceptance that a fraction of your build
dependencies just have to be built twice...&lt;&#x2F;p&gt;
&lt;h1 id=&quot;philosophy&quot;&gt;Philosophy&lt;&#x2F;h1&gt;
&lt;p&gt;Crane is designed around the idea of composing cargo invocations such that they
can take advantage of the artifacts generated in previous invocations. This
allows for both flexible configurations and great caching (à la Cachix) in CI
and local development builds.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how it works at a high level: when a cargo workspace is built its source
is first transformed such that only the dependencies listed by the &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;
and &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; files are built, and none of the crate&#x27;s real source is
included. This allows cargo to build all dependency crates and prevents Nix from
invalidating the derivation whenever the source files are updated. Then, a
second derivation is built, this time using the real source files, which also
imports the cargo artifacts generated in the first step.&lt;&#x2F;p&gt;
&lt;p&gt;This pattern can be used with any arbitrary sequence of commands, regardless of
whether those commands are running additional lints, performing code coverage
analysis, or even generating types from a model schema. Let&#x27;s take a look at two
examples at how very similar configurations can give us very different behavior!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-one&quot;&gt;Example One&lt;&#x2F;h2&gt;
&lt;p&gt;Suppose we are developing a crate and want to run our CI assurance checks
via &lt;code&gt;nix flake check&lt;&#x2F;code&gt;. Perhaps we want the CI gate to be very strict and block
any changes which raise warnings when run with &lt;code&gt;cargo clippy&lt;&#x2F;code&gt;. Oh, and we want
to enforce some code coverage too!&lt;&#x2F;p&gt;
&lt;p&gt;Except we do not want to push our strict guidelines on any downstream consumers
who may want to build our crate. Suppose they need to build the crate with a
different compiler version (for one reason or another) which comes with a new lint
whose warnings we have not yet addressed. We don&#x27;t want to make their life
harder, so we want to make sure we do not run &lt;code&gt;cargo clippy&lt;&#x2F;code&gt; as part of the
crate&#x27;s actual derivation, but at the same time, we don&#x27;t want to have to
rebuild dependencies from scratch.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how we can set up our flake to achieve our goals:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:NixOS&#x2F;nixpkgs&#x2F;nixpkgs-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:ipetkov&#x2F;crane&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:numtide&#x2F;flake-utils&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, ... &lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;eachDefaultSystem &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;pkgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;craneLib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;.&#x2F;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build *just* the cargo dependencies, so we can reuse
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# all of that work (e.g. via cachix) when running in CI
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;buildDepsOnly &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Run clippy (and deny all warnings) on the crate source,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# resuing the dependency artifacts (e.g. from build scripts or
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# proc-macros) from above.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Note that this is done as a separate derivation so it
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# does not impact building just the crate by itself.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-clippy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;cargoClippy &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoClippyExtraArgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;-- --deny warnings&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build the actual crate itself, reusing the dependency
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# artifacts from above.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;buildPackage &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Also run the crate tests under cargo-tarpaulin so that we can keep
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# track of code coverage
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-coverage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;cargoTarpaulin &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;      {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;defaultPackage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;my-crate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;checks &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build the crate as part of `nix flake check` for convenience
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-clippy
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-coverage&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we run &lt;code&gt;nix flake check&lt;&#x2F;code&gt; the following will happen:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The sources for any dependency crates will be fetched&lt;&#x2F;li&gt;
&lt;li&gt;They will be built without our crate&#x27;s code and the artifacts propagated&lt;&#x2F;li&gt;
&lt;li&gt;Our crate, the clippy checks, and code coverage collection will be built,
each reusing the same set of artifacts from the initial source-free build. If
enough cores are available to Nix it may build all three derivations
completely in parallel, or schedule them in some arbitrary order.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Splitting up our builds like this also gives us the benefit of granular control
over what is rebuilt. Suppose we change our mind and decide to adjust the clippy
flags (e.g. to allow certain lints or forbid others). Doing so will &lt;em&gt;only&lt;&#x2F;em&gt;
rebuild the clippy derivation, without having to rebuild and rerun any of our
other tests!&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;img
    src=&quot;.&#x2F;parallel.dot.svg&quot;
    alt=&quot;The clippy, my-crate, and coverage derivations each depend on the src source and the deps derivation. The deps derivation depends on the crates.io sources.&quot;
  &#x2F;&gt;
  &lt;figcaption&gt;
    The arrows show which way the results &quot;flow&quot;, from sources (represented in
    boxes) to intermediate and final derivations (represented as circles).
  &lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;example-two&quot;&gt;Example Two&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s take an alternative approach to the example above. Suppose instead that we
care more about not wasting any resources building certain tests (even if they
would succeed!) if another particular test fails. Perhaps binary substitutes are
readily available so that we do not mind if anyone building from source is bound
by our rules, and we can be sure that all tests have passed as part of the
build.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:NixOS&#x2F;nixpkgs&#x2F;nixpkgs-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:ipetkov&#x2F;crane&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:numtide&#x2F;flake-utils&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, ... &lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;flake-utils&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;eachDefaultSystem &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;pkgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;craneLib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;crane&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;.&#x2F;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build *just* the cargo dependencies, so we can reuse
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# all of that work (e.g. via cachix) when running in CI
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;buildDepsOnly &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# First, run clippy (and deny all warnings) on the crate source.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-clippy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;cargoClippy &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoClippyExtraArgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;-- --deny warnings&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Next, we want to run the tests and collect code-coverage, _but only if
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# the clippy checks pass_ so we do not waste any extra cycles.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-coverage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;cargoTarpaulin &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;my-crate-clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build the actual crate itself, _but only if the previous tests pass_.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;craneLib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;buildPackage &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cargoArtifacts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;my-crate-coverage&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;      {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;defaultPackage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;my-crate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;checks &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Build the crate as part of `nix flake check` for convenience
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate
&lt;&#x2F;span&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;my-crate-coverage&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we run &lt;code&gt;nix flake check&lt;&#x2F;code&gt; the following will happen:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The sources for any dependency crates will be fetched&lt;&#x2F;li&gt;
&lt;li&gt;They will be built without our crate&#x27;s code and the artifacts propagated&lt;&#x2F;li&gt;
&lt;li&gt;Next the clippy checks will run, reusing the dependency artifacts above.&lt;&#x2F;li&gt;
&lt;li&gt;Next the code coverage tests will run, reusing the artifacts from the clippy
run&lt;&#x2F;li&gt;
&lt;li&gt;Finally the actual crate itself is built&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In this case we lose the ability to build derivations independently, but we gain
the ability to enforce a strict build order. However, we can easily change our
mind, which would be much more difficult if we had written everything as one
giant derivation.&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;img
    src=&quot;.&#x2F;sequential.dot.svg&quot;
    alt=&quot;The my-crate derivation depends on the src source and the coverage derivation. The coverage derivation depends on the src source and the clippy derivation. The clippy derivation depends on the src source and the deps derivation. The deps derivation depends on the crates.io sources.&quot;
  &#x2F;&gt;
  &lt;figcaption&gt;
    The arrows show which way the results &quot;flow&quot;, from sources (represented in
    boxes) to intermediate and final derivations (represented as circles).
  &lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h1 id=&quot;try-it-out&quot;&gt;Try it out&lt;&#x2F;h1&gt;
&lt;p&gt;I wanted to get an initial version out in the open, but there is, of course,
more work to be done. &lt;del&gt;Support for git dependencies and private registries is
missing, but something I&#x27;d like to add in the near future.&lt;&#x2F;del&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the meantime, feel free to check it out for yourself and kick the tires. The
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane#getting-started&quot;&gt;getting started&lt;&#x2F;a&gt; guide, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&#x2F;tree&#x2F;master&#x2F;examples&quot;&gt;examples&lt;&#x2F;a&gt;, and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;crane&#x2F;blob&#x2F;master&#x2F;docs&#x2F;API.md&quot;&gt;API&lt;&#x2F;a&gt; documentation will be useful
resources.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;d love to know what you think!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Edit 2022-01-30: alternate cargo registry support has landed in Crane v0.2.0!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Edit 2022-02-11: git dependency support has landed in Crane v0.3.0!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Tips and Tricks for Nix Flakes</title>
		<published>2021-12-12T00:00:00+00:00</published>
		<updated>2021-12-12T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/tips-and-tricks-for-nix-flakes/" type="text/html"/>
		<id>https://ipetkov.dev/blog/tips-and-tricks-for-nix-flakes/</id>
		<content type="html">&lt;p&gt;After working with Nix flakes for a while you develop a sense for how to
interact with them in more efficient or ergonomic ways. That said, a number of
the interactions I&#x27;m about to describe were &lt;em&gt;extremely non-obvious&lt;&#x2F;em&gt; to me,
especially as someone who had never peeked at their actual implementation.&lt;&#x2F;p&gt;
&lt;p&gt;This is the cheat-sheet I wish someone had shown me when I first started
tinkering with flakes. I hope you find it useful.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h1 id=&quot;wrangling-flake-inputs&quot;&gt;Wrangling Flake Inputs&lt;&#x2F;h1&gt;
&lt;p&gt;The flake input schema allows for:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Having your flake pull in &lt;em&gt;another flake&lt;&#x2F;em&gt; as an input&lt;&#x2F;li&gt;
&lt;li&gt;Having your flake pull in an input that is specified by &lt;em&gt;another flake&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Forcing &lt;em&gt;another flake&lt;&#x2F;em&gt; to use an input specified in your flake&lt;&#x2F;li&gt;
&lt;li&gt;Forcing &lt;em&gt;another flake&lt;&#x2F;em&gt; to use an input specified by &lt;strong&gt;yet a different
flake&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Being aware of this functionality can be useful in ensuring that all inputs
agree on the same common dependency: for example, using the same revision of
&lt;code&gt;nixpkgs&lt;&#x2F;code&gt; can avoid having multiple versions of the same package floating in the
output closure, each built with slightly different dependencies coming from
different &lt;code&gt;nixpkgs&lt;&#x2F;code&gt; commits.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take a look at some examples.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Case 1, pulling in some flake(s) we care about, locked to some revision
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;dotfiles&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:ipetkov&#x2F;dotfiles&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mypinned-nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:NixOS&#x2F;nixpkgs&#x2F;34ad3ffe08adfca17fcb4e4a47bb5f3b113687be&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Case 2, pulling in an input specified by another flake. In this case
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# we may want to treat the `dotfiles` flake as some common source-of-truth
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# and use the nixpkgs version from there
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mynixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;dotfiles&#x2F;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Case 3, forcing another flake to use one of our inputs
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;home-manager &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:nix-community&#x2F;home-manager&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;mypinned-nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Case 4, forcing another falke to use a _different flake&amp;#39;s input_ as its
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# own, but without pulling said input in our scope
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;deploy-rs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:serokell&#x2F;deploy-rs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;flake-compat&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;dotfiles&#x2F;flake-compat&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;dotfiles&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;mypinned-nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;mynixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;home-manager&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;deploy-rs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# NB: no ... wildcard here, these are all the inputs we have declared for
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# our flake!
&lt;&#x2F;span&gt;&lt;span&gt;  }: {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Rest of flake...
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When in doubt, &lt;code&gt;nix flake info&lt;&#x2F;code&gt; will show all inputs and what revision (or
other flake&#x27;s inputs) are being tracked!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;updating-inputs&quot;&gt;Updating Inputs&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;nix flake update&lt;&#x2F;code&gt; will try to update &lt;em&gt;all&lt;&#x2F;em&gt; inputs where possible
&lt;ul&gt;
&lt;li&gt;Inputs pinned to specific revisions will, of course, remain pinned&lt;&#x2F;li&gt;
&lt;li&gt;Easiest way to ensure everything stays up to date&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nix flake lock --update-input $NAME&lt;&#x2F;code&gt; will only try to update the &lt;code&gt;$NAME&lt;&#x2F;code&gt;
input
&lt;ul&gt;
&lt;li&gt;Useful for updating one particular input more frequently (e.g. via
automation) without necessarily updating other &lt;em&gt;unpinned&lt;&#x2F;em&gt; inputs (like
&lt;code&gt;nixpkgs&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The common flake option &lt;code&gt;--override-input $INPUT $NEW&lt;&#x2F;code&gt; can be used to
substitute a different input for the current invocation &lt;em&gt;without&lt;&#x2F;em&gt; updating the
lock file
&lt;ul&gt;
&lt;li&gt;This could be useful for building the current flake while programmatically
bisecting an input&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h1 id=&quot;flake-checks&quot;&gt;Flake Checks&lt;&#x2F;h1&gt;
&lt;p&gt;The &lt;code&gt;nix flake check&lt;&#x2F;code&gt; command is a great way to ensure that the entire flake
configuration is up to snuff with a single invocation. It&#x27;s also a great target
for your CI system to run so you don&#x27;t have to keep reconfiguring it whenever a
new package or system configuration is added.&lt;&#x2F;p&gt;
&lt;p&gt;Other benefits include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;All &lt;code&gt;nixosConfigurations&lt;&#x2F;code&gt; are evaluated (but not built) to check for any
option&#x2F;configuration collisions without needing to go through &lt;code&gt;nixos-rebuild dry-build --flake .&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Checks can include any arbitrary derivation. I personally like to include all
of my package definitions as well so that they can be built with the same &lt;code&gt;nix flake check&lt;&#x2F;code&gt; invocation (caching will take care of this being fast).&lt;&#x2F;li&gt;
&lt;li&gt;You can include extra targets in there, especially stuff like
linters&#x2F;formatters which you would want to gate CI on (but not necessarily
prevent downstream consumers from building packages if these tests fail).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;exploring-flake-contents&quot;&gt;Exploring Flake Contents&lt;&#x2F;h1&gt;
&lt;p&gt;Sometimes it can be useful to (interactively) explore what a flake holds which
you can&#x27;t easily spot via something like &lt;code&gt;nix flake show&lt;&#x2F;code&gt; (things like &quot;what is
the actual derivation for &lt;em&gt;X&lt;&#x2F;em&gt; check&quot;, or exploring the fully evaluated
configurations of a NixOS configuration, etc.). This is where &lt;code&gt;nix repl&lt;&#x2F;code&gt; becomes
very useful.&lt;&#x2F;p&gt;
&lt;p&gt;In the same way that &lt;code&gt;:l &amp;lt;nixpkgs&amp;gt;&lt;&#x2F;code&gt; can be invoked to load a Nix expression and
bring it into scope, &lt;code&gt;:lf .&lt;&#x2F;code&gt; will load a Nix flake from the current directory
and add it to the scope. The &lt;code&gt;output&lt;&#x2F;code&gt; attribute will already be evaluated so
tab-completion will work with something like
&lt;code&gt;outputs.nixosConfigurations.&amp;lt;TAB&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the &lt;code&gt;:lf&lt;&#x2F;code&gt; built-in is available in Nix 2.4 or later. Flakes can also
be loaded via &lt;code&gt;builtins.getFlake (toString .&#x2F;.)&lt;&#x2F;code&gt; on earlier Nix versions which
have the experimental flakes feature enabled.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;shell-completions&quot;&gt;Shell Completions&lt;&#x2F;h1&gt;
&lt;p&gt;Check to see if you have shell completions enabled for your favorite shell, if
they aren&#x27;t already. I like to use &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;fishshell.com&#x2F;&quot;&gt;fish&lt;&#x2F;a&gt; which has really good completion
support out of the box, especially with completions already configured for other
packages via NixOS&#x2F;home-manager configs.&lt;&#x2F;p&gt;
&lt;p&gt;Completions didn&#x27;t used to work a while back, but they sure do now! So next time
you invoke a command on a flake, try out something like &lt;code&gt;nix build .#packages.x86_64-linux.&amp;lt;TAB&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;general-flake-consumption&quot;&gt;General Flake Consumption&lt;&#x2F;h1&gt;
&lt;p&gt;Contrary to how it appears at first, there are only a handful of flake
properties which are &lt;del&gt;magical&lt;&#x2F;del&gt; built-in and understood by Nix itself:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Reading&#x2F;managing the &lt;code&gt;flake.lock&lt;&#x2F;code&gt; file&lt;&#x2F;li&gt;
&lt;li&gt;Pulling in input sources to the store&lt;&#x2F;li&gt;
&lt;li&gt;Evaluating the &lt;code&gt;outputs&lt;&#x2F;code&gt; function with the inputs passed in&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Besides that, everything else behaves like any other nix expression. Sure, the
CLI is aware of things like &lt;code&gt;checks&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;packages&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;devShells&lt;&#x2F;code&gt;, or it may expect
certain formats like &lt;code&gt;checks&lt;&#x2F;code&gt; being derivations or &lt;code&gt;nixosConfigurations&lt;&#x2F;code&gt; nix
modules, but it won&#x27;t mind or stop you from defining your own attributes on the
flake itself. It will just ignore them.&lt;&#x2F;p&gt;
&lt;p&gt;For example, here&#x27;s how we can define our own home-manager configuration.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# flake.nix
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&#x2F;nixos-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;home-manager &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:nix-community&#x2F;home-manager&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;home-manager &lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;homeManagerConfigurations&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;x86_64-linux &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;myConfig &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;home-manager&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;homeManagerConfiguration &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;x86_64-linux&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;username &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;ivan&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;homeDirectory &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;home&#x2F;ivan&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;stateVersion &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;21.03&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;configuration &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Some config
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we want to manually build (and cache) the packages associated with the
configuration, we can invoke &lt;code&gt;nix build .#homeManagerConfigurations.x86_64-linux.myConfig.activationPackage&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we wanted to automate building all home-manager configurations for a
particular system in our CI, we can add the file below and configure our CI to
execute &lt;code&gt;nix build -f ciHomeManagerConfigurations.nix&lt;&#x2F;code&gt;!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# ciHomeManagerConfigurations.nix
&lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;system &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;? &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;builtins&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;currentSystem &lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;flake &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;builtins&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;getFlake &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;toString &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;.&#x2F;.&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;flake&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;homeManagerConfigsForSystem &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;attrByPath
&lt;&#x2F;span&gt;&lt;span&gt;    [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    {}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;flake&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;homeManagerConfigurations&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Return all home-manager configuration derivations matching the current system
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;attrsets&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;mapAttrs
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;hmConfig&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;hmConfig&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;activationPackage&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;homeManagerConfigsForSystem
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Building with SQLx on Nix</title>
		<published>2021-12-09T00:00:00+00:00</published>
		<updated>2022-01-21T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/building-with-sqlx-on-nix/" type="text/html"/>
		<id>https://ipetkov.dev/blog/building-with-sqlx-on-nix/</id>
		<content type="html">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;launchbadge&#x2F;sqlx&quot;&gt;SQLx&lt;&#x2F;a&gt; is a Rust crate for asynchronously accessing SQL databases. It works by
checking all queries at compile time, which means it needs access to the
database when building.&lt;&#x2F;p&gt;
&lt;p&gt;Although it supports an offline-mode (intended for CI or network-blocked
builds), I prefer avoiding having to remember to manually run commands to keep
schemas in sync.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take a look at how we can efficiently automate this with &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;naersk&quot;&gt;Naersk&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# mycrate.nix
&lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;naersk
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;runCommand
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;sqlx-cli
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;targetPlatform
&lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;.&#x2F;mycrate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;                                                &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# 1
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;srcMigrations &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;src &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;migrations&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;                              &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# 2
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sqlx-db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;runCommand &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;sqlx-db-prepare&amp;quot;                          &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# 3
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nativeBuildInputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;sqlx-cli &lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    mkdir $out
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    export DATABASE_URL=sqlite:$out&#x2F;db.sqlite3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    sqlx database create
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    sqlx migrate --source &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;srcMigrations&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt; run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;  &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;naersk&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;targetPlatform&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;buildPackage &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;doCheck &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;CARGO_BUILD_INCREMENTAL &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;false&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;RUST_BACKTRACE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;full&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;copyLibs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;overrideMain &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;old&lt;&#x2F;span&gt;&lt;span&gt;: {                                           &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# 4
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;linkDb &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;      export DATABASE_URL=sqlite:&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;sqlx-db&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;db.sqlite3            # 5
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;    &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;preBuildPhases &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;linkDb&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;++ &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;old&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;preBuildPhases &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;or &lt;&#x2F;span&gt;&lt;span&gt;[ ])&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# 6
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At a high level, Naersk builds the crate in two parts: one derivation builds all
cargo dependencies on their own, and second derivation uses the artifacts from
the first when building the actual crate source. This pattern can be extended by
adding a &lt;em&gt;third&lt;&#x2F;em&gt; derivation which can prepare a SQLite database which &lt;code&gt;sqlx&lt;&#x2F;code&gt; can
use for query validation.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s break down the configuration above:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;We define a path to the cargo root. I prefer to keep the crate files in their
own sub-directory so that builds don&#x27;t get accidentally invalidated when
other files get changed (e.g. extra nix files, READMEs, etc.). It is possible
to use &lt;code&gt;cleanSourceWith&lt;&#x2F;code&gt; or &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;manual&#x2F;nixpkgs&#x2F;unstable&#x2F;#sec-pkgs-nix-gitignore&quot;&gt;&lt;code&gt;nix-gitignore&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to filter out extra files, but
it can get a bit fiddly at times, and easy to forget to allow&#x2F;block list new
files.&lt;&#x2F;li&gt;
&lt;li&gt;Regardless of where the crate source is hosted, we want to make sure that the
source we pass into &lt;code&gt;sqlx&lt;&#x2F;code&gt; &lt;em&gt;only contains the &lt;code&gt;migrations&lt;&#x2F;code&gt;&lt;&#x2F;em&gt; directory. This
will avoid having to rebuild the database unnecessarily.&lt;&#x2F;li&gt;
&lt;li&gt;This command defines the script for having &lt;code&gt;sqlx&lt;&#x2F;code&gt; create the database and
perform any migrations, using the source from step #2, and saving the result
to the derivation&#x27;s &lt;code&gt;$out&lt;&#x2F;code&gt; directory.&lt;&#x2F;li&gt;
&lt;li&gt;Naersk will, by default, pass all of its inputs to &lt;em&gt;both&lt;&#x2F;em&gt; the crate and deps
derivations. Here we use &lt;code&gt;overrideMain&lt;&#x2F;code&gt; such that our changes apply &lt;em&gt;only to
the final crate derivation&lt;&#x2F;em&gt;. Since the deps derivation does not need to use
&lt;code&gt;sqlx&lt;&#x2F;code&gt; we can avoid having to rebuild it if the database schema changes.&lt;&#x2F;li&gt;
&lt;li&gt;We define our &lt;code&gt;linkDb&lt;&#x2F;code&gt; step which will set the &lt;code&gt;DATABASE_URL&lt;&#x2F;code&gt; variable that
&lt;code&gt;sqlx&lt;&#x2F;code&gt; will use when doing the query validation.&lt;&#x2F;li&gt;
&lt;li&gt;And lastly, we register the step as a &lt;code&gt;preBuildPhase&lt;&#x2F;code&gt; since it needs to run
before all cargo build steps are invoked.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This leaves us  with the following (minimal) dependency tree:&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;img
    src=&quot;.&#x2F;deps.dot.svg&quot;
    alt=&quot;The mycrate derivation depends on the sqlx-db-prepare and mycrate-deps derivations along with the .&#x2F;mycrate source. The mycrate-deps derivation depends only on the .&#x2F;mycrate&#x2F;Cargo.lock source. The sqlx-db-prepare derivation only depends on the .&#x2F;mycrate&#x2F;migrations source. The .&#x2F;mycrate source &amp;quot;depends&amp;quot; (i.e. contains) the .&#x2F;mycrate&#x2F;Cargo.lock and .&#x2F;mycrate&#x2F;migrations sources.&quot;
  &#x2F;&gt;
  &lt;figcaption&gt;
    The arrows show which way the results &quot;flow&quot;, from sources (represented in
    boxes) to intermediate and final derivations (represented as circles).
  &lt;&#x2F;figcaption&gt;
&lt;figure&gt;
&lt;details&gt;
  &lt;summary&gt;Auxiliary example files can be found here.&lt;&#x2F;summary&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# flake.nix
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&#x2F;nixpkgs-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;naersk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:nix-community&#x2F;naersk&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;utils &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;github:numtide&#x2F;flake-utils&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;@{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;naersk&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;utils&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;, ... &lt;&#x2F;span&gt;&lt;span&gt;}:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;utils&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;eachSystem &lt;&#x2F;span&gt;&lt;span&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;x86_64-linux&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;] (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;pkgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;nixpkgs &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;      {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;defaultPackage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;callPackage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;.&#x2F;mycrate.nix &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;naersk&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;devShell &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;mkShell &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;inputsFrom &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;defaultPackage&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#f29718;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#bfbab0;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;          ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;buildInputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;pkgs&lt;&#x2F;span&gt;&lt;span&gt;; [
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;sqlx-cli
&lt;&#x2F;span&gt;&lt;span&gt;          ]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# mycrate&#x2F;.env
&lt;&#x2F;span&gt;&lt;span&gt;DATABASE_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;sqlite:.&#x2F;db.sqlite3
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# mycrate&#x2F;Cargo.toml
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;package&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;mycrate&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;0.1.0&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;edition &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;2021&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;sqlx&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;0.5.9&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;features &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;macros&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;migrate&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;runtime-tokio-rustls&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;sqlite&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;tokio&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;1.14&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#59c2ff;&quot;&gt;features &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;macros&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sql&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sql &quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;* mycrate&#x2F;migrations&#x2F;20211209212234_first.sql *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;CREATE TABLE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt; (
&lt;&#x2F;span&gt;&lt;span&gt;  id &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;INTEGER PRIMARY KEY&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  favorite_song &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;TEXT
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sql&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sql &quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;* mycrate&#x2F;migrations&#x2F;20211209212255_second.sql *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;ALTER TABLE &lt;&#x2F;span&gt;&lt;span&gt;users
&lt;&#x2F;span&gt;&lt;span&gt;ADD COLUMN favorite_color &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;TEXT&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; mycrate&#x2F;src&#x2F;main.rs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;sqlx&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;{Connection&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; SqliteConnection&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;migrate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Migrator}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;MIGRATOR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; Migrator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;sqlx&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;migrate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;.&#x2F;migrations&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;tokio&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; conn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;SqliteConnection&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;connect(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;sqlite:.&#x2F;db.sqlite3&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;await
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;failed to get conn&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;MIGRATOR
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; conn)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;await
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;failed to run migrations&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; result &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;sqlx&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;query_scalar&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;SELECT count(*) FROM users WHERE favorite_color = &amp;#39;green&amp;#39;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;fetch_one&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff7733;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; conn)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;await
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;failed to count users&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f07178;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;number of users: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; result)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bfbab0cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;details&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Installing NixOS and ZFS on my Desktop</title>
		<published>2021-01-24T00:00:00+00:00</published>
		<updated>2024-03-19T00:00:00+00:00</updated>
		<link href="https://ipetkov.dev/blog/installing-nixos-and-zfs-on-my-desktop/" type="text/html"/>
		<id>https://ipetkov.dev/blog/installing-nixos-and-zfs-on-my-desktop/</id>
		<content type="html">&lt;p&gt;&lt;em&gt;This write up was originally published within my
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ipetkov&#x2F;dotfiles&#x2F;blob&#x2F;fdb4df76ca2b031f4dcc668f6a8b58edb1948a52&#x2F;docs&#x2F;machine_init.md&quot;&gt;dotfiles&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;NixOS is a great tool for declaratively managing system configurations (namely
what packages and other config files are available), but there are still a
number of imperative steps to run when setting up a brand new machine before
installation. (Okay, there &lt;em&gt;are&lt;&#x2F;em&gt; some projects which seek to automate this
process as well, but unless you are constantly (re-)provisioning new machines,
it is probably overkill...). There&#x27;s a number of available tutorials and guides
on how to prepare a machine for NixOS installation, but I found all of them to
be incredibly basic (e.g.  set up single ext4 partition and move on), or didn&#x27;t
quite fit the requirements I was imposing.&lt;&#x2F;p&gt;
&lt;p&gt;Since this was also my first &quot;real&quot; Linux install, there were a number of things
I was unsure of and had to research on my own to figure out whether it was
relevant or what configurations to choose. Here I document all the steps I went
through, along with (an attempt!) to capture my assumptions and deliberate
decisions so that whether I got something wrong, it stops being correct in the
future, or you simply disagree with my choices, it becomes easy to spot where to
stray and where to follow this guide.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;&#x2F;h2&gt;
&lt;p&gt;Huge thanks to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;grahamc.com&quot;&gt;Graham Christensen&lt;&#x2F;a&gt; whose blog posts were
my main inspiration and guide for installation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20190831102758&#x2F;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;nixos-on-dell-9560&quot;&gt;NixOS on a Dell 9560&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20200621003223&#x2F;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;nixos-on-zfs&quot;&gt;ZFS Datasets for NixOS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20201124122057&#x2F;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;erase-your-darlings&quot;&gt;Erase your darlings&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;assumptions-and-requirements&quot;&gt;Assumptions and Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;Below is a quick summary of the assumptions and requirements I had for the
system to provide some historical context and keep the rest of the guide
focused on running each step.&lt;&#x2F;p&gt;
&lt;p&gt;The installation was done in early December of 2020 on a brand new 1 TiB SSD.
The disk has four partitions, and here is the final result:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A 1 GiB unencrypted boot partition (more on this later). I chose 1 GiB
because I&#x27;ve been bitten by having too small of a boot partition in the
past, and it will be a headache to try to resize the partition if it turns
out too small. Most people recommend using 300-500 MiB, but since I have
plenty of storage to spare I decided to use 1 GiB and forget about it (note
that every NixOS generation adds links in this partition, so having too
many generations laying around can fill it up as well).&lt;&#x2F;li&gt;
&lt;li&gt;A 32 MiB LUKS encrypted partition which contains the key for the remaining
partitions. I forget exactly why I went with 32 MiB exactly, but I wanted
to make this partition large enough to handle any LUKS upgrades or extra
key configurations, and I have space to spare (I think the LUKS2 max header
size is 4 MiB, and most people recommend having a partition about this big
plus some space for the actual key).&lt;&#x2F;li&gt;
&lt;li&gt;A 32 GiB swap partition because this machine has 16 GiB of RAM and I left
some headroom in case I upgrade it. I don&#x27;t plan on enabling swap (to avoid
wearing out my SSD), but I made the partition anyway in case I change my
mind.&lt;&#x2F;li&gt;
&lt;li&gt;The remainder of the disk is managed by ZFS split into the following
datasets:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;local&lt;&#x2F;code&gt; - dataset for mounting &lt;code&gt;&#x2F;nix&#x2F;store&lt;&#x2F;code&gt;. It is not snapshotted since
the nix store can be trivially repopulated&#x2F;rebuilt if the data is lost or
corrupted&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;reserved&lt;&#x2F;code&gt; - A 100 GiB reserved partition to act as an over-provisioning
guard and preserve the SSD performance (SSDs avoid wearing out individual
blocks by moving writes around. But if the drive fills up, the speed and
health of the drive will decrease. By never mounting this dataset, and
asking ZFS to ensure there is always 100 GiB available for it, I&#x27;m
effecitvely capping the disk at 90%).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;system&lt;&#x2F;code&gt; - dataset for mounting &lt;code&gt;&#x2F;root&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;var&lt;&#x2F;code&gt;. This dataset is
regularly snapshotted so I can rollback in case something catastrophic
happens. I have not yet decided to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;grahamc.com&#x2F;blog&#x2F;erase-your-darlings&quot;&gt;erase my
darlings&lt;&#x2F;a&gt; but if I do I
would move my &lt;code&gt;&#x2F;root&lt;&#x2F;code&gt; mount...&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;user&lt;&#x2F;code&gt; - dataset for storing user home directories, regularly
snapshotted&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;why-zfs&quot;&gt;Why ZFS?&lt;&#x2F;h3&gt;
&lt;p&gt;I had generally heard good things about it, namely that it&#x27;s a stable file
system implementation which supports efficient snapshots, rollbacks, and data
exports. I briefly looked into btrfs which also supports very similar
features, but the NixOS support (at the time) was lacking, and since I had
not previously used neither btrfs nor zfs, I went with the latter since I
expected the experience to be smoother.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-about-ssd-over-provisioning&quot;&gt;What about SSD over-provisioning?&lt;&#x2F;h3&gt;
&lt;p&gt;SSDs are made up of flash storage which supports a (large, but) finite number
of write operations before the medium begins to degrade. The SSD controller
performs wear leveling by effectively writing new data in a new location by
transparently remapping the block identifier to the new location. This
requires having some free space on the disk to &quot;move&quot; the blocks around. If
the disk fills up, the controller will be forced to do subsequent writes in
the same spot.&lt;&#x2F;p&gt;
&lt;p&gt;Over-provisioning is a name that storage vendors give to the concept of
reserving some storage capacity to avoid accidentally filling it up and
degrading performance. Some vendors state that their modern products
automatically achieve this in their firmware without any manual intervention
(maybe the drive itself has more storage than advertised?). Other vendors
peddle special tools like Samsung Data Magician (which simply creates an empty
partition) to achieve the task.&lt;&#x2F;p&gt;
&lt;p&gt;Since I have lots of storage to spare on my 1 TiB drive, I decided to
over-provision 10% of its capacity by creating a reserved ZFS pool which I
will never mount. I can easily remove or shrink that reservation if needed, so
this seemed like a sensible choice.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-an-unencrypted-boot-partition&quot;&gt;Why an unencrypted boot partition?&lt;&#x2F;h3&gt;
&lt;p&gt;Ultimately, you have to trust some piece of software somewhere to take your
keyboard input and unlock the disk without leaking the key somehow. An
unencrypted boot partition means someone who gets access to the disk can put a
compromised boot loader that can steal the key. Using an encrypted boot
partition avoids this risk, but that means that the UEFI implementation needs
to do the decryption, and someone who can access it could flash a compromised
implementation which also steals the key. A solution to that can be to use
Secure boot&#x2F;Trusted boot but now we have to trust that the hardware itself
isn&#x27;t compromised with some other back-door... It&#x27;s turtles all the way down.&lt;&#x2F;p&gt;
&lt;p&gt;My threat model does not include someone physically accessing my machine, so
an unencrypted boot partition works fine for me. Setting up a trusted boot
sequence sounds interesting, but it&#x27;s a project for another time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-luks-and-not-native-zfs-encryption&quot;&gt;Why LUKS and not native-ZFS encryption?&lt;&#x2F;h3&gt;
&lt;p&gt;I chose to go with using LUKS to encrypt the entire disk and run ZFS from
within it. LUKS has been around for a while and there is plenty of
tooling&#x2F;documentation&#x2F;guides around it, so it seemed like a safe approach.&lt;&#x2F;p&gt;
&lt;p&gt;ZFS apparently supports natively encrypting the disk, which avoids some double
indirection when trimming SSD blocks (and then having the decryption mapper
propagate those to the device). There are some potential security concerns
(like leaking dataset names&#x2F;sizes and dedup tables), but none of them are
within my threat model. What really convinced me against using native-ZFS
encryption was the impression that the feature was somewhat newer, and I
didn&#x27;t want to risk having it eat my laundry...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-use-the-allowdiscards-flag-with-luks&quot;&gt;Why use the &lt;code&gt;allowDiscards&lt;&#x2F;code&gt; flag with LUKS?&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;allowDiscards&lt;&#x2F;code&gt; option instructs the mapper to propagate trim commands
issued by the underlying filesystem, which allows the SSD to better perform
wear leveling. This option is disabled by default since there are some
theoretical attack vectors from having it enabled (namely leaking which blocks
are trimmed, an some potential oracle attacks if the attacker can influence
what data is written to the disk).&lt;&#x2F;p&gt;
&lt;p&gt;Since this doesn&#x27;t fit my threat model (namely someone gaining physical access
to my disk) and since I am more worried about maintaining my SSD performance,
I decided to enable this option.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;&#x2F;h2&gt;
&lt;p&gt;On to the good stuff, actual installation steps start here! Note all commands
should be run as root.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;installer-preparation&quot;&gt;Installer preparation&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;download.html&quot;&gt;Download an installer&lt;&#x2F;a&gt; and burn it to a
bootable USB drive. Worth noting that if you already have an existing nix
install you can create your own custom installer (e.g. if you&#x27;re a power
user or you need specific tools available during installation), but the
base installer should cover all the bases.&lt;&#x2F;li&gt;
&lt;li&gt;If there is an existing Windows installation on this machine (even if it is
on an entirely separate drive), consider &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;askubuntu.com&#x2F;questions&#x2F;1291758&#x2F;ubuntu-20-04-and-fenvi-ax200-wifi-bluetooth-card-drivers-or-soolution-to-wifi&quot;&gt;turning off the &quot;Enable fast
startup&quot; option&lt;&#x2F;a&gt;
and rebooting before continuing. I had to do this to get my bluetooth&#x2F;wifi
(AX200) adapter to work (yay Windows hacks to gain speedup!).&lt;&#x2F;li&gt;
&lt;li&gt;(Optional) if you have other drives in the machine, consider unplugging
them to avoid accidentally overwriting the wrong disk due to a typo...&lt;&#x2F;li&gt;
&lt;li&gt;Plug in the USB, reboot the computer, hit the appropriate keys during the
BIOS, and boot into the USB&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;partitioning-the-disk&quot;&gt;Partitioning the Disk&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If a graphical installer image was used, it should drop us in a desktop
environment which should set up some basic stuff like networking. The rest
of the commands all need root privileges, so open a terminal and switch to
root to avoid having to prefix everything with &lt;code&gt;sudo&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; su
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Next, we need to figure out which disk we want to use.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;In my case this is my second NVMe in this machine so I will be using
&lt;code&gt;nvme1n1&lt;&#x2F;code&gt;, but you may see a different number based on what is connected.
We&#x27;ll store this in a variable to make it easier to copy-paste other
commands, so &lt;strong&gt;make sure to replace the &lt;code&gt;...&lt;&#x2F;code&gt; with your selected drive&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;dev&#x2F;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Next, it&#x27;s time to partition the actual disk. I&#x27;m going to be creating the
following partitions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1 GiB (unencrypted) boot partition - for storing the initial boot files&lt;&#x2F;li&gt;
&lt;li&gt;32 MiB LUKS key partition - the key for the rest of the disk. This will be
encrypted with a password that we remember (and type in during boot)&lt;&#x2F;li&gt;
&lt;li&gt;32 GiB swap partition - for enabling system swap&lt;&#x2F;li&gt;
&lt;li&gt;The remainder of the drive will be our actual, usable, partition&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We&#x27;re going to be using &lt;code&gt;gdisk&lt;&#x2F;code&gt; below, but if you know how to use another
disk partition program, feel free to use it instead.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;gdisk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;details&gt;
  &lt;summary&gt;Click to expand!&lt;&#x2F;summary&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;GPT fdisk (gdisk) version 1.0.5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Partition table scan:
&lt;&#x2F;span&gt;&lt;span&gt;  MBR: not present
&lt;&#x2F;span&gt;&lt;span&gt;  BSD: not present
&lt;&#x2F;span&gt;&lt;span&gt;  APM: not present
&lt;&#x2F;span&gt;&lt;span&gt;  GPT: not present
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Creating new GPT entries in memory.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): o
&lt;&#x2F;span&gt;&lt;span&gt;This option deletes all partitions and creates a new protective MBR.
&lt;&#x2F;span&gt;&lt;span&gt;Proceed? (Y&#x2F;N): Y
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): n
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (1-128, default 1):
&lt;&#x2F;span&gt;&lt;span&gt;First sector (34-1953525134, default = 2048) or {+-}size{KMGTP}:
&lt;&#x2F;span&gt;&lt;span&gt;Last sector (2048-1953525134, default = 1953525134) or {+-}size{KMGTP}: +1G
&lt;&#x2F;span&gt;&lt;span&gt;Current type is 8300 (Linux filesystem)
&lt;&#x2F;span&gt;&lt;span&gt;Hex code or GUID (L to show codes, Enter = 8300): EF00
&lt;&#x2F;span&gt;&lt;span&gt;Changed type of partition to &amp;#39;EFI system partition&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): n
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (2-128, default 2): 2
&lt;&#x2F;span&gt;&lt;span&gt;First sector (34-1953525134, default = 2099200) or {+-}size{KMGTP}:
&lt;&#x2F;span&gt;&lt;span&gt;Last sector (2099200-1953525134, default = 1953525134) or {+-}size{KMGTP}: +32M
&lt;&#x2F;span&gt;&lt;span&gt;Current type is 8300 (Linux filesystem)
&lt;&#x2F;span&gt;&lt;span&gt;Hex code or GUID (L to show codes, Enter = 8300):
&lt;&#x2F;span&gt;&lt;span&gt;Changed type of partition to &amp;#39;Linux filesystem&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): c
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (1-2): 2
&lt;&#x2F;span&gt;&lt;span&gt;Enter name: luks key
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): n
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (3-128, default 3):
&lt;&#x2F;span&gt;&lt;span&gt;First sector (34-1953525134, default = 2164736) or {+-}size{KMGTP}:
&lt;&#x2F;span&gt;&lt;span&gt;Last sector (2164736-1953525134, default = 1953525134) or {+-}size{KMGTP}: +32G
&lt;&#x2F;span&gt;&lt;span&gt;Current type is 8300 (Linux filesystem)
&lt;&#x2F;span&gt;&lt;span&gt;Hex code or GUID (L to show codes, Enter = 8300):
&lt;&#x2F;span&gt;&lt;span&gt;Changed type of partition to &amp;#39;Linux filesystem&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): c
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (1-3): 3
&lt;&#x2F;span&gt;&lt;span&gt;Enter name: swap
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): n
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (4-128, default 4):
&lt;&#x2F;span&gt;&lt;span&gt;First sector (34-1953525134, default = 69273600) or {+-}size{KMGTP}:
&lt;&#x2F;span&gt;&lt;span&gt;Last sector (69273600-1953525134, default = 1953525134) or {+-}size{KMGTP}:
&lt;&#x2F;span&gt;&lt;span&gt;Current type is 8300 (Linux filesystem)
&lt;&#x2F;span&gt;&lt;span&gt;Hex code or GUID (L to show codes, Enter = 8300):
&lt;&#x2F;span&gt;&lt;span&gt;Changed type of partition to &amp;#39;Linux filesystem&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): c
&lt;&#x2F;span&gt;&lt;span&gt;Partition number (1-4): 4
&lt;&#x2F;span&gt;&lt;span&gt;Enter name: root
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): p
&lt;&#x2F;span&gt;&lt;span&gt;Disk &#x2F;dev&#x2F;nvme1n1: 1953525168 sectors, 931.5 GiB
&lt;&#x2F;span&gt;&lt;span&gt;Model: Samsung SSD 970 EVO Plus 1TB
&lt;&#x2F;span&gt;&lt;span&gt;Sector size (logical&#x2F;physical): 512&#x2F;512 bytes
&lt;&#x2F;span&gt;&lt;span&gt;Disk identifier (GUID): 22610B10-DB5F-467D-8B9E-ECD88878ABA5
&lt;&#x2F;span&gt;&lt;span&gt;Partition table holds up to 128 entries
&lt;&#x2F;span&gt;&lt;span&gt;Main partition table begins at sector 2 and ends at sector 33
&lt;&#x2F;span&gt;&lt;span&gt;First usable sector is 34, last usable sector is 1953525134
&lt;&#x2F;span&gt;&lt;span&gt;Partitions will be aligned on 2048-sector boundaries
&lt;&#x2F;span&gt;&lt;span&gt;Total free space is 2014 sectors (1007.0 KiB)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Number  Start (sector)    End (sector)  Size       Code  Name
&lt;&#x2F;span&gt;&lt;span&gt;   1            2048         2099199   1024.0 MiB  EF00  EFI system partition
&lt;&#x2F;span&gt;&lt;span&gt;   2         2099200         2164735   32.0 MiB    8300  luks key
&lt;&#x2F;span&gt;&lt;span&gt;   3         2164736        69273599   32.0 GiB    8300  swap
&lt;&#x2F;span&gt;&lt;span&gt;   4        69273600      1953525134   898.5 GiB   8300  root
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Command (? for help): w
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
&lt;&#x2F;span&gt;&lt;span&gt;PARTITIONS!!
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Do you want to proceed? (Y&#x2F;N): Y
&lt;&#x2F;span&gt;&lt;span&gt;OK; writing new GUID partition table (GPT) to &#x2F;dev&#x2F;nvme1n1.
&lt;&#x2F;span&gt;&lt;span&gt;The operation has completed successfully.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;details&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;luks-setup&quot;&gt;LUKS Setup&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Now that the disk is partitioned, it&#x27;s time to turn on encryption! First
we&#x27;ll initialize our &lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition and fill it with random data.
This will eventually become the key to decrypt our actual drive. Note that
&lt;strong&gt;this is the day-to-day password used to unlock the computer at boot&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksFormat&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p2&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksOpen &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; cryptkey
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;dd&lt;&#x2F;span&gt;&lt;span&gt; if=&#x2F;dev&#x2F;urandom of=&#x2F;dev&#x2F;mapper&#x2F;cryptkey bs=1024 status=progress
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Next, we initialize the swap partition (which will share the same key
written to our &lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition along with the rest of the drive). Note
that there is no backup key set for this partition, but there should never
be any reason to try to recover any data written in the swap in case the
&lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition is damaged.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksFormat&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --type&lt;&#x2F;span&gt;&lt;span&gt; luks1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --key-file&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p3&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Mount the partition after creation
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksOpen&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --key-file&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p3&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; cryptswap
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Now it&#x27;s time to encrypt the rest of the drive. Note that first we&#x27;ll
initialize the drive with a &lt;em&gt;backup passphrase&lt;&#x2F;em&gt;. Make this a strong
password (e.g. diceware) &lt;strong&gt;and write it down and store is someplace safe&lt;&#x2F;strong&gt;.
If the &lt;code&gt;cryptkey&lt;&#x2F;code&gt; partition becomes damaged, this will be the only way to
recover the data on the drive!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Initialize with a passphrase
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksFormat&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --type&lt;&#x2F;span&gt;&lt;span&gt; luks1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p4&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Add the cryptkey partition as a keyfile for unlocking during boot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksAddKey&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --new-keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Finally, mount the root partition. &lt;strong&gt;Note the use of &lt;code&gt;--allow-discards&lt;&#x2F;code&gt;
which may be a security risk&lt;&#x2F;strong&gt;. Read about the choices and assumptions
above as to why I have chosen to use this flag, but feel free to omit it if
desired.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;cryptsetup&lt;&#x2F;span&gt;&lt;span&gt; luksOpen&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --keyfile-size&lt;&#x2F;span&gt;&lt;span&gt; 8192&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --key-file&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptkey&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --allow-discards &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; cryptroot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Note that some guides recommend filling the drive with random data before
doing the encryption to avoid leaking information about how big the drive
is and which blocks are encrypted, etc. I am going to omit this step since
I want to avoid wearing out my SSD,&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;filesystem-setup&quot;&gt;Filesystem setup&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Initialize the boot partition as vfat&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkfs.vfat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p1&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Initialize the swap partition&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkswap&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptswap
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Next, it&#x27;s time to initialize zfs. Feel free to pick any pool name you want,
but consider keeping it unique if you manage other zfs pools elsewhere&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;POOL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;nvme-pool &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# change as desired
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span&gt; create &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;mapper&#x2F;cryptroot
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# autotrim enabled to maintain SSD performance
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zpool&lt;&#x2F;span&gt;&lt;span&gt; set autotrim=on &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Create the desired root datasets (or mounts) in the pool. Note that at the
time of writing, using &lt;code&gt;mountpoint=legacy&lt;&#x2F;code&gt; is required for correct NixOS
interoperation.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#0f1419;color:#bfbab0;&quot;&gt;&lt;code&gt;&lt;span&gt;zfs create -o compression=on -o mountpoint=legacy &amp;quot;${POOL}&#x2F;local&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;zfs create -o compression=on -o mountpoint=legacy &amp;quot;${POOL}&#x2F;local&#x2F;nix&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;zfs create -o compression=on -o mountpoint=legacy &amp;quot;${POOL}&#x2F;system&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;zfs create -o compression=on -o mountpoint=legacy &amp;quot;${POOL}&#x2F;user&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;zfs create -o compression=on -o mountpoint=legacy &amp;quot;${POOL}&#x2F;reserved&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Set a variable with the default username you wish to use which we&#x27;ll use
for creating a home directory later&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;MY_USER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29668;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Next, we create any child datasets. Note that the &lt;code&gt;acltype=posixacl&lt;&#x2F;code&gt; flag
is required wherever &lt;code&gt;&#x2F;var&lt;&#x2F;code&gt; will be mounted, so that users can access their
own journal logs&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; xattr=sa&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; acltype=posixacl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;system&#x2F;var&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;system&#x2F;root&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;user&#x2F;home&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; create &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;user&#x2F;home&#x2F;$&lt;&#x2F;span&gt;&lt;span&gt;{MY_USER}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Set a quota and reservation on the &lt;code&gt;reserved&lt;&#x2F;code&gt; data set. This will ensure
that the disk always has the specified amount of space available, and since
we will never mount this partition, we&#x27;re effectively saving some space
from never being written (i.e. over-provisioning the SSD to maintain its
performance)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; set reservation=100G &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;reserved&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; set quota=100G &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;reserved&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# ensure we can&amp;#39;t accidentally write more than 100G to this partition
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Next, we enable local snapshotting so that we can quickly recover past
state if something goes wrong. Note that we only need to snapshot user data
and the system root. Other easily-rebuilt partitions (like &lt;code&gt;local&lt;&#x2F;code&gt;) don&#x27;t
need snapshotting enabled. Also note that the actual snapshot frequency
will be managed by our NixOS configuration&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; set com.sun:auto-snapshot=true &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;system&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;zfs&lt;&#x2F;span&gt;&lt;span&gt; set com.sun:auto-snapshot=true &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;user&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Lastly, &lt;em&gt;mount everything&lt;&#x2F;em&gt;! If you forget to mount a zfs dataset to the
right place, then data may get written in the wrong place and fail during
boot!&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I made the mistake of forgetting to mount the &lt;code&gt;&#x2F;nix&#x2F;store&lt;&#x2F;code&gt; path on the
new drive. The installer happily filled the root partition with the data,
but when my configuration correctly mounted the right dataset during
boot, suddenly all the packages were missing!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Mount the root partition itself
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;system&#x2F;root&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Make directory entries for the subsequent mounts
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;boot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;nix
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;var
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -p &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;&#x2F;mnt&#x2F;home&#x2F;$&lt;&#x2F;span&gt;&lt;span&gt;{MY_USER}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Mount the boot partition
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{DISK}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;p1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;boot
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Mount the rest of our zfs datasets
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;local&#x2F;nix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;nix
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;system&#x2F;var&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt&#x2F;var
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; zfs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span&gt;{POOL}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&#x2F;user&#x2F;home&#x2F;$&lt;&#x2F;span&gt;&lt;span&gt;{MY_USER}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot; &amp;quot;&#x2F;mnt&#x2F;home&#x2F;$&lt;&#x2F;span&gt;&lt;span&gt;{MY_USER}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c2d94c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;nixos-installation&quot;&gt;NixOS installation&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Finally it&#x27;s time to get nix involved! Run the generation command below
and it should do a good job at auto-detecting any hardware and filesystem
configurations&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixos-generate-config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29718;&quot;&gt; --root&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Edit the generated config in &lt;code&gt;&#x2F;mnt&#x2F;etc&#x2F;nixos&#x2F;configuration.nix&lt;&#x2F;code&gt;. If you&#x27;re
new to NixOS, or missing your favorite editor&#x2F;environment setup, consider
lightly tweaking the default config (e.g. turning on ssh, setting up
networking, etc.) to get things going and come back to flesh it out later.
But before we continue there are a few more things to double check:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure that the &lt;code&gt;initrd.luks.devices&lt;&#x2F;code&gt; are correctly configured. If
anything is missing, or the disk uuid is incorrect, &lt;strong&gt;carefully&lt;&#x2F;strong&gt; update
the config and double check everything&lt;&#x2F;li&gt;
&lt;li&gt;Also carefully note that the &lt;code&gt;cryptkey&lt;&#x2F;code&gt; declaration shows up before any
other partions which are unlocked by it!&lt;&#x2F;li&gt;
&lt;li&gt;Make sure to update the &lt;code&gt;keyFileSize&lt;&#x2F;code&gt; parameter to whatever was used
during initialization&lt;&#x2F;li&gt;
&lt;li&gt;Also make sure to set the &lt;code&gt;allowDiscards&lt;&#x2F;code&gt; flag if used above
(&lt;strong&gt;noting the security caveats from before&lt;&#x2F;strong&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Make sure that all filesystems are correctly mapped to their zfs data
sets.&lt;&#x2F;li&gt;
&lt;li&gt;Add any missing &lt;code&gt;boot.initrd.availableKernelModules&lt;&#x2F;code&gt;. For example, I
had to add &lt;code&gt;&quot;amdgpu&quot;&lt;&#x2F;code&gt; to fix some screen resolution issues during early
boot.&lt;&#x2F;li&gt;
&lt;li&gt;Add your default user and set their home directory&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Time to actually install NixOS now! After the initial install is done,
reboot and hope everything went well...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#0f1419;color:#bfbab0;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;nixos-install
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffb454;&quot;&gt;reboot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;If you got this far and were able to log in, congrats, you did it! A few
more things to consider doing:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Change the password for your default user&lt;&#x2F;li&gt;
&lt;li&gt;Change the root password, or even better, lock the root account so no one
can log into it directly&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
	</entry>
</feed>
