<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>zerforschen&#43;</title>
    <link>https://zerforschen.plus/</link>
    <description>Recent content on zerforschen&#43;</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Mon, 15 Sep 2025 20:00:00 +0200</lastBuildDate>
    <atom:link href="https://zerforschen.plus/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Keeping scrapers out</title>
      <link>https://zerforschen.plus/posts/keeping-scrapers-out/</link>
      <pubDate>Mon, 15 Sep 2025 20:00:00 +0200</pubDate>
      <guid>https://zerforschen.plus/posts/keeping-scrapers-out/</guid>
      <description>&lt;p&gt;After reading an &lt;a href=&#34;https://lwn.net/Articles/1008897/&#34; target=&#34;_blank&#34;&gt;LWN article on high AI scraper traffic&lt;/a&gt;, I also wanted to do something to &amp;ldquo;protect&amp;rdquo; the blog.&#xA;I do not see any continuous load peaks, but I dislike the idea of giant corporations profiting off of my writing without any negotiation.&lt;/p&gt;&#xA;&lt;p&gt;One solution that stands out currently is &lt;a href=&#34;https://anubis.techaro.lol/&#34; target=&#34;_blank&#34;&gt;anubis&lt;/a&gt;.&#xA;It tries to challenge requests in a way that is hard or resource intensive for scrapers at scale, but easy and resource-light for normal users.&lt;/p&gt;&#xA;&lt;p&gt;I could not find a good summary on how to proxy an nginx virtual host through anubis, so here we go.&lt;/p&gt;&#xA;&lt;!-- more --&gt;&#xA;&lt;h3 id=&#34;starting-configuration&#34;&gt;Starting configuration&lt;/h3&gt;&#xA;&lt;p&gt;The following examples are based on the configuration of this blog.&#xA;Most things not relevant here are removed, but you can take a look at the &lt;a href=&#34;https://git.berlin.ccc.de/vinzenz/nixos-configuration/src/commit/5f5c7267dc8c734eca2de87b5c0168523c9fa3b3/hosts/hetzner-vpn2/nginx.nix&#34; target=&#34;_blank&#34;&gt;original&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;nginx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recommendedProxySettings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recommendedTlsSettings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recommendedGzipSettings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recommendedOptimisation &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    virtualHosts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;zerforschen.plus&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        addSSL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        enableACME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        root &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;zerforschen-plus-content;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;hide-real-host&#34;&gt;Hide real host&lt;/h3&gt;&#xA;&lt;p&gt;The first thing to do is hiding the real website.&#xA;Otherwise, a scraper can just use whatever we rename it to.&lt;/p&gt;&#xA;&lt;p&gt;I wanted to forward everything through unix domain socket.&#xA;The kind I&amp;rsquo;ll use behave like a file, which means we do not have to make sure that e.g. the application only listens on localhost.&#xA;It also makes permission management trivial, but we&amp;rsquo;ll see that later.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# /run/nginx already exists&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  blog-domain-socket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/nginx/blog.sock&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;nginx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    virtualHosts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;zerforschen.plus&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        addSSL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        enableACME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# we do not have anything hosted here anymore&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# a new virtual host contains the site now&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blog-in-anubis&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        root &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;zerforschen-plus-content;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# specifying any listen overrides the defaults&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        listen &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# this makes nginx create the unix domain socket&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            addr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unix:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; blog-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;create-anubis-instance&#34;&gt;Create anubis instance&lt;/h3&gt;&#xA;&lt;p&gt;Next, we need an anubis service that forwards to the socket created by nginx.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  blog-domain-socket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/nginx/blog.sock&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# previous nginx config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anubis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;instances&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;main &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      settings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TARGET &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unix://&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; blog-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;forward-public-host-to-anubis&#34;&gt;Forward public host to anubis&lt;/h3&gt;&#xA;&lt;p&gt;Now we have an anubis instance running, but no way to access it from outside.&lt;/p&gt;&#xA;&lt;p&gt;I did not want to expose anubis to the public internet directly, so I configured another unix domain socket for this purpose.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  blog-domain-socket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/nginx/blog.sock&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  anubis-domain-socket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/anubis/anubis-blog.sock&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nginx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      virtualHosts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;zerforschen.plus&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          addSSL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          enableACME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          locations&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# HTTP over unix domain socket&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            proxyPass &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://unix:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; anubis-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# &amp;#34;blog-in-anubis&amp;#34; = { ... };&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anubis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;instances&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;main &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      settings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# this makes anubis create and listen to the socket&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        BIND &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; anubis-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TARGET &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unix://&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; blog-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;socket-permissions&#34;&gt;Socket permissions&lt;/h3&gt;&#xA;&lt;p&gt;The config is nearly complete now.&#xA;Applying the configuration now produces permission errors when trying to access the site, because the sockets are owned by the service user and grou with a 660 permission.&#xA;In my case, I simply added the services to each others groups.&#xA;If this was a server I was making my living with, I&amp;rsquo;d probably create a new group and folder and add both services to that one.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  systemd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;services &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nginx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;serviceConfig&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SupplementaryGroups &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;anubis&amp;#34;&lt;/span&gt; ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anubis-main&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;serviceConfig&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SupplementaryGroups &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt; ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;final-configuration&#34;&gt;Final configuration&lt;/h3&gt;&#xA;&lt;p&gt;Overall, I think NixOS makes the configuration required easy to read and write.&#xA;The &lt;a href=&#34;https://search.nixos.org/options&#34; target=&#34;_blank&#34;&gt;NixOS options search&lt;/a&gt; is a great storage of knowledge for any software configurable through the NixOS configuration.&#xA;If the &lt;a href=&#34;https://github.com/TecharoHQ/anubis/blob/f745d37d9006c3431bf3d435c61565250ab53a3e/data/botPolicies.yaml&#34; target=&#34;_blank&#34;&gt;default policy&lt;/a&gt; does not fit your needs, that would be another step required&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Update: Asking ChatGPT about this article indicates everything is working as intended:&#xA;&lt;img src=&#34;chat-screenshot.png&#34; alt=&#34;A chat bot screenshot. When asked about the URL of this article, the AI responds with &amp;ldquo;Hey — I tried opening that “Keeping Scrapers Out” post on Zerforschen and got “Access Denied”.&amp;rdquo;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;My &lt;a href=&#34;https://git.berlin.ccc.de/vinzenz/nixos-configuration/src/commit/7a17930dd4f225cda4047f1df7d650249c91f29b/nixosConfigurations/hetzner-vpn2/nginx.nix#&#34; target=&#34;_blank&#34;&gt;final configuration&lt;/a&gt; for nginx and anubis was as follows:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  blog-domain-socket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/nginx/blog.sock&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  anubis-domain-socket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/anubis/anubis-blog.sock&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  systemd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;services &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nginx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;serviceConfig&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SupplementaryGroups &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;anubis&amp;#34;&lt;/span&gt; ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anubis-main&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;serviceConfig&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SupplementaryGroups &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt; ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nginx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      recommendedProxySettings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      recommendedTlsSettings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      recommendedGzipSettings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      recommendedOptimisation &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      virtualHosts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;zerforschen.plus&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          addSSL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          enableACME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          locations&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            proxyPass &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://unix:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; anubis-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blog-in-anubis&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          root &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;zerforschen-plus-content;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          listen &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              addr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unix:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; blog-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anubis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;instances&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;main &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      settings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        BIND &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; anubis-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TARGET &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unix://&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; blog-domain-socket;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Part of the reason I am writing this article is to check if my RSS reader can handle it.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>WHY 2025 - Day 1</title>
      <link>https://zerforschen.plus/posts/why-2025/day1/</link>
      <pubDate>Sat, 16 Aug 2025 23:00:00 +0200</pubDate>
      <guid>https://zerforschen.plus/posts/why-2025/day1/</guid>
      <description>&lt;p&gt;I went to WHY2025, a Dutch hacker camp.&lt;/p&gt;&#xA;&lt;p&gt;This is the third part of my travel log, covering everything happening on day 1.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&lt;details&gt;&#xA;    &lt;summary&gt;Disclaimer WHY2025&lt;/summary&gt;&#xA;   &lt;p&gt;I am trying to write more, so I am experimenting with a series of travel-log style post.&#xA;The resulting text is boring to read, the contained conclusions are obvious for anyone with two or more brain cells&#xA;and you will just waste your time reading it.&lt;/p&gt;&#xA;&lt;p&gt;Some posts contain photos, so I should probably tell you about the photo policy of events like this.&#xA;People are allowed to take pictures, but only after asking every single person in the photo individually.&#xA;In practice this means you cannot really take good pictures to capture the vibe of the place -&#xA;you are either photographing an object or a mostly empty space.&lt;/p&gt;&#xA;&lt;p&gt;As with all other posts, I may update previous ones without telling anyone.&#xA;You may want to wait until I added all the photos and polished the text a bit.&lt;/p&gt;&#xA;&#xA;&lt;/details&gt;&#xA;&#xA;&lt;h3 id=&#34;waking-up&#34;&gt;Waking up&lt;/h3&gt;&#xA;&lt;p&gt;At day 1 I woke up in a warm tent to ABBAs &amp;ldquo;Gimme Gimme&amp;rdquo;, making further sleep impossible.&#xA;The weather service now predicted hotter weather than originally planned for, so I had to ration my cooler clothing for the hottest days, which had yet to come.&lt;/p&gt;&#xA;&lt;p&gt;I got a pancake in the food court and continued writing.&#xA;After saturation settled in, the next level in the pyramid of needs was social connections, so I walked around a bit.&lt;/p&gt;&#xA;&lt;h3 id=&#34;angry-nerds&#34;&gt;Angry Nerds&lt;/h3&gt;&#xA;&lt;p&gt;After a while I came across a village by the &amp;ldquo;Angry Nerds&amp;rdquo; podcast, which is sadly in Dutch so I was not familiar with it.&#xA;One of the creators of it was there and we talked for a while about differences between the German and Dutch hacker events.&#xA;WHY20205 feels less political than the events by CCC.&#xA;This may seem weird given that there is a big support for Ukraine tent, but at Congress there is a bunch of talks and assemblies about civil rights and climate action, by e.g. Netzpolitik.org or Bits&amp;amp;Bäume.&lt;/p&gt;&#xA;&lt;p&gt;He also pointed out the preparations of the firewall (marked by big flames on the map) and showed me a sneak peek.&#xA;Without being told, I could not have guessed what those grey boxes do.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;firewall_off.jpg&#34; alt=&#34;Suspicius grey boxes on a hill&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;As we can time travel here, you can also see the firewall at night already:&lt;/p&gt;&#xA;&#xA;&lt;video loop src=&#34;https://zerforschen.plus/posts/why-2025/day1/firewall_on.webm&#34; width=&#34;100%&#34; autoplay muted&gt;&lt;/video&gt;&#xA;&#xA;&lt;p&gt;After a while, I did not want to bother my captive audience anymore so I continued exploring.&lt;/p&gt;&#xA;&lt;h3 id=&#34;anderstorps&#34;&gt;Anderstorps&lt;/h3&gt;&#xA;&lt;p&gt;I walked past a bar at one of the villages playing very loud music to something you could describe as art.&#xA;I had just found Anderstorps, right next to BornHack.&lt;/p&gt;&#xA;&lt;p&gt;// FIXME: add picture of intact art piece&lt;/p&gt;&#xA;&lt;p&gt;As it seems like I do not have a picture of the art piece intact, here is a short description.&#xA;There was a pavillion with a white table in the middle.&#xA;On the table there was a black iron cage containing an accordeon.&#xA;In front of the table there was a huge &amp;ldquo;accordeons forbidden&amp;rdquo; sign.&lt;/p&gt;&#xA;&lt;p&gt;When asked about it, the inhabitants told me to come back later as they were too hung over from the night of Day 0, when different music will be playing.&#xA;As I wanted to sit down and write some more, I used the provided shade here.&#xA;Not much later, I noticed they were &lt;em&gt;literally&lt;/em&gt; playing the same music, as in looping a single track.&lt;/p&gt;&#xA;&lt;p&gt;🎵 Faxe Kondi by Klumben &amp;amp; Raske Penge&lt;/p&gt;&#xA;&lt;p&gt;On Day 3 or so, the cage including the instrument were gone, which may or may not have been planned beforehands.&#xA;They did not provide any further context apart from &amp;ldquo;have you heard what they sound like?&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;stolen_instrument.jpg&#34; alt=&#34;Installation without cage and instrument&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;first-talk&#34;&gt;First talk&lt;/h3&gt;&#xA;&lt;p&gt;Next up was a talk that made me realize more stuff that was different from CCCamp.&#xA;It expected a talk about either cloud security in general, or one about finding vulnerabilities in a deployment.&#xA;Instead, this talk was about securing &lt;em&gt;proprietary&lt;/em&gt; Microsoft Azure services (a company still rightiously considered evil in many parts of the chaos) using other proprietary Microsoft Azure services.&#xA;Whenever there was a security issue, the solution was to use more Azure services.&#xA;There was barely enough context to figure out how to generalize what was said for other products, so it was not really helpfull for me.&#xA;The following questions were also about specific products and services.&#xA;I am pretty sure this would not have been on the Fahrplan in Germany, and as stated by others this would also have raised eyebrows in the Dutch hacker community one or two decades ago.&lt;/p&gt;&#xA;&lt;h3 id=&#34;power-issues&#34;&gt;Power issues&lt;/h3&gt;&#xA;&lt;p&gt;I wanted to get a new mate, but had to walk to a different bar because of issues with the payment system again.&#xA;As Heaven announced, the power outage was not on site and affected all of North Holland.&#xA;This meant that everything that was attached to the regional power grid, which was meant to be more stable than the on-site generators, did not work.&#xA;Because of this, all talks for the rest of the day were cancelled and mostly rescheduled in the following days.&#xA;At least bar payments were possible again shortly thereafter.&lt;/p&gt;&#xA;&lt;p&gt;When the sun started to settle, the soundcheck of a Metallica tribute band fittingly called &lt;em&gt;Sad but Tribute&lt;/em&gt; started.&#xA;From then on, the evening was filled with surprisingly close covers.&#xA;The castle-shaped stage (&amp;ldquo;party area&amp;rdquo;) and the flamethrowers attached to the towers were visible from all over the camping grounds.&lt;/p&gt;&#xA;&lt;h3 id=&#34;what-the-fog&#34;&gt;What the fog&lt;/h3&gt;&#xA;&lt;p&gt;In the nights, it got really foggy, and I mean &lt;em&gt;really&lt;/em&gt; foggy.&#xA;This made all the lights everywhere stand out even more.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;projector.jpg&#34; alt=&#34;A projector running at the party bar, producing rays of colorful lights in the fog&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Combine this with a bunch of very strong fog machines and you could maybe see two meters into the distance.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;mastodon-embed&#34; data-embed-url=&#34;https://chaos.social/@vinzenz/115001634006324155/embed&#34; style=&#34;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&#34;&gt; &lt;a href=&#34;https://chaos.social/@vinzenz/115001634006324155&#34; target=&#34;_blank&#34; style=&#34;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Oxygen, Ubuntu, Cantarell, &#39;Fira Sans&#39;, &#39;Droid Sans&#39;, &#39;Helvetica Neue&#39;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&#34;&gt; &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; width=&#34;32&#34; height=&#34;32&#34; viewBox=&#34;0 0 79 75&#34;&gt;&lt;path d=&#34;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&#34; fill=&#34;currentColor&#34;/&gt;&lt;/svg&gt; &lt;div style=&#34;color: #787588; margin-top: 16px;&#34;&gt;Post by @vinzenz@chaos.social&lt;/div&gt; &lt;div style=&#34;font-weight: 500;&#34;&gt;View on Mastodon&lt;/div&gt; &lt;/a&gt; &lt;/blockquote&gt; &lt;script data-allowed-prefixes=&#34;https://chaos.social/&#34; async src=&#34;https://chaos.social/embed.js&#34;&gt;&lt;/script&gt;&#xA;&lt;br /&gt;&#xA;&lt;p&gt;Someone described their shift as customers popping into existance in front of the bar, ordering, and returning into nothingness after receiving their drinks.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;thick_fog.jpg&#34; alt=&#34;Fog so thick you can only see general shapes and big diffused spots of light&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;After turning of the fog machines at milliways, it cleared up quicky around us.&#xA;It looked unreal even in person.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;less_fog.jpg&#34; alt=&#34;Fog on the hills with lights peeking through it, but no fog in the foreground&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The rest of the night I played PolyGen, which will be described &lt;a href=&#34;https://zerforschen.plus/posts/why-2025/polygen/&#34;&gt;in a future blog post&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>WHY 2025 - Day 0</title>
      <link>https://zerforschen.plus/posts/why-2025/day0/</link>
      <pubDate>Sat, 09 Aug 2025 19:00:00 +0200</pubDate>
      <guid>https://zerforschen.plus/posts/why-2025/day0/</guid>
      <description>&lt;p&gt;I went to WHY2025, a Dutch hacker camp.&lt;/p&gt;&#xA;&lt;p&gt;This is the second part of my travel log, covering everything happening on day 0 after arriving on the site.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&lt;details&gt;&#xA;    &lt;summary&gt;Disclaimer WHY2025&lt;/summary&gt;&#xA;   &lt;p&gt;I am trying to write more, so I am experimenting with a series of travel-log style post.&#xA;The resulting text is boring to read, the contained conclusions are obvious for anyone with two or more brain cells&#xA;and you will just waste your time reading it.&lt;/p&gt;&#xA;&lt;p&gt;Some posts contain photos, so I should probably tell you about the photo policy of events like this.&#xA;People are allowed to take pictures, but only after asking every single person in the photo individually.&#xA;In practice this means you cannot really take good pictures to capture the vibe of the place -&#xA;you are either photographing an object or a mostly empty space.&lt;/p&gt;&#xA;&lt;p&gt;As with all other posts, I may update previous ones without telling anyone.&#xA;You may want to wait until I added all the photos and polished the text a bit.&lt;/p&gt;&#xA;&#xA;&lt;/details&gt;&#xA;&#xA;&lt;h3 id=&#34;entrance&#34;&gt;Entrance&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;map.png&#34; alt=&#34;Map of the area&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The shuttle dropped us off on a parking lot next to the event area.&#xA;To my surprise, there was also a team you could pass your luggage to that were driving everything to the info tent.&#xA;I wondered what would happen if there were issues with your ticket in that case.&#xA;Also, I did not want to have to search where I could get my tent back in case time mattered to get a good spot,&#xA;and I wanted my tent near the border between the cyan and red fields, which meant I did not have to walk &lt;em&gt;as&lt;/em&gt; far.&lt;/p&gt;&#xA;&lt;p&gt;The ticket checking was very fast without any queue.&#xA;This year&amp;rsquo;s ribbon is dark blue with star patterns on it - pretty!&#xA;I also liked the fact you only had to show your ID in case you wanted an  additional &amp;ldquo;18+&amp;rdquo; ribbon to be able to buy alcohol and so on (and you did not need an ID later to get drinks).&#xA;I felt kind of flattered by the fact I had to show mine, as I started getting self conscious about my age when someone guessed 10y too high a year ago.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;ribbons.jpg&#34; alt=&#34;Entrance and 18+ ribbons&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;People were handed a paper goodie bag which were supposed to also include stickers, but ended up mostly containing ads for the sponsors of the event.&#xA;I usually &lt;em&gt;really&lt;/em&gt; dislike ads, but in this case I liked the organisations beaing advertised for (e.g. NIST and Support for Ukraine), so I did not mind.&#xA;It also contained &lt;em&gt;one&lt;/em&gt; sticket and a paper map as well as guidance for muggles that did not read the wiki.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tent&#34;&gt;Tent&lt;/h3&gt;&#xA;&lt;p&gt;I found a good spot exactly where I wanted one. It ended up right next to a power station, which meant my short extension/splitter was enough to reach it. Being able to charge laptop and phone overnight in your tent is a &lt;em&gt;must&lt;/em&gt; on a hacker camp.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;power-station.jpg&#34; alt=&#34;White power distrubution box next to tent&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;At CCCamp, I did bring a router and long ethernet cable, but did not end up using it much because there was great WiFi coverage.&#xA;This time I did not, and because life is hard and unfair, neither my laptop nor phone were able to keep a connection while in the tent.&#xA;That meant I sadly did not use a &lt;em&gt;Datenklo&lt;/em&gt; (data toilet).&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;datenklo.jpg&#34; alt=&#34;Datenklo in it&amp;rsquo;s natural environment&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;While I got my home base ready, the sound check on the stages started, as stated on signs at the entrance earlier. The next half hour was filled with an instrumental version of &amp;ldquo;Never gonna give you up&amp;rdquo; with different equalizer settings and volumes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildup&#34;&gt;Buildup&lt;/h3&gt;&#xA;&lt;p&gt;With events like this, the days are literally numbered, with day one being the day of the opening.&#xA;A big team consisting of mostly unpaid volunteers had already spent a week on site building up the infrastructure.&#xA;As with the German camp, the existing fixed infrastructure is not enough for the thousands of people going to the toilet, expecting cooled mate, playing on &lt;a href=&#34;https://wiki.why2025.org/Project:Arcade&#34; target=&#34;_blank&#34;&gt;arcade machines&lt;/a&gt; or running &lt;a href=&#34;https://wiki.why2025.org/Village:Yolocation&#34; target=&#34;_blank&#34;&gt;pop-up data centers&lt;/a&gt;. On Day 0 (also sometimes called Day -0), heavy machinery was still driving around when I started exploring.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;unicorns.jpg&#34; alt=&#34;real unicorns&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;heading&#34;&gt;😱🍾💸&lt;/h3&gt;&#xA;&lt;p&gt;Being near the food court had the advantage that the first thing I found was a bar, so I wanted to get a mate.&#xA;I was shocked (&lt;em&gt;shocked!&lt;/em&gt;) twice.&lt;/p&gt;&#xA;&lt;p&gt;The first thing was the mate itself.&#xA;I was used to choosing between brands, Flora Power being my favorite, but here it was all the different flavors of Club-Mate.&lt;/p&gt;&#xA;&lt;p&gt;// FIXME: ask at the bar to take a photo of the fridge and put it here&lt;/p&gt;&#xA;&lt;p&gt;The other thing was that they did not acccept any cash.&#xA;The German hacker events I went to were very proud about &lt;em&gt;not&lt;/em&gt; accepting digital payments (&lt;em&gt;Jede Kartenzahlung wird überwacht&lt;/em&gt;), and here it was the other way around!&#xA;There was a way to pay pseudonymously though, and that was to charge an event payment card with cash at the info desk.&#xA;According to the sticker on the card, you can reprogram them to do something else afterwards, which is nice.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;payment-card.jpg&#34; alt=&#34;Payment card&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;What this prepaid card did not solve though was that you cannot pay if power is down.&#xA;Later in the evening one of the bars had to close early due to exactly this issue.&#xA;Whenever power was cut, the switch that provided PoE and internet to the payment terminals had to reboot, which took a while.&#xA;Because they were frequent enough, that process repeated mutliple times without them being able to sell anything.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;switch.jpg&#34; alt=&#34;The problematic switch&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;As with the mate, I think there would be a good middle ground somewhere in between.&#xA;Maybe there could have been one cash register per bar at WHY and one accepting cards at C3.&#xA;But I am not an organizer of things like this, so what do I know.&lt;/p&gt;&#xA;&lt;p&gt;I continued exploring properly caffeinated.&lt;/p&gt;&#xA;&lt;h3 id=&#34;light-and-sound-installation&#34;&gt;Light and sound installation&lt;/h3&gt;&#xA;&lt;p&gt;// FIXME: ask V what it is called&lt;/p&gt;&#xA;&lt;p&gt;Near the entrance of the event, there was a hill with a huge sign on it.&#xA;A colorful contruction caught my eye, so I wanted to take a closer look.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;isopod.jpg&#34; alt=&#34;isopod&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I got to know the artist, let&amp;rsquo;s call them V here, who was still setting it up.&#xA;They built a tent out of foamy, semi-translucent packing material, with RDB light strips adding movement.&#xA;It looked like a giant isopod crawling up the hill.&lt;/p&gt;&#xA;&lt;p&gt;The installation noticed when someone was outside and made an old rotary dial phone inside ring, which prompted the visitor to go inside and listen to the voice on the other end.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;future.jpg&#34; alt=&#34;inside the isopod&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;angel-badge&#34;&gt;Angel badge&lt;/h3&gt;&#xA;&lt;p&gt;As I was already exhausted, I did not feel like volunteering that day, but I still got my angel status set to arrived and got the very pretty badge:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;angel-badge.jpg&#34; alt=&#34;angel badge&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;milliways&#34;&gt;Milliways&lt;/h3&gt;&#xA;&lt;p&gt;I also checked Milliways, the restaurant at the end of the universe.&#xA;They have a village or assembly at many hacker events and seem to have grown a lot over the years.&#xA;Hacking area, bar, kitchen and midnight snacks all in one.&lt;/p&gt;&#xA;&lt;p&gt;As usual, they brought their geodesic dome, this time decorated to feel jungle-like inside.&#xA;The dome was one of the places playing techno most day and night.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;dome.jpg&#34; alt=&#34;Looking up in the dome&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;What I did not know was that they usually get &lt;a href=&#34;https://wiki.milliways.info/index.php?title=Challenge_coins&#34; target=&#34;_blank&#34;&gt;challenge coins&lt;/a&gt; made to finance the material costs.&#xA;They were very pretty, but only payable in cash.&#xA;As I hoped to not have to go to the next ATM in Alkmaar because of the cashless bars and food court, so I made a mental note to come back at the end of the event.&lt;/p&gt;&#xA;&lt;h3 id=&#34;need-a-pillow&#34;&gt;Need a pillow?&lt;/h3&gt;&#xA;&lt;p&gt;I found V at one of the other bars and we talked for a while.&#xA;As this was their first hacker event, it was a great opportunity to share some great experiences I had at other events while drinking our first &lt;a href=&#34;https://entropia.de/Tschunk&#34; target=&#34;_blank&#34;&gt;Tschunk&lt;/a&gt;.&#xA;When I told him that when someone needs anything, it can usually be found, they asked for advice regarding camping gear.&#xA;V did not know this was a camp before coming here, which was also why the installation was tent-shaped.&#xA;I told them to ask at the info desk, which apparently worked great as they just got handed a blanket and pillow there for free.&lt;/p&gt;&#xA;&lt;p&gt;I was yearning for exploration, so we went our separate ways.&#xA;Even though the opening was still more than half a day in the future, the camp was already glowing in all colors of the rainbow.&#xA;Parties and hackers everywhere, I had a great time finding orientation in the big area.&#xA;My phone said I walked around 13,5k steps before 12 am.&lt;/p&gt;&#xA;&lt;h3 id=&#34;going-to-sleep&#34;&gt;Going to sleep&lt;/h3&gt;&#xA;&lt;p&gt;The sanitary conditions were &lt;em&gt;great&lt;/em&gt; for a festival, and would still have been okay for a conference.&#xA;After such a long day, I was not going to sleep without a proper shower.&#xA;Without control over the temperature, I did not expect it to be super comfortable, but I really struggled cleaning myself because the water was &lt;em&gt;freezing&lt;/em&gt;.&#xA;Maybe it was my tiredness at 3:30 am after being awake for 21h, but I did not take a shower as cold in a decade.&#xA;The next day the water was heated and maybe even too warm, so I do not know what happened there.&lt;/p&gt;&#xA;&lt;p&gt;UPDATE: As it turned out, the gas for the water heater was just empty.&#xA;They later put up a sign.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;cold-shower.jpg&#34; alt=&#34;Laminated sign stating that the gas may have run out if the water is cold, with a QR code to get in touch with people able to fix it.&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>WHY 2025 - Preparations</title>
      <link>https://zerforschen.plus/posts/why-2025/prep/</link>
      <pubDate>Fri, 08 Aug 2025 02:30:00 +0200</pubDate>
      <guid>https://zerforschen.plus/posts/why-2025/prep/</guid>
      <description>&lt;p&gt;I went to WHY2025, a Dutch hacker camp.&lt;/p&gt;&#xA;&lt;p&gt;This is the first part of my travel log, covering everything happening before arriving on site.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&lt;details&gt;&#xA;    &lt;summary&gt;Disclaimer WHY2025&lt;/summary&gt;&#xA;   &lt;p&gt;I am trying to write more, so I am experimenting with a series of travel-log style post.&#xA;The resulting text is boring to read, the contained conclusions are obvious for anyone with two or more brain cells&#xA;and you will just waste your time reading it.&lt;/p&gt;&#xA;&lt;p&gt;Some posts contain photos, so I should probably tell you about the photo policy of events like this.&#xA;People are allowed to take pictures, but only after asking every single person in the photo individually.&#xA;In practice this means you cannot really take good pictures to capture the vibe of the place -&#xA;you are either photographing an object or a mostly empty space.&lt;/p&gt;&#xA;&lt;p&gt;As with all other posts, I may update previous ones without telling anyone.&#xA;You may want to wait until I added all the photos and polished the text a bit.&lt;/p&gt;&#xA;&#xA;&lt;/details&gt;&#xA;&#xA;&lt;h3 id=&#34;expectations&#34;&gt;Expectations&lt;/h3&gt;&#xA;&lt;p&gt;What Hackers Yearn 2025 is a so-called hackercamp. From the wiki:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;At its core, a hackercamp is a self-organized space where hackers, makers, artists, activists, and technology enthusiasts come together to learn, create, and celebrate technology. The landscape comes alive with colorful LED installations, interactive art, hand-built sculptures, and high-tech experiments happening in every corner.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://wiki.why2025.org/Newcomers_Guide#The_essence_of_a_hacker_camp&#34; target=&#34;_blank&#34;&gt;wiki.why2025.org/Newcomers_Guide&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;As is tradition with the CCCamp, the event takes place every four years, which means overall there is one &amp;ldquo;big&amp;rdquo; hackercamp every two years.&#xA;It&amp;rsquo;s one of those events where your do not have to worry about stuff being stolen from your rent as much, but where you should install any available security patches beforehand.&lt;/p&gt;&#xA;&lt;p&gt;While much of the infrastructure is semi-centrally managed, part of the fun is exploring the assemblies, villages and self organized sessions.&#xA;As many of the talks are recorded and can be watched on &lt;a href=&#34;https://media.ccc.de/c/WHY2025&#34; target=&#34;_blank&#34;&gt;media.ccc.de&lt;/a&gt; afterwards, I was mostly interested workshops and the social aspects of the event.&lt;/p&gt;&#xA;&lt;p&gt;For me, this was the first hacker event in the Netherlands, the second hacker &lt;em&gt;camp&lt;/em&gt;, and the sixth hacker event overall.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tickets&#34;&gt;Tickets&lt;/h3&gt;&#xA;&lt;p&gt;Compared to the Chaos Communication Camp 2023, where it felt like getting a ticket required a good internet connection and solving a captcha quick enough, you could just go to their website and complete your purchase. The tickets did sell out in the end, but according to the public stats that happened over the span of days, not seconds.&lt;/p&gt;&#xA;&lt;p&gt;By planning ahead, I was able to convince myself that taking a train very early in the morning was a good idea as the arrival time was more manageable.&#xA;While I did say I &amp;ldquo;planned ahead&amp;rdquo;, that did not mean I committed to this early.&lt;/p&gt;&#xA;&lt;p&gt;I booked my train ticket only a few days in advance, which meant that the FlexPreis (a ticket that is valid for any connection instead of a specific one) seemed like a good idea. I later noticed that when traveling over the border, seat reservations are required, defeating the whole purpose of buying the more expensive ticket for that part of the journey. Booking late also meant no bike tickets were left for the good connections, so I left that at home (I would have had to fix a flat first anyways).&lt;/p&gt;&#xA;&lt;p&gt;Because I have a &lt;em&gt;Deutschlandticket&lt;/em&gt; I can ride any regional trains for free. What that also means though is that your rights regarding connections are limited. Because of that, I usually take a train earlier so I do not miss my inter city train. In that case it meant getting up even earlier just so I could wait at Ostbahnhof for an hour.&lt;/p&gt;&#xA;&lt;h3 id=&#34;packing&#34;&gt;Packing&lt;/h3&gt;&#xA;&lt;p&gt;As usual with events like this, I pushed any packing and so on to the last hours of the day before. Of course work also took longer than expected.&#xA;Luckily just the weekend before, I was at the wonderful Brimborium, a tiny festival near the border to Poland, so I did not bother to store away my camping gear. That meant the basics were still scatered around on the living room floor and just had to be put back into (or attached to) the backpack.&lt;/p&gt;&#xA;&lt;p&gt;I packed both way too much stuff and not enough. Whenever I thought I was done, I remembered something essential that was missing.&lt;/p&gt;&#xA;&lt;p&gt;Because I had to carry all of this, I weighed what I wanted to take with me. Overall I had over 35kg of stuff. Though I did know that was too much, it was too late to send anything by mail or re-pack everything. This was now a problem for future me. Do you notice a theme yet?&lt;/p&gt;&#xA;&lt;h3 id=&#34;getting-there&#34;&gt;Getting there&lt;/h3&gt;&#xA;&lt;p&gt;Boy did I regret all my decisions when my alarm rang. Going to bed at the usual time and just waking up really early did not get me started in a good mood.&lt;/p&gt;&#xA;&lt;p&gt;Apart from some last-minute adjustments, I still had no cash, nothing to eat and nothing to do in the 10 hours of train travel I was going to do.&lt;/p&gt;&#xA;&lt;p&gt;At the &lt;em&gt;Späti&lt;/em&gt; (kiosk that never closes), I had the idea of buying some cheap headphones, as my five year old ones gave up only half a year ago and I did not get around to compare the gazillion options till now. I always wondered who buys stuff like that, now I know. First I was surprised they only cost 10€, but I found out why after getting them out of the package. They weighed nothing, which meant the badly fitting ear pieces were pulled out by the cables all the time. Before even boarding the first train, one of them fell apart because of a manufacturing defect in the molded plastic, revealing one of the two cables inside was not isolated at all. The sound was even worse than expected, producing a loud hiss while audio was playing. That made listening to podcasts especially annoying as after each sentence, the noise would stop for half a second, only to start again when someone continued to talk. The good news is that I did not have to endure that for long, as both earpieces fell apart while boarding my first connection and I was not able to fix them while on the train. 0/10 stars, worse than not having anything. Samsung, you should do better or not sell this crap at all.&lt;/p&gt;&#xA;&lt;p&gt;As I did have a longer wait at Ostbahnhof, I was finally able to get some food and coffee. You should have seen me juggle my giant backpack, the big duffel bag, the food and a hot cup of black coffee. What had to happen did happen, and so the rest of the day I walked around with a big stain on my shirt and a slightly burned chest.&lt;/p&gt;&#xA;&lt;p&gt;Update from more than a week later: the burned area is still clearly visible.&#xA;The strap chafing on my chest all day probably did not help.&lt;/p&gt;&#xA;&lt;p&gt;The actual train ride was comfortable and had a delay of only 30m, which is &lt;em&gt;fine&lt;/em&gt; for a days worth of travel. My biggest complaint is that none of the toilets I checked had soap. If I had not packed as much stuff, it would say it was a better experience than getting there by car. I think it was funny that there Dutch crew stressed the point that you do not have to take a specific train in the Netherlands, even with the SparPreis, eliminating the last possible reason to have bought the expensive ticket.&lt;/p&gt;&#xA;&lt;p&gt;From the train station, the event provided a free shuttle service to the camping ground.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Optimizing Rust binary size</title>
      <link>https://zerforschen.plus/posts/tiny-binaries-rust/</link>
      <pubDate>Wed, 09 Apr 2025 20:29:48 +0200</pubDate>
      <guid>https://zerforschen.plus/posts/tiny-binaries-rust/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://berlin.ccc.de/&#34; target=&#34;_blank&#34;&gt;CCC Berlin&lt;/a&gt;, there is a large pixel matrix hanging on the wall that we call &amp;ldquo;ServicePoint display&amp;rdquo;.&#xA;It receives commands from the local network via UDP, which contain things like very basic text rendering and overwriting parts of the pixel buffer.&#xA;The commands are sent in an efficient binary data structure.&#xA;I wrote (most of) the Rust library &lt;a href=&#34;https://crates.io/crates/servicepoint&#34; target=&#34;_blank&#34;&gt;servicepoint&lt;/a&gt;, which implements this protocol including serialisation,  deserialisation and a bunch of extras for easily crating these packets.&#xA;There are also bindings for other languages, &lt;a href=&#34;https://git.berlin.ccc.de/servicepoint/servicepoint-binding-c&#34; target=&#34;_blank&#34;&gt;including C&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;A few weeks ago, the only user of those C bindings I know informed me, with a big grin on their face, that they&amp;rsquo;d stop using the library and instead wanted to write everything by hand.&#xA;While I know from experience that writing such a library is great fun (and thus does not need another reason), I was intrigued and wanted to know why.&#xA;The main reason they cited was binary size, and while there&amp;rsquo;s probably something wrong with your computer if you do not have 1 MB to spare, I agreed that it was too big for what it does and that I would investigate.&#xA;They knew what they were doing and it worked, I was immediately nerd-sniped and could not think about anything else in my spare time for a whole week.&#xA;I &lt;em&gt;had&lt;/em&gt; to find out why it was so big, and there would &lt;em&gt;have&lt;/em&gt; to be a way to fix it.&lt;/p&gt;&#xA;&lt;p&gt;This is part one, where I optimize the core library for size for fun and experience.&#xA;The order in which I tried all the options is changed for a better text structure, but the results are re-created in the order they appear using the stated tools.&#xA;In a future post, I also want to document how I got the C bindings smaller, as those use all features by default and cannot be reasoned about as much by the Rust compiler.&lt;/p&gt;&#xA;&lt;p&gt;Most of the techniques I used are descibed in &lt;a href=&#34;https://github.com/johnthagen/min-sized-rust&#34; target=&#34;_blank&#34;&gt;Minimizing Rust Binary Size&lt;/a&gt;, though I hope the specific example I provide makes the topic interesting to readers not writing Rust code.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s get hacking!&lt;/p&gt;&#xA;&lt;h2 id=&#34;starting-point&#34;&gt;Starting point&lt;/h2&gt;&#xA;&lt;p&gt;The commit I started on was &lt;a href=&#34;https://git.berlin.ccc.de/servicepoint/servicepoint/src/tag/tiny-rust-binaries-before&#34; target=&#34;_blank&#34;&gt;fe67160974d9fed542eb37e5e9a202eaf6fe00dc&lt;/a&gt;, which is not part of &lt;code&gt;main&lt;/code&gt; as of the writing of this post.&lt;/p&gt;&#xA;&lt;p&gt;As I needed some binary to compare, I chose the example &lt;a href=&#34;https://git.berlin.ccc.de/servicepoint/servicepoint/src/tag/tiny-rust-binaries-before/examples/announce.rs&#34; target=&#34;_blank&#34;&gt;announce&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;//! An example for how to send text to the display.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/// [1]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; clap::Parser;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; servicepoint::{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CharGrid, CharGridCommand, ClearCommand, Connection, UdpConnection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;TILE_WIDTH&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/// [2]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#[derive(Parser, Debug)]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Cli&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#[arg(short, long, default_value = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;localhost:2342&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        help = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Address of the display&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;)]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    destination: String,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#[arg(short, long, num_args = 1.., value_delimiter = &amp;#39;\n&amp;#39;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        help = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Text to send - specify multiple times for multiple lines&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;)]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    text: Vec&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#[arg(short, long, default_value_t = true,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        help = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Clear screen before sending text&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;)]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    clear: &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/// example: `cargo run -- --text &amp;#34;Hallo&amp;#34; --text &amp;#34;CCCB&amp;#34;`&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;/// [3]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; cli &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Cli::parse();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; cli.text.is_empty() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cli.text.push(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, CCCB!&amp;#34;&lt;/span&gt;.to_string());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;/// [4]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; connection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; UdpConnection::open(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;cli.destination)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .expect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;could not connect to display&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;/// [5]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; cli.clear {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        connection.send(ClearCommand).expect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sending clear failed&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; text &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cli.text.join(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#e6db74&#34;&gt;/// [6]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; command: &lt;span style=&#34;color:#a6e22e&#34;&gt;CharGridCommand&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; CharGrid::wrap_str(&lt;span style=&#34;color:#66d9ef&#34;&gt;TILE_WIDTH&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;text).into(); &lt;span style=&#34;color:#e6db74&#34;&gt;/// [7]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    connection.send(command).expect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sending text failed&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#e6db74&#34;&gt;/// [8]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s just run you through the program quickly.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Some imports of the used libraries.&lt;/li&gt;&#xA;&lt;li&gt;The structure &lt;code&gt;Cli&lt;/code&gt; is defined to hold the command line arguments. &lt;a href=&#34;https://crates.io/crates/clap&#34; target=&#34;_blank&#34;&gt;clap&lt;/a&gt; is used to automatically derive a &lt;code&gt;Parser&lt;/code&gt; from the attributes on the fields.&lt;/li&gt;&#xA;&lt;li&gt;The command line arguments are parsed and a default value for the text to send is set.&lt;/li&gt;&#xA;&lt;li&gt;A UDP connection is opened&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#xA;&lt;li&gt;Depending on the arguments, the screen is cleared.&lt;/li&gt;&#xA;&lt;li&gt;All text snippets provided as an argument are concatenated with newlines in between. &lt;code&gt;--text &amp;quot;Hallo&amp;quot; --text &amp;quot;CCCB&amp;quot;&lt;/code&gt; turns into &lt;code&gt;Hallo\nCCCB&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;The string is wrapped to the width of the display, resulting in a &lt;code&gt;CharGrid&lt;/code&gt;, which is then immediately turned into a &lt;code&gt;CharGridCommand&lt;/code&gt;. No fields are changed after this, so the text will be rendered in the top left of the screen when executed on the display.&lt;/li&gt;&#xA;&lt;li&gt;The command is sent to the display.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;At some steps, the program panics with an error message in case something went wrong.&lt;/p&gt;&#xA;&lt;p&gt;I started with &lt;code&gt;rustc 1.82.0 (f6e511eec 2024-10-15)&lt;/code&gt; from nixpkgs &lt;code&gt;0ff09db9d034a04acd4e8908820ba0b410d7a33a&lt;/code&gt;.&#xA;For compiling the example, I just used the usual &lt;code&gt;cargo build --release --example announce&lt;/code&gt; and checked the binary size with &lt;code&gt;ll -B target/release/examples&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The resulting size was 1.1 MB, which should be easy enough to beat.&lt;/p&gt;&#xA;&lt;h2 id=&#34;low-hanging-fruits&#34;&gt;Low hanging fruits&lt;/h2&gt;&#xA;&lt;h3 id=&#34;compiler-options&#34;&gt;Compiler options&lt;/h3&gt;&#xA;&lt;p&gt;The first thing that came to mind was telling the compiler to optimize for size, like with &lt;code&gt;gcc -Os&lt;/code&gt;. The Rust equivalent is &lt;code&gt;opt-level = &amp;quot;s&amp;quot;&lt;/code&gt;, and for even more optimization, &lt;code&gt;z&lt;/code&gt; also disables loop vectorization.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Option&lt;/th&gt;&#xA;          &lt;th&gt;size in isolation (change)&lt;/th&gt;&#xA;          &lt;th&gt;size cumulative (change)&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;baseline&lt;/td&gt;&#xA;          &lt;td&gt;1.137.384&lt;/td&gt;&#xA;          &lt;td&gt;1.137.384&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;opt-level = &amp;lsquo;z&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;1.186.104 (+48.720)&lt;/td&gt;&#xA;          &lt;td&gt;1.186.104 (+48.720)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;opt-level = &amp;rsquo;s&#39;&lt;/td&gt;&#xA;          &lt;td&gt;1.120.416 (-16.968)&lt;/td&gt;&#xA;          &lt;td&gt;1.120.416 (-65.688)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;lto = true&lt;/td&gt;&#xA;          &lt;td&gt;914.496 (-222.888)&lt;/td&gt;&#xA;          &lt;td&gt;808.528 (-311.888)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;codegen-units = 1&lt;/td&gt;&#xA;          &lt;td&gt;982.904 (-154.480)&lt;/td&gt;&#xA;          &lt;td&gt;775.888 (-32.640)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;panic = &amp;lsquo;abort&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;979.840 (-157.544)&lt;/td&gt;&#xA;          &lt;td&gt;703.096 (-72.792)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;strip = true&lt;/td&gt;&#xA;          &lt;td&gt;915.944 (-221.440)&lt;/td&gt;&#xA;          &lt;td&gt;580.056 (-123.040)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;switching back to opt-level = &amp;lsquo;z&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;/td&gt;&#xA;          &lt;td&gt;555.480 (-24.576)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;So it turns out, if you want to halve your binary size, a few flags are enough in stable Rust.&#xA;The most significant impacts came from link time optimization (LTO) and stripping of symbols from the binary.&#xA;Interestingly, differnet combinations of these settings didn&amp;rsquo;t scale the way I would have intuitively thought.&lt;/p&gt;&#xA;&lt;p&gt;The only compromise apart from compilation time with these settings is the change in panic behavior, as this means no stack traces on crash&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;To only compile like this in specific scenarios, you can add a new profile to a crates &lt;code&gt;Cargo.toml&lt;/code&gt; like this:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;profile&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;size-optimized&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;inherits&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;release&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;opt-level&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s&amp;#39;&lt;/span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;# Optimize for size&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lto&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;          &lt;span style=&#34;color:#75715e&#34;&gt;# Enable link-time optimization&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;codegen-units&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;# Reduce number of codegen units to increase optimizations&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;panic&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;abort&amp;#39;&lt;/span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;# Abort on panic&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;strip&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Strip symbols from binary&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The profile can be used by passing &lt;code&gt;--profile=size-optimized&lt;/code&gt; instead of &lt;code&gt;--release&lt;/code&gt; to &lt;code&gt;cargo build&lt;/code&gt;.&#xA;Because of the different profile, the binary ends up in a different folder (&lt;code&gt;ll -B target/size-optimized/examples&lt;/code&gt; to check size).&lt;/p&gt;&#xA;&lt;h3 id=&#34;features&#34;&gt;Features&lt;/h3&gt;&#xA;&lt;p&gt;Rust has a very handy way to represent variability in a library called features.&#xA;The &lt;code&gt;servicepoint&lt;/code&gt; library has the following declaration in it&amp;rsquo;s &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;features&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;compression_lzma&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;protocol_udp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cp437&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compression_zlib&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:flate2&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compression_bzip2&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:bzip2&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compression_lzma&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:rust-lzma&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compression_zstd&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:zstd&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;all_compressions&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;compression_zlib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;compression_bzip2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;compression_lzma&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;compression_zstd&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;rand&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:rand&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol_udp&lt;/span&gt; = []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol_websocket&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:tungstenite&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cp437&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dep:once_cell&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Line two means by default, cargo will enable LZMA compression, sending via UDP sockets and conversion between CP-437 and UTF-8.&#xA;Each of those features pulls in an optional dependency (which is why I made those features toggleable in the first place).&#xA;In the code, CP-437 and compression are not needed&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, but UDP is obviously used.&lt;/p&gt;&#xA;&lt;p&gt;Features can be toggled on the command line, which means the invocation can be changed to the following: &lt;code&gt;cargo build --example announce --profile=size-optimized --no-default-features --features=protocol_udp&lt;/code&gt;&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&#xA;Doing that means less library code and less dependencies are pulled into the compilation process.&lt;/p&gt;&#xA;&lt;p&gt;The result is a 555.480 Byte binary, which is exactly the same as without those flags.&#xA;This is not really surprising, as we enabled a bunch of compiler options that help remove whole sections of code that are not needed, especially link time optimization.&#xA;It is cool to see that the binary is identical, though.&lt;/p&gt;&#xA;&lt;p&gt;In the rest of this post, I will omit those parameters, probably to the detriment of compilation time.&lt;/p&gt;&#xA;&lt;h2 id=&#34;digging-deeper&#34;&gt;Digging deeper&lt;/h2&gt;&#xA;&lt;p&gt;While this was a big improvement already, this was still 50 times the size of the C program.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;If it was this easy halving it, can I do that a second time?&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Everything from here on required unstable features of the rust toolchain, both because tooling depends on it for more information about the program, and because the compiler options from here on are (and maybe never will be) stabilized.&lt;/p&gt;&#xA;&lt;p&gt;The version I ended up with was &lt;code&gt;rustc 1.88.0-nightly (5e17a2a91 2025-04-05)&lt;/code&gt;.&#xA;In my environment, I had to call nightly cargo with &lt;code&gt;rustup run nightly cargo&lt;/code&gt;, but that part is not included in the rest of the commands.&#xA;The executables I got with the unstable version were already a bit smaller again (546.528 bytes).&lt;/p&gt;&#xA;&lt;p&gt;The first thing I noticed was that I got some new warnings when compiling, all of which I fixed immediately. As it was mostly inside of the documentation, I did not expect this to affect file size.&lt;/p&gt;&#xA;&lt;p&gt;Next up, I added cargo-bloat to my flake. This tool can show you which functions take up most of the space in your binary.&#xA;The invocation is similar to building - &lt;code&gt;cargo bloat --example announce --profile=size-optimized&lt;/code&gt; resulted in the following output:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;File  .text     Size        Crate Name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 1.0%   5.5%  21.0KiB clap_builder clap_builder::parser::parser::Parser::get_matches_with&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.9%   5.3%  20.5KiB          std std::backtrace_rs::symbolize::gimli::Cache::with_global&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.6%   3.3%  12.6KiB          std std::backtrace_rs::symbolize::gimli::Context::new&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.4%   2.4%   9.2KiB          std gimli::read::dwarf::Unit&amp;lt;R&amp;gt;::new&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.4%   2.1%   7.9KiB          std addr2line::line::LazyLines::borrow&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.3%   2.0%   7.5KiB     announce announce::main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.3%   1.8%   7.1KiB          std miniz_oxide::inflate::core::decompress&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.3%   1.6%   6.3KiB          std addr2line::unit::ResUnit&amp;lt;R&amp;gt;::find_function_or_location::{{closure}}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.3%   1.5%   5.6KiB clap_builder clap_builder::builder::command::Command::_build_self&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.4%   5.3KiB clap_builder clap_builder::output::help_template::HelpTemplate::write_templated_help&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.3%   5.1KiB clap_builder clap_builder::error::Error&amp;lt;F&amp;gt;::print&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.3%   4.9KiB clap_builder clap_builder::parser::parser::Parser::react&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.2%   4.8KiB clap_builder clap_builder::output::help_template::HelpTemplate::write_args&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.2%   4.6KiB          std gimli::read::unit::parse_attribute&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.1%   4.4KiB          std addr2line::function::Function&amp;lt;R&amp;gt;::parse_children&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.0%   3.7KiB clap_builder clap_builder::output::help_template::HelpTemplate::write_subcommands&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.0%   3.7KiB clap_builder clap_builder::output::usage::Usage::write_arg_usage&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.2%   1.0%   3.7KiB          std gimli::read::rnglists::RngListIter&amp;lt;R&amp;gt;::next&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.1%   0.8%   3.1KiB          std std::backtrace_rs::symbolize::gimli::elf::&amp;lt;impl std::backtrace_rs::symbolize::gimli::Mapping&amp;gt;::new_debug&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0.1%   0.8%   3.0KiB clap_builder clap_builder::parser::parser::Parser::match_arg_error&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.8%  61.8% 237.3KiB              And 993 smaller methods. Use -n N to show more.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;17.5% 100.0% 384.2KiB              .text section size, the file size is 2.1MiB&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Starting with the largest, the biggest functions in the program are shown.&#xA;From the table, we can already see some interesting stuff.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;For some reason, the &lt;code&gt;.text&lt;/code&gt; section (the machine code) is only a small part of the executable, and the total size increased by a factor of 4.&lt;/li&gt;&#xA;&lt;li&gt;The biggest function and a bunch of other big ones are from &lt;code&gt;clap_builder&lt;/code&gt;, a crate that is part of the command line argument parser.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;std&lt;/code&gt; thakes up most of the rest.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;main&lt;/code&gt; is unexpectedly huge?&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;servicepoint&lt;/code&gt; does not even show up in the top list.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s cover those points in order.&lt;/p&gt;&#xA;&lt;h3 id=&#34;1-unexpected-binary-size-when-building-via-cargo-bloat&#34;&gt;1. Unexpected binary size when building via cargo-bloat&lt;/h3&gt;&#xA;&lt;p&gt;Using &lt;code&gt;GNU size&lt;/code&gt;, we can check the size per section in the ELF binary.&#xA;Using &lt;code&gt;-G&lt;/code&gt; or &lt;code&gt;-B&lt;/code&gt; output formats does not work for this, as it will only show the &lt;code&gt;.text&lt;/code&gt; and &lt;code&gt;.data&lt;/code&gt; section, which in this case only make up around 500KB.&#xA;Thus the command I used was &lt;code&gt;size -A --common target/size-optimized/examples/announce&lt;/code&gt;, giving the following result:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;section                size     addr&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.dynsym                1680      856&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.dynstr                1198     3500&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.rela.dyn             22800     4704&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.gcc_except_table      3728    27552&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.rodata               36592    31280&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.eh_frame_hdr          8116    67872&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.eh_frame             52488    75992&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.text                393449   132576&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.data.rel.ro          18760   530248&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.relro_padding         2888   550072&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.data                  2400   554168&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.debug_abbrev          1810        0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.debug_info          525404        0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.debug_aranges         6256        0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.debug_ranges        157856        0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.debug_str           726991        0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.debug_line          149936        0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Total               2115147&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(I filtered out the rows &amp;lt;1KB for brevity)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Turns out &lt;code&gt;cargo-bloat&lt;/code&gt; disables symbol stripping, because it needs those to show to the user.&#xA;It&amp;rsquo;s not even the symbols that are included in release builds by default - &lt;em&gt;all&lt;/em&gt; the debugging information is included.&#xA;That means, I can ignore that problem and focus on the &lt;code&gt;.text&lt;/code&gt; size.&lt;/p&gt;&#xA;&lt;h3 id=&#34;2-removing-clap&#34;&gt;2. Removing clap&lt;/h3&gt;&#xA;&lt;p&gt;While clap is super handy, it looks like the code needed to parse two simple arguments blows up the executable.&#xA;As the C program I was comparing against had all the parameters hard-coded, I just ripped out the dependency and hard-coded the values I needed.&lt;/p&gt;&#xA;&lt;p&gt;The result is the first version of &lt;code&gt;tiny_announce&lt;/code&gt;, as I did not want to change the existing example.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;//! An example for how to send text to the display.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; servicepoint::{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CharGrid, CharGridCommand, ClearCommand, Connection, UdpConnection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;TILE_WIDTH&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/// example: `cargo run -- --text &amp;#34;Hallo&amp;#34; --text &amp;#34;CCCB&amp;#34;`&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; text &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, CCCB!&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; connection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; UdpConnection::open(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;127.0.0.1:2342&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .expect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;could not connect to display&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    connection.send(ClearCommand).expect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sending clear failed&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; command: &lt;span style=&#34;color:#a6e22e&#34;&gt;CharGridCommand&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; CharGrid::wrap_str(&lt;span style=&#34;color:#66d9ef&#34;&gt;TILE_WIDTH&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;text).into();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    connection.send(command).expect(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sending text failed&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command to compile changed slightly because of the new name. &lt;code&gt;cargo build --example tiny_announce --profile=size-optimized &amp;amp;&amp;amp; ll -B target/size-optimized/examples/tiny_announce&lt;/code&gt; gave me the new binary size.&#xA;Drumroll&amp;hellip; 324.624 Bytes!&#xA;With argument parsing removed, we saved 40% of the remaining binary size.&#xA;This also makes the main disappear from the top sized functions for now.&lt;/p&gt;&#xA;&lt;p&gt;While removing a library you do not really need is also available in stable Rust, I was only able to notice that with tooling only available on nightly, so I am putting it into that category.&lt;/p&gt;&#xA;&lt;h3 id=&#34;3-build-std&#34;&gt;3. build-std&lt;/h3&gt;&#xA;&lt;p&gt;Looking at the biggest functions again (now &lt;code&gt;cargo bloat --example tiny_announce --profile=size-optimized&lt;/code&gt;) showed that all the big functions left were from &lt;code&gt;std&lt;/code&gt;.&#xA;Most of that looked like stack unwinding and debug data parsing, which is odd as we added &lt;code&gt;panic = &#39;abort&#39;&lt;/code&gt; in the first chapter.&lt;/p&gt;&#xA;&lt;p&gt;As it turns out, as an optimization for the development workflow, by default cargo does not recompile the standard library.&#xA;Instead, a prebuilt version included in the toolchain is used.&#xA;The compiler arguments for that are fixed, and to change that and get more control over how &lt;code&gt;stdlib&lt;/code&gt; is compiled and linked, we neeed the unstable option &lt;code&gt;-Zbuild-std&lt;/code&gt; and have to list which sub-crates we want to build (which is pretty much all of them).&#xA;Because we also have &lt;code&gt;panic = &amp;quot;abort&amp;quot;&lt;/code&gt; set, we need to also pass in &lt;code&gt;-Zbuild-std-features=&amp;quot;panic_immediate_abort&amp;quot;&lt;/code&gt; so there is no compilation error.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;cargo build --example tiny_announce --profile=size-optimized -Zbuild-std=&amp;quot;core,std,alloc,proc_macro,panic_abort&amp;quot; -Zbuild-std-features=&amp;quot;panic_immediate_abort&amp;quot;&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;This produces a binary that is now only 30.992 bytes!&lt;/p&gt;&#xA;&lt;h3 id=&#34;in-between-find-to_socket_addrs&#34;&gt;In-between find: to_socket_addrs&lt;/h3&gt;&#xA;&lt;p&gt;The remaining top 3 functions were:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; File  .text    Size         Crate Name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 4.4%  11.0%  2.0KiB           std &amp;lt;&amp;amp;T as std::net::socket_addr::ToSocketAddrs&amp;gt;::to_socket_addrs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 3.8%   9.4%  1.7KiB tiny_announce tiny_announce::main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 2.9%   7.3%  1.4KiB     [Unknown] main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Main shows up again! But what is that? 4.4% used by &lt;code&gt;to_socket_addrs&lt;/code&gt;?&#xA;We found the last string parsing code, this time in the standard library, to read the IP and Port from a string.&#xA;After changing it in the example, it still showed up which brings me to the first and only time I actually changed the &lt;code&gt;servicepoint&lt;/code&gt; library as a result from this saga.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-patch&#34; data-lang=&#34;patch&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;- let socket = UdpSocket::bind(&amp;#34;0.0.0.0:0&amp;#34;)?;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ let addr = SocketAddr::from(([0, 0, 0, 0], 0));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ let socket = UdpSocket::bind(addr)?;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This also seemed to remove other functions as well, as the size was down to 17.272 bytes, nearly halving the size &lt;em&gt;again&lt;/em&gt;.&#xA;It is now smaller than this article as plain text markdown.&lt;/p&gt;&#xA;&lt;h3 id=&#34;4-no_main&#34;&gt;4. no_main&lt;/h3&gt;&#xA;&lt;p&gt;You&amp;rsquo;d think that now &lt;code&gt;main&lt;/code&gt; is the top function, but &lt;code&gt;Iter::next&lt;/code&gt; is now the biggest function for some reason.&#xA;Still, &lt;code&gt;[Unknown] main&lt;/code&gt; and the actual main take up 10% of the remaining size according to &lt;code&gt;cargo bloat&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We surely cannot reduce that, right? Wrong!&#xA;With #[no_main], you can tell Rust to not add any initialization code.&#xA;This means the normal &lt;code&gt;fn main()&lt;/code&gt; does not get used, and the linker complains about the missing function.&#xA;To fix this, the function can be converted to a C-style main.&lt;/p&gt;&#xA;&lt;p&gt;I also removed some more code by initializing the CharGrid directly instead of wrapping a string, which saved 400 bytes.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#![no_main]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; servicepoint::{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CharGrid, CharGridCommand, ClearCommand, Connection, UdpConnection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; std::net::SocketAddr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#[unsafe(no_mangle)]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(_argc: &lt;span style=&#34;color:#66d9ef&#34;&gt;isize&lt;/span&gt;, _argv: &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;isize&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// not parsing the address from str removes 3KB&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; addr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; SocketAddr::from(([&lt;span style=&#34;color:#ae81ff&#34;&gt;172&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;29&lt;/span&gt;], &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; connection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; UdpConnection::open(addr).unwrap();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    connection.send(ClearCommand).unwrap(); &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;--&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; grid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; CharGrid::from_vec(&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;vec!&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;H&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;e&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;l&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;l&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;o&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;W&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;o&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;l&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;d&amp;#39;&lt;/span&gt;]).unwrap();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    connection.send(CharGridCommand::from(grid)).unwrap();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This resulted in a 8.064 byte executable, finally beating both GCC and LLVM compiling the minimal C program (around 10KB).&#xA;If we were to remove the marked line and not clear the screen, we could drop it further to 7.696 bytes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;advanced-compiler-abuse&#34;&gt;Advanced compiler abuse&lt;/h3&gt;&#xA;&lt;p&gt;There are two things left to reach the absolute bottom without ripping out the standard libary alltogether.&lt;/p&gt;&#xA;&lt;p&gt;In Rust, a function can tell the compiler to get the calling location as a parameter to the function.&#xA;With &lt;code&gt;-Zlocation-detail=none&lt;/code&gt;, we instruct the Rust compiler to just not bother with that.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;-Zfmt-debug=none&lt;/code&gt; is similar but worse, because it changes all the default &lt;code&gt;Debug&lt;/code&gt; implementations to do nothing at all.&#xA;The change in behavior is not obvious in this example, but do this in an application that has logging and it will be horribly broken.&lt;/p&gt;&#xA;&lt;p&gt;As an icing on the cake, those two options cannot be passed via &lt;code&gt;cargo&lt;/code&gt; arguments, so we have to use the environment variable &lt;code&gt;RUSTFLAGS&lt;/code&gt; to pass this through to when &lt;code&gt;rustc&lt;/code&gt; is invoked.&lt;/p&gt;&#xA;&lt;p&gt;The final command to build the tiniest possible announce in all it&amp;rsquo;s glory:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUSTFLAGS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-Zlocation-detail=none -Zfmt-debug=none&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cargo build &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --example tiny_announce &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --profile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;size-optimized &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --no-default-features &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --features&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;protocol_udp &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    -Zbuild-std&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;core,std,alloc,proc_macro,panic_abort&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    -Zbuild-std-features&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;panic_immediate_abort&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All of this reduces the final binary size to 8.064 bytes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;Through this journey, I&amp;rsquo;ve managed to reduce the size of the binary from an unwieldy 1.1 MB to an impressive 8 KB, without sacrificing all of the standard library.&#xA;For me the most unexpected was the size of &lt;code&gt;clap&lt;/code&gt; code, though I learned dozens of things at every step about the intricacies of how &lt;code&gt;cargo build&lt;/code&gt; produces your final binary.&lt;/p&gt;&#xA;&lt;p&gt;There is no single option that in itself is the solution, it’s a matter of experimenting with a combination of compiler flags, feature toggles, and code optimizations.&#xA;While extreme options can be great if you want to squeeze out the last bytes, it&amp;rsquo;s probably not worth using those in a &amp;ldquo;normal&amp;rdquo; computer scenario.&lt;/p&gt;&#xA;&lt;p&gt;The key takeaway is that optimizing binary size in Rust, while not always straightforward, is achievable with the right techniques.&#xA;It is certainly easier to create a big binary than in C, calling Rust bloated is blaming the language a bit too much.&lt;/p&gt;&#xA;&lt;p&gt;Stay tuned for part two, in which I will try to do something similar with a C version of the example, using the C bindungs of the &lt;code&gt;servicepoint&lt;/code&gt; crate.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Yes, I know UDP does not have connections. Internally, this just opens a UDP socket&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Technically, you can catch a panic while unwinding and there may even be a weird performance argument for doing that, see &lt;!-- TODO find article about making serde faster with panic catching --&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;Some commands can be compressed, but the text ones (both CP-437 and UTF-8) cannot. Clear is a &lt;em&gt;very&lt;/em&gt; simple command that does not have any payload, so no compression there either. If a &lt;code&gt;BitmapCommand&lt;/code&gt; was used instead, using &lt;code&gt;into()&lt;/code&gt; on a &lt;code&gt;Bitmap&lt;/code&gt; would have hidden the fact that the default compression is used in that case. The default compression in turn is either LZMA or no compression, depending on whether the LZMA feature is enabled.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;This works here because &lt;code&gt;announce&lt;/code&gt; is an example inside of the library itself. As an actual dpendent, you would specify this in your &lt;code&gt;Cargo.toml&lt;/code&gt;.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Why I do not use flake-utils</title>
      <link>https://zerforschen.plus/posts/why-i-do-not-use-flake-utils/</link>
      <pubDate>Sun, 06 Apr 2025 14:49:03 +0200</pubDate>
      <guid>https://zerforschen.plus/posts/why-i-do-not-use-flake-utils/</guid>
      <description>&lt;p&gt;I have been using &lt;a href=&#34;https://nixos.org/&#34; target=&#34;_blank&#34;&gt;Nix&lt;/a&gt; for a while now. Around a year ago, I switched everything from the &lt;a href=&#34;https://git.berlin.ccc.de/servicepoint/servicepoint&#34; target=&#34;_blank&#34;&gt;servicepoint&lt;/a&gt; library to my &lt;a href=&#34;https://git.berlin.ccc.de/vinzenz/nixos-configuration&#34; target=&#34;_blank&#34;&gt;machine configuration&lt;/a&gt; over to flakes.&lt;/p&gt;&#xA;&lt;p&gt;For me the biggest advantage flakes bring is not additional functionality. Instead, they are an easier and semi-standardized way to do what you could before.&lt;/p&gt;&#xA;&lt;p&gt;When learning flakes, you often see &lt;a href=&#34;https://github.com/numtide/flake-utils&#34; target=&#34;_blank&#34;&gt;flake-utils&lt;/a&gt; being used. With it, you can shorten your flakes by not having to specify everything per system.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Edit&lt;/em&gt;: The patterns described here as well as &lt;code&gt;flake-parts&lt;/code&gt; are also compared in &lt;a href=&#34;https://vtimofeenko.com/posts/practical-nix-flake-anatomy-a-guided-tour-of-flake.nix/#flake-utils-flakeparts-etc&#34; target=&#34;_blank&#34;&gt;Practical Nix flake anatomy&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;without-anything&#34;&gt;Without anything&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  description &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Flake utils demo - without flakes&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  outputs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { self&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; flake-utils }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    packages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x86_64-linux&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rec&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          hello &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          default &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    packages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aarch64-linux&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rec&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          hello &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          default &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# more systems ...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;with-flake-utils&#34;&gt;With flake-utils&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  description &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Flake utils demo&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  inputs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;flake-utils&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github:numtide/flake-utils&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  outputs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { self&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; flake-utils }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    flake-utils&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;eachDefaultSystem (system:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pkgs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;legacyPackages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;system&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        packages &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rec&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          hello &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          default &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;with-function-in-flake&#34;&gt;With function in flake&lt;/h2&gt;&#xA;&lt;p&gt;To make a long story short, here is what I usually do instead:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  description &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;forAllSystems demo&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  outputs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { self&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; nixpkgs }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      supported-systems &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#75715e&#34;&gt;# [1]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x86_64-linux&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aarch64-linux&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      forAllSystems &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        f:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;genAttrs supported-systems &lt;span style=&#34;color:#75715e&#34;&gt;/* [2] */&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          system:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          f &lt;span style=&#34;color:#66d9ef&#34;&gt;rec&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            pkgs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;legacyPackages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;system&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;# [3]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; system;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        );&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      packages &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; forAllSystems ({ pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }: &lt;span style=&#34;color:#66d9ef&#34;&gt;rec&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        hello &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hello;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        default &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; default;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s definitely more code! - Yes, but it also includes more information in the flake, while getting rid of an external dependency.&#xA;While more code can be intimidating for beginners, it actually helps remove a barrier to understanding how the flake works in this case.&#xA;For me, it wasn’t a problem to ignore boilerplate like this at first, slowly learning more language features until I finally understood everything.&lt;/p&gt;&#xA;&lt;p&gt;At &lt;strong&gt;[1]&lt;/strong&gt;, the supported systems are specified. I personally use &lt;code&gt;x86_64-linux&lt;/code&gt; and &lt;code&gt;aarch64-linux&lt;/code&gt;, but I also usually support &lt;code&gt;x86_64-darwin&lt;/code&gt; and &lt;code&gt;aarch64-darwin&lt;/code&gt; in public projects.&#xA;If you want to support any system, you can use &lt;a href=&#34;https://github.com/NixOS/nixpkgs/blob/374e6bcc403e02a35e07b650463c01a52b13a7c8/lib/systems/default.nix#L58&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;nixpkgs.lib.system.flake-exposed&lt;/code&gt;&lt;/a&gt; at &lt;strong&gt;[2]&lt;/strong&gt; instead of defining your own list.&lt;/p&gt;&#xA;&lt;h3 id=&#34;example-variations&#34;&gt;Example variations&lt;/h3&gt;&#xA;&lt;p&gt;Because the definition is right inside the flake, you can tweak what gets passed to the function.&#xA;By doing that, you have to explicitly add the new identifier to each part that uses it, instead of having a global &lt;code&gt;let&lt;/code&gt; binding that is implicitly used.&#xA;&lt;code&gt;system&lt;/code&gt; being available here is another bonus, as otherwise this would require duplicate &lt;code&gt;let&lt;/code&gt;s everywhere.&lt;/p&gt;&#xA;&lt;p&gt;An example for how to do it is already right there: at &lt;strong&gt;[3]&lt;/strong&gt;, &lt;code&gt;pkgs&lt;/code&gt; is provided.&#xA;Some real-world usages I wrote or encountered:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://git.berlin.ccc.de/vinzenz/servicepoint-life/src/commit/5f5e10d39f09f4d60b4301e76f0158636afee6d1/flake.nix&#34; target=&#34;_blank&#34;&gt;servicepoint-life flake&lt;/a&gt;: passes in initialized &lt;code&gt;naersk&lt;/code&gt; instance and a shorthand to refer to packages defined in the flake itself&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gitlab.redox-os.org/redox-os/redox/-/blob/cb34b9bd862f46729c0082c37a41782a3b1319c3/flake.nix#L38&#34; target=&#34;_blank&#34;&gt;RedoxOS development flake&lt;/a&gt;: uses it to pass a custom rust-toolchain&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://git.berlin.ccc.de/vinzenz/nixos-configuration/src/commit/3d27f554015ece713fa22fe829d711b430d6bbda/flake.nix&#34; target=&#34;_blank&#34;&gt;my NixOS flake&lt;/a&gt;: uses something similar for per-host config&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Another possible tweak: You may want to define separate supported systems for each output.&#xA;This is useful, for example, if the target environment you&amp;rsquo;re developing for cannot support a development shell.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;For me, the trade-offs are worth it, as they provide greater transparency and control over the flake configuration.&#xA;For you, this may be different, in which case keep using it!&#xA;Ultimately, it&amp;rsquo;s also matter of personal preference.&lt;/p&gt;&#xA;</description>
    </item>
  </channel>
</rss>
