<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Nixos-Anywhere on Haseeb Majid</title>
    <link>https://haseebmajid.dev/tags/nixos-anywhere/</link>
    <description>Recent content in Nixos-Anywhere on Haseeb Majid</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 31 Dec 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://haseebmajid.dev/tags/nixos-anywhere/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to Setup a New PC With Lanzaboote, TPM Decryption, sops-nix, Impermanence and nixos-anywhere</title>
      <link>https://haseebmajid.dev/posts/2025-12-31-how-to-setup-a-new-pc-with-lanzaboote-tpm-decryption-sops-nix-impermanence-nixos-anywhere/</link>
      <pubDate>Wed, 31 Dec 2025 00:00:00 +0000</pubDate>
      
      <guid>https://haseebmajid.dev/posts/2025-12-31-how-to-setup-a-new-pc-with-lanzaboote-tpm-decryption-sops-nix-impermanence-nixos-anywhere/</guid>
      <description>&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;details
  class=&#34;notice warning&#34;
  open=&#34;true&#34;
&gt;
    &lt;summary class=&#34;notice-title&#34;&gt;Be Careful&lt;/summary&gt;
  
  &lt;p&gt;Make sure if you follow this guide you could lose your data. Make sure to back up whatever important data you have.
Or do what I did and test this on a new device where it doesn&amp;rsquo;t matter if something goes wrong.&lt;/p&gt;
&lt;p&gt;But don&amp;rsquo;t try to do this on a machine that has important data, or you need to use day to day. Though I was able to
set up a new laptop in about 20 mins once I got everything working. It can be fiddly.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="background">Background</h2>
<details
  class="notice warning"
  open="true"
>
    <summary class="notice-title">Be Careful</summary>
  
  <p>Make sure if you follow this guide you could lose your data. Make sure to back up whatever important data you have.
Or do what I did and test this on a new device where it doesn&rsquo;t matter if something goes wrong.</p>
<p>But don&rsquo;t try to do this on a machine that has important data, or you need to use day to day. Though I was able to
set up a new laptop in about 20 mins once I got everything working. It can be fiddly.</p>

</details>

<p>Since finishing the second round of development on my game/web app banter bus (currently not deployed anywhere since I took down
my k8s cluster), I have been looking for something else to sink my teeth into.</p>
<p>I decided I was going to sell my custom-built PC and then use the money to get a Framework desktop.
So I thought I might as well go with something simpler that would work just as well for development.</p>
<p>As part of this, I decided to finally tackle some of the tasks I wanted to complete with my Nix configuration. Mainly
setting up <a href="https://wiki.nixos.org/wiki/Impermanence">impermanence</a>, which means files we don&rsquo;t persist will get deleted
across reboots, forcing us to specify more of our machine in config/nix code. I haven&rsquo;t done this yet with home-manager,
but will at some point do that as well, though that will take much more effort and also be more dangerous.</p>
<p>Whilst doing this, I decided that I would also like to set up Secure Boot with <a href="https://github.com/nix-community/lanzaboote">Lanzaboote</a>
and LUKS but using TPM decryption, vs needing to type in a LUKS password then another password to login.</p>
<p>I set up my new device using nixos-anywhere, a great tool when you have a well-defined nix config to build from, which
can build and install NixOS on a device if it can SSH to it. My favourite tool for installing NixOS whenever I need to
(probably more often than I&rsquo;d like to admit). Whilst this all worked great and eventually I managed to get my setup
working, I am writing this blog post on my new Framework Desktop. I wondered if we could cut down the number of manual
steps, originally inspired by <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>However, I hit some issues with all of the tools above playing nice. Mostly sops-nix with impermanence, getting
the SSH keys on the machine so I could use my secrets. In this increasingly long blog post, I will show you how I got it
set up. I won&rsquo;t go into lots of detail about each specific tool. I will assume you are somewhat familiar with them.
Each could have their own blog post (or maybe YouTube video; I should start creating videos again, I think).</p>
<p>I will show you the final config I managed, with minimal manual effort needed. This should work on any Framework
device (especially the Secure Boot part).</p>
<h2 id="config">Config</h2>
<p>Now I&rsquo;ll quickly show you how I have set up my Nix config for the various tools above. These configurations are interdependent: impermanence creates the persist structure, sops-nix needs persisted SSH keys for decryption, and Lanzaboote needs persisted signing keys for Secure Boot. Link to my <a href="https://gitlab.com/hmajid2301/nixicle/-/tree/7ffe47fb27c804383d5c53405e918f7b4749bfaf">config</a> (at the point I published this article).</p>
<details
  class="notice info"
  open="true"
