<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Nixos on mapletree.moe</title><link>https://mapletree.moe/tags/nixos/</link><description>Recent content in Nixos on mapletree.moe</description><generator>Hugo -- 0.160.1</generator><language>en-us</language><copyright>This work is licensed under the MIT0 License.</copyright><lastBuildDate>Sun, 04 Aug 2019 01:00:00 -0600</lastBuildDate><atom:link href="https://mapletree.moe/tags/nixos/index.xml" rel="self" type="application/rss+xml"/><item><title>NixOS Part 1 - Introduction &amp; Basic Setup</title><link>https://mapletree.moe/posts/nixos-part-1/</link><pubDate>Sun, 04 Aug 2019 01:00:00 -0600</pubDate><author>bakayuki</author><guid>https://mapletree.moe/posts/nixos-part-1/</guid><description>&amp;lt;no value&amp;gt;</description><content type="text/html" mode="escaped"><![CDATA[<p><strong>EDIT (2026/04/25):</strong> <em>The remaining parts of this tutorial were never
completed, but I do still hold a special place in my heart for NixOS.</em></p>
<p>Once again, various life stressors have resulted in me attempting to retreat
into my little shell, and whenever that happens I always seem to find something
new to work on. In this particular instance, the stress seemed to perfectly
coincide with my discovery of a new Linux distribution, <a href="https://nixos.org/" title="NixOS Homepage">NixOS</a>. I ended up
becoming very fond of the distribution almost immediately, and after two weeks
of living on it and learning a bit more about it, I recently redid the MacBook
utilizing Nix as the sole operating system on it.</p>
<p>The next series of blog posts, assuming I manage to stay consistent, will be
about my journey using NixOS, why I have become so fond of it so quickly, and
other interesting things I come up with along the way.</p>
<h1 id="why-nixos">Why NixOS<a href="#why-nixos" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>The most predominant form of package management in linux distributions tends to
be <a href="https://en.wikipedia.org/wiki/Imperative_programming" title="Imperative Programming">imperative</a> package management. Even in distributions like Gen/Funtoo,
the make file is in general a static entity composed of variables that resolve
how imperative commands, such as <code>emerge system</code> are executed. Essentially, we
spend our time telling the system <em>how</em> we want it to accomplish <em>what</em> we
actually want, and by following the list of imperative commands we
(theoretically) end up with what we wanted.</p>
<p>The problem is, this doesn&rsquo;t always work. To quote GlaDOS, &ldquo;This former Linux
Developer would like to remind you that <a href="https://en.wikipedia.org/wiki/Dependency_hell" title="It is a real place.">Dependency Hell</a> is a real place
where you <strong>WILL</strong> be sent at the first sign of poor imperative order control.&rdquo;
Essentially, because we are so focused on <em>how</em> something will be accomplished,
if anything along that chain breaks we end up in a genuinely unfortunate
situation.</p>
<p>This is not an old problem, and many distributions have attempted to resolve
this. Back in 2004/2005 when I was starting to get interested in Linux I spent
some time talking to a friend about what I was using to tinker. While I cannot
remember the specific distributions, I do know that <a href="https://en.wikipedia.org/wiki/RPM_Package_Manager">RPM</a> was the primary
mode of package management on them. He essentially scoffed at me, and said while
he was glad I was using Linux, he wished me luck when I inevitably discovered
&ldquo;RPM Hell,&rdquo; perhaps one of the earliest forms of dependency hell.</p>
<p>When I inquired as to what he was using, he told me about <a href="https://en.wikipedia.org/wiki/Gentoo_Linux">Gentoo</a>. This was
a very very long time ago, where Stage 1/Stage 2/Stage 3 installations were a
thing. The benefit, I was told, is that because literally every part of the
package is imperatively defined ahead of time, you mitigate the chance of
dependency hell, because you&rsquo;re modifying the entire operating system as a
single unit.</p>
<p>This began my extremely long and at times complicated history with the
Gen/Funtoo community during my past life. I still hold an incredible soft spot
for their ecosystem, but there are situations that can occur even within the
portage subsystem, and the method of doing things imperatively often means that
the problem isn&rsquo;t discovered until the middle of rebuilding your system, for
example with an <code>emerge world</code>. Not to mention there <em>is</em> a penalty, and it was
even worse during the P3/P4 days, for building everything completely from
source.</p>
<p>Various hybrid Binary/Source systems were developed over time, one that I
remember offhand is <a href="https://en.wikipedia.org/wiki/Sabayon_Linux">Sabayon</a> which started as a layer over Gentoo if I
remember correctly, that would install unmodified packages from binary but
anything modified would be built. However, this technique just solves the speed
issue, it does nothing to resolve the imperative issues.</p>
<h1 id="how-does-nix-help">How does Nix Help<a href="#how-does-nix-help" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>So Nix works by utilizing a <a href="https://en.wikipedia.org/wiki/Declarative_programming">declarative</a> form of package management.
Essentially, instead of focusing on telling Nix <em>how</em> we want our system, we
tell it <em>what</em> system we want. We declare the Operating System we desire as a
function, Nix evaluates that function, and then <em>it</em> decides <em>how</em> it will form
that system. This is combined with transactional, atomic, procedures. Every
&ldquo;Generation&rdquo; of Nix is a stand alone operating system. Installing/Un-installing
packages never leaves any cruft behind because the packages are just dynamically
linked upon boot. Removing the package from our declaration removes the request
to symbolically link it to the system, which means it never existed.</p>
<p>Nix, in particular, is a <a href="https://en.wikipedia.org/wiki/Functional_programming">functional</a> package manager, an even more strict
form of declarative package management. Instead of rehashing the explanations,
I&rsquo;ll let the wonderful <a href="https://nixos.org/nix/about.html">nix webpage</a> explain the difference. NixOS is simply
an entire operating system built on top of Nix.</p>
<p>Beyond the benefits discussed on the official Nix website, there are other
benefits to putting the entire operating system under functional control.</p>
<p>As an example, let us take the boot process. Since the system we are going to
get to below utilizes encrypted swap and an encrypted root, you would expect
that we need to handle a custom initrd, custom fstab, etc etc. You would be
right! But instead of handling multiple files to get this done, we can actually
do everything right in our <code>configuration.nix</code>.</p>
<h2 id="swap">Swap<a href="#swap" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">swapDevices</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">device</span> <span class="o">=</span> <span class="s2">&#34;/dev/disk/by-uuid/f6533f92-baf2-4804-afda-880a7b5975ac&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">encrypted</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">enable</span>  <span class="o">=</span> <span class="no">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">keyFile</span> <span class="o">=</span> <span class="s2">&#34;/mnt-root/root/swap.key&#34;</span><span class="p">;</span> <span class="c1"># Believe it or not, this is correct.</span>
</span></span><span class="line"><span class="cl">      <span class="n">label</span>   <span class="o">=</span> <span class="s2">&#34;nixos-swap&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">blkDev</span>  <span class="o">=</span> <span class="s2">&#34;/dev/disk/by-uuid/6babbdb8-26ec-43ee-b7ab-76b43015acd3&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span></code></pre></div><h2 id="root-fs">Root FS<a href="#root-fs" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">boot</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">initrd</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">luks</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">devices</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">decrypted-disk-name</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">device</span> <span class="o">=</span> <span class="s2">&#34;/dev/disk/by-uuid/0765a1fc-6045-45af-978e-db49609bc0e3&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="n">keyFile</span> <span class="o">=</span> <span class="s2">&#34;/root.key&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Additionally, while some distributions have opted to have several tools for
building your <code>grub.cfg</code>, those still rely on modifying external files, for
example under <code>/etc/default</code> or other directories. Instead, we add it right into
our <code>configuration.nix</code> as well. We are just declaring what we want Nix to do,
whatever else it decides it needs is up to it.</p>
<h2 id="grub-configuration">Grub Configuration<a href="#grub-configuration" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="n">boot</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">grub</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">device</span>                <span class="o">=</span> <span class="s2">&#34;nodev&#34;</span><span class="p">;</span>                <span class="c1"># This isn&#39;t for BIOS.</span>
</span></span><span class="line"><span class="cl">    <span class="n">efiInstallAsRemovable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span>                   <span class="c1"># Try to use Standard EFI.</span>
</span></span><span class="line"><span class="cl">    <span class="n">efiSupport</span>            <span class="o">=</span> <span class="no">true</span><span class="p">;</span>                   <span class="c1"># This IS for EFI.</span>
</span></span><span class="line"><span class="cl">    <span class="n">enable</span>                <span class="o">=</span> <span class="no">true</span><span class="p">;</span>                   <span class="c1"># Grub is needed for our weird shit</span>
</span></span><span class="line"><span class="cl">    <span class="n">enableCryptodisk</span>      <span class="o">=</span> <span class="no">true</span><span class="p">;</span>                   <span class="c1"># Add LUKS support</span>
</span></span><span class="line"><span class="cl">    <span class="n">extraInitrd</span>           <span class="o">=</span> <span class="s2">&#34;/boot/initrd.keys.gz&#34;</span><span class="p">;</span> <span class="c1"># LUKS Key</span>
</span></span><span class="line"><span class="cl">    <span class="n">zfsSupport</span>            <span class="o">=</span> <span class="no">true</span><span class="p">;</span>                   <span class="c1"># Add ZFS support</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Some people may note right away that we&rsquo;re building our key into the initrd and
may worry about security issues, but we will get to that as well!</p>
<p>Needless to say, literally everything that is handled in configuration files
throughout a normal linux distribution, is instead located in a centralized
file. We can break that file up and import others as well, similar to any other
programming language. Essentially, NixOS reduces the entire operating system to
a series of Nix-Language source files, and we let Nix handle all the rest!</p>
<h1 id="about-our-system">About Our System<a href="#about-our-system" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>So, for this initial article I will be discussing what I wanted out of my new
daily driver operating system, and how I went about implementing it. You can
look at my entire Nix-Configuration through the GitHub repository
<a href="https://github.com/zyradyl/nix-configuration">of the same name</a>, but I won&rsquo;t be referring to any specific files yet
because the repository is going to change layouts several times throughout this
series of articles, as I attempt to convert to a more functional form of
creating my system.</p>
<p>So, without further ado, what are our requirements?</p>
<ul>
<li>Encrypted Root Partition</li>
<li>ZFS Root Partition</li>
<li>Encrypted Boot(!) Partition, to protect our kernels and initrd</li>
<li>Encrypted Swap</li>
<li>Hibernation Support <em>with</em> encrypted swap(!)</li>
</ul>
<p>There are actually more requirements, but these form the basis for this article.
Before we get into it, it is worth noting that I used several different sources
to compile all the steps needed to accomplish everything.</p>
<p>First, for Nix on ZFS, the <a href="https://nixos.wiki/wiki/NixOS_on_ZFS">NixOS Wiki Page</a> of the same name was
instrumental in solving the basic requirements of our work. We skip over ZFS
Native encryption, because while it is not leaky in relevant ways, it is still
<em>slightly</em> leaky. From <code>man zfs</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">zfs will not encrypt metadata related to the pool structure, including dataset
</span></span><span class="line"><span class="cl">names, dataset hierarchy, file size, file holes, and dedup tables.
</span></span></code></pre></div><p>Next, we need to ensure that we can encrypt the boot directory. This
<a href="https://elvishjerricco.github.io/2018/12/06/encrypted-boot-on-zfs-with-nixos.html">blog post</a> was instrumental in getting things to work. Had I not found this
post, its possible that I would have forgone boot partition encryption, and I&rsquo;m
very glad I was able to get it done.</p>
<p>Last, but not least, encrypted swap with hibernation was enabled by following
the first answer to <a href="https://unix.stackexchange.com/questions/529047/is-there-a-way-to-have-hibernate-and-encrypted-swap-on-nixos">this stack exchange question</a> with some gentle
modifications made.</p>
<p>Additionally, it is worth noting that the <code>configuration.nix</code> file was simply
copied from my previous trial system, and tweaks made to it. The primary reason
the repository is out of date is that while trying to get the system up and
running, I ignored most standards of aesthetics, so I&rsquo;d like to get it cleaned
up proper before releasing it.</p>
<p>Let&rsquo;s get started!</p>
<h1 id="part-1---live-environment-pre-work">Part 1 - Live Environment Pre-Work<a href="#part-1---live-environment-pre-work" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>While installing the trial system, I simply used the minimal disk environment,
without a GUI, and used my phone to access documentation. However, with the
number of things I wanted to try this time, I figured it would be best to have a
graphical environment to refer to the three sources mentioned above. This poses
a unique problem on a Mac, as the proprietary NVIDIA driver is the only driver
at the time of writing that will get an X-Session up and running.</p>
<p>Adding additional complexity is the fact that while preparing for this process,
I disassembled my MacBook and somewhere along the way caused some sort of issue
with the IO Board, which means I was limited to only one USB 3.0 port on the
left side of the computer.</p>
<p>To start, I used macOS to install the new macOS beta. This was important because
the only way to update MacBook firmware is through macOS. By installing a beta
release, I was trying to get out ahead of any firmware updates to be released in
the next six months. Fingers crossed, this is all that will be required, and we
won&rsquo;t need to figure out how to get macOS back because of a new firmware
exploit.</p>
<p>Once the beta was installed, and everything was good to go, I downloaded a quick
live-image of ElementaryOS (I knew the Nix live image would be a problem, and
wanted to wait till the system was ready for installation to deal with it), and
used Etcher to write it to a USB disk.</p>
<p>Rebooting into ElementaryOS, I ran a series of commands on the main SSD.
Starting with <code>blkdiscard</code>, I initiated a manual <a href="https://en.wikipedia.org/wiki/Trim_(computing)">TRIM</a> on the disk to mark
every sector as free of data. Next, I used an <a href="https://ata.wiki.kernel.org/index.php/ATA_Secure_Erase">ATA Secure Erase</a> command,
per the <a href="https://wiki.archlinux.org/index.php/Solid_state_drive/Memory_cell_clearing">Arch Wiki Memory Cell</a> article to reset the drive to factory
default write speed. For good measure, I ran the <code>--security-erase-enhanced</code>
form of the wipe. Finally, I ran another <code>blkdiscard</code> on the drive, just to be
<em>really sure</em> that everything was gone.</p>
<p>Next, we rebooted into ElementaryOS again, this time telling GRUB I wanted the
whole live system to be stored in RAM. When this was done, I downloaded the
NixOS Graphical Install CD, and burned the ISO to the USB drive.</p>
<p>Rebooting, I was presented with the boot menu, and I made sure to load NixOS
entirely into RAM as well. The NixOS live CD does not contain any non-free
firmware or software, which means the Mac Broadcom WIFI chipset will not be
detected. I already needed to deal with one small issue with the live system,
and it would be easier to simply unplug the USB drive and use a USB-&gt;Ethernet
dongle to connect for the majority of the installation.</p>
<p>So, now we are inside the NixOS Live System, at a command prompt, and we have an
internet connection. Attempting to boot into a GUI, as expected, results in a
failure to find a valid display device. This isn&rsquo;t as much of an issue as it
could be on other systems, we simply need to edit <code>/etc/nixos/configuration.nix</code>
on the live-system to include <code>services.xserver.videoDrivers = [ &quot;nvidia&quot; ];</code>
and then run <code>nixos-rebuild switch</code>. Once this completes, we run the given
command to start the X-Session, and viola, it works. Checking all of our
networking areas, we see that we have a proper internet connection, and we can
move on to the more fun things.</p>
<h1 id="part-2---disk-configuration">Part 2 - Disk Configuration<a href="#part-2---disk-configuration" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>This part is fairly straight forward. We use <code>gdisk</code> to set up three partitions.
The first partition is for our EFI Boot Partition, the second will be for our
Swap partition, made large enough to handle hibernation plus a little extra, and
the third is our new root partition, where ZFS will live.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">$ gdisk /dev/sda
</span></span><span class="line"><span class="cl">GPT fdisk (gdisk) version 1.0.4
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Partition table scan:
</span></span><span class="line"><span class="cl">  MBR: not present
</span></span><span class="line"><span class="cl">  BSD: not present
</span></span><span class="line"><span class="cl">  APM: not present
</span></span><span class="line"><span class="cl">  GPT: not present
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Creating new GPT entries in memory.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): o
</span></span><span class="line"><span class="cl">This option deletes all partitions and creates a new protective MBR.
</span></span><span class="line"><span class="cl">Proceed? (Y/N): Y
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): n
</span></span><span class="line"><span class="cl">Partition number (1-128, default 1): 1
</span></span><span class="line"><span class="cl">First sector (34-2097118, default = 2048) or {+-}size{KMGTP}:
</span></span><span class="line"><span class="cl">Last sector (2048-2097118, default = 2097118) or {+-}size{KMGTP}: +200M
</span></span><span class="line"><span class="cl">Current type is &#39;Linux filesystem&#39;
</span></span><span class="line"><span class="cl">Hex code or GUID (L to show codes, Enter = 8300): ef00
</span></span><span class="line"><span class="cl">Changed type of partition to &#39;EFI System&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): n
</span></span><span class="line"><span class="cl">Partition number (1-128, default 2): 2
</span></span><span class="line"><span class="cl">First sector (34-2097118, default = 2048) or {+-}size{KMGTP}:
</span></span><span class="line"><span class="cl">Last sector (2048-2097118, default = 2097118) or {+-}size{KMGTP}: +20G
</span></span><span class="line"><span class="cl">Current type is &#39;Linux filesystem&#39;
</span></span><span class="line"><span class="cl">Hex code or GUID (L to show codes, Enter = 8300): 8200
</span></span><span class="line"><span class="cl">Changed type of partition to &#39;Linux swap&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): n
</span></span><span class="line"><span class="cl">Partition number (2-128, default 3): 3
</span></span><span class="line"><span class="cl">First sector (34-2097118, default = 411648) or {+-}size{KMGTP}:
</span></span><span class="line"><span class="cl">Last sector (411648-2097118, default = 2097118) or {+-}size{KMGTP}:
</span></span><span class="line"><span class="cl">Current type is &#39;Linux filesystem&#39;
</span></span><span class="line"><span class="cl">Hex code or GUID (L to show codes, Enter = 8300):
</span></span><span class="line"><span class="cl">Changed type of partition to &#39;Linux filesystem&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): w
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
</span></span><span class="line"><span class="cl">PARTITIONS!!
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Do you want to proceed? (Y/N): Y
</span></span><span class="line"><span class="cl">OK; writing new GUID partition table (GPT) to /dev/sda.
</span></span><span class="line"><span class="cl">The operation has completed successfully.
</span></span></code></pre></div><p>Now we can take a look at what we have:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">$ gdisk /dev/sda
</span></span><span class="line"><span class="cl">GPT fdisk (gdisk) version 1.0.4
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Partition table scan:
</span></span><span class="line"><span class="cl">  MBR: protective
</span></span><span class="line"><span class="cl">  BSD: not present
</span></span><span class="line"><span class="cl">  APM: not present
</span></span><span class="line"><span class="cl">  GPT: present
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Found valid GPT with protective MBR; using GPT.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): p
</span></span><span class="line"><span class="cl">Disk /dev/sda: 977105060 sectors, 465.9 GiB
</span></span><span class="line"><span class="cl">Model: APPLE SSD SM0512
</span></span><span class="line"><span class="cl">Sector size (logical/physical): 512/4096 bytes
</span></span><span class="line"><span class="cl">Disk identifier (GUID): C35223A0-E004-474E-8B79-230B64658AB0
</span></span><span class="line"><span class="cl">Partition table holds up to 128 entries
</span></span><span class="line"><span class="cl">Main partition table begins at sector 2 and ends at sector 33
</span></span><span class="line"><span class="cl">First usable sector is 34, last usable sector is 977105026
</span></span><span class="line"><span class="cl">Partitions will be aligned on 2048-sector boundaries
</span></span><span class="line"><span class="cl">Total free space is 2014 sectors (1007.0 KiB)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Number  Start (sector)    End (sector)  Size       Code  Name
</span></span><span class="line"><span class="cl">   1            2048          411647   200.0 MiB   EF00  EFI System
</span></span><span class="line"><span class="cl">   2          411648        42354687   20.0 GiB    8200  Linux swap
</span></span><span class="line"><span class="cl">   3        42354688       977105026   445.7 GiB   8300  Linux filesystem
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Command (? for help): q
</span></span></code></pre></div><p>So, everything is now set up on disk, it is time to build our filesystems.</p>
<h1 id="part-3---filesystems">Part 3 - Filesystems<a href="#part-3---filesystems" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>With our disk structures on place, let&rsquo;s talk about our filesystems. There will
be three &ldquo;main&rdquo; ones, but it gets a bit more complex than that. First, let&rsquo;s
start by setting up our new EFI System Partition</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">mkfs.vfat /dev/sda1
</span></span></code></pre></div><p>That solves that issue, next we need to set up our two encrypted partitions.
Despite the fact that we are going to use keyfiles, we should still establish a
typed passphrase in the event we need to tweak the partitions from outside the
operating system built on it. After setting up the encryption, we open each
encrypted container and assign it a friendly name to work with.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cryptsetup luksFormat /dev/sda2
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Enter passphrase:
</span></span><span class="line"><span class="cl">Verify passphrase:
</span></span><span class="line"><span class="cl">Command successful.
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cryptsetup luksFormat /dev/sda3
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Enter passphrase:
</span></span><span class="line"><span class="cl">Verify passphrase:
</span></span><span class="line"><span class="cl">Command successful.
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cryptsetup luksOpen /dev/sda2 nixos-swap
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Enter passphrase:
</span></span><span class="line"><span class="cl">Command successful.
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cryptsetup luksOpen /dev/sda3 nixos-root
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Enter passphrase:
</span></span><span class="line"><span class="cl">Command successful.
</span></span></code></pre></div><p>Okay, so now we have our containers. Next step is to form the basic filesystems
inside of each one. Swap on our swap device, ZFS on our ZFS device. It is
important that we use the <code>/dev/disk/by-id/</code> entry with the UUID specification
<em>and</em> the friendly name of the device. This makes identifying things easier when
we work with them, and helps ZFS to understand what exactly is going on.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">mkswap /dev/disk/by-id/dm-uuid-CRYPT-LUKS1-deadbeef-nixos-swap
</span></span></code></pre></div><p>Before we get to the ZFS setup, I&rsquo;d like to explain the options I am using.
While the explanations are available on the wiki page, they are restated here
for brevity.</p>
<ul>
<li><code>-O compression=lz4</code> - Disk space on an SSD is more valuable than CPU time.
Using LZ4 will not impact the user experience to any discernible degree.</li>
<li><code>-O normalization=formD</code> - Our whole filesystem will be in Unicode with
this. While not really required, it could let you do some interesting things,
and in general I like to use Unicode wherever possible.</li>
<li><code>-O xattr=sa</code> - Boost performance with certain file attributes, this could
become useful if I ever attempt system hardening (I likely will at some point)</li>
<li><code>-O acltype=posixacl</code> - Required for <code>systemd-journald</code></li>
<li><code>-O mountpoint=none</code> - This turns off ZFS&rsquo; automount machinery. In certain
instances, ZFS&rsquo; and NixOS&rsquo; boot time automounting machinery could trigger a
race condition and prevent the system from booting. This allows us you bypass
that potential completely.</li>
<li><code>-o ashift=12</code> - Force 4K sectors. It is very likely ZFS would have done
this anyways, but instead of risking the chance that it would read the
hardware incorrectly, I just manually declare it.</li>
</ul>
<p>So, with that out of the way, here is what our nice bulky <code>zpool</code> creation
command looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">zpool create -O <span class="nv">compression</span><span class="o">=</span>lz4 -O <span class="nv">normalization</span><span class="o">=</span>formD -O <span class="nv">xattr</span><span class="o">=</span>sa -O <span class="nv">acltype</span><span class="o">=</span>posixacl -O <span class="nv">mountpoint</span><span class="o">=</span>none -o <span class="nv">ashift</span><span class="o">=</span><span class="m">12</span> zroot /dev/disk/by-id/dm-uuid-CRYPT-LUKS1-deadbeef-nixos-root
</span></span></code></pre></div><p>With our zpool initialized, next we need to form the filesystems under it. We
will do three things. First, we will create a separate dataset for our <code>/home</code>
directory, so that user data is kept somewhere separate from the root partition.
Next, we will define a <code>root</code> dataset, and within that, a <code>nixos</code> dataset. This
means, should we ever want to, we could run multiple distributions off of the
same ZPool by nesting them under the <code>root</code> dataset, and pointing their <code>/home</code>
at our home dataset. Is it likely we will ever do this? No, but it would be nice
to have if we ever decided to try it!</p>
<p>Once again, we set our mount points to legacy to ensure that the automount
machinery has absolutely nothing to go on, preventing it from firing during
boot.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">zfs create -o <span class="nv">mountpoint</span><span class="o">=</span>none zroot/root
</span></span><span class="line"><span class="cl">zfs create -o <span class="nv">mountpoint</span><span class="o">=</span>legacy zroot/root/nixos
</span></span><span class="line"><span class="cl">zfs create -o <span class="nv">mountpoint</span><span class="o">=</span>legacy zroot/home
</span></span></code></pre></div><p>Where does this leave us? As of right now, we have our EFI System Partition,
freshly created with nothing on it. We have our Swap Partition, nested within a
LUKS encrypted volume, and we have our three ZFS datasets, within our <code>zroot</code>
zpool, within a LUKS encrypted volume.</p>
<p>Not yet done, we need to mount everything to the proper locations, and then do
some additional work to make sure everything will boot as we want it to. To
begin with, we will set up the easy ZFS mount points. Next, we need to mount our
EFI System Partition to <code>/mnt/efi</code>. We do this because it will allow GRUB to
write to the EFI partition, and have that point to our actual, <em>encrypted</em> boot
directory, which we also create here. Lastly, for some additional work we will
do here in a moment, we manually create the <code>/root</code> directory.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">mount -t zfs zroot/root/nixos /mnt
</span></span><span class="line"><span class="cl">mkdir /mnt/home
</span></span><span class="line"><span class="cl">mount -t zfs zroot/home /mnt/home
</span></span><span class="line"><span class="cl">mkdir /mnt/efi
</span></span><span class="line"><span class="cl">mount /dev/sda1 /mnt/efi
</span></span><span class="line"><span class="cl">mkdir /mnt/boot
</span></span><span class="line"><span class="cl">mkdir /mnt/root
</span></span></code></pre></div><p>Now, we mentioned above that we would like to have the system automatically
unlock. This is secure, because before we can even access GRUB directly, we will
have to type in our decryption passphrase for our nixos-root partition.
Essentially, everything we are about to do will be encrypted based on that
master passphrase anyways, so there&rsquo;s no real chance of a leak occurring.</p>
<p>To do this, we will create two binary keyfiles. <code>swap.key</code> will be the binary
key for the Swap partition, and <code>root.key</code> the binary key for the root
partition. We will use LUKS to assign those keys to their respective LUKS
encrypted volumes, allowing the volumes to be decrypted both with a binary
keyfile and a passphrase. The <code>root.key</code> file will then be packaged into a CPIO
archive, and GRUB will append this to the initrd image made by NixOS.</p>
<p>During boot, we will type in our master password to unlock GRUB, select our boot
entry, and then GRUB will hand over control to the initrd after appending our
CPIO archive. During boot, the initrd will unlock <code>/dev/sda3</code> using <code>root.key</code>
and then hand over control to <code>systemd</code>. SystemD will continue the boot, and
then load <code>swap.key</code> to unlock the swap partition. Since the swap partition is
not encrypted randomly each time, this process can be repeated, thus enabling
hibernation to function properly.</p>
<p>The end result of all of this is that a single master passphrase only needs to
be entered once to allow the system to boot properly. Without this method, we
would have to re-enter the <code>nixos-root</code> passphrase twice, and the <code>nixos-swap</code>
passphrase once. I am not sure, but this also might break our hibernation
capabilities.</p>
<p>Let&rsquo;s get started. First we will create our binary keyfiles from <code>/dev/urandom</code>,
then assign them to the volumes, then create the CPIO archive and stash it where
it needs to be.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">dd <span class="nv">count</span><span class="o">=</span><span class="m">4096</span> <span class="nv">bs</span><span class="o">=</span><span class="m">1</span> <span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>/mnt/root/root.key
</span></span><span class="line"><span class="cl">dd <span class="nv">count</span><span class="o">=</span><span class="m">4096</span> <span class="nv">bs</span><span class="o">=</span><span class="m">1</span> <span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>/mnt/root/swap.key
</span></span><span class="line"><span class="cl">cryptsetup luksAddKey /dev/sda2 /mnt/root/swap.key
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Enter passphrase:
</span></span><span class="line"><span class="cl">Command successful.
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cryptsetup luksAddKey /dev/sda3 /mnt/root/root.key
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Enter passphrase:
</span></span><span class="line"><span class="cl">Command successful.
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">cd</span> /mnt/root
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> ./root.key <span class="p">|</span> cpio -o -H newc -R +0:+0 --reproducible <span class="p">|</span> gzip -9 &gt; /mnt/boot/initrd.keys.gz
</span></span></code></pre></div><p>With that last string of commands, we are all set. To recap what was
accomplished in this section:</p>
<ul>
<li>We created the FAT filesystem for our EFI System Partition</li>
<li>LUKS formatted /dev/sda2 and /dev/sda3 with a passphrase</li>
<li>Opened /dev/sda2 and /dev/sda3 and assigned them to nixos-swap and nixos-root, respectively</li>
<li>Created a swap FS on nixos-swap</li>
<li>Created a zpool on nixos-root</li>
<li>Created 3 datasets on nixos-root</li>
<li>Mounted everything correctly</li>
<li>Generated 2 binary keyfiles</li>
<li>Assigned each binary keyfile to its respective partition</li>
<li>Generated a CPIO archive for our initrd.</li>
</ul>
<p>It&rsquo;s time to move on to installing NixOS and configuring it to make use of our
work.</p>
<h1 id="end-of-part-1">End of Part 1<a href="#end-of-part-1" class="anchor" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
      stroke-linecap="round" stroke-linejoin="round" class="feather">
      <path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
      <line x1="8" y1="12" x2="16" y2="12"></line>
   </svg></a></h1>
<p>While I had intended for us to have a system up and running by the end of part
one, this post is close to breaking 600 lines, and to be completely honest, this
is the most I have written in quite a while. Part 2 will cover getting the
system up and running, as well as a little preview of what our
<code>configuration.nix</code> file will look like. Expect that installment to be quite a
bit smaller than this one. Finally, part 3 will deal with the initial
declarative configuration of our <code>/home</code> directory.</p>
<p>The end goal is that all user data will end up kept in a <code>~/.library</code> directory,
similar to the <code>nix-store</code>, and upon login, a symbolic-link farm will be built
according to our declarative home-management system. In this way, everything,
from <code>/etc/nixos</code> to various dotfiles will be kept in an easy to understand
layout, and just linked to their less-easy to understand directories by the
derivation created by home-management.</p>
<p>But, for another time.</p>
]]></content></item></channel></rss>