<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Luka Dekanozishvili - Blog posts</title>
    <subtitle>Welcome to my website! Here you&#39;ll find my tech blog, as well as my career path, projects, and hobbies.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://lukadeka.com/blog/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-27T00:00:00+00:00</updated>
    <id>https://lukadeka.com/blog/atom.xml</id>
    <entry xml:lang="en">
        <title>DMARC is not that hard</title>
        <published>2026-09-27T00:00:00+00:00</published>
        <updated>2026-09-27T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/dmarc-is-not-that-hard/"/>
        <id>https://lukadeka.com/blog/dmarc-is-not-that-hard/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/dmarc-is-not-that-hard/">&lt;h2 id=&quot;what-s-dmarc&quot;&gt;What&#39;s DMARC?&lt;/h2&gt;
&lt;p&gt;Domain based Message Authentication, Reporting or Conformance, or DMARC for short,
tells receiving mailservers how to handle mail that fails SPF (who&#39;s allowed to send mail on behalf of this email?), DKIM (did this mail really originate from the domain?), or both, and can provide reporting to help you discover misconfigurations.
If delivering a mail fails, or a mailserver rejects a mail because SPF or DKIM failed (most likely because of spam/scams), if configured, a DMARC report would be sent to the offender. Oftentimes, even if DMARC passes, an email is still sent to the reporting address to signify success.&lt;/p&gt;
&lt;p&gt;The reporting address is specified in a DNS record, e.g.:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_dmarc.example.com. IN TXT &amp;quot;v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Fun fact: &lt;code&gt;IN&lt;/code&gt; stands for internet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;DMARC reports are in XML, and aren&#39;t really human-readable. Take a look at this mess:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;xml&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; version&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; encoding&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt; ?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;feedback&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;report_metadata&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;org_name&lt;/span&gt;&lt;span&gt;&amp;gt;lukadeka.com&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;org_name&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;email&lt;/span&gt;&lt;span&gt;&amp;gt;noreply-dmarc@lukadeka.com&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;email&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;report_id&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;report_id&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;date_range&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;begin&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;begin&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;end&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;end&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;date_range&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;report_metadata&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;policy_published&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;domain&lt;/span&gt;&lt;span&gt;&amp;gt;lukadeka.com&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;domain&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;adkim&lt;/span&gt;&lt;span&gt;&amp;gt;r&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;adkim&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;aspf&lt;/span&gt;&lt;span&gt;&amp;gt;r&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;aspf&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;reject&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;sp&lt;/span&gt;&lt;span&gt;&amp;gt;reject&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;sp&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;fo&lt;/span&gt;&lt;span&gt;&amp;gt;0&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;fo&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;policy_published&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;record&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;row&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;source_ip&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;source_ip&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;count&lt;/span&gt;&lt;span&gt;&amp;gt;2&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;count&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;policy_evaluated&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;disposition&lt;/span&gt;&lt;span&gt;&amp;gt;reject&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;disposition&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;dkim&lt;/span&gt;&lt;span&gt;&amp;gt;fail&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;dkim&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;spf&lt;/span&gt;&lt;span&gt;&amp;gt;fail&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;spf&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;policy_evaluated&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;row&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;identifiers&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;envelope_from&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;envelope_from&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;header_from&lt;/span&gt;&lt;span&gt;&amp;gt;lukadeka.com&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;header_from&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;identifiers&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;auth_results&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;spf&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;domain&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;domain&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;helo&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;result&lt;/span&gt;&lt;span&gt;&amp;gt;none&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;result&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;spf&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;spf&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;domain&lt;/span&gt;&lt;span&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;domain&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;mfrom&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;scope&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;result&lt;/span&gt;&lt;span&gt;&amp;gt;fail&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;result&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;spf&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;auth_results&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;record&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;record&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;record&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;feedback&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, they&#39;re meant to be processed by automatic aggregation tools. Free third party services exist, but Stalwart Mail (the mailserver I use) has a built-in tool. This is a DMARC report received by my mailserver from Google (they love sending me DMARC reports):&lt;/p&gt;
&lt;div class=&quot;center&quot;&gt;
  &lt;img style=&quot;margin: auto;&quot; width=700 src=&quot;/images/stalwart-dmarc.png&quot;/&gt;
&lt;/div&gt;
&lt;h2 id=&quot;how-could-you-mess-this-up&quot;&gt;How could you mess this up?&lt;/h2&gt;
&lt;p&gt;Now that we understand DMARC, we can look at what happened many times in my mailbox.&lt;/p&gt;
&lt;p&gt;My mailserver sends DMARC reports to other mailservers whenever I send an email and it gets delivered.
It&#39;s surprising how many people misconfigure their mailservers where either the address doesn&#39;t exist, or doesn&#39;t accept incoming mails (that&#39;s the whole point!).
In both cases I get a mail from either my mailserver&#39;s mailer daemon or their mailserver that delivery failed.&lt;/p&gt;
&lt;p&gt;I use a catch-all email setup, so I receive (almost) all mails sent at &lt;code&gt;@lukadeka.com&lt;/code&gt;, and these failures end up in my mailbox.&lt;/p&gt;
&lt;p&gt;I even received an automatic mail from a &quot;&lt;strong&gt;Technology Leader&lt;/strong&gt;&quot; from &lt;strong&gt;SAP&lt;/strong&gt;, telling me they were in India, and working from a different timezone:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Thank you for your message. I am travelling and will be working from the Bangalore office from August 24 to August 28 during India hours.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;center&quot;&gt;
  &lt;img style=&quot;margin: auto;&quot; width=300 src=&quot;/images/facepalm.jpg&quot;/&gt;
&lt;/div&gt;
&lt;p&gt;I wonder why the &quot;Technology Leader&quot; never checked why DMARC reports constantly land in their mailbox.&lt;/p&gt;
&lt;p&gt;Other domains included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ashbyhq.com - Job application platform&lt;/li&gt;
&lt;li&gt;cresta.ai - Where I applied for a job&lt;/li&gt;
&lt;li&gt;gozauber.com - Where I applied for a job&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This gave me an idea, to write a follow-up email informing them of the misconfiguration, and offering that I could fix it if they were to hire me, but people don&#39;t get the best first-impression when they&#39;re told they messed up.&lt;/p&gt;
&lt;p&gt;All in all, seeing these mails when I wake up just makes me laugh a little, and I wanted to share that experience.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building an app-unaware multi-app proxy: One domain, many backends</title>
        <published>2026-07-01T00:00:00+00:00</published>
        <updated>2026-07-01T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/building-an-app-unaware-multi-app-proxy/"/>
        <id>https://lukadeka.com/blog/building-an-app-unaware-multi-app-proxy/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/building-an-app-unaware-multi-app-proxy/">&lt;h2 id=&quot;preface&quot;&gt;Preface&lt;/h2&gt;
&lt;p&gt;At my job we provide software, and install sensors for buses/trains/trams that count passengers. The software aggregates the data, allowing it to be analyzed. One of the web-apps communicates directly with all of the sensors of each vehicle of the organization, gathering status, logs, and miscellaneous data. These sensors all have webservers that can be accessed via an IP, e.g. in the browser.&lt;/p&gt;
&lt;p&gt;We have different types of sensors, many of which aren&#39;t manufactured inhouse, so we don&#39;t have control of the web-apps. This appeared to be a nuisance when we wanted the customers to be able to access the sensor applications along with us.&lt;/p&gt;
&lt;h2 id=&quot;proposed-solutions&quot;&gt;Proposed solutions&lt;/h2&gt;
&lt;p&gt;The obvious idea was to grant access to the sensors via a VPN. While being the simplest solution, this was unfortunately rejected because it required each customer to install a VPN client, our provided certificates, and would cause possible complexity for our IT, along with ever-updating ACLs.&lt;/p&gt;
&lt;p&gt;The following idea to &quot;just use a reverse-proxy&quot; wouldn&#39;t work since the customers had way too many sensors to manually maintain one-by-one with a reverse-proxy like nginx. Even though we have many different kinds of sensors, &lt;em&gt;none&lt;/em&gt; of them supported being proxied from a specific path. This means we&#39;d need a (sub)domain for each sensor, with an authentication guard behind each of them. Managing this across teams would mean: for each modified vehicle/sensor or login identity, the customer would have to submit a ticket, we&#39;d have to forward it to IT, and wait for them to manually update it. This system only scales well on opposite day.&lt;/p&gt;
&lt;p&gt;The IT tried to make their proxy work, and hardcoded paths from the same domain to the sensors, but this broke the apps that weren&#39;t designed to be proxied from somewhere other than the root of the domain (&lt;code&gt;/&lt;/code&gt;). The &quot;authentication guard&quot; I mentioned before was only done via &lt;em&gt;IP whitelisting&lt;/em&gt;, which, given the dynamic nature of IP addresses, is insecure as well.&lt;/p&gt;
&lt;p&gt;So, what other solution was there? Naturally, I did what any other reasonable engineer would do: I promised my team to write a custom reverse-proxy inside our Java Spring app that handles proxying the requests to the right sensor based on path variables while the apps aren&#39;t aware they&#39;re being proxied - so I did just that.&lt;/p&gt;
&lt;h2 id=&quot;challenges&quot;&gt;Challenges&lt;/h2&gt;
&lt;p&gt;Let&#39;s assume the API path is:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://example.com/api/v1/proxy/123/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Which proxies to the 123rd app, which is running at e.g. &lt;code&gt;http://10.0.0.0/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A request to:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://example.com/api/v1/proxy/123/index.html&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;should land at:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://10.0.0.0/index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since the apps aren&#39;t aware they&#39;re being proxied, they make assumptions that the website &lt;em&gt;is&lt;/em&gt; running at the root. This causes unintended behavior:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Root-relative fetches in the HTML like &lt;code&gt;src=&quot;/style.css&quot;&lt;/code&gt; resolve to wrong paths like &lt;code&gt;https://example.com/style.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Elements like CSS can make network requests that land at the wrong API path&lt;/li&gt;
&lt;li&gt;Digest authentication can&#39;t be proxied since it was designed to prevent Man-In-The-Middle (MITM) attacks&lt;/li&gt;
&lt;li&gt;Javascript updates the DOM to inject elements that can make more requests&lt;/li&gt;
&lt;li&gt;Javascript can redirect the user to a wrong location, e.g. if it detects the browser isn&#39;t on a specific path&lt;/li&gt;
&lt;li&gt;Apps can use relative paths with a backwards traversal like &lt;code&gt;src=&quot;../image.jpeg&quot;&lt;/code&gt; even though they&#39;re running on root, and break the API path&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#39;s how I addressed those:&lt;/p&gt;
&lt;h2 id=&quot;solutions-in-detail&quot;&gt;Solutions in detail&lt;/h2&gt;
&lt;p&gt;Fixing these, and more, required iteration, and creative solutions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1. Root-relative fetches in the HTML like &lt;code&gt;src=&quot;/style.css&quot;&lt;/code&gt; resolve to wrong paths like &lt;code&gt;https://example.com/style.css&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;2. Elements like CSS can make network requests that land at the wrong API path&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To start, traditional reverse-proxies like nginx already handle these cases - rewriting HTML is trivial. I decided to make all &lt;code&gt;src&lt;/code&gt;/&lt;code&gt;href&lt;/code&gt;/&lt;code&gt;action&lt;/code&gt; attributes have absolute paths, e.g. &lt;code&gt;src=&quot;/api/v1/proxy/123/style.css&quot;&lt;/code&gt;, while making sure 3rd party domains or other paths like these aren&#39;t rewritten:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;javascript:&lt;/code&gt;, &lt;code&gt;mailto:john@example.com&lt;/code&gt;, &lt;code&gt;{{ ... }}&lt;/code&gt; (Angular variable)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;3. Digest authentication can&#39;t be proxied since it was designed to prevent Man-In-The-Middle (MITM) attacks&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&#39;s a TLDR on how Digest auth works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The server sends the client a realm (predetermined string) and a nonce (random number)&lt;/li&gt;
&lt;li&gt;The client generates an MD5 hash (response) using that nonce, the username, password, the request URI path, and other stuff&lt;/li&gt;
&lt;li&gt;The server knows all of these in advance and validates the hash&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s a sample processed &lt;code&gt;Authorization&lt;/code&gt; header by the browser sent to the server:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Digest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;username=&amp;quot;secret_agent_007&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;realm=&amp;quot;example.com&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nonce=&amp;quot;k6a95db6b55k5lrw5yezq3p2lu4l6k2m&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;uri=&amp;quot;/&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response=&amp;quot;g0s8qt3n5kf588fm0efib2f4o4g0x2yv&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If Digest auth were to be proxied, the browser would compute an incorrect hash because of the API path in the &lt;code&gt;uri&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;While I could&#39;ve gone for Basic auth, and computed the hashes inside the proxy, I decided against that approach. This would&#39;ve added more complexity, and would&#39;ve made this part of the proxy stateful.&lt;/p&gt;
&lt;p&gt;Instead, I utilized the app&#39;s database, which already stores the credentials for the sensors. So now, if a &lt;code&gt;401 UNAUTHORIZED&lt;/code&gt; is received for any request to the sensor, it&#39;s retried using the credentials from the DB using Digest auth.&lt;/p&gt;
&lt;p&gt;Since Digest auth acts as a &quot;session token&quot; of sorts, I put that token in a cookie &lt;code&gt;DIGEST_AUTH&lt;/code&gt; that I set in the browser. This way, if the proxy receives a request with that cookie, it assumes the user is authenticated and constructs the correct &lt;code&gt;Authorization&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;This comes with a drawback - if the credentials are ever changed, the proxy will stop working until the credentials in the database are manually updated. In our case this can be done simply, and the tradeoff is definitely worth it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;4. Javascript updates the DOM to inject elements that can make more requests&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Handling this was a bit tricky. Since Angular does this aggressively, ignoring or hardcoding this wouldn&#39;t work. The only approach that worked was monkeypatching JavaScript by inlining a script tag in the initial HTML. The Javascript listens to updates, and makes sure the paths are generated correctly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;5. Javascript can redirect the user to a wrong location, e.g. if it detects the browser isn&#39;t on a specific path&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Inside the same &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, I inlined a class &lt;code&gt;window.__PROXY_LOCATION__&lt;/code&gt;, a mock of &lt;code&gt;window.location&lt;/code&gt;, along with its methods. Afterward, I added a Regex inside the proxy that replaces &lt;code&gt;window.location&lt;/code&gt;, &lt;code&gt;document.location&lt;/code&gt;, &lt;code&gt;location&lt;/code&gt; etc. safely with my mock class in the Javascript. This is necessary because the proxy doesn&#39;t run any Javascript and can&#39;t intervene during execution-time. The mock class makes sure that redirects, so &lt;code&gt;href&lt;/code&gt;, &lt;code&gt;pathname&lt;/code&gt;, &lt;code&gt;assign&lt;/code&gt;, &lt;code&gt;replace&lt;/code&gt;, and so on are handled with consideration of the proxy prefix (&lt;code&gt;/api/v1/proxy/{SENSOR_ID}/&lt;/code&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6. Apps can use relative paths with a backwards traversal like &lt;code&gt;src=&quot;../image.jpeg&quot;&lt;/code&gt; even though they&#39;re running on root, and break the API path&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While regular relative imports get handled correctly, ones that try a backwards traversal (&lt;code&gt;../&lt;/code&gt;) while still being on root break the API path, e.g. &lt;code&gt;http://10.0.0.0/image.jpeg&lt;/code&gt;. The backwards traversal here has no good reason to exist, since &lt;code&gt;../image.jpeg&lt;/code&gt; and &lt;code&gt;./image.jpeg&lt;/code&gt; mean the same thing on the root.&lt;/p&gt;
&lt;p&gt;To handle network requests that might&#39;ve slipped through the Javascript patching, or paths with backwards traversal, I added a Service Worker which is fetched for each page.&lt;/p&gt;
&lt;p&gt;The Service Worker intercepts all network requests, and double-checks that requests to the API path have the correct path. E.g. if a resource &lt;code&gt;../image.jpeg&lt;/code&gt; was resolved to&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://example.com/api/v1/proxy/image.jpeg&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;instead of the correct&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://example.com/api/v1/proxy/123/image.jpeg&lt;/code&gt;,&lt;/p&gt;
&lt;p&gt;the Service Worker would try to fix the path by doing a greedy find-and-replace of the API path.&lt;/p&gt;
&lt;p&gt;While this isn&#39;t a perfect solution, and it doesn&#39;t work for backwards-relative paths with too many &lt;code&gt;../&lt;/code&gt;s, there weren&#39;t many options to handle apps that put &lt;code&gt;../&lt;/code&gt; at the root for the fun of it.&lt;/p&gt;
&lt;h2 id=&quot;other-challenges&quot;&gt;Other challenges&lt;/h2&gt;
&lt;p&gt;While there were other challenges as well, the aforementioned ones were the most interesting. I felt like I wasn&#39;t going to overcome some of them, and there wasn&#39;t going to be an elegant (or even acceptable) solution that didn&#39;t include hardcoding. Nevertheless I didn&#39;t give up and managed to get the unorthodox proxy working piece-by-piece.&lt;/p&gt;
&lt;p&gt;Other challenges included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proxying WebSockets (stateful)&lt;/li&gt;
&lt;li&gt;Handling &lt;code&gt;multipart/x-mixed-replace&lt;/code&gt; streams in a non-blocking way&lt;/li&gt;
&lt;li&gt;Cookie path rewriting&lt;/li&gt;
&lt;li&gt;Injecting a &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; tag in the HTML, and dealing with apps that also inject one&lt;/li&gt;
&lt;li&gt;Upgrading 3rd party HTTP requests to HTTPS implicitly&lt;/li&gt;
&lt;li&gt;Maintaining browser interactivity&lt;/li&gt;
&lt;li&gt;Testing that one change didn&#39;t break other sensors&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;While the app isn&#39;t perfect, it&#39;s still incredible that it works, and is more-or-less generalizable for every application type. It was a really interesting challenge, and I learnt a lot about network protocols, proxies, browsers, frontend/backend interactions, SSL, and many more.&lt;/p&gt;
&lt;p&gt;Special thanks to my online friend who works at Netflix for helping me with the design and my roadblocks in the Java implementation.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Introducing HexName - a free DNS service</title>
        <published>2026-02-04T00:00:00+00:00</published>
        <updated>2026-02-04T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/introducing-hexname/"/>
        <id>https://lukadeka.com/blog/introducing-hexname/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/introducing-hexname/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;After 4.5 months of work, I&#39;m proud to finally announce the launch of my project &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;https://hexname.com&quot;&gt;HexName&lt;/a&gt;, the backend/frontend/infrastructure of which I built on my own.&lt;/p&gt;
&lt;div class=&quot;center&quot;&gt;
  &lt;img style=&quot;margin: auto;&quot; width=700 src=&quot;/images/hexname-homepage.webp&quot;/&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-motivation&quot;&gt;The motivation&lt;/h2&gt;
&lt;p&gt;When I first started out with homelabbing, I eventually wanted to make my services available to the public via port-forwarding.
To not have to remember my dynamic IP every time it updated, I used &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://noip.com&quot;&gt;No-IP&lt;/a&gt;, a Dynamic DNS (DDNS) service that lets you periodically update a DNS record to point to dynamic IP, like &lt;code&gt;example.hopto.org&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The problem with No-IP was that you had to log in and confirm your domain &lt;em&gt;every 30 days&lt;/em&gt;, otherwise it would be deactivated. I found this really annoying.&lt;/p&gt;
&lt;p&gt;I then discovered &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://duckdns.org&quot;&gt;DuckDNS&lt;/a&gt;, a similar service that lets you register up to 5 subdomains like &lt;code&gt;example.duckdns.org&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After having used their services for quite a while, I can say that their service is slow and unreliable. The DNS resolution frequently times out, and you end up having to retry until it eventually resolves, or access your server via an IP (which defeats the whole purpose of DDNS).&lt;/p&gt;
&lt;p&gt;Additionally, both providers only allow you to publish a single DNS record per domain, disallowing any fun/advanced DNS configurations.&lt;/p&gt;
&lt;p&gt;There&#39;s also &lt;a href=&quot;https://freedns.afraid.org/&quot;&gt;afraid.org&lt;/a&gt; which has been operated since 2001 and serves multiple thousand DNS queries per second. They also offer DDNS with subdomain registration up to 5 subdomains for free, but with an added twist - people can &quot;submit&quot; their domains to let other people register subdomains off of it.&lt;/p&gt;
&lt;p&gt;There is an obvious problem with this though, as addressed in the &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://freedns.afraid.org/faq/&quot;&gt;FAQ&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Q: How can I protect myself from using a domain that may disappear from &lt;code&gt;freedns.afraid.org&lt;/code&gt; and/or become &quot;broken&quot;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A: &quot;... If you wish to use a shared domain in the system for any sort of long term use (like email/web services) then it is recommended you use one of the domains owned by me personally ...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This kind of defeats the whole purpose of the idea.&lt;/p&gt;
&lt;p&gt;Additionally, a couple of things stood out to me that I didn&#39;t like about the service:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The password length is limited to 4-16 characters (4 characters in 2026, really? We&#39;re still doing that?). I usually generate much longer passwords with my password manager&lt;/li&gt;
&lt;li&gt;The registration form didn&#39;t include the correct attributes in the HTML for my browser/password manager to save/autofill the login credentials automatically&lt;/li&gt;
&lt;li&gt;Every action (registering a subdomain/domain) required a captcha that I didn&#39;t find particularly easy to solve&lt;/li&gt;
&lt;li&gt;There was no possibility to register subdomains off of the subdomain, e.g. &lt;code&gt;mail.example.mooo.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This inspired me to provide a better DNS service where users had freedom to do anything they wanted with their domain - run a mailserver, host various services - even change the nameservers, and all that without annoying the user, for free, forever.&lt;/p&gt;
&lt;h2 id=&quot;development-cycle&quot;&gt;Development cycle&lt;/h2&gt;
&lt;p&gt;Since I&#39;m currently studying computer science full time at a university, as well as working a part-time job, I didn&#39;t have much time to work on the project. Nevertheless I decided to try and dedicate my free time to the project.&lt;/p&gt;
&lt;h3 id=&quot;backend&quot;&gt;Backend&lt;/h3&gt;
&lt;p&gt;I started working on the backend for the project in the middle of October. I decided this was a great opportunity to learn a programming language I had heard great things about - Rust. I have to say, I absolutely loved the experience and the community behind it, providing great support and packages.&lt;/p&gt;
&lt;p&gt;While developing the backend, I had to integrate it with &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://doc.powerdns.com/authoritative/index.html&quot;&gt;PowerDNS&#39;s authoritative nameserver&lt;/a&gt;, the DNS server I settled on to run. The API wasn&#39;t straightforward, forcing me to write helper functions to interact with it properly, but eventually I got it working.&lt;/p&gt;
&lt;p&gt;After many iterations, refactors, and switching the routing framework, I finished working on the backend two months after starting, afterward only implementing after-thought features and bugfixes.&lt;/p&gt;
&lt;h3 id=&quot;frontend&quot;&gt;Frontend&lt;/h3&gt;
&lt;p&gt;Since I had no previous experience with frontend development (except building this stunning portfolio website), I did a lot of research beforehand, comparing different technologies I could use.&lt;/p&gt;
&lt;p&gt;I settled on &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://svelte.dev/docs/kit/introduction&quot;&gt;SvelteKit&lt;/a&gt; for routing/reactivity, along with &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://tailwindcss.com/&quot;&gt;TailwindCSS&lt;/a&gt;, and a component library for it called &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;https://daisyui.com/&quot;&gt;DaisyUI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;DaisyUI significantly helped with the initial design of the website, thanks to which I didn&#39;t get stuck for hours trying to tweak login forms and buttons.&lt;/p&gt;
&lt;p&gt;After three months, I finished the frontend as well. I decided to make the source-code publically available at &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://git.lukadeka.com/LukaDeka/HexName-Frontend&quot;&gt;my personal Git repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since it&#39;s my first real experience with frontend development, there are glaring issues with the website, but overall I&#39;m proud of how it turned out. You can check out a live demo at &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;https://hexname.com&quot;&gt;hexname.com&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;deployment&quot;&gt;Deployment&lt;/h3&gt;
&lt;p&gt;Being familiar with homelabbing and hosting my services with NixOS, the deployment was a breeze. I got another VPS from Hetzner Cloud and installed NixOS on it.&lt;/p&gt;
&lt;p&gt;After playing around with oci-containers and making sure the services can reliably interact with each other, I set up logical replication with Postgres so that every change would also be reflected on the second nameserver in real-time, which I&#39;m running on my personal Hetzner instance (the one serving this blog).&lt;/p&gt;
&lt;p&gt;Other than that, I set up incremental backups of the database to be executed every 10 minutes to ensure no data is lost. Because I&#39;m running/backing up the data between two VPSes in different regions, &lt;em&gt;technically&lt;/em&gt; I&#39;m running multi-region.&lt;/p&gt;
&lt;p&gt;Additionally, to send/receive emails for my project, I set up another mailserver in two days, which gets a 10/10 score on &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.mail-tester.com/&quot;&gt;Mail-Tester&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For monitoring, I use Uptime-Kuma to make sure the services stay up-and-running.&lt;/p&gt;
&lt;p&gt;The NixOS configuration for the entire deployment is also available at &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://git.lukadeka.com/LukaDeka/HexName-NixOS&quot;&gt;my Git repo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-product&quot;&gt;The product&lt;/h2&gt;
&lt;div class=&quot;center&quot;&gt;
  &lt;img style=&quot;margin: auto;&quot; width=700 src=&quot;/images/hexname-dashboard.webp&quot;/&gt;
&lt;/div&gt;
&lt;p&gt;As of now, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;https://hexname.com&quot;&gt;HexName&lt;/a&gt; offers the registration of 20 total subdomains off of the following domains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hexname.com&lt;/li&gt;
&lt;li&gt;loves-beer.com&lt;/li&gt;
&lt;li&gt;dickdns.org (you can tell why I went with this last one)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As well as 200 DNS records per subdomain from the supported record types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A&lt;/li&gt;
&lt;li&gt;AAAA&lt;/li&gt;
&lt;li&gt;CNAME&lt;/li&gt;
&lt;li&gt;TXT&lt;/li&gt;
&lt;li&gt;MX&lt;/li&gt;
&lt;li&gt;NS&lt;/li&gt;
&lt;li&gt;SRV&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, HexName offer a DDNS service for &lt;code&gt;A&lt;/code&gt; records, allowing users to update the IP periodically, just like the DDNS providers mentioned before.&lt;/p&gt;
&lt;p&gt;Practically, all of this means that users can register domains like &lt;code&gt;george.loves-beer.com&lt;/code&gt;, use them to host their services (like game servers), blogs, and even receive emails with them (e.g. &lt;code&gt;contact@george.loves-beer.com&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&quot;credits&quot;&gt;Credits&lt;/h2&gt;
&lt;p&gt;While learning Rust for the backend, and Svelte, I had a lot of questions about language syntax, semantics, as well as general programming concepts. Fortunately, I&#39;m in a very helpful online community where they were able to assist me along the journey.&lt;/p&gt;
&lt;p&gt;Doesn&#39;t matter what you&#39;re learning, being around experienced people is a significant help.&lt;/p&gt;
&lt;h2 id=&quot;moving-forward&quot;&gt;Moving forward&lt;/h2&gt;
&lt;p&gt;Since I don&#39;t expect to make any money off this project, I made it solely for the sake of wanting to offer a better free service, as well as a learning opportunity.&lt;/p&gt;
&lt;p&gt;I plan to support/maintain the project for a long time as well as update the programs/system periodically. I don&#39;t expect this to take too much time since I&#39;m familiar with the technologies used for deployment and I went with a minimalistic approach.&lt;/p&gt;
&lt;p&gt;Currently, the yearly costs of the project are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;€49.8 for the VPS (ns1.hexname.com)&lt;/li&gt;
&lt;li&gt;$14.98 for the domain hexname.com&lt;/li&gt;
&lt;li&gt;$14.98 for the domain loves-beer.com&lt;/li&gt;
&lt;li&gt;$12.98 for the domain dickdns.org&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So &lt;code&gt;101.0$/year&lt;/code&gt; or &lt;code&gt;8.5$/month&lt;/code&gt; in total.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to support the project, feel free to &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;https://hexname.com/#contact&quot;&gt;contact me here&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rescuing NixOS stuck on Stage 1 boot</title>
        <published>2025-10-27T00:00:00+00:00</published>
        <updated>2025-10-27T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/recovering-nixos-stuck-on-stage-1-boot/"/>
        <id>https://lukadeka.com/blog/recovering-nixos-stuck-on-stage-1-boot/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/recovering-nixos-stuck-on-stage-1-boot/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;One of the main selling points of NixOS is that it allows you to have many different binaries of the same program at the same time. Along with program isolation and dependency management, this enables the user to have many of the so-called NixOS generations at the same time.&lt;/p&gt;
&lt;p&gt;How it works is simple: when applying any change to the system, like installing a program or changing an option declaratively, you have to rebuild the system. You can either switch to it immediately like so:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nixos-rebuild switch&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or switch to it only when you reboot the machine:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; nixos-rebuild boot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the rebuild succeeds, it creates a new generation. The user is still able to switch to a previous generation though, and this comes in very handy when either a rebuild succeeds but the system is left unusable. Or if something hangs/breaks after a reboot, you are able to boot into a different generation.&lt;/p&gt;
&lt;h2 id=&quot;the-issue&quot;&gt;The issue&lt;/h2&gt;
&lt;p&gt;I have a service enabled that garbage-collects previous generations older than 2 weeks:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;nix&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;gc&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  automatic&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  dates&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Fri *-*-* 04:00:00&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  options&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;--delete-older-than 14d&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means, if I were to make a change that broke the booting sequence of my system, and I only noticed it 2 weeks after, I&#39;ll be left with an unbootable system. While this might sound scary, it doesn&#39;t happen often. Unluckily for me, this is exactly what happened.&lt;/p&gt;
&lt;p&gt;My issue was that the system was waiting indefinitely for the kernel module &lt;code&gt;vfio_pci&lt;/code&gt; to load, which wasn&#39;t responding. After making sure there were no timeouts in place, I rebooted the system into a &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://nixos.org/download/#:~:text=without%20a%20desktop.-,Minimal%20ISO%20image,-The%20minimal%20installation&quot;&gt;NixOS minimal installation image&lt;/a&gt; and began diagnosing.&lt;/p&gt;
&lt;h2 id=&quot;fixing-the-issue&quot;&gt;Fixing the issue&lt;/h2&gt;
&lt;p&gt;I&#39;m using &lt;code&gt;zfs&lt;/code&gt; for my boot drive, so the first step was to mount it.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Escalate your privileges&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; su&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Load the zfs kernel module&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;modprobe&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zfs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# List all available pools (that are not imported)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zpool&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; import&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Show all available datasets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zfs&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NAME                           USED  AVAIL  REFER  MOUNTPOINT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvmepool                      &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;51.3G   406G    96K&lt;/span&gt;&lt;span&gt;  none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvmepool&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span&gt;home                  &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;156M   406G   156M&lt;/span&gt;&lt;span&gt;  legacy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvmepool&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span&gt;nix                  &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;16.7G   406G  16.7G&lt;/span&gt;&lt;span&gt;  legacy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvmepool&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span&gt;root                 &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;11.8M   406G  11.8M&lt;/span&gt;&lt;span&gt;  legacy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvmepool&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;/&lt;/span&gt;&lt;span&gt;var                  &lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;1.35G   406G  1.35G&lt;/span&gt;&lt;span&gt;  legacy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;nvmepool&lt;/code&gt; is the name of my &lt;code&gt;zpool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now create the directories to mount the datasets on:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /mnt/home /mnt/nix /mnt/root /mnt/var&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and mount them:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zfs nvmepool/root /mnt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zfs nvmepool/home /mnt/home&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zfs nvmepool/nix /mnt/nix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;nvmepool/root&lt;/code&gt; refers to the &lt;code&gt;/&lt;/code&gt; directory, also known as the root directory, and &lt;strong&gt;not&lt;/strong&gt; to the &lt;code&gt;/root/&lt;/code&gt; directory, which is the root user&#39;s home directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The boot directory also has to be mounted explicitly for NixOS to be able to build generations, so find out which is your boot partition:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; lsblk&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --fs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;NAME&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        FSTYPE     FSVER LABEL    UUID                FSAVAIL FSUSE% MOUNTPOINTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nvme0n1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;├─nvme0n1p1&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; vfat       FAT32 boot     6445-6413            906.6M    11% /boot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;└─nvme0n1p2&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zfs_member&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5000&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  nvmepool&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 6733023062829592015&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, look for &lt;code&gt;vfat&lt;/code&gt;, or for the &lt;code&gt;EFI&lt;/code&gt; or &lt;code&gt;ESP&lt;/code&gt; label. The boot partition shouldn&#39;t be larger than a few gigabytes.&lt;/p&gt;
&lt;p&gt;Afterward, mount it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev/nvme0n1p1 /mnt/boot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my case, I also had to mount these directories:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rbind&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /dev /mnt/dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rbind&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /sys /mnt/sys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --rbind&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /proc /mnt/proc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, enter the mounted system:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nixos-enter&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --root&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; /mnt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure networking works (for cache.nixos.org):&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ping&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; google.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, navigate to your NixOS config directory, edit and revert the changes manually, and execute:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nixos-rebuild&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; boot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or this, if you&#39;re using flakes:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nixos-rebuild&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; boot&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --flake&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .#&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If that succeeds, exit the chrooted environment:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and export the &lt;code&gt;zpool&lt;/code&gt; cleanly:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zpool&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; export nvmepool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: the last step isn&#39;t really necessary if you don&#39;t have &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://search.nixos.org/options?channel=unstable&amp;amp;show=boot.zfs.forceImportRoot&quot;&gt;this NixOS option&lt;/a&gt; set:
&lt;code&gt;boot.zfs.forceImportRoot = true;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally reboot the system (and make sure not to boot into the live image). Afterward, you should be able to boot into your system normally.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My research paper on Functional Paradigms and LISP</title>
        <published>2025-09-19T00:00:00+00:00</published>
        <updated>2025-10-01T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/my-research-paper-on-functional-paradigms-and-lisp/"/>
        <id>https://lukadeka.com/blog/my-research-paper-on-functional-paradigms-and-lisp/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/my-research-paper-on-functional-paradigms-and-lisp/">&lt;h2 id=&quot;preface&quot;&gt;Preface&lt;/h2&gt;
&lt;p&gt;In the Summer semester 2025 I signed up to a seminar worth 3 ECTS points at the Technical University Berlin since attending one seminar is mandatory for a Bachelor&#39;s degree in Computer Science.&lt;/p&gt;
&lt;p&gt;Since seminar slots are hard to get for this exact reason, my university usually hosts a &quot;meta-page&quot; where you can rank your top choices and get assigned a seminar.&lt;/p&gt;
&lt;p&gt;So I got assigned the seminar &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://moseskonto.tu-berlin.de/moses/modultransfersystem/bolognamodule/beschreibung/anzeigen.html?number=40996&amp;amp;version=1&quot;&gt;Open Distributed Systems&lt;/a&gt; (ODS).&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The whole point of a seminar is to learn how to do research and gather first-hand experiences at writing your first scientific paper.&lt;/p&gt;
&lt;p&gt;The process was split up like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We had a few introductory classes&lt;/li&gt;
&lt;li&gt;Then we were instructed to write an extended abstract (max. two pages) based on a research paper from their curated list&lt;/li&gt;
&lt;li&gt;After which we had to anonymously give feedback to two other research papers using a template&lt;/li&gt;
&lt;li&gt;After we received the feedback, we had to prepare a 10 minute presentation, present it, and answer questions from the audience for an additional 5 minutes&lt;/li&gt;
&lt;li&gt;And in the end, after considering all the feedback, we had to submit 5-6 pages of the final research paper&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the while having 4 classes in total on how to do research, write a good research paper, how to present, the formalities, etc.&lt;/p&gt;
&lt;h2 id=&quot;topic&quot;&gt;Topic&lt;/h2&gt;
&lt;p&gt;I picked the paper &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www-formal.stanford.edu/jmc/recursive.pdf&quot;&gt;Recursive functions of symbolic expressions and their computation by machine, part I&lt;/a&gt; by &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)&quot;&gt;John McCarthy&lt;/a&gt;. I chose this topic because my friend was recommending Lisps, and I wanted to learn more about Functional Programming (FP) in general.&lt;/p&gt;
&lt;p&gt;I ended up phrasing my title like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;&lt;em&gt;Functional paradigms in LISP and its contribution to reliable, maintainable software&lt;/em&gt;&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And my research question like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;&lt;em&gt;In what way do the functional programming paradigms introduced in LISP contribute to the development of more reliable and maintainable software?&lt;/em&gt;&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I mostly talked about the benefits of FP over imperative, how it supports Test-Driven Development (TDD), and what the benefits of enforcing static types as well as pure functions has.&lt;/p&gt;
&lt;p&gt;I also argued that FP is very useful when a language rewrite is necessary, and when the priorities shift to codebase maintainability, readability, and minimizing runtime errors - since a lack thereof accounts to over 50% of project costs in practice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;&lt;em&gt;...a common misconception among beginner software developers is that designing and writing efficient programs is the most important task of the job. In practice, incorrect, unreadable, and hard to maintain software accounts to over fifty percent of the project costs. Tremendous resources could be saved if the focus were shifted to readability, reliability and correctness, but the reality shows that most businesses favor rapid development and software that just works in the present.&lt;/em&gt;&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-paper&quot;&gt;The paper&lt;/h2&gt;
&lt;p&gt;Click here to &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;/resources/functional-paradigms-and-lisp.pdf&quot;&gt;open the PDF in a new tab&lt;/a&gt;.&lt;/p&gt;
&lt;object data=&quot;/resources/functional-paradigms-and-lisp.pdf&quot; type=&quot;application/pdf&quot; aria-label=&quot;My research paper &#39;Functional paradigms in LISP and its contributions to reliable, maintainable software&#39;&quot; width=&quot;100%&quot; height=&quot;700px&quot; allow=&quot;fullscreen&quot;&gt;
  &lt;p&gt;This browser does not support PDFs. Please try &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer dofollow&quot; href=&quot;/resources/functional-paradigms-and-lisp.pdf&quot;&gt;opening it in a new tab&lt;/a&gt;, or &lt;a href=&quot;/resources/functional-paradigms-and-lisp.pdf&quot; download=&quot;Functional paradigms and LISP.pdf&quot;&gt;download the PDF to view it&lt;/a&gt;.&lt;/p&gt;
&lt;/object&gt;
&lt;h2 id=&quot;shortcomings&quot;&gt;Shortcomings&lt;/h2&gt;
&lt;p&gt;As stated in the paper, I didn&#39;t have enough time, and was unable to find solid evidence to support all my claims. Because of this, I had to resort to logical reasoning, which wasn&#39;t as scientific as it should&#39;ve been for a research paper, which I acknowledged here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;&lt;em&gt;Despite a lot of research being FP-centric, finding solid empirical evidence in industrial and enterprise contexts proved to be challenging. Due to a limited availability of published enterprise data, we relied on logical reasoning where empirical validation was unavailable.&lt;/em&gt;&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Overall, I made it harder for myself by choosing such a broad topic, and trying to argue against a very popular paradigm.&lt;/p&gt;
&lt;p&gt;Because I focused on FP, I didn&#39;t cover Lisps enough. I failed to mention and explain Lisp&#39;s macro system, which is its defining characteristic, which allows code to programmatically modify other parts of the code.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, I learned a lot about FP and the history of LISP by doing the research, as well as languages like Clojure, and BEAM-based languages like Erlang and Elixir. The experience gained in doing research will also come in handy for my Bachelor thesis.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to cite my paper, here is the BibTeX:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@misc{FunctionalParadigmsAndLisp,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  author = {Luka Dekanozishvili},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  title = {Functional paradigms in LISP and its contribution to reliable, maintainable software},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  howpublished = {\url{https://lukadeka.com/resources/functional-paradigms-and-lisp.pdf}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  email = {research@lukadeka.com},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  school = {Technical University Berlin},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  address = {Berlin, DE},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  year = {2025},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  month = {September}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Setting up Netbird with Zitadel on NixOS</title>
        <published>2025-08-28T00:00:00+00:00</published>
        <updated>2025-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/setting-up-netbird-with-zitadel-on-nixos/"/>
        <id>https://lukadeka.com/blog/setting-up-netbird-with-zitadel-on-nixos/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/setting-up-netbird-with-zitadel-on-nixos/">&lt;h2 id=&quot;preface&quot;&gt;Preface&lt;/h2&gt;
&lt;p&gt;Deploying Netbird&#39;s management server on NixOS proved particularly difficult since no step-by-step guide was provided for NixOS. I had to piece things together by reading documentation from many different documentation sources, including source code, and experimenting.&lt;/p&gt;
&lt;p&gt;Since the options at &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://search.nixos.org/options?channel=unstable&amp;amp;&quot;&gt;search.nixos.org&lt;/a&gt; were well documented, I was able to get a working setup after some trial and error, and debugging.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://netbird.io/&quot;&gt;NetBird&lt;/a&gt; is an open-source VPN management platform built on top of WireGuard making it easy to create secure private networks for your organization or home.&lt;/p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;Netbird requires an Identity Provider for authentication/authorization. The supported self-hosted options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zitadel&lt;/li&gt;
&lt;li&gt;Keycloak&lt;/li&gt;
&lt;li&gt;Authentik&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;zitadel&quot;&gt;Zitadel&lt;/h3&gt;
&lt;h4 id=&quot;configuration&quot;&gt;Configuration&lt;/h4&gt;
&lt;p&gt;Here&#39;s an example config for Zitadel, along with its database:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;example.com&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zitadel&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    openFirewall&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    masterKeyFile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/zitadel/master_key&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    extraStepsPaths&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/zitadel/admin_steps&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    extraSettingsPaths&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/zitadel/settings&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    tlsMode&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;external&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    settings&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      Port&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 39995&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      ExternalPort&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 443&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      ExternalDomain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;auth.${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      Database&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        postgres&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Host&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Port&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5432&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Database&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;zitadel&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          MaxOpenConns&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 15&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          MaxIdleConns&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          MaxConnLifetime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;1h&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          MaxConnIdleTime&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;5m&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Postgres database for Zitadel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  virtualisation&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;oci-containers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;containers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zitadel-db&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;postgres:17&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ports&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;5432:5432&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    environmentFiles&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;/path/to/zitadel/postgres_env&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;/var/lib/zitadel-db:/var/lib/postgresql/data&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  networking&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;firewall&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;allowedTCPPorts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 80 443&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Ensure the mounted directory for the database exists&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  system&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;activationScripts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;makeZitadelDir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; lib&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;stringAfter&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;var&amp;quot;&lt;/span&gt;&lt;span&gt; ]&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    mkdir -p /var/lib/zitadel-db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Proxy the SSO provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nginx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nginx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;virtualHosts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;auth.${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    forceSSL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    enableACME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    locations&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      proxyPass&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;http://127.0.0.1:39995&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      proxyWebsockets&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      extraConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        proxy_set_header Host $host;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        proxy_set_header X-Forwarded-Proto $scheme;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  security&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;acme&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    acceptTerms&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    defaults&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;you@example.com&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;environment-variables&quot;&gt;Environment variables&lt;/h4&gt;
&lt;p&gt;Generate the &lt;code&gt;master_key&lt;/code&gt; with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -dc&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; A-Za-z0-9&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;/dev/urandom&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c 32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and populate the &lt;code&gt;admin_steps&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;FirstInstance&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  InstanceName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Zitadel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  Org&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    Human&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      UserName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; John&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      FirstName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; John&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      LastName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Lackland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      DisplayName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; John&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      Password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make-sure-this-is-secure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      PasswordChangeRequired&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      Email&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        Address&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; you@example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        Verified&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and populate the &lt;code&gt;settings&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;Database&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  postgres&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    User&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      Username&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zitadel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      Password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make-sure-this-is-secure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      SSL&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        Mode&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; disable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    Admin&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      Username&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      Password&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make-sure-this-is-secure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      SSL&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        Mode&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; disable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;postgres&lt;/code&gt; user is used as a oneshot to initialize the &lt;code&gt;zitadel&lt;/code&gt; user after the initial database creation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Create and populate the &lt;code&gt;postgres_env&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_USER=p&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;ostgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_PASSWORD=s&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;et-the-same-password-as-in-settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;POSTGRES_DB=p&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;ostgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;registration&quot;&gt;Registration&lt;/h4&gt;
&lt;p&gt;Afterward, log in with your &lt;code&gt;Admin&lt;/code&gt; account at &lt;code&gt;auth.example.com&lt;/code&gt;, and follow Netbird&#39;s documentation on &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.netbird.io/selfhosted/identity-providers#zitadel&quot;&gt;how to configure Zitadel&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make sure to put &lt;code&gt;netbird.example.com&lt;/code&gt; as the domain in the &lt;strong&gt;Redirect Settings&lt;/strong&gt; and not &lt;code&gt;auth.example.com&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Put the &lt;code&gt;ClientSecret&lt;/code&gt; from Zitadel in the &lt;code&gt;client_secret&lt;/code&gt; file, and hold on to the &lt;code&gt;Client ID&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;Client ID&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a secret so it&#39;s okay to hardcode it in the NixOS configuration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;netbird&quot;&gt;Netbird&lt;/h3&gt;
&lt;p&gt;Afterward, set up Netbird:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{ config&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lib&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;, ...&lt;/span&gt;&lt;span&gt; }:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;example.com&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;netbird.${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  clientId&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;lt;YOUR_CLIENT_ID_FROM_ZITADEL&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  imports&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ./zitadel.nix&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;netbird&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    enableNginx&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    coturn&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      passwordFile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/netbird/turn_password&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    signal&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enableNginx&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    dashboard&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enableNginx&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      settings&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        AUTH_AUTHORITY&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https://auth.${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        AUTH_CLIENT_ID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        AUTH_AUDIENCE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    management&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enableNginx&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      domain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      turnDomain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      singleAccountModeDomain&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; netbirdDomain&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      oidcConfigEndpoint&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https://auth.${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/.well-known/openid-configuration&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      settings&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        Signal&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;URI&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}:443&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        HttpConfig&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AuthAudience&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        IdpManagerConfig&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ClientConfig&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ClientID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        DeviceAuthorizationFlow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ProviderConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Audience&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          ClientID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        PKCEAuthorizationFlow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;ProviderConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Audience&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          ClientID&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clientId&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        TURNConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Secret&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;_secret&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/netbird/turn_password&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          CredentialsTTL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;12h&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          TimeBasedCredentials&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Turns&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;              Password&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;_secret&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/netbird/turn_password&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;              Proto&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;udp&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;              URI&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;turn:${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}:3478&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;              Username&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;netbird&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        Relay&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Addresses&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;rels://${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}:33080&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          CredentialsTTL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;24h&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;          Secret&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;_secret&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/netbird/relay_secret&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        DataStoreEncryptionKey&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;_secret&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/netbird/data_store_encryption_key&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Make the env available to the systemd service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  systemd&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;netbird-management&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;serviceConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    EnvironmentFile&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/to/netbird/setup.env&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Override ACME settings to get a cert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;nginx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;virtualHosts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; lib&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mkMerge&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        enableACME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        forceSSL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  # Run the Netbird relay with TLS to allow relaying over TCP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  virtualisation&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;oci-containers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;containers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;netbird-relay&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;netbirdio/relay:latest&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ports&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;33080:33080&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;/var/lib/acme/${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}/:/certs:ro&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    environment&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      NB_LOG_LEVEL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;info&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      NB_LISTEN_ADDRESS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;:33080&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      NB_EXPOSED_ADDRESS&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;rels://${&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;netbirdDomain&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;}:33080&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      NB_TLS_CERT_FILE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/certs/fullchain.pem&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      NB_TLS_KEY_FILE&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/certs/key.pem&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    environmentFiles&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;/path/to/netbird/relay_secret_container&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  networking&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;firewall&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;allowedTCPPorts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 80 443 3478 10000 33080&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  networking&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;firewall&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;allowedUDPPorts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3478 5349 33080&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  networking&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;firewall&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;allowedUDPPortRanges&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    from&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 40000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    to&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 40050&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }];&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # TURN ports&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;environment-files&quot;&gt;Environment files&lt;/h4&gt;
&lt;p&gt;Generate the &lt;code&gt;turn_password&lt;/code&gt; and &lt;code&gt;data_store_encryption_key&lt;/code&gt; with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate the &lt;code&gt;relay_secret&lt;/code&gt; with:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -base64 32&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;s/=//g&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And also put it in the &lt;code&gt;relay_secret_container&lt;/code&gt; file for the Podman container:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NB_AUTH_SECRET=t&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;he-same-secret-as-in-relay-secret&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and populate the &lt;code&gt;setup.env&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;https://auth.example.com/.well-known/openid-configuration&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_USE_AUTH0=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Since we&amp;#39;re using Zitadel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_CLIENT_ID=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;lt;YOUR_CLIENT_ID_FROM_ZITADEL&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_SUPPORTED_SCOPES=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;openid profile email offline_access api&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_AUDIENCE=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;lt;YOUR_CLIENT_ID_FROM_ZITADEL&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_REDIRECT_URI=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/auth&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_SILENT_REDIRECT_URI=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;/silent-auth&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_DEVICE_AUTH_PROVIDER=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;hosted&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;lt;YOUR_CLIENT_ID_FROM_ZITADEL&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_MGMT_IDP=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;zitadel&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_IDP_MGMT_CLIENT_ID=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;netbird&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_IDP_MGMT_CLIENT_SECRET=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;lt;YOUR_CLIENT_SECRET_FROM_ZITADEL&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_IDP_MGMT_EXTRA_MANAGEMENT_ENDPOINT=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;https://netbird.example.com/management/v1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_MGMT_IDP_SIGNKEY_REFRESH=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_DOMAIN=&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;netbird.example.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_DISABLE_LETSENCRYPT=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Since Netbird is behind nginx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_MGMT_API_PORT=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETBIRD_SIGNAL_PORT=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TURN_MIN_PORT=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;40000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TURN_MAX_PORT=&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;40050&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;cloud-providers&quot;&gt;Cloud providers&lt;/h4&gt;
&lt;p&gt;Many cloud providers like Hetzner Cloud use stateless firewalls (since they&#39;re cheaper to run than SPI firewalls). These can interfere with Netbird&#39;s operation.&lt;/p&gt;
&lt;p&gt;If your VPS provider uses a stateless firewall, you have to open up the required dynamic ports that Netbird uses in the cloud provider&#39;s UI.&lt;/p&gt;
&lt;p&gt;To see which ports you need to open, run:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cat /proc/sys/net/ipv4/ip_local_port_range&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.netbird.io/selfhosted/selfhosted-guide#advanced-additional-configurations-for-cloud-providers&quot;&gt;additional configurations for cloud providers&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;additional-configuration&quot;&gt;Additional configuration&lt;/h2&gt;
&lt;p&gt;To enable the Netbird client, set:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  services&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;netbird&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;enable&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;/h2&gt;
&lt;h3 id=&quot;setup-issues&quot;&gt;Setup issues&lt;/h3&gt;
&lt;p&gt;The generated configuration for the management interface is stored in &lt;code&gt;/var/lib/netbird-mgmt/management.json&lt;/code&gt;. Verify this file if you suspect the environment variables aren&#39;t being applied properly, or to check if you&#39;re correctly overriding &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://search.nixos.org/options?channel=unstable&amp;amp;show=services.netbird.server.management.settings&amp;amp;query=services.netbird.server.management.settings&quot;&gt;the defaults&lt;/a&gt; with &lt;code&gt;services.netbird.server.management.settings&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can check if the TURN/STUN and Relay servers are working properly with the online tester &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/&quot;&gt;Trickle ICE&lt;/a&gt;. A &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.netbird.io/selfhosted/troubleshooting&quot;&gt;simple guide for troubleshooting&lt;/a&gt; is provided here by Netbird.&lt;/p&gt;
&lt;h3 id=&quot;client-issues&quot;&gt;Client issues&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;netbird status -d&lt;/code&gt; to check the details of the client as well as available relays. This also shows the connection status with other peers.&lt;/p&gt;
&lt;p&gt;A more detailed description of diagnosing client issues can be found in &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.netbird.io/how-to/troubleshooting-client&quot;&gt;Netbird&#39;s documentation&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to cope with losing a public IP as a homelabber</title>
        <published>2025-08-24T00:00:00+00:00</published>
        <updated>2025-09-04T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/how-to-cope-with-losing-a-public-ip-as-a-homelabber/"/>
        <id>https://lukadeka.com/blog/how-to-cope-with-losing-a-public-ip-as-a-homelabber/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/how-to-cope-with-losing-a-public-ip-as-a-homelabber/">&lt;h2 id=&quot;preface&quot;&gt;Preface&lt;/h2&gt;
&lt;p&gt;This post explains how IP routing, NATs and CGNATs (or double-NATs) work, discusses different strategies for homelabbers to bypass CGNAT restrictions, and focuses on Netbird as a solution.&lt;/p&gt;
&lt;p&gt;This post is mainly intended for homelabbers, beginner network engineers, or curious system or DevOps administrators.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I used to have my own residential IP address before June 2025, and exposing services to the internet was trivial. I only needed to punch holes through my router (i.e., port forwarding), and the services were accessible from anywhere.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that port forwarding is a potential attack surface, and should not be done carelessly. I heeded this warning and ensured I followed proper security practices (like zero-trust approaches, IP blocklisting, etc.).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In June 2025 my ISP (Internet Service Provider) decided to install their routers for everyone in the building. Given the guaranteed downtime, they decided to kill two birds with one stone and rob everyone of their public IP addresses, including me. We were put behind a CGNAT (Carrier Grade Network Address Translation).&lt;/p&gt;
&lt;p&gt;A CGNAT functions like a NAT we all know and love: the router. It hands out private IP addresses that are unroutable from the WAN (Wide Area Network) to its hosts. When a host wants to access a website, the router changes the source IP address of the host (i.e., the private one) to the WAN IP address the router has received. This address is commonly a public-facing one. The router keeps track of which port (from its ephemeral port range) was used to send out the request, and returns the resources back to the correct host.&lt;/p&gt;
&lt;p&gt;Since IPv4 addresses started running out and getting more expensive, NATs were introduced to allow multiple hosts to share the same IPv4 address.&lt;/p&gt;
&lt;p&gt;I mentioned before that a router&#39;s WAN IP address doesn&#39;t have to be public. This is exactly where a CGNAT comes in: it hands out private IP addresses to the hosts (so routers), and translates them to public ones, just like a run-of-the-mill router would. This is why a network behind a CGNAT is commonly called a double-NAT.&lt;/p&gt;
&lt;p&gt;So like hosts on the LAN can share a public IP address, different LANs on different routers behind a CGNAT can share one as well. Commonly a pool of public IP addresses is used.&lt;/p&gt;
&lt;p&gt;Since I couldn&#39;t forward ports on the CGNAT to point to my router, which would then point to my home-server, I needed a different approach than port forwarding.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution?&lt;/h2&gt;
&lt;p&gt;Since I was already using &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.wireguard.com/&quot;&gt;WireGuard&lt;/a&gt; to self-host VPNs to my home-servers, I decided to buy a cheap VPS, and &quot;just use WireGuard&quot;, as many people recommended in forums, to expose my services.&lt;/p&gt;
&lt;p&gt;I set up a WireGuard server on the VPS and a WireGuard client on my home-server that would always keep a connection with the server. This way, the home-server was reachable from only the VPS.&lt;/p&gt;
&lt;p&gt;Once I made another subnet for the VPN, and forwarded the ports I wanted (so ports 80 and 443 for HTTP and HTTPS) from the VPS to the home-server, the setup worked great, and was reliable.&lt;/p&gt;
&lt;p&gt;Only after I wanted to access the server from outside my home network did I encounter weird issues: SSH didn&#39;t work after forwarding the SSH port for my home-server. After debugging for a long time, and failing to find a solution online, I gave up.&lt;/p&gt;
&lt;p&gt;Had the SSH connection worked, I still wouldn&#39;t&#39;ve been satisfied. Every time I wanted to forward a port, using that port on the VPS would&#39;ve been impossible. This was especially problematic for the HTTPS port (443) since it meant I could only serve websites from one machine.&lt;/p&gt;
&lt;p&gt;While not sounding like a huge deal, I didn&#39;t want a suboptimal setup when I had heard of better alternatives, so I started investigating.&lt;/p&gt;
&lt;h2 id=&quot;considerations&quot;&gt;Considerations&lt;/h2&gt;
&lt;p&gt;Before I could consider my options to continue exposing services to the internet, I needed to write down my requirements for the software/service:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ability to connect to my home network from anywhere&lt;/li&gt;
&lt;li&gt;Ability to act like an exit node (common VPN functionality)&lt;/li&gt;
&lt;li&gt;Allow me to expose any service I want on any port&lt;/li&gt;
&lt;li&gt;Integrate well with other servers I have&lt;/li&gt;
&lt;li&gt;Uncomplicated networking&lt;/li&gt;
&lt;li&gt;Allow me to only expose what I need to (zero-trust)&lt;/li&gt;
&lt;li&gt;Free and open-source software only, ideally self-hostable&lt;/li&gt;
&lt;li&gt;As few external third-party dependencies as possible&lt;/li&gt;
&lt;li&gt;Good documentation&lt;/li&gt;
&lt;li&gt;Simple and reliable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I considered &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/configure-warp/route-traffic/split-tunnels/&quot;&gt;Cloudflare tunnels&lt;/a&gt;, which allow you to expose anything you want using their proxies. I ultimately decided against it since it violates 7. and 8., and privacy reasons, even though it&#39;s free.&lt;/p&gt;
&lt;p&gt;I then considered &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://tailscale.com/&quot;&gt;Tailscale&lt;/a&gt;, which is a mesh VPN based on WireGuard. While a popular choice for connecting many hosts on different networks together, and having a free tier, their control-server is closed-source, and not self-hostable. This is not a huge privacy deal though since the control server only connects hosts to each other, and optionally acts as a relay for end-to-end encrypted data when the connection can&#39;t be established. I also didn&#39;t really like the mobile app.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://headscale.net/stable/&quot;&gt;Headscale&lt;/a&gt; is an alternative free and open-source self-hostable Tailscale-compatible control server (that was a lot of words), whose integral contributor also works at Tailscale. I briefly tried it out, but ultimately decided against using it since they don&#39;t support exit nodes, and don&#39;t plan on adding the functionality anytime soon. The documentation also wasn&#39;t comprehensive and I had trouble getting it to run properly on NixOS, my server operating system of choice.&lt;/p&gt;
&lt;p&gt;My second to final consideration was &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://zrok.io/&quot;&gt;Zrok&lt;/a&gt; which is based on &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://openziti.io/&quot;&gt;OpenZiti&lt;/a&gt;. I believe this would have been a solid choice, but I couldn&#39;t figure out how my network architecture would look like, and it ended up being too complicated to run on NixOS.&lt;/p&gt;
&lt;p&gt;This is where I came across Netbird.&lt;/p&gt;
&lt;h2 id=&quot;introducing-netbird&quot;&gt;Introducing Netbird&lt;/h2&gt;
&lt;p&gt;Similar to Tailscale, &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://netbird.io/&quot;&gt;Netbird&lt;/a&gt; is a mesh VPN based on WireGuard that allows devices to connect to each other peer-to-peer or fall back to a relay if NAT traversal fails.&lt;/p&gt;
&lt;p&gt;To answer all my requirements, Netbird allows you to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connect to a network with at least one Netbird peer (with support for high-availability with redundant peers)&lt;/li&gt;
&lt;li&gt;Use any peer as an exit node&lt;/li&gt;
&lt;li&gt;Proxy services very easily using private Netbird IPs&lt;/li&gt;
&lt;li&gt;Support for Linux, Android, Windows, Mac, iOS, and even OpenWRT routers&lt;/li&gt;
&lt;li&gt;Subnets are well supported, as well as DNS management, and different client profiles&lt;/li&gt;
&lt;li&gt;Supports zero-trust principles using groups, ACLs (Access Control Lists) with posture checks (minimum client requirements, IP filtering, etc.)&lt;/li&gt;
&lt;li&gt;Self-hostable, free and open-source software. They also offer a managed free tier&lt;/li&gt;
&lt;li&gt;The easy-to-comprehend management interface shows which peer is online/offline, and no critical feature seems to be lacking&lt;/li&gt;
&lt;li&gt;Great documentation at &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.netbird.io/&quot;&gt;docs.netbird.io&lt;/a&gt;, along with an active, friendly and helpful community of developers, and administrators&lt;/li&gt;
&lt;li&gt;The management interface is easy to comprehend, and doesn&#39;t confuse the user with unnecessary options&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That being said, I bought a cheap VPS, and deployed the management server there. From that point on, all I had to do was install the Netbird client on all my devices. Thankfully this is as easy as copy pasting a simple install script:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https://pkgs.netbird.io/install.sh&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and for NixOS, adding one line to my declarative config:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  services&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;netbird&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;enable&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main benefit of Netbird was the hugely simplified management of peers, how easy ACLs were to set up, how straightforward the setup was, and how it allows me to have a clear overview of the status of the peers. Also compared to the setup with WireGuard I had before, peer-to-peer connections are now possible instead of always relaying everything. Not to mention, I really like the design of the management interface (if you couldn&#39;t tell (and haven&#39;t seen how it looks like)).&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Deploying Netbird on NixOS took some time since I couldn&#39;t find a guide for NixOS specifically, and had to go off reading documentation at many different places, reading source code, and experimenting. Eventually I managed to get it up and running, and decided to write &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://lukadeka.com/blog/setting-up-netbird-with-zitadel-on-nixos/&quot;&gt;a guide on setting up Netbird for NixOS&lt;/a&gt; to spare potential headaches.&lt;/p&gt;
&lt;p&gt;Netbird has been working great ever since the initial deployment.&lt;/p&gt;
&lt;p&gt;Since the VPS has a publicly routable IP (how else would you access it?), all that&#39;s needed is to proxy the desired traffic to the home-server via the Netbird IP, and that&#39;s all she wrote.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Setting up Seafile on NixOS</title>
        <published>2024-12-03T00:00:00+00:00</published>
        <updated>2025-08-21T00:00:00+00:00</updated>
        
        <author>
          <name>Luka Dekanozishvili</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lukadeka.com/blog/setting-up-seafile-on-nixos/"/>
        <id>https://lukadeka.com/blog/setting-up-seafile-on-nixos/</id>
        
        <content type="html" xml:base="https://lukadeka.com/blog/setting-up-seafile-on-nixos/">&lt;h2 id=&quot;preface&quot;&gt;Preface&lt;/h2&gt;
&lt;p&gt;After I decided I wanted to set up Seafile, a file server, I found little
documentation for NixOS.&lt;/p&gt;
&lt;p&gt;After experimenting with the options, and asking the maintainer for help, I
finally got a working configuration, and decided to write a wiki entry as well
to help future NixOS newcomers.&lt;/p&gt;
&lt;p&gt;This entry is also available on
&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://wiki.nixos.org/wiki/Seafile&quot;&gt;wiki.nixos.org&lt;/a&gt; and
&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://nixos.wiki/wiki/Seafile&quot;&gt;nixos.wiki&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.seafile.com/&quot;&gt;Seafile&lt;/a&gt; is a file-hosting software
system with a simple web interface and client applications for file
access. Seafile&#39;s functionality is similar to file-hosting services
such as Dropbox and Google Drive.&lt;/p&gt;
&lt;p&gt;As opposed to &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://nextcloud.com/&quot;&gt;Nextcloud&lt;/a&gt;, Seafile offers simpler
user administration and better file-server performance.&lt;/p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;Minimal configuration of Seafile:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  services&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;seafile&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    adminEmail&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;admin@example.com&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    initialAdminPassword&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;change this later!&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    ccnetSettings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;General&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;SERVICE_URL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https://seafile.example.com&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    seafileSettings&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      fileserver&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        host&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unix:/run/seafile/server.sock&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use nginx to serve Seafile from a unix socket:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  services&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;nginx&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;virtualHosts&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;seafile.example.com&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    forceSSL&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    enableACME&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    locations&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        proxyPass&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;http://unix:/run/seahub/gunicorn.sock&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        extraConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_set_header   Host $host;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_set_header   X-Real-IP $remote_addr;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_set_header   X-Forwarded-Host $server_name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_read_timeout  1200s;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          client_max_body_size 0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;/seafhttp&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        proxyPass&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;http://unix:/run/seafile/server.sock&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        extraConfig&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          rewrite ^/seafhttp(.*)$ $1 break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          client_max_body_size 0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_connect_timeout  36000s;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_read_timeout  36000s;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          proxy_send_timeout  36000s;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          send_timeout  36000s;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;#39;&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;additional-configuration&quot;&gt;Additional configuration&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  services&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;seafile&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    seafileSettings&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      quota&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;50&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Amount of GB allotted to users&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      history&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;keep_days&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;14&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Remove deleted files after 14 days&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      fileserver&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        host&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;unix:/run/seafile/server.sock&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        web_token_expire_time&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 18000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # Expire the token in 5h to allow longer uploads&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Enable weekly collection of freed blocks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    gc&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      enable&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;      dates&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Sun 03:00:00&amp;quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To change the directory of the database, create the directory with the
appropriate permissions, &lt;code&gt;chown -R seafile:seafile&lt;/code&gt; it and set:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot; &gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  services&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;seafile&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    dataDir&lt;/span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;/path/seafile/data&amp;quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;initialAdminPassword&lt;/code&gt; is set only once when the server is first
initialized. Any changes to it afterward will have no effect on it. If
you cannot log in for the first time, delete &lt;code&gt;/var/lib/seafile/data&lt;/code&gt;,
remove the Seafile configuration from your config, rebuild, re-add it,
and the password will be set in the next rebuild.&lt;/p&gt;
&lt;p&gt;Logs for Seafile and SeaHub (Seafile&#39;s web interface) are stored
in &lt;code&gt;/var/log/seafile/server.log&lt;/code&gt; and &lt;code&gt;/var/log/seafile/seahub.log&lt;/code&gt; respectively.&lt;/p&gt;
&lt;p&gt;For additional options, refer to the &lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://manual.seafile.com/13.0/config/&quot;&gt;Seafile Admin
Manual&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
</feed>