>
    <summary class="notice-title">One Disk</summary>
  
  My setup also assumes you are just setting up a single disk, i.e., one NVMe.
</details>

<h3 id="sops-nix">sops-nix</h3>
<p>When we have secrets that we don&rsquo;t want to keep in plaintext, we can use sops to encrypt the data with our age/SSH keys.
Either host key for NixOS secrets or our age key for home-manager related secrets. For example, for defining the user&rsquo;s
password, which in our secrets.yaml file looks like <code>user_password: ENC[AES256_GCM,data:wSbEwtgPzM1FLYAb3rMCXneXJr2xM4w4lydvwA+DDP1i4DNPKQvC7VUKe00wIp3rDhjLTept/WA8uIGEJsPaf30/iYc2txdDWVvjDL81UnXtIfFoXKsYWQ7vrftShMJckByMiD5uZoYkSA==,iv:0YpQ5RL5CSjfS6jfpZArore25jn42uW3IRr8xLK/798=,tag:oVyxq1uIsKfV/HQWum6LQA==,type:str]</code>. But this can be decrypted by our Nix config and stored at <code>/run/secrets</code> (and other folders next to it).</p>
<p>This means when we do a nixos-anywhere install, we need to send it relevant SSH keys/age keys so that it can decrypt
our secrets such that we can log in. Otherwise, there will be no secret and we won&rsquo;t be able to log in to our machine.</p>
<p>In my <code>hosts/framework/default.nix</code> config I have:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">sops</span><span class="o">.</span><span class="n">secrets</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_password</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">sopsFile</span> <span class="o">=</span> <span class="sr">./secrets.yaml</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">neededForUsers</span> <span class="o">=</span> <span class="no">true</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></span><span class="line"><span class="cl">  <span class="n">user</span><span class="o">.</span><span class="n">passwordSecretFile</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">sops</span><span class="o">.</span><span class="n">secrets</span><span class="o">.</span><span class="n">user_password</span><span class="o">.</span><span class="n">path</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And then when defining users, we can do something like this in <code>modules/nixos/user/default.nix</code>, where we can define the hash of the password above:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">users</span><span class="o">.</span><span class="n">mutableUsers</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">users</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="si">${</span><span class="n">cfg</span><span class="o">.</span><span class="n">name</span><span class="si">}</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">hashedPasswordFile</span> <span class="o">=</span> <span class="n">cfg</span><span class="o">.</span><span class="n">passwordSecretFile</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And finally my <code>modules/nixos/security/sops/default.nix</code> config:</p>
<p>I reference this file in the persist, which I&rsquo;m not sure I need to do:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">sops</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">age</span><span class="o">.</span><span class="n">sshKeyPaths</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">&#34;/persist/etc/ssh/ssh_host_ed25519_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></code></pre></div><h3 id="lanzaboote-secure-boot">Lanzaboote (Secure Boot)</h3>
<p>We will use Lanzaboote so we can enable Secure Boot.</p>
<blockquote>
<p>Secure Boot usually refers to a platform firmware capability to verify the boot components and ensure that only your own operating system is allowed to boot. - NixOS Wiki <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
</blockquote>
<p>Here are the relevant parts of my Nix config <code>modules/nixos/system/boot/default.nix</code> for Secure Boot.
We want to persist the /etc/secureboot folder, which is where our signing keys will be auto-generated by Lanzaboote
on our first boot. We also need to disable systemd-boot if we are using Lanzaboote.</p>
<p>The combination of auto-generate keys and auto-enroll means fewer manual steps we need to take post-install to enable
Secure Boot. However, the first time I did this, I did set this up manually following the Lanzaboote getting started guide.
Do whichever you prefer; it&rsquo;s not like it&rsquo;s many steps anyway.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">boot</span><span class="o">.</span><span class="n">lanzaboote</span> <span class="o">=</span> <span class="n">mkIf</span> <span class="n">cfg</span><span class="o">.</span><span class="n">secureBoot</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">pkiBundle</span> <span class="o">=</span> <span class="s2">&#34;/etc/secureboot&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">autoGenerateKeys</span><span class="o">.</span><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">autoEnrollKeys</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">autoReboot</span> <span class="o">=</span> <span class="no">true</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></span><span class="line"><span class="cl">  <span class="n">boot</span><span class="o">.</span><span class="n">systemd-boot</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">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">configurationLimit</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">editor</span> <span class="o">=</span> <span class="no">false</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></span><span class="line"><span class="cl">  <span class="n">environment</span><span class="o">.</span><span class="n">persistence</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;/persist&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">directories</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;/etc/secureboot&#34;</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><h3 id="impermanence">Impermanence</h3>
<p>My <a href="https://gitlab.com/hmajid2301/nixicle/-/blob/7ffe47fb27c804383d5c53405e918f7b4749bfaf/modules/nixos/system/impermanence/default.nix#L1">impermanence module</a> is longish,
so I won&rsquo;t go into lots of details. But we use btrfs to be able to roll back to a clean state, then copy files we specify
in our <code>persist</code> btrfs subvolume.</p>
<h4 id="disko">disko</h4>
<p>I use disko with nixos-anywhere to be able to partition my disks without lots of manual commands. Here is <a href="https://gitlab.com/hmajid2301/nixicle/-/blob/7ffe47fb27c804383d5c53405e918f7b4749bfaf/hosts/framework/disks.nix">my disko config</a>.
You can see the subvolumes we create for our btrfs setup, i.e., <code>/persist</code> for persisting files between reboots.</p>
<p>Here is where I define my LUKS settings as well, so that our data will be encrypted at rest (full-disk encryption).</p>
<h3 id="pcr-15">PCR 15</h3>
<details
  class="notice warning"
  open="true"
>
    <summary class="notice-title">TPM</summary>
  
  <p>Take what I say here with a grain of salt; this is all based on my understanding.
This is from reading articles, and a bit of asking Claude to explain/draw stuff to make it more visual.</p>
<p>I have linked a few articles/videos that I found useful.</p>

</details>

<p>Eventually, we will want to enroll TPM to decrypt LUKS so that it is decrypted automatically but will only work with our
TPM chip soldered onto our motherboard. Part of this will be specifying the PCRs. I don&rsquo;t know loads about how it works.</p>
<p><a href="https://wiki.archlinux.org/title/Trusted_Platform_Module#Accessing_PCR_registers">PCR</a>, Platform Configuration Registers.</p>
<blockquote>
<p>Platform Configuration Registers (PCR) allow binding of the encryption of secrets to specific software versions and system state via hashes, so that the enrolled key is only accessible (may be &ldquo;unsealed&rdquo;) if specific trusted software and/or configuration is used. - Arch Wiki</p>
</blockquote>
<p>We check the previous registers before we give access to the data inside the TPM, i.e., our LUKS password stored inside
the TPM. There is a really good post <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> about how TPM decryption might not be secure enough, though I don&rsquo;t think we need
to worry about PCR 9 <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> (due to checksums on initrd, from what I understand anyway).</p>
<p>I may do a longer post about how this all works when I learn more myself. But if we don&rsquo;t check PCR 15, someone could
just copy the metadata and pretend they have our disk, assuming they have physical access to our PC. The TPM
is not checking the PCR 15 value, so therefore would just spit out our LUKS password, which they could then use
on our original disk. Now, of course, this all depends on your threat model, but I thought it&rsquo;d be fun to fix this issue,
at least on my laptop.</p>
<p>So I copied the <a href="https://forge.lel.lol/patrick/nix-config/src/commit/ab2cb2b4d554040ce208fc60624fe729a9d5e32b/modules/ensure-pcr.nix">module</a>.
Until the expected option is configured, it won&rsquo;t do anything; we won&rsquo;t know this until the system has been built.
So it&rsquo;ll be one more manual step we need to take, but perhaps worth it to make my system more secure.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">security</span><span class="o">.</span><span class="n">nixicle</span><span class="o">.</span><span class="n">pcr-verification</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="c1"># expectedPcr15 = &#34;caf33e79c645b65849256238a11fa68ae197e5cb89730c463c1cdf1d9128376f&#34;;</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="steps">Steps</h2>
<p>Now onto how I deploy NixOS onto a new system/device with all the above playing nice and reducing the number of
manual steps we need to take. Normally, I had Claude create some scripts I can use with <code>go-task</code>, but for the sake
of this blog post, we will do it step by step, i.e., normally I would do <code>task install:secure</code>. Where we could then
follow the script using <a href="https://github.com/charmbracelet/gum">charm&rsquo;s gum</a> to make nice interactive scripts.
This includes info like the username, IP to SSH onto.</p>
<p>Anyway, make sure the device can be SSH&rsquo;d onto; usually you can just use a live media USB. I build my own with nixos-generators.
But any live media should be fine; use NixOS if you don&rsquo;t have anything set up. I do something like this:
<code>mkdir -p ~/.ssh &amp;&amp; curl https://github.com/hmajid2301.keys &gt; ~/.ssh/authorized_keys</code>, so that I can SSH onto the live
media. Also, take note of the IP address of the machine; you can find this by running <code>ip addr</code>.</p>
<p>For example, on my local network it might be <code>192.168.1.71</code>.</p>
<h3 id="install">Install</h3>
<p>Enter our encryption password to a file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">MY_PASS</span><span class="o">=</span><span class="k">$(</span>mktemp<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;YOUR_LUKS_PASSWORD&#34;</span> &gt; <span class="nv">$MY_PASS</span>
</span></span></code></pre></div><p>Get SSH keys ready for copying onto the new machine; this is so that sops can decrypt the various secrets. Either you
can copy the existing SSH keys and replace them after, or you can generate new ones and update your sops config and sops
files with these new keys. The latter is the more secure option, but I went with the first one as I was feeling lazy
(security through inconvenience is still security, right? Right?):</p>
<blockquote>
<p>Note: If this is your first installation and you don&rsquo;t have existing SSH keys at <code>/persist/etc/ssh/</code>, you can either generate temporary keys or skip this step and regenerate your secrets after installation with the new host keys that will be created.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">SSH_KEYS</span><span class="o">=</span><span class="k">$(</span>mktemp -d<span class="k">)</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">/persist/etc/ssh&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo cp /persist/etc/ssh/ssh_host_ed25519_key <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">/persist/etc/ssh/&#34;</span>
</span></span><span class="line"><span class="cl">sudo cp /persist/etc/ssh/ssh_host_ed25519_key.pub <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">/persist/etc/ssh/&#34;</span>
</span></span><span class="line"><span class="cl">sudo cp /persist/etc/ssh/ssh_host_rsa_key <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">/persist/etc/ssh/&#34;</span> 2&gt;/dev/null
</span></span><span class="line"><span class="cl">sudo cp /persist/etc/ssh/ssh_host_rsa_key.pub <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">/persist/etc/ssh/&#34;</span> 2&gt;/dev/null
</span></span></code></pre></div><p>Update permissions on the SSH keys folder:</p>
<blockquote>
<p>Note: This step is crucial for sops-nix to work with impermanence. If you skip this, you&rsquo;ll need to re-encrypt your secrets with new host keys.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo chmod <span class="m">600</span> <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">/persist/etc/ssh&#34;</span>/ssh_host_*_key 2&gt;/dev/null
</span></span><span class="line"><span class="cl">sudo chown -R <span class="k">$(</span>id -u<span class="k">)</span>:<span class="k">$(</span>id -g<span class="k">)</span> <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">&#34;</span>
</span></span></code></pre></div><p>Then finally we can start the install process:</p>
<blockquote>
<p>Note: Update the username@host as needed, nixos is the default user for the NixOS ISO.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nixos-anywhere <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--flake <span class="s2">&#34;.#framework&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--disk-encryption-keys /tmp/disk-encryption.key <span class="s2">&#34;</span><span class="nv">$MY_PASS</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--extra-files <span class="s2">&#34;</span><span class="nv">$SSH_KEYS</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--build-on-remote <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="s2">&#34;nixos@192.168.1.71&#34;</span>
</span></span></code></pre></div><h3 id="post-install">Post Install</h3>
<p>After the command is done, your PC will reboot. At this point, you can start to get it ready for Secure Boot if you want.
For a Framework laptop to enable Secure Boot, first we need to erase the Secure Boot settings.</p>
<p>It may differ on your device:</p>
<pre tabindex="0"><code>Framework-specific: Enter Setup Mode

On Framework you can enter the setup mode like this:

    Select &#34;Administer Secure Boot&#34;
    Select &#34;Erase all Secure Boot Settings&#34;

When you are done, press F10 to save and exit.
</code></pre><p>Then enter your password for LUKS so it can decrypt your drive and boot like normal. You will see your PC reboot
due to the auto-reboot we set above with Lanzaboote. That&rsquo;s fine; it&rsquo;s all very normal.
If your computer starts speaking Latin or emitting smoke, that&rsquo;s NOT normal. Please consult a priest or your local fire department.</p>
<p>On my Framework device, it then told me it&rsquo;s going to enroll my keys, and I didn&rsquo;t interrupt the process.
Then I logged into my device and enabled TPM decryption:</p>
<blockquote>
<p>Note: Replace <code>/dev/nvme0n1p2</code> with your actual LUKS partition. Check your disko config to confirm the correct partition path.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># The --tpm2-pcrs=15:sha256=0000... uses all zeros as a placeholder that will be updated after first boot</span>
</span></span><span class="line"><span class="cl">sudo systemd-cryptenroll /dev/nvme0n1p2 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --wipe-slot<span class="o">=</span>tpm2 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --tpm2-device<span class="o">=</span>auto <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --tpm2-pcrs<span class="o">=</span>0+2+7 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --tpm2-pcrs<span class="o">=</span>15:sha256<span class="o">=</span><span class="m">0000000000000000000000000000000000000000000000000000000000000000</span>
</span></span></code></pre></div><p>Check and make sure it all looks normal; you should see files signed (except perhaps one old one):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">❯ sudo -E sbctl verify
</span></span><span class="line"><span class="cl"><span class="o">[</span>sudo<span class="o">]</span> password <span class="k">for</span> haseeb:
</span></span><span class="line"><span class="cl">Verifying file database and EFI images in /boot...
</span></span><span class="line"><span class="cl">✓ /boot/EFI/BOOT/BOOTX64.EFI is signed
</span></span><span class="line"><span class="cl">✓ /boot/EFI/Linux/nixos-generation-40-7ik2vgrngo25ml7c2wb43uy52pt7ahpovfrrxczp445y76u56dlq.efi is signed
</span></span><span class="line"><span class="cl">✗ /boot/EFI/nixos/kernel-6.18.2-otn6nn3tkudhh5xpj5736u2q3h4kjzojd6fkg4rqzdf5l5c7gxuq.efi is not signed
</span></span><span class="line"><span class="cl">✓ /boot/EFI/systemd/systemd-bootx64.efi is signed
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verify Secure Boot is working</span>
</span></span><span class="line"><span class="cl">sudo bootctl status
</span></span></code></pre></div><p>Now we can enable Secure Boot; again, this may vary on your device.</p>
<pre tabindex="0"><code>On Framework you need to manually enable Secure Boot:

    Select &#34;Administer Secure Boot&#34;
    Enable &#34;Enforce Secure Boot&#34;

When you are done, press F10 to save and exit.
</code></pre><p>Finally, after logging in again, we can run the following to get the actual PCR 15 hash value:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">❯ systemd-analyze pcrs <span class="m">15</span> --json<span class="o">=</span>short
</span></span><span class="line"><span class="cl"><span class="o">[{</span><span class="s2">&#34;nr&#34;</span>:15,<span class="s2">&#34;name&#34;</span>:<span class="s2">&#34;system-identity&#34;</span>,<span class="s2">&#34;sha256&#34;</span>:<span class="s2">&#34;0000000000000000000000000000000000000000000000000000000000000000&#34;</span><span class="o">}]</span>
</span></span></code></pre></div><p>Take the sha256 value from this output and update your config&rsquo;s <code>security.nixicle.pcr-verification.expectedPcr15</code> field with the actual hash, then run:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo nixos-rebuild switch --flake .#framework
</span></span></code></pre></div><p>Then, of course, go about setting up everything else. If you copied existing SSH keys during installation,
you may want to rotate them for better security by generating new host keys and re-encrypting your sops secrets with the new keys.</p>
<p>That&rsquo;s it! Hopefully, you found that useful! I appreciate it was very long-winded, but that&rsquo;s how I was able to do a mostly
unattended install with few manual steps after getting the process started.
If you made it this far, you deserve a cookie 🍪 (or at least a functioning NixOS installation).</p>
<h2 id="appendix">Appendix</h2>
<p>I had to do a bunch of research whilst working on this; here are some useful links I used:</p>
<ul>
<li>A really interesting post about how you can break TPM encryption with Secure Boot: <a href="https://oddlama.org/blog/bypassing-disk-encryption-with-tpm2-unlock/#crude-implementation-of-pcr15-verification">https://oddlama.org/blog/bypassing-disk-encryption-with-tpm2-unlock/#crude-implementation-of-pcr15-verification</a></li>
<li>Lanzaboote getting started guide: <a href="https://github.com/nix-community/lanzaboote/blob/master/docs/getting-started/enable-secure-boot.md">https://github.com/nix-community/lanzaboote/blob/master/docs/getting-started/enable-secure-boot.md</a></li>
<li>Idea for copying SSH keys: <a href="https://github.com/nix-community/nixos-anywhere/issues/604">https://github.com/nix-community/nixos-anywhere/issues/604</a></li>
<li>nixos-anywhere SSH keys copy: <a href="https://github.com/nix-community/nixos-anywhere/blob/main/docs/howtos/secrets.md#example-decrypting-an-openssh-host-key-with-pass">https://github.com/nix-community/nixos-anywhere/blob/main/docs/howtos/secrets.md#example-decrypting-an-openssh-host-key-with-pass</a></li>
<li>Discourse post with same issue as mine: <a href="https://discourse.nixos.org/t/impermanence-sops-nix-nixos-anywhere-lead-to-missing-hashedpasswordfile-s/66472">https://discourse.nixos.org/t/impermanence-sops-nix-nixos-anywhere-lead-to-missing-hashedpasswordfile-s/66472</a></li>
<li>Another discourse post with a similar issue: <a href="https://discourse.nixos.org/t/nixos-anywhere-failing-to-deploy-secrets/68392">https://discourse.nixos.org/t/nixos-anywhere-failing-to-deploy-secrets/68392</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://ryanseipp.com/posts/nixos-automated-deployment/">https://ryanseipp.com/posts/nixos-automated-deployment/</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://wiki.nixos.org/wiki/Secure_Boot">https://wiki.nixos.org/wiki/Secure_Boot</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://oddlama.org/blog/bypassing-disk-encryption-with-tpm2-unlock/#crude-implementation-of-pcr15-verification">https://oddlama.org/blog/bypassing-disk-encryption-with-tpm2-unlock/#crude-implementation-of-pcr15-verification</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://www.youtube.com/watch?v=hXblxnDS6eU">https://www.youtube.com/watch?v=hXblxnDS6eU</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>Part 5B: Installing Our Nix Configuration (NixOS Anywhere) as Part of Your Workflow</title>
      <link>https://haseebmajid.dev/posts/2024-05-02-part-5b-installing-our-nix-configuration-as-part-of-your-workflow/</link>
      <pubDate>Thu, 02 May 2024 00:00:00 +0000</pubDate>
      
      <guid>https://haseebmajid.dev/posts/2024-05-02-part-5b-installing-our-nix-configuration-as-part-of-your-workflow/</guid>
      <description>&lt;p&gt;I wanted to do a short article showing you how you can use your Nix config to install NixOS on a new device. Have your
device setup with NixOS in a few commands with all the packages and tooling you want.&lt;/p&gt;
&lt;p&gt;Previously I was creating my own ISO and then burning that to a USB and using that USB as live media to install my config.
I had a &lt;a href=&#34;https://gitlab.com/hmajid2301/dotfiles/-/blob/3371d7774c133a36d4986a9dcaeb972d4e4638a2/hosts/iso/configuration.nix#L73&#34;&gt; custom script &lt;/a&gt;
&lt;code&gt;nix_installer&lt;/code&gt;, which would run automatically when you loaded into the gnome shell.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I wanted to do a short article showing you how you can use your Nix config to install NixOS on a new device. Have your
device setup with NixOS in a few commands with all the packages and tooling you want.</p>
<p>Previously I was creating my own ISO and then burning that to a USB and using that USB as live media to install my config.
I had a <a href="https://gitlab.com/hmajid2301/dotfiles/-/blob/3371d7774c133a36d4986a9dcaeb972d4e4638a2/hosts/iso/configuration.nix#L73"> custom script </a>
<code>nix_installer</code>, which would run automatically when you loaded into the gnome shell.</p>
<p>However, I think I have found a slightly better way to do this, recently (earlier this week). This is the process I used
recently to reinstall my workstation. We will be doing this using this really cool tool
<a href="https://github.com/nix-community/nixos-anywhere">nixos-anywhere</a>. Which involves installing our config using SSH.</p>
<blockquote>
<p>Note you can still generate an ISO using the snowfall library, but I haven&rsquo;t tested it yet with my config.</p>
</blockquote>
<h2 id="what-do-you-need">What do you need?</h2>
<ul>
<li>Nix configuration: The nix configuration we want to install</li>
<li>Two devices</li>
<li>Target device: My personal desktop, this is where we will install the config onto
<ul>
<li>Need to be able to connect to this from the source device</li>
</ul>
</li>
<li>Source device: My laptop, which can connect to my desktop to install the config</li>
<li>Disko configuration: So we know how to partition our disk(s)</li>
</ul>
<h2 id="disko">Disko</h2>
<p>To partition our disks, we can use the fantastic <a href="https://github.com/nix-community/disko">disko tool</a>. Which allows us to
declaratively declare how to partition our disk(s), in nix configuration. Having a look at an example, one I have:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">disko</span><span class="o">.</span><span class="n">devices</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">disk</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">nvme0n1</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">type</span> <span class="o">=</span> <span class="s2">&#34;disk&#34;</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/nvme0n1&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">type</span> <span class="o">=</span> <span class="s2">&#34;gpt&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="n">partitions</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">ESP</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="n">label</span> <span class="o">=</span> <span class="s2">&#34;boot&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">              <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;ESP&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">              <span class="n">size</span> <span class="o">=</span> <span class="s2">&#34;512M&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">              <span class="n">type</span> <span class="o">=</span> <span class="s2">&#34;EF00&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">              <span class="n">content</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">type</span> <span class="o">=</span> <span class="s2">&#34;filesystem&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">format</span> <span class="o">=</span> <span class="s2">&#34;vfat&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/boot&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">mountOptions</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                  <span class="s2">&#34;defaults&#34;</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="n">luks</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="n">size</span> <span class="o">=</span> <span class="s2">&#34;100%&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">              <span class="n">label</span> <span class="o">=</span> <span class="s2">&#34;luks&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">              <span class="n">content</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">type</span> <span class="o">=</span> <span class="s2">&#34;luks&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;cryptroot&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">extraOpenArgs</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                  <span class="s2">&#34;--allow-discards&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="s2">&#34;--perf-no_read_workqueue&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="s2">&#34;--perf-no_write_workqueue&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># https://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html</span>
</span></span><span class="line"><span class="cl">                <span class="n">settings</span> <span class="o">=</span> <span class="p">{</span><span class="n">crypttabExtraOpts</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;fido2-device=auto&#34;</span> <span class="s2">&#34;token-timeout=10&#34;</span><span class="p">];};</span>
</span></span><span class="line"><span class="cl">                <span class="n">content</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                  <span class="n">type</span> <span class="o">=</span> <span class="s2">&#34;btrfs&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                  <span class="n">extraArgs</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;-L&#34;</span> <span class="s2">&#34;nixos&#34;</span> <span class="s2">&#34;-f&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                  <span class="n">subvolumes</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;/root&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountOptions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;subvol=root&#34;</span> <span class="s2">&#34;compress=zstd&#34;</span> <span class="s2">&#34;noatime&#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="s2">&#34;/home&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/home&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountOptions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;subvol=home&#34;</span> <span class="s2">&#34;compress=zstd&#34;</span> <span class="s2">&#34;noatime&#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="s2">&#34;/nix&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/nix&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountOptions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;subvol=nix&#34;</span> <span class="s2">&#34;compress=zstd&#34;</span> <span class="s2">&#34;noatime&#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="s2">&#34;/persist&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/persist&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountOptions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;subvol=persist&#34;</span> <span class="s2">&#34;compress=zstd&#34;</span> <span class="s2">&#34;noatime&#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="s2">&#34;/log&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/var/log&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountOptions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;subvol=log&#34;</span> <span class="s2">&#34;compress=zstd&#34;</span> <span class="s2">&#34;noatime&#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="s2">&#34;/swap&#34;</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                      <span class="n">mountpoint</span> <span class="o">=</span> <span class="s2">&#34;/swap&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                      <span class="n">swap</span><span class="o">.</span><span class="n">swapfile</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="s2">&#34;64G&#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><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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">fileSystems</span><span class="o">.</span><span class="s2">&#34;/persist&#34;</span><span class="o">.</span><span class="n">neededForBoot</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">fileSystems</span><span class="o">.</span><span class="s2">&#34;/var/log&#34;</span><span class="o">.</span><span class="n">neededForBoot</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Here we create a LUKS encrypted using BTRFS. Where we have a bunch of sub volumes intended to be used for impermanence
setup and we even have a swap sub volume.</p>
<p>The cool thing about this it removes the manual partition we would have to-do and now nixos-anywhere can do it for us.
In our system configuration, the disk config is imported like so, in my snowfall-based nix config <code>systems/x86_64-linux/workstation/default.nix</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">pkgs</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">lib</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">  <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">imports</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="sr">./hardware-configuration.nix</span>
</span></span><span class="line"><span class="cl">    <span class="sr">./disks.nix</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="install">Install</h2>
<p>Assuming the target device has no OS on it yet, you can simply boot from the normal NixOS ISO (say gnome). Which provides
us an SSH service we can connect to from our source device (my laptop). You can see more details
<a href="https://github.com/nix-community/nixos-anywhere/blob/main/docs/howtos/no-os.md#installing-on-a-machine-with-no-operating-system">here</a>.</p>
<h3 id="on-target-device">On target device</h3>
<ul>
<li>Boot from live media ISO</li>
<li>Grab IP address <code>ip addr</code>
<ul>
<li>Likely something like <code>192.168.1.8</code> (see output below)</li>
</ul>
</li>
<li>Copy our public SSH keys of the source device and put them into the <code>authorized_keys</code>
<ul>
<li>In my case, I can grab them from GitHub
<ul>
<li><code>mkdir -p ~/.ssh curl https://github.com/hmajid2301.keys &gt; ~/.ssh/authorized_keys</code></li>
</ul>
</li>
</ul>
</li>
<li>Now we can SSH from source to target</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"> ip addr
</span></span><span class="line"><span class="cl">1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu <span class="m">65536</span> qdisc noqueue state UNKNOWN group default qlen <span class="m">1000</span>
</span></span><span class="line"><span class="cl">    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
</span></span><span class="line"><span class="cl">    inet 127.0.0.1/8 scope host lo
</span></span><span class="line"><span class="cl">       valid_lft forever preferred_lft forever
</span></span><span class="line"><span class="cl">    inet6 ::1/128 scope host noprefixroute
</span></span><span class="line"><span class="cl">       valid_lft forever preferred_lft forever
</span></span><span class="line"><span class="cl">2: enp16s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu <span class="m">1500</span> qdisc mq state UP group default qlen <span class="m">1000</span>
</span></span><span class="line"><span class="cl">    link/ether 74:56:3c:bb:2f:41 brd ff:ff:ff:ff:ff:ff
</span></span><span class="line hl"><span class="cl">    inet 192.168.1.8/24 brd 192.168.1.255 scope global noprefixroute enp16s0
</span></span><span class="line"><span class="cl">       valid_lft forever preferred_lft forever
</span></span><span class="line"><span class="cl">    inet6 2a0a:ef40:10f9:e01:b554:c3ad:550d:8fcd/64 scope global temporary dynamic
</span></span><span class="line"><span class="cl">       valid_lft 84920sec preferred_lft 2120sec
</span></span><span class="line"><span class="cl">    inet6 2a0a:ef40:10f9:e01:7135:7af1:7f82:9ac/64 scope global dynamic mngtmpaddr noprefixroute
</span></span><span class="line"><span class="cl">       valid_lft 84920sec preferred_lft 2120sec
</span></span><span class="line"><span class="cl">    inet6 fe80::7203:6b95:514e:c231/64 scope link noprefixroute
</span></span><span class="line"><span class="cl">       valid_lft forever preferred_lft forever
</span></span></code></pre></div><h3 id="on-source-device">On source device</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone git@github.com:hmajid2301/dotfiles.git ~/dotfiles/
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> dotfiles
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">nix develop
</span></span><span class="line"><span class="cl">nixos-anywhere -- --flake <span class="s1">&#39;.#workstation&#39;</span> nixos@192.168.1.8
</span></span></code></pre></div><p>Then follow and answer the question it asks you, like the password to use for LUKS. This is basically a really nice way
we can now install NixOS onto a new or existing device. With minimal effort, in my opinion.</p>
<p><img
        loading="lazy"
        src="/posts/2024-05-02-part-5b-installing-our-nix-configuration-as-part-of-your-workflow/images/nixos-infection.jpeg"
        type=""
        alt="nixos infect"
        
      /></p>
<p><a href="https://old.reddit.com/r/NixOS/comments/1bfc9tm/meme_nixos_infection/">credit for meme</a></p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
