<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>No terms or conditions on gvisoc.com</title>
    <link>https://gvisoc.com/en/</link>
    <description>Recent content in No terms or conditions on gvisoc.com</description>
    <image>
      <title>gvisoc.com</title>
      <url>https://gvisoc.com/images/site-umina-gs.jpg</url>
      <link>https://gvisoc.com/images/site-umina-gs.jpg</link>
    </image>
    <generator>Hugo -- 0.151.0</generator>
    <language>en-AU</language>
    <managingEditor>gabriel@gvisoc.com (Gabriel Viso Carrera)</managingEditor>
    <webMaster>gabriel@gvisoc.com (Gabriel Viso Carrera)</webMaster>
    <copyright>Gabriel Viso Carrera</copyright>
    <lastBuildDate>Sun, 07 Sep 2025 07:49:35 +0000</lastBuildDate>
    <atom:link href="https://gvisoc.com/en/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Forward TCP and UDP Traffic Across the Network With iptables</title>
      <link>https://gvisoc.com/en/posts/iptables-router/</link>
      <pubDate>Sun, 07 Sep 2025 07:49:35 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/iptables-router/</guid>
      <description>This method enables routing TCP and UDP traffic between machines when no proxy is needed, or solutions based in proxies fail</description>
      <content:encoded><![CDATA[<p>This is the third post of the series that started with &ldquo;<a href="https://gvisoc.com/en/posts/changes-xmpp/">Changes to My Network, Sponsored By XMPP</a>&rdquo;.</p>
<h2 id="the-problem">The Problem</h2>
<p>In that article, nearly at the very end, I was pointing out that a solution was needed for the XMPP traffic on non-Web ports (TCP and UDP other than 80 and 443) to be routed from a cloud VPS to my home server.</p>
<p>I tried some NGINX configuration using its module <code>streams</code>, but it didn&rsquo;t work, so I will post here how I ended up solving that using Linux&rsquo; &ndash;the kernel itself&ndash; packet filter rules through <a href="https://www.netfilter.org/projects/iptables/index.html">iptables</a>.</p>
<p>I learned and adapted my solution from the content of this <a href="https://ryanwelch.me/blog/port-forward-with-tailscale/">article</a> by <a href="https://ryanwelch.me">Ryan Welch</a>.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250910-solution.png"
         alt="The diagram that represents the goal we&#39;ve just went through."/> <figcaption>
            <p>The goal</p>
        </figcaption>
</figure>

<p>At the end of the post, though, I will also post how to configure NGINX to work with TCP and UDP general traffic, just in case we need it later, or maybe you want to try it and tell me what I did wrong.</p>
<h2 id="solution">Solution</h2>
<p>As explained before, Linux (NOT GNU/Linux, but just &ldquo;Linux&rdquo;, the kernel) has network packet filtering capabilities built-in that can be configured to our needs.</p>
<p>To configure the VPS to do it, SSH into the machine and enable IP forwarding in the kernel:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo sysctl -w net.ipv4.ip_forward=1
</span></span></span></code></pre></div><p>This may or may not be persitent between boots, depending on your distribution. To be sure, uncomment the line <code>net.ipv4.ip_forward=1</code> in <code>/etc/sysctl.conf</code>.</p>
<p>Then, you will be able to redirect ports and ranges with sentences like the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5222 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5222
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 5222 -j MASQUERADE
</span></span></span></code></pre></div><p>And, for ranges of ports:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 -m multiport --dports 49152:65535 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:49152-65535
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;Upstream VPN IP&gt; -m multiport --dports 49152:65535 -j MASQUERADE
</span></span></span></code></pre></div><p>You&rsquo;ll have to change the ports in this example, as well as putting your own remote IP address instead of the <code>&lt;Upstream VPN IP&gt;</code> placeholder.</p>
<p>Add all the forwarding rules corresponding to all the XMPP server ports, where <code>&lt;Upstream VPN IP&gt;</code> would be the Tailscale IP of my home server, the one we were calling <em>potato</em> in <a href="https://gvisoc.com/en/posts/vps-homeserver/">the previous article of the series</a>):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5222 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5222
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 5222 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5269 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5269
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 5269 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5000 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5000
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 5000 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 3478 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:3478
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 3478 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 3479 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:3479
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 3479 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 3478 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:3478
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;Upstream VPN IP&gt; --dport 3478 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 3479 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:3479
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;Upstream VPN IP&gt; --dport 3479 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5349 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5349
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 5349 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5350 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5350
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;Upstream VPN IP&gt; --dport 5350 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 5349 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5349
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;Upstream VPN IP&gt; --dport 5349 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 5350 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:5350
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;Upstream VPN IP&gt; --dport 5350 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 -m multiport --dports 49152:65535 -j DNAT --to-destination &lt;Upstream VPN IP&gt;:49152-65535
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;Upstream VPN IP&gt; -m multiport --dports 49152:65535 -j MASQUERADE
</span></span></span></code></pre></div><p>Test the set up, and when everything works, save the iptables rules by <code>sudo iptables-save &gt; /etc/iptables/rules.v4</code> so that these rules are applied at every boot of the VPS.</p>
<p>In <a href="https://ryanwelch.me/blog/port-forward-with-tailscale/">his article</a>, Ryan adds more considerations for things like congestion control and such. Check it out to know more and apply whatever suits your needs.</p>
<h2 id="bonus-nginx-with-generic-tcpudp-traffic">Bonus: NGINX With Generic TCP/UDP Traffic</h2>
<blockquote>
<p>Take this with a pinch of salt: as I stated at the beginning of the post, this didn&rsquo;t work for me and my XMPP server of choice, <a href="https://snikket.org/">Snikket</a>. However, according to NGINX&rsquo; documentation, this is the way it is configured for handling non-Web traffic.</p></blockquote>
<p>Install <code>libnginx-mod-stream</code> to support UDP and TCP reverse proxies.</p>
<p>Modify <code>/etc/nginx/nginx.conf</code> to add a stream block:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">stream {
        include /etc/nginx/streams-enabled/*;
}
</code></pre><p>Then, create the directories following the existing schema NGINX has for webs: <code>sudo mkdir -p /etc/nginx/streams-available /etc/nginx/streams-enabled</code></p>
<p>Create an <code>/etc/nginx/streams-available/tcpudpservice.example.com.conf</code> with rules like the following:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf"># TCP Port (non-HTTP traffic):
server {
        listen 5222;
        proxy_pass &lt;Upstream VPN IP&gt;:5222;
}

# ...

# UDP Port:
server {
        listen 3478 udp;
        proxy_pass &lt;Upstream VPN IP&gt;:3478;
}

# ...

# Ranges are accepted, too. In this case, note the
# use of $server_port in the proxy_pass sentence.

server {
        listen 49152-65535 udp;
        proxy_pass &lt;Upstream VPN IP&gt;:$server_port;
}
</code></pre><p>In the case of defining very large range of ports, such as the ranges that Snikket proposes for XMPP audio and video services in multi-users configurations, NGINX will throw an error due to having too many files open. Snikket expects to be able to establish 16384 UDP connections.</p>
<p>If you want to solve this instead of reducing the range of UDP ports, we must increase the <code>LimitNOFILE</code> parameter of NGINX in systemd by doing <code>sudo systemctl edit nginx.service</code>. This will open an editor for a drop-in extension to the service unit.</p>
<p>Write the following and save the file:</p>
<pre tabindex="0"><code class="language-unit" data-lang="unit">[Service]
LimitNOFILE=65535
</code></pre><p>Then, in the preamble of the <code>/etc/nginx/nginx.conf</code> (outside of any <code>http</code>, <code>events</code> or <code>stream</code>), add a line <code>worker_rlimit_nofile</code> with a value less than 65535 (30000 will work for the Snikket case), and increase the <code>worker_connections</code> inside <code>events</code>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">...
include /etc/nginx/modules-enabled/*.conf;

worker_rlimit_nofile 30000;

events {
        # worker_connections 768;
        # 3 times 8192 will suffice   
        worker_connections 24576;
        # multi_accept on;
}

...
</code></pre><p>As I said before, this configuration did not work with XMPP, but it can be useful for other use cases.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Exposing Services Hosted at Home Through a VPS and Tailscale</title>
      <link>https://gvisoc.com/en/posts/vps-homeserver/</link>
      <pubDate>Fri, 05 Sep 2025 05:40:00 +1000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/vps-homeserver/</guid>
      <description>An easy way of exposing services hosted at your home network without having to open ports on your router and without the need of a static IP address</description>
      <content:encoded><![CDATA[<h2 id="the-problem">The Problem</h2>
<p>This text shows the steps to follow to connect an <a href="https://nginx.org">NGINX</a> reverse proxy installed on a server A, and provide access through it to services hosted in a different machine, B. If the machines are in different locations or networks, we can solve the connectivity in several ways, one of them being a VPN.</p>
<p>In my personal case, this allows me to install NGINX on a VPS and use it to expose services hosted at my home server, &ldquo;barcas&rdquo;. To connect the two machines and allow NGINX to reach the upstream services, I have used <a href="https://tailscale.com">Tailscale</a>.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250905-solution.png"
         alt="The diagram that represents the goal we&#39;ve just went through."/> <figcaption>
            <p>The goal</p>
        </figcaption>
</figure>

<p>This post continues the series that started with &ldquo;<a href="/en/posts/changes-xmpp">Changes to My Network, Sponsored by XMPP</a>&rdquo;. If you&rsquo;re wondering why would we do that, or what value brings this configuration, please check read that one first.</p>
<h2 id="solution">Solution</h2>
<p>You&rsquo;ll need the following:</p>
<ol>
<li>A VPS server rented from your provider of choice, to which you can access through SSH.</li>
<li>A server at your home, with at least one service accepting HTTP connections, let&rsquo;s say, through the port 5000. (<code>0.0.0.0:5000</code>). I will call this host <em>potato</em> in the remainder of this post, just for the sake of brevity and readability.</li>
<li>A free <a href="https://tailscale.com">Tailscale</a> account. In general, we could do this with any VPN provider and even one self-hosted by us, preferably providing service based on <a href="https://en.wikipedia.org/wiki/WireGuard">WireGuard</a>, as it is more performant than <a href="https://es.wikipedia.org/wiki/OpenVPN">OpenVPN</a>.</li>
<li>Optionally, or probably for this post to be meaningful, we should have a domain with their DNS records pointing to the VPS of point #1.</li>
</ol>
<p>For the rest of the article I will assume that the hosts (the VPS and <em>potato</em>) have installed an Ubuntu LTS Server, such as 24.04.</p>
<p>If there were no issues you should have all this up and running in about 20 minutes.</p>
<h3 id="home-server">Home Server</h3>
<p>We&rsquo;ll log into (the) <em>potato</em>, where our service is waiting for requests behind port 5000.</p>
<p><a href="https://tailscale.com/download">Install Tailscale</a> and authenticate <em>potato</em> against our account. This will give <em>potato</em> an IP address within the VPN:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">#</span> Tailscale install commands are not reproduced, as they can 
</span></span><span class="line"><span class="cl"><span class="gp">#</span> change at any point in time.
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="go">sudo tailscale up
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="gp">#</span> Follow the instructions
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="gp">#</span> Enable Tailscale as a system service, permanently running
</span></span><span class="line"><span class="cl"><span class="go">sudo systemctl enable tailscaled --now
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="gp">#</span> Obtain and write down the IP address at the tailnet.
</span></span><span class="line"><span class="cl"><span class="go">tailscale ip -4
</span></span></span><span class="line"><span class="cl"><span class="go">100.85.67.22
</span></span></span></code></pre></div><p>At Tailscale&rsquo;s dashboard we can see the host&rsquo;s local name, and also the IP address returned by the last command.</p>
<p>We can also configure the host so that we don&rsquo;t have to re-authenticate it into the VPN, disabling the expiry of the key used to authenticate the machine to Tailscale.</p>
<figure class="ma0 w-10">
    <img loading="lazy" src="/images/20250905-keyexpiry.png"
         alt="A context menu option of the Tailscale control panel that disables the key expiry"/> <figcaption>
            <p>Relevant option to disable the key expiry</p>
        </figcaption>
</figure>

<p>Optionally, we can also enable &ldquo;MagicDNS&rdquo; to be able to refer to the hosts by a domain name instead of by an IP address, with no local configuration to do in the machines.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250905-magicdns.png"
         alt="&#34;MagicDNS&#34; options in Tailscale&#39;s control panel, shown as &#34;Automatically register domain names for devices in your tailnet. This lets you to use a machine’s name instead of its IP address.&#34;. In the picture it is already enabled."/> <figcaption>
            <p>&ldquo;MagicDNS&rdquo; options in Tailscale&rsquo;s control panel. In the picture it is already enabled.</p>
        </figcaption>
</figure>

<p>Once the machine is already in Tailscale, we must <strong>open port 5000 in the <em>potato</em>&rsquo;s firewall</strong>, if we hadn&rsquo;t done so yet, so that it can receive requests from the VPS through that port.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo iptables -A INPUT -p tcp -m tcp --dport 5000 -j ACCEPT
</span></span></span></code></pre></div><p>Regarding this:</p>
<ol>
<li>If your machine doesn&rsquo;t have <code>iptables-persistent</code> installed, this is a good moment to install it so that we can save the firewall rules to be applied automatically at boot time.</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo apt install iptables-persistent 
</span></span></span><span class="line"><span class="cl"><span class="go">sudo iptables-save &gt; /etc/iptables/rules.v4
</span></span></span></code></pre></div><ol start="2">
<li>I personally open the ports in all the network interfaces, not only in Tailscale&rsquo;s.
<ul>
<li>As I won&rsquo;t have that port open in the router, I am not doing anything that would leave me overly exposed.</li>
<li>This way I don&rsquo;t need to always use Tailscale to perform tests on <em>potato</em> from home.</li>
<li>Each case is different: you should decide what to do with your firewall depending on how critical the service you&rsquo;re configuring is, and how sensitive the data it manages is.</li>
</ul>
</li>
</ol>
<h3 id="vps">VPS</h3>
<p>Connect to the VPS through SSH and install a reverse proxy. Even if we&rsquo;re not going to have more than one web (80, 443) service
listening, configuring, understanding and managing an HTTP reverse proxy is way easier than handle IP redirects and their relevant firewall DNAT rules.</p>
<p>I use NGINX.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo apt update &amp;&amp; sudo apt install nginx
</span></span></span></code></pre></div><p><a href="https://tailscale.com/download">Install Tailscale</a> and follow all the steps we did with <em>potato</em>. Write down the VPS&rsquo; IP address in &ldquo;the tailnet&rdquo;, for example <code>100.85.77.36</code>.</p>
<p>Get a Let&rsquo;s Encrypt certificate your your domain, with CertBot. For this:</p>
<ul>
<li>We must have already configured the DNS records of our domain, <code>example.com</code>, to point to the public IP of the VPS (not its IP at Tailscale) we&rsquo;re working on.</li>
<li>We may have to stop NGINX (<code>sudo systemctl stop nginx</code>) before, depending on our domain provider and their CertBot plugins available, if any.</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo certbot certonly --standalone -d example.com
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">Successfully received certificate.
</span></span></span><span class="line"><span class="cl"><span class="go">Certificate saved at: /etc/letsencrypt/live/example.com/fullchain.pem;
</span></span></span><span class="line"><span class="cl"><span class="go">Key is saved at:      /etc/letsencrypt/live/example.com/privkey.pem;
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span></code></pre></div><p>Configure now the service in the reverse proxy, writing the IP of <em>potato</em> in Tailscale in the <code>proxy_pass</code> directive. For this, we&rsquo;ll create a configuration file under <code>/etc/nginx/sites-available/</code>, for example <code>example.com.conf</code> for an <code>https://example.com</code> website.</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">upstream exampleweb {
        # Replace [IP or host name] for your &#39;potato&#39; value
        # **in Tailscale**.
        # 100.85.67.22 in the post&#39;s example.
        server [IP or host name]:5000;
        keepalive 64;
}

server {
        server_name example.com;
        listen 80;

        location / {
                return 301 https://$host$request_uri;
        }
}

server {
        server_name example.com;
        listen 443 ssl http2;

        # Other SSL stuff goes here
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;

        ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        location / {
                # The final `/` is important.
                proxy_pass http://exampleweb/;
                add_header X-Frame-Options SAMEORIGIN;
                add_header X-XSS-Protection &#34;1; mode=block&#34;;
                proxy_redirect off;
                proxy_buffering off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Forwarded-Port $server_port;
                proxy_read_timeout 90;
        }
}
</code></pre><p>We&rsquo;ll create now a symbolic link to this file under <code>/etc/nginx/sites-enabled</code>, test NGINX&rsquo; configuration and, if all goes well, reload it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">cd /etc/nginx/sites-enabled/
</span></span></span><span class="line"><span class="cl"><span class="go">sudo ln -s ../sites-available/example.com.conf
</span></span></span><span class="line"><span class="cl"><span class="go">sudo nginx -t
</span></span></span><span class="line"><span class="cl"><span class="go">nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
</span></span></span><span class="line"><span class="cl"><span class="go">nginx: configuration file /etc/nginx/nginx.conf test is successful
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="gp">#</span> If we had to stop NGINX to get the certificate, we start it up<span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="gp">#</span> otherwise:
</span></span><span class="line"><span class="cl"><span class="go">sudo systemctl reload nginx
</span></span></span></code></pre></div><p>At this point we should be able to interact with our service at <em>potato</em> through <code>https://example.com</code>.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<ul>
<li><strong>This thing doesn&rsquo;t render anything, the service seems to be not replying</strong>. If there is activity in NGINX&rsquo; logs in the VPS (<code>sudo tail -f /var/log/nginx/access.log</code>), and the request is abandoned after a time out, there are a few possible causes for this in my limited experience. At <em>potato</em>:
<ul>
<li>The service upstream we want to access from NGINX is not working, and we have to start it up.</li>
<li>the service upstream is exposed through port 5000 of a specific network interface, instead of <code>0.0.0.0</code> (which means <code>all network interfaces</code> of <em>potato</em>), and other than Tailscale&rsquo;s; for example, <code>127.0.0.1</code>,</li>
<li>or we did something wrong in the firewall and the request is being rejected in that way.</li>
</ul>
</li>
<li><strong>NGINX&rsquo; settings are OK</strong> (<code>sudo nginx -t</code> says 👍)<strong>, but NGINX doesn&rsquo;t start</strong> or dies when you reload the configuration. The most frequent cause is that NGINX can&rsquo;t reach or find the upstream at <em>potato</em>, the one pointed by the <code>proxy_pass</code> directive.
<ul>
<li>We may have a typo in the <code>proxy_pass</code>,</li>
<li>NGINX may have tried to reach <em>potato</em> before Tailscale&rsquo;s tunnel was up, for example if this happens upon a VPS reboot,</li>
<li>maybe Tailscale is down in any of the two hosts.</li>
<li>This cause can be checked by looking for a <code>host not found in upstream</code> in the output of <code>sudo systemctl status nginx</code>:</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">nginx.service - A high performance web server and a reverse proxy server
</span></span></span><span class="line"><span class="cl"><span class="go">     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
</span></span></span><span class="line"><span class="cl"><span class="go">    Drop-In: /etc/systemd/system/nginx.service.d
</span></span></span><span class="line"><span class="cl"><span class="go">             └─override.conf
</span></span></span><span class="line"><span class="cl"><span class="go">     Active: active (running) since Fri 2025-08-29 11:05:51 UTC; 3 days ago
</span></span></span><span class="line"><span class="cl"><span class="go">       Docs: man:nginx(8)
</span></span></span><span class="line"><span class="cl"><span class="go">    Process: 1154 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
</span></span></span><span class="line"><span class="cl"><span class="go">    Process: 1156 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
</span></span></span><span class="line"><span class="cl"><span class="go">    Process: 58676 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=1/FAILURE)
</span></span></span><span class="line"><span class="cl"><span class="go">   Main PID: 1157 (nginx)
</span></span></span><span class="line"><span class="cl"><span class="go">      Tasks: 3 (limit: 1110)
</span></span></span><span class="line"><span class="cl"><span class="go">     Memory: 46.9M (peak: 200.2M)
</span></span></span><span class="line"><span class="cl"><span class="go">        CPU: 29min 57.349s
</span></span></span><span class="line"><span class="cl"><span class="go">     CGroup: /system.slice/nginx.service
</span></span></span><span class="line"><span class="cl"><span class="go">             ├─1157 &#34;nginx: master process /usr/sbin/nginx -g daemon on; master_process on;&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">             ├─1158 &#34;nginx: worker process&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">             └─1159 &#34;nginx: cache manager process&#34;
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">Sep 02 05:32:49 vps-hostingprovider nginx[58676]: 2025/09/02 05:32:49 [emerg] 58676#58676: host not found in upstream &#34;100.85.77.22&#34; in /etc/nginx/sites-enabled/example.com.conf&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">Sep 02 05:32:49 vps-hostingprovider systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
</span></span></span><span class="line"><span class="cl"><span class="go">Sep 02 05:32:49 vps-hostingprovider systemd[1]: Reload failed for nginx.service - A high performance web server and a reverse proxy server.
</span></span></span><span class="line"><span class="cl"><span class="go">lines 1-28/28 (END)
</span></span></span></code></pre></div><ul>
<li><strong>We get an HTTP Status Code 502</strong>. This means that, while NGINX is doing well, the upstream service we&rsquo;re trying to reach at <em>potato</em>&rsquo;s port 500 is throwing errors.
<ul>
<li>If you go and do a test from the <em>potato</em> and goes well, almost for sure this is a matter of <strong>trusted proxies</strong>. To describe the problem in depth and correctly is outside of the scope of this post, but in summary the point is that you must tell your application that the VPS that is hosting the reverse proxy, a machine other than <em>potato</em>, is trustworthy. This is done by configuring VPS&rsquo; IP address in Tailscale as a trusted proxy. <strong>Check your specific web application logs</strong> to confirm this hypothesis.</li>
<li>This is not a problem, but a rather interesting security feature.</li>
<li>For example, this happened to me with both my Mastodon instance and Nextcloud. In both cases, each application&rsquo;s documentation had the solution for it: <a href="https://docs.joinmastodon.org/admin/config/#trusted_proxy_ip">Mastodon &ndash; trusted proxies</a>, <a href="https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html#defining-trusted-proxies">Nextcloud &ndash; trusted proxies</a></li>
<li>Depending on how the service we&rsquo;re trying to fix is written, you may have to set a trusted proxy using an IP or you may be able to set a domain name, or either. Don&rsquo;t desist if it doesn&rsquo;t work at first try.</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Changes to My Network, Sponsored by XMPP</title>
      <link>https://gvisoc.com/en/posts/changes-xmpp/</link>
      <pubDate>Sun, 31 Aug 2025 00:49:35 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/changes-xmpp/</guid>
      <description>A few days ago, someone recommended Snikket to me as an easy-to-install and maintain XMPP server, and as a result, I&amp;#39;ve changed the way I expose my services to the internet.</description>
      <content:encoded><![CDATA[<p><strong>A few days ago, someone recommended <a href="https://snikket.org">Snikket</a> to me as a simple option for setting up an XMPP server<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, and I jumped in</strong> head first. Halfway through the descent, I encountered a bunch of interesting problems to solve, which I will break down step by step in the next few posts.</p>
<p>In this one, I&rsquo;m going to tell you what those problems are, why they arise, why I want to solve them, and how I&rsquo;ve solved them, but from a design point of view for now. You won&rsquo;t find a set of commands to solve all this, but rather some context about what I&rsquo;m trying to solve; detailed instructions will come in the future.</p>
<p>Until now, all my services hosted &ldquo;underneath my printer&rdquo; were Web services, that is, based on communications through ports 80 and 443 (HTTP and HTTPs). These ports were enough to connect all my services with my devices or my browser, or with other servers in the case of my Mastodon instance. To serve so many services behind the same ports, I use <a href="https://nginx.org/">NGINX</a> as a <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a>:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250901-before.png"
         alt="A diagram showing the connectivity between Cloudflare and a server called barcas, which contains NGINX and a series of services running on Docker"/> <figcaption>
            <p>&ldquo;Barcas&rdquo; is the name of my server.</p>
        </figcaption>
</figure>

<p>Unlike my other services, <strong>XMPP uses more TCP and UDP ports than 80 and 443</strong>: 5000, 5222, 5269, etc. In the case of Snikket, as many or all other alternatives might as well, ports 80 and 443 are also used to provide a web control panel and to manage users and chat rooms.</p>
<p>In principle, the easiest configuration for installing Snikket would be as follows:</p>
<ul>
<li>Configure ports 80 and 443 in NGINX to be able to use Snikket&rsquo;s user and conversation control panel.</li>
<li>Configure direct access to all other Snikket ports: 5222, 5269, etc. Here is the <a href="https://snikket.org/service/help/advanced/firewall/">complete list</a>. As they are not shared amongst other services, reverse-proxying them is not needed.</li>
<li>Configure the DNS for my XMPP service with my domain provider, which is <a href="https://www.cloudflare.com/">Cloudflare</a>.</li>
</ul>
<p>This configuration, which would look good at first glance, looks like the following:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250902-snikketsimple.png"
         alt="A picture showing the connectivity between Cloudflare and a server called barcas, which contains NGINX and a series of services running on Docker."/> <figcaption>
            <p>This configuration, although it seems to make sense, does not work. Cloudflare only offers proxy functions for ports 80 and 443 in its free account, so traffic from the rest of Snikket&rsquo;s ports is discarded.</p>
        </figcaption>
</figure>

<p><strong>However, there is a problem that is not obvious, and the above configuration does not work</strong> out of the box. The Cloudflare security features that are available to free accounts in the form of “the Cloudflare proxy” only support ports 80 and 443. With the Cloudflare proxy enabled, all non-web traffic (80 and 443) was discarded, so none of the ports involved in XMPP conversations reached my server.</p>
<p>Disabling the Cloudflare proxy for the Snikket subdomain configuration makes everything work, and looks like this:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250902-snikketactual.png"
         alt="A diagram showing the connectivity between Cloudflare and a server called barcas, which contains NGINX and a series of services running on Docker"/> <figcaption>
            <p>This configuration, although it works, poses a risk. By disabling the proxy function, my home IP address (where &ldquo;barcas&rdquo; is accessed) is exposed to the entire internet. A distributed denial-of-service attack affecting my internet service provider could leave the entire house without internet, which we don&rsquo;t like.</p>
        </figcaption>
</figure>

<p><strong>Disabling Cloudflare&rsquo;s proxy is not ideal because it exposes the server&rsquo;s IP address</strong> to the rest of the internet. My server is at home, so a DDoS attack that, by pure chance, included the IP address assigned to me by my internet service provider would bring down my entire home network. That would prevent us from working or studying from home and would probably cause problems with my service provider.</p>
<p>An alternative to this is to hire a cheap server from any cloud hosting provider (a <a href="https://en.wikipedia.org/wiki/Virtual_private_server">VPS</a>) and move all my NGINX configuration to it, connecting this cloud server to my home server via a VPN (the free <a href="https://tailscale.com">Tailscale</a> account works very well and is more than enough).</p>
<ul>
<li>The cloud hosting provider would protect my server because the exposed IP would be theirs, not my home&rsquo;s, and these types of companies protect their infrastructure from attacks, at least at the network level. Behind the XMPP ports there is no content, just a messaging service that also encrypts traffic, so there is no problem with losing the security and anti-bot layer that Cloudflare provides for these ports.</li>
<li>Connecting the VPS to my server via a VPN is perfect for this case because it hides the IP address of my home network, saving me from having to configure it in the DNS control panel and also from having to open ports on my router. In addition, for all traffic between the VPS and my server, a layer of encryption would be applied to protect it in case it was not already encrypted.</li>
</ul>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250902-snikketvps.png"
         alt="A diagram showing the connectivity between Cloudflare, a VPS containing NGINX, and between it and a server called barcas using Tailscale. Barcas contains a series of services running on Docker."/> <figcaption>
            <p>This configuration works and solves the problem of the previous configuration, but it requires finding a solution to redirect traffic from all ports other than 80 and 443 to ‘barcas’.</p>
        </figcaption>
</figure>

<p>Why move only the NGINX configuration and not all services? For reasons of resources and price: to run NGINX and a series of firewall rules, the requirements we need are minimal. A server with 1 GB of RAM and a CPU is more than enough, and that costs between 3 and 6€ per month. If I moved everything<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, I would need between 8 and 16 GB of RAM, much more storage, CPU power, a backup solution, etc. All of this would cost me around 40€ or more per month. Since I have a server at home where I can run the services, moving everything to the VPS would be an unnecessary expense in my case.</p>
<p>So, it seems that hiring a simple VPS to have NGINX configured there and connecting it to the home server via Tailscale would solve my problems at a very low cost (3 to 6€ per month).</p>
<p>The only additional complication with this method is that we need to have some mechanism to redirect traffic from the XMPP ports (several ports such as 5222, 5269, etc. on TCP and UDP) from the server we hire to our server (at home or wherever). In the end, I solved it by configuring the VPS to do IP forwarding and then setting up a series of DNAT<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> rules on its firewall.</p>
<p>We will look at the configuration of all the elements in more detail in future posts.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><em><a href="https://es.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol">Extensible Messaging and Presence Protocol</a></em> &ndash; XMPP is a protocol that connects communities of users through their servers, creating conversations between pairs of users or rooms for group conversations. Google Talks was the most popular example of an XMPP application. One advantage of XMPP is that it is a federated protocol, meaning that even if I connect to a server where I am the only user, I can establish contact with any other user of any other service that uses XMPP on the planet. Usernames in XMPP have the same format as an email address, and servers communicate with each other when their users need them to.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Although in this article I talk almost exclusively about Snikket, I have many other services on my home server: Mastodon, Castopod, a few blogs, Linkwarden, FreshRSS, Actual Budget, Forgejo, and Nextcloud.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><em>Destination <a href="https://en.wikipedia.org/wiki/Network_address_translation">NAT</a></em>. Destination Network Address Translation.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Podcasts</title>
      <link>https://gvisoc.com/en/podcasts/</link>
      <pubDate>Fri, 08 Aug 2025 00:00:00 +1000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/podcasts/</guid>
      <description>&lt;p&gt;🚨 Currently, all my podcasting activity is in Spanish 🚨&lt;/p&gt;
&lt;p&gt;These are the podcasts where you can listen to my rambling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://podcast.gvisoc.com/@sobrelamarcha&#34;&gt;Sobre la marcha&lt;/a&gt; is a podcast about technology, various things that sparked my curiosity, and sometimes life in Australia.
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s available wherever you listen to your podcasts.&lt;/li&gt;
&lt;li&gt;You can also subscribe manually using &lt;a href=&#34;https://podcast.gvisoc.com/@sobrelamarcha/feed.xml&#34;&gt;its feed&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s got its own fediverse account at: &lt;a href=&#34;https://podcast.gvisoc.com/@sobrelamarcha/follow&#34;&gt;@sobrelamarcha@podcast.gvisoc.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<p>🚨 Currently, all my podcasting activity is in Spanish 🚨</p>
<p>These are the podcasts where you can listen to my rambling:</p>
<ul>
<li><a href="https://podcast.gvisoc.com/@sobrelamarcha">Sobre la marcha</a> is a podcast about technology, various things that sparked my curiosity, and sometimes life in Australia.
<ul>
<li>It&rsquo;s available wherever you listen to your podcasts.</li>
<li>You can also subscribe manually using <a href="https://podcast.gvisoc.com/@sobrelamarcha/feed.xml">its feed</a>.</li>
<li>It&rsquo;s got its own fediverse account at: <a href="https://podcast.gvisoc.com/@sobrelamarcha/follow">@sobrelamarcha@podcast.gvisoc.com</a>.</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>About</title>
      <link>https://gvisoc.com/en/about/</link>
      <pubDate>Sun, 20 Jul 2025 05:31:48 +0200</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/about/</guid>
      <description>&lt;p&gt;My name is Gabriel Viso Carrera and this is my blog. Here I write about various things, but more than anything else about &lt;strong&gt;personal technology&lt;/strong&gt;, and the how we deal with all that.&lt;/p&gt;
&lt;p&gt;Devices, services, applications and operating systems that are useful and respectful to us. Those that don&amp;quot;t get in the way, instead of fighting to keep our attention when the work is already done. Things that are at our service and under our control, and not the other way around.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>My name is Gabriel Viso Carrera and this is my blog. Here I write about various things, but more than anything else about <strong>personal technology</strong>, and the how we deal with all that.</p>
<p>Devices, services, applications and operating systems that are useful and respectful to us. Those that don&quot;t get in the way, instead of fighting to keep our attention when the work is already done. Things that are at our service and under our control, and not the other way around.</p>
<p>All this content is published under a Creative Commons <a href="https://creativecommons.org/licenses/by-sa/4.0/deed.en">CC BY-SA 4.0</a></p>
<p><img alt="A storm moving away from Umina beach, in New South Wales (Australia)" loading="lazy" src="/images/site-umina-gs.jpg" title="A storm moving away from Umina beach, in New South Wales (Australia)"></p>
]]></content:encoded>
    </item>
    <item>
      <title>Cookies and Your Privacy</title>
      <link>https://gvisoc.com/en/privacy/</link>
      <pubDate>Fri, 29 Mar 2024 10:39:10 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/privacy/</guid>
      <description>&lt;p&gt;This page is written using &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; and hosted in CloudFlare Pages.&lt;/p&gt;
&lt;p&gt;This site uses no cookies. No tracking of you, whatsoever:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;A screenshot of the developer tools showing the cookies this website uses.&#34; loading=&#34;lazy&#34; src=&#34;https://gvisoc.com/images/site-no-cookies-en.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Find me on the fediverse at &lt;a href=&#34;https://fedi.gvisoc.com/@gabriel&#34;&gt;https://fedi.gvisoc.com/@gabriel&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>This page is written using <a href="https://gohugo.io">Hugo</a> and hosted in CloudFlare Pages.</p>
<p>This site uses no cookies. No tracking of you, whatsoever:</p>
<p><img alt="A screenshot of the developer tools showing the cookies this website uses." loading="lazy" src="/images/site-no-cookies-en.png"></p>
<p>Find me on the fediverse at <a href="https://fedi.gvisoc.com/@gabriel">https://fedi.gvisoc.com/@gabriel</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why do You Want to Install Your Personal Mastodon Instance at Home</title>
      <link>https://gvisoc.com/en/posts/mastodon-at-home-html/</link>
      <pubDate>Tue, 10 Jan 2023 00:00:00 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/mastodon-at-home-html/</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This post is about the rationale of installing my own personal Mastodon instance at home, not in a VPS or in a cloud provider.&lt;/p&gt;
&lt;p&gt;In it, you will find hints on how to do it, but not a detailed recipe to overcome all the tasks, as such is not the goal of the article.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;m not going to relate all my trajectory on Mastodon because I want to make things short.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>TL;DR</strong>:</p>
<blockquote>
<p>This post is about the rationale of installing my own personal Mastodon instance at home, not in a VPS or in a cloud provider.</p>
<p>In it, you will find hints on how to do it, but not a detailed recipe to overcome all the tasks, as such is not the goal of the article.</p></blockquote>
<p>I&rsquo;m not going to relate all my trajectory on Mastodon because I want to make things short.</p>
<p>The idea is that Mastodon is an application with non-trivial machine requirements, and <strong>the Cloud is Expensive</strong>.</p>
<h2 id="mastodon-is-heavy">Mastodon is Heavy</h2>
<p>Let&rsquo;s see where Mastodon&rsquo;s footprint comes from, from my very limited understanding of things and my limited experience:</p>
<ul>
<li>
<p>Mastodon is a Ruby on Rails application that has <em>at least</em> three independent processes, or services, as shown in <code>systemd</code>:</p>
</li>
<li>
<p>The web application, that offers a user-facing applicaton. In it, we <em>need to do things</em> in order for the application to fetch information. It&rsquo;s very passive.</p>
</li>
<li>
<p>The streaming API, which does things in the background and streams things to the clients, both web and mobile. An example of this is sending the notifications to the web application, as they happen.</p>
</li>
<li>
<p>The Sidekiq worker, which runs in the background and implements the federation, or so I believe, in the sense of replicating data in and out of our instance to the other known instances.<a href="/en/posts/mastodon-at-home-html/#fn1">[1]</a></p>
</li>
<li>
<p>It depends also on a Postgresql database.</p>
</li>
<li>
<p>It uses Redis, an in-memory cache backed into the disk, to support Sidekiq processes.</p>
</li>
<li>
<p>It uses <em><strong>A Lot</strong></em> of disk space, as a result of two things:</p>
</li>
<li>
<p>The activity and uploaded media of the instance&rsquo;s users.</p>
</li>
<li>
<p>The federated content coming from other instances.<a href="/en/posts/mastodon-at-home-html/#fn2">[2]</a></p>
</li>
<li>
<p>You will need several other smaller services hanging around, like an NGINX to act as a web server and gateway.</p>
</li>
</ul>
<p>In my experience, if we use a Digital Ocean Droplet of 2GB RAM and 2 CPU, the  Mastodon services will have to be stopped for us to be able to run maintenance tasks without Digital Ocean killing them. 4 GB and 2 CPU will be the minimum suitable droplet, and a disk space of less than 60 GB will be tight.</p>
<p>And that&rsquo;s just a minimal installation. Add HA (High Availablity) on those components, and you&rsquo;ll have to put much more hardware and extra networking services.</p>
<p>That is to say, the beast is heavy.</p>
<h2 id="the-cloud-is-expensive">The Cloud is Expensive</h2>
<p>One of the aforementioned droplets would cost you US$24/month, which in Australian dollars is about A$40/month.</p>
<p>That&rsquo;s a lot of money: A$480 a year. And the droplet is a dumb and isolated virtual machine that doesn&rsquo;t do <em>anything</em> for you with regards to maintenance and administration.</p>
<ul>
<li>Do you want application backups? They are charged separately.</li>
<li>Do you want machine snapshots? They are charged separately.</li>
<li>Do you want alerting when the droplet is down or slow? Charged separately.</li>
<li>Are you running things in HA? Do you need extra network things on top of the droplets you&rsquo;re adding? Charged separately!</li>
</ul>
<p>And, of course, consider your labour. You must keep not only Mastodon, but also the droplet&rsquo;s operating system up to date and finely tuned. That&rsquo;s a lot of work, on top of being a lot of money.</p>
<h2 id="what-it-takes">What it Takes</h2>
<p>Here&rsquo;s the thing:</p>
<ul>
<li>In little over 2 months, you would have spent more money than the cost of an ARM single board computer, that exceeds the above requirements (like the Raspberry Pi<a href="/en/posts/mastodon-at-home-html/#fn3">[3]</a> 4B, 4GB) <em>and the electricity cost of running it for that time</em>.</li>
<li>In another 2-3 months, you can add to the pack an SSD drive of hundreds of GB, and externalise all the disk usage to it.</li>
<li>From there, you are effectively saving a lot of money that you could use to support the projects around the network, or the instances you sympathise with. Or ☕.</li>
</ul>
<p>The only things that you need are:</p>
<ul>
<li>
<p>A small computer with enough resources.</p>
</li>
<li>
<p>4 GB of RAM, 60 GB or more of storage, 4 core is enough to get you up and running.</p>
</li>
<li>
<p>In the medium term, if you&rsquo;re using an SD card for the system, attach some proper storage for high I/O load for performance and reliability. Small SSD and USB 3.0 cases for them are very cheap.</p>
</li>
<li>
<p>A domain managed by a domain provider that supports DDNS<a href="/en/posts/mastodon-at-home-html/#fn4">[4]</a>,</p>
</li>
<li>
<p>Install <code>ddclient</code> (from <a href="https://github.com/ddclient/ddclient">its GitHub repository</a>) on your machine <a href="/en/posts/mastodon-at-home-html/#fn5">[5]</a>,</p>
</li>
<li>
<p>A router that supports NAT and that allow you to expose services at ports <code>80</code> and <code>443</code>.<a href="/en/posts/mastodon-at-home-html/#fn6">[6]</a></p>
</li>
<li>
<p>A decent internet connection.<a href="/en/posts/mastodon-at-home-html/#fn7">[7]</a></p>
</li>
</ul>
<blockquote>
<p>🌱 Preferably, choose a low power device. Don&rsquo;t run Mastodon 24/7 on your forest-burning gaming PC 🌷</p></blockquote>
<p>It won&rsquo;t support more than a few friends and family members. But if your instance is personal, or if your crew is limited, you&rsquo;ll be fine. The amount of extra work that you need to do by having the instance at home, compared to having it in a provider like Digital Ocean, is negligible.</p>
<p>And it&rsquo;s <strong>a lot cheaper</strong>.</p>
<hr>
<ol>
<li></li>
</ol>
<p>A federated application is not a distributed application. While in a distributed application all instances try to discover all other instances and be able to communicate with each other, a federated application is passive. The instances will communicate only if they know each other. How an instance can know other instances? In Activity Pub, only through the users&rsquo; actions. If I decide to follow you at <a href="https://mastodon.social">https://mastodon.social</a> from my <a href="https://fedi.gvisoc.com">https://fedi.gvisoc.com</a>, then those two instances will begin talking to each other. From that moment, they will talk <strong>a lot</strong>, but the federation details are out of the scope of this article. Just let&rsquo;s assume that there is a lot of media files and data going back and forth. <a href="/en/posts/mastodon-at-home-html/#fnref1">↩︎</a></p>
<ol start="2">
<li></li>
</ol>
<p>Mastodon caches a lot of information, including, and especially, pictures and videos from other instances. It will cache media from all the accounts you follow across any instance, and from all the known, but not followed accounts, such as those whose posts appear in your timeline as someone you actually follow boosts them. From all those, it will cache avatars, headers, emojos, and all the attachments of the posts that are <em>visible</em> in your timelines. Visible doesn&rsquo;t mean viewed: those resources will be cached in your instance&rsquo;s disk even if you never see them. And I&rsquo;m sure this doesn&rsquo;t end there, but I am not 100% sure of all the implications of the federation and ActivityPub. <a href="/en/posts/mastodon-at-home-html/#fnref2">↩︎</a></p>
<ol start="3">
<li></li>
</ol>
<p>Although <a href="https://www.buzzfeednews.com/article/chrisstokelwalker/raspberry-pi-hired-ex-cop-mastodon-controversy">the people around the Raspberry Pi is not very popular at the moment</a>, the community around these machines is huge and I&rsquo;m sure many of us will find some at the bottom of a drawer. <a href="/en/posts/mastodon-at-home-html/#fnref3">↩︎</a></p>
<ol start="4">
<li></li>
</ol>
<p>I have all my domains at Cloudflare, who are ethically very slow and tone deaf as well (please suit yourself with a web search engine for this one claim), but very cheap. And in the free tier of Cloudflare, you can update the DNS record for your machine through their API, which is spoken by <code>ddclient</code>. <a href="/en/posts/mastodon-at-home-html/#fnref4">↩︎</a></p>
<ol start="5">
<li></li>
</ol>
<p>Check my configuration (last reviewed at the time of this writing) in this <a href="https://gist.github.com/gvisoc/9bc137a7c01a149f5d5e146f1827f211">public Gist</a> at my GitHub account. <a href="/en/posts/mastodon-at-home-html/#fnref5">↩︎</a></p>
<ol start="6">
<li></li>
</ol>
<p>I haven&rsquo;t found any router that wouldn&rsquo;t allow you to do so. Even the provided by the ISPs can be configured in such way (I am using one of those right now). <a href="/en/posts/mastodon-at-home-html/#fnref6">↩︎</a></p>
<ol start="7">
<li></li>
</ol>
<p>I am getting very good results with an internet connection that offers 20 Mbps upload speed. This includes not only me accessing information on the go, but also the other instances to find my information quickly: there are posts that get reactions almost immediately after they are published&hellip; in those rare cases I publish anything interesting. <a href="/en/posts/mastodon-at-home-html/#fnref7">↩︎</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Verify Your Downloads!</title>
      <link>https://gvisoc.com/en/posts/verify-downloads/</link>
      <pubDate>Wed, 28 Apr 2021 00:00:00 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/verify-downloads/</guid>
      <description>&lt;p&gt;When we download software, we need to verify two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The integrity of the software we have just downloaded.&lt;/li&gt;
&lt;li&gt;The authenticity of the package.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Checking these two things will ensure that the download went well, and that the software is authentic (and not malware, for example).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Verifying the integrity and authenticity of a Manjaro ISO&#34; loading=&#34;lazy&#34; src=&#34;https://gvisoc.com/images/20210428-manjaro.gif&#34;&gt;&lt;/p&gt;
&lt;p&gt;For the impatient, here is the process assuming that we have downloaded:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A software package we want to use, in the example &lt;code&gt;software.pkg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A file containing the reference hash; in the example, &lt;code&gt;software.pkg.sha256&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A file containing the signature of the Software Author; in the example, &lt;code&gt;software.sig&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The public keys of the Software Author; in the example, &lt;code&gt;author.gpg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    $ sha256sum -c software.pkg.sha256          # 1. Check the download integrity
    $ gpg --import author.gpg                   # 2a) Import downloaded public keys
    $ gpg --keyserver hkp://&amp;lt;server&amp;gt; \
                   --search-keys &amp;lt;shortID&amp;gt;      # 2b) Import public keys from a server
    $ gpg --verify software.sig software.pkg    # 3) Verify signatures
    $ gpg --list-public-keys --with-sig-check   # 4) If needed, check web of trust
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These commands, why we run them, how they work, and how we should understand them, are discussed next. All the commands are Linux-specific, but information on Windows equivalents can be found in plenty of sites and I will probably write other post in the next few days.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>When we download software, we need to verify two things:</p>
<ul>
<li>The integrity of the software we have just downloaded.</li>
<li>The authenticity of the package.</li>
</ul>
<p>Checking these two things will ensure that the download went well, and that the software is authentic (and not malware, for example).</p>
<p><img alt="Verifying the integrity and authenticity of a Manjaro ISO" loading="lazy" src="/images/20210428-manjaro.gif"></p>
<p>For the impatient, here is the process assuming that we have downloaded:</p>
<ul>
<li>A software package we want to use, in the example <code>software.pkg</code></li>
<li>A file containing the reference hash; in the example, <code>software.pkg.sha256</code></li>
<li>A file containing the signature of the Software Author; in the example, <code>software.sig</code></li>
<li>The public keys of the Software Author; in the example, <code>author.gpg</code></li>
</ul>
<pre tabindex="0"><code>    $ sha256sum -c software.pkg.sha256          # 1. Check the download integrity
    $ gpg --import author.gpg                   # 2a) Import downloaded public keys
    $ gpg --keyserver hkp://&lt;server&gt; \
                   --search-keys &lt;shortID&gt;      # 2b) Import public keys from a server
    $ gpg --verify software.sig software.pkg    # 3) Verify signatures
    $ gpg --list-public-keys --with-sig-check   # 4) If needed, check web of trust
</code></pre><p>These commands, why we run them, how they work, and how we should understand them, are discussed next. All the commands are Linux-specific, but information on Windows equivalents can be found in plenty of sites and I will probably write other post in the next few days.</p>
<h1 id="checking-the-integrity-of-a-download">Checking the Integrity of a Download</h1>
<p>We want to check the integrity of a downloaded package to ensure that there were no transmission errors, and that nobody between our computer and the server exchanged the package for something else. We are checking that the download went well and we obtained <em>whatever</em> there was in the server: no more, and no less.</p>
<p>To do this, we verify the checksums of the files. Checksums are representations of the content smaller than the content itself, calculated by algorithms that ensure a stupidly small probability of two different files producing the same result. Some of those algorithms are members of a family called &ldquo;hashes&rdquo;. Most useful checksums, and hashes particularly, always have the same length.</p>
<p>If there was a single bit of the file that got changed over the wire, the checksum calculated in our computer over the corrupted file would be different than the checksum of the server&rsquo;s file: the checksum wouldn&rsquo;t verify.</p>
<p>In order to calculate a checksum we only need the file itself, and the right program installed.</p>
<p>For example, if we go to the <a href="https://github.com/VSCodium/vscodium/releases">downloads page</a> for <a href="https://vscodium.com/">VSCodium</a>, a fully Open Source version of Visual Studio Code, we can see that for every package there is an extra file, ending in <code>.sha256</code>:</p>
<pre><code>codium-1.55.2-1618361370.el8.x86_64.rpm
codium-1.55.2-1618361370.el8.x86_64.rpm.sha256
</code></pre>
<p>This extra file contains the reference checksum calculated over the server&rsquo;s file, and that is the exact same value that we should obtain in our computer from the downloaded copy.</p>
<p>The idea is to download both files to the same directory, and run the following command <code>sha256sum -c</code> over the checksums file:</p>
<pre><code>$ sha256sum -c codium-1.55.2-1618361370.el8.x86_64.rpm.sha256 
codium-1.55.2-1618361370.el8.x86_64.rpm: OK
</code></pre>
<p>What happened here is that the program <code>sha256sum</code> checked (<code>-c</code>) that the reference checksums present in the file <code>codium-1.55.2-1618361370.el8.x86_64.rpm.sha256</code> could be calculated locally using the downloaded file. The <code>.sha256</code> file content is the following:</p>
<pre><code>75b9f844c22c98d4da33e64b6c7c49e8b4d0d94a438e4f8ce976e7e54b40a682  codium-1.55.2-1618361370.el8.x86_64.rpm
</code></pre>
<p>That line is a &ldquo;properly formatted SHA256 checksum line&rdquo;, which is built by a SHA256 hash, two (2) spaces, and the name of the file the hash was calculated from in the server. From there, the check <code>sha256sum -c</code> performs is just to find a file that has the same name as in that line, calculate its SHA256 hash, and compare it with the first part of the line.</p>
<p>In this case the verification was complete and correct.</p>
<p>A file like that can have plenty of lines, not just one, and <code>sha256sum -c</code> will run all the checks in a batch.</p>
<p>Another possibility can be to have only the file to download, and the SHA256 line in the website, for you to see. In that case, we&rsquo;d download the file and get the SHA256 locally by executing the <code>sha256sum</code> over the downloaded file, without <code>-c</code>:</p>
<pre><code>$ sha256sum codium-1.55.2-1618361370.el8.x86_64.rpm
75b9f844c22c98d4da33e64b6c7c49e8b4d0d94a438e4f8ce976e7e54b40a682  codium-1.55.2-1618361370.el8.x86_64.rpm
</code></pre>
<p>That would give us the previously mentioned line, and we should just visually compare the hashes.</p>
<p>When the checksums are correct, we are sure that the download went well, <strong>but nothing else</strong>. It&rsquo;s up to us whether or not we trust that the publisher of the software is publishing authentic software, made by its true authors.</p>
<h1 id="checking-the-authorship-and-authenticity-of-the-software">Checking the Authorship and Authenticity of the Software</h1>
<p>If we don&rsquo;t trust the Software Publisher, that is to say, the website or the server we downloaded the package from, then checking the integrity of the download is not enough. The Publisher could have offered anything else in that file, and calculate a perfect valid reference checksum for a counterfeit package.</p>
<p>In such case of distrust, we want to check the software authorship, and therefore its authenticity. We can do that by obtaining a cryptographic signature of the package, created by the Software Author, and verifying it cryptographically.</p>
<p>There are many cryptographic signature mechanisms and algorithms, but here we will focus on signatures produced using asymmetric cryptography because they are the ones used most often, if not the only ones used to sign software.</p>
<p>In most asymmetric cryptography frameworks like PGP and GPG, the signature works as follows:</p>
<ul>
<li>
<p>A Software Author would have two keys: Private or Secret key, and Public Key. They are generated in the same process and they are inextricably linked.</p>
</li>
<li>
<p>The Public Key is generally available; the Secret Key is never shared with anyone.</p>
</li>
<li>
<p>Using their Secret Key, the software author produce a cryptographic signature, which in the case of PGP (or GPG), it consists in:</p>
</li>
<li>
<p>calculating a hash, similar that the ones we&rsquo;ve just discussed,</p>
</li>
<li>
<p>signing the hash using the Secret Key and a cryptographic singing algorithm.</p>
</li>
</ul>
<p>The idea of signing a hash and not the file itself is that a file can have a size from a few bytes to Gigabytes or Terabytes. By signing the hash, which is much smaller and has a fixed length, the result is produced in a predictable amount of time.</p>
<p>As the Secret and Public Keys are an inextricable pair, only the Public Key of the software Author will verify correctly the signature produced with the corresponding Secret Key. As the Public Key is made available, everybody can verify the signatures using the right software.</p>
<p>Here&rsquo;s what we need to do to check a signature with a real example, a Manjaro GNU/Linux ISO file.</p>
<p><strong>First</strong>: Download the software from an, in principle, trusted server. In this case, we will download a file named <code>manjaro-xfce-21.0.2-210419-linux510.iso</code> from the <a href="https://manjaro.org/downloads/official/xfce/">Manjaro XFCE download page</a>.  This file has an associated GPG signature that we will also download, <code>manjaro-xfce-21.0.2-210419-linux510.iso.sig</code>, and a SHA1 hash printed in the web page, <code>7d9d5d886188ebb0a05c9ceeabdb068fb2544feb</code>.</p>
<p><img alt="Manjaro download page" loading="lazy" src="/images/20210428-manjarodownload.png"></p>
<p><strong>Second</strong>: <strong>Check the hash</strong> as we discussed earlier in this post, to make sure that the package is uncorrupted. In this case we need to compute the hash and compare it visually with the reference one, present in the download page.</p>
<pre><code>$ sha1sum manjaro manjaro-xfce-21.0.2-210419-linux510.iso
7d9d5d886188ebb0a05c9ceeabdb068fb2544feb  manjaro-xfce-21.0.2-210419-linux510.iso
</code></pre>
<p>It verifies, so let&rsquo;s go with the GPG signature.</p>
<p><strong>Third</strong>: For us to be able to verify a GPG signature, we first need to <strong>obtain the public keys of the Software Author</strong>. In this case, <a href="https://wiki.manjaro.org/index.php?title=How-to_verify_GPG_key_of_official_.ISO_images">Manjaro offers two sets of public keys</a>, the general Manjaro ones, and Philip Müller&rsquo;s, &ldquo;just in case we didn&rsquo;t trust the server where Manjaro made the general keys file available&rdquo;. That statement is a bit of food for thought that we&rsquo;ll discuss later, and a good example because it shows two ways for obtaining public keys.</p>
<p>First, we download and import the Manjaro general keys.</p>
<pre><code>$ wget https://[url to the manjaro keys]/manjaro.gpg -O manjaro.gpg
$ gpg --import manjaro.gpg
</code></pre>
<p>On April 28th 2021 this imported 22 keys into the keyring, allowing us to verify packages signed by several people and machines at Manjaro.</p>
<p>To download Philip Müller&rsquo;s keys from a public PGP Key Server, use the following:</p>
<pre><code>$ gpg --keyserver hkp://pool.sks-keyservers.net --search-keys 11C7F07E
gpg: data source: http://194.95.66.28:11371
(1) Philip Müller (Called Little) &lt;REDACTED@manjaro.org&gt;
      2048 bit RSA key CAA6A59611C7F07E, created: 2012-05-05
Keys 1-1 of 1 for &quot;11C7F07E&quot;.  Enter number(s), N)ext, or Q)uit &gt; 1
gpg: key CAA6A59611C7F07E: &quot;Philip Müller (Called Little) &lt;REDACTED@manjaro.org&gt;&quot; not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
</code></pre>
<p>Note that <code>Enter number(s), N)ext, or Q)uit &gt;</code> is an actual prompt and we have to select the key, <code>1</code> in this case. Pay attention to the <code>CAA6A59611C7F07E</code> part: is an identifier for the key. Another thing to note is that the string we used to search the key (<code>11C7F07E</code>) is part of the key identifier. The lower part of a key&rsquo;s ID is often referred to as &ldquo;short identifier of the key&rdquo; for obvious reasons.</p>
<p>The keys can also be searched by some other identificative fields, for example an email (real email omitted for privacy reasons!):</p>
<pre><code>$ gpg --keyserver hkp://pool.sks-keyservers.net --search-keys &quot;REDACTED@manjaro.org&quot;

gpg: data source: http://194.95.66.28:11371
(1) Philip Müller (Called Little) &lt;REDACTED@manjaro.org&gt;
      2048 bit RSA key CAA6A59611C7F07E, created: 2012-05-05
...
</code></pre>
<p>The key ID identifies the pair of keys, not just the Public Key. It is important to know the ID of key pair, as it is the only way to really identify a key used to produce a signature and therefore the key needed to verify it. There can be many keys for a single email address, not all of them legit. The way to know the key needed to verify a signature is try to verify it without importing any key, as it will output the ID of the key pair that was used:</p>
<pre><code>gpg: Signature made Mon 19 Apr 2021 18:47:28 AEST
gpg:                using RSA key 3B794DE6D4320FCE594F4171279E7CF5D8D56EC8
gpg: Can't check signature: No public key
</code></pre>
<p><strong>Fourth</strong>: If the download of the iso verified the hash on previous steps, then check the signatures:</p>
<pre><code>$ gpg --verify manjaro-xfce-21.0.2-210419-linux510.iso.sig  manjaro-xfce-21.0.2-210419-linux510.iso
gpg: Signature made Mon 19 Apr 2021 18:47:28 AEST
gpg:                using RSA key 3B794DE6D4320FCE594F4171279E7CF5D8D56EC8
gpg: Good signature from &quot;Manjaro Build Server &lt;build@manjaro.org&gt;&quot; [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 3B79 4DE6 D432 0FCE 594F  4171 279E 7CF5 D8D5 6EC8
</code></pre>
<p>In this case, the signing key was one of the keys present in the file <code>manjaro.gpg</code>, the one for the <em>Manjaro Build Server</em> with identifier <code>3B794DE6D4320FCE594F4171279E7CF5D8D56EC8</code>. The verification process was correct, so we need that something called <em>Manjaro Build Server</em> is the creator of the ISO we&rsquo;ve just downloaded.</p>
<p><strong>Fifth</strong>: If we want to check the authenticity of such <em>Manjaro Build Server</em> dude, we can do so by validating its key using Philip Müller&rsquo;s key (provided we  trust him). That can be done by check the <em>web of trust</em> for Manjaro Build Server key, and see whether Philip is part of that web of trust. For this one, issue the following command:</p>
<pre><code>$ gpg --list-public-keys --with-sig-check
</code></pre>
<p>Within the output of this command we can see all the public keys we have in our keyring, and who has signed them. Signing a Public Key with your own secret key is, in this context, the ultimate vouching act. In the case of the Manjaro Build Server, which we can identify by looking at its identifier, we can see that within its signers there is Philip Müller (the ID is the same previously imported <code>CAA6A59611C7F07E</code>):</p>
<pre><code>pub   rsa3072 2020-10-28 [SC] [expires: 2022-10-28]
      3B794DE6D4320FCE594F4171279E7CF5D8D56EC8
uid           [ unknown] Manjaro Build Server &lt;build@manjaro.org&gt;
sig!         8238651DDF5E0594 2020-10-29  Matti Hyttinen &lt;REDACTED@manjaro.org&gt;
sig!         DAD3B211663CA268 2020-10-29  Bernhard Landauer &lt;REDACTED@manjaro.org&gt;
sig!         084A7FC0035B1D49 2020-10-29  Dan Johansen (Manjaro) &lt;REDACTED@manjaro.org&gt;
sig!         CAA6A59611C7F07E 2020-10-29  Philip Müller (Called Little) &lt;REDACTED@manjaro.org&gt;
sig!3        279E7CF5D8D56EC8 2020-10-28  Manjaro Build Server &lt;build@manjaro.org&gt;
sub   rsa3072 2020-10-28 [E] [expires: 2022-10-28]
sig!         279E7CF5D8D56EC8 2020-10-28  Manjaro Build Server &lt;build@manjaro.org&gt;
</code></pre>
<p>Therefore, if we trust Philip Müller, we can trust the downloaded ISO signature because Philip has endorsed the Manjaro Build Server by signing its key with his own.</p>
<h1 id="package-managers">Package Managers</h1>
<p>The above process is what we need to do for the software we download manually, from the web.</p>
<p>Package Managers for GNU/Linux, as apt, pacman or yum among others, for Windows as Chocolatey, and for macOS as homebrew, <em>should</em> do all the avobe automatically, transparently and by default. Check the documentation of the system and package manager you use (and trust) to check specific details.</p>
<h1 id="this-is-all-about-who-we-trust">This is All About Who We Trust</h1>
<p>If we pay attention to how this works, we&rsquo;ll se that all this is about trust. There is no technique that would give us 100% certainty of the authenticity of a software package. We need to judge if we trust the Software Publisher, and if we trust the Software Author, and if we believe their public keys really belong to them &ndash;the actual persons or companies. Check after check, we are traversing a web of trust that is effective as long as we can find a point we can trust.</p>
<h1 id="further-reading">Further Reading</h1>
<p>A good introduction of the web of trust, and links to further material, can be found <a href="https://en.wikipedia.org/wiki/Web_of_trust">in the Wikipedia</a>.</p>
<p>More on the cryptographic suite used by most software publishers, authors and distribution channels can be found in the <a href="https://www.gnupg.org/gph/en/manual.html">GNU Privacy Handbook</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fixing a Common User Home Service Error in Synology NASes</title>
      <link>https://gvisoc.com/en/posts/fixing-homes-error-synology-nas/</link>
      <pubDate>Sat, 06 Feb 2021 16:32:00 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/fixing-homes-error-synology-nas/</guid>
      <description>&lt;p&gt;If you have a Synology NAS and you are a technology enthusiast, or have some interest in using such machines as home servers, you may run into a problem that is quite common. Judging from the amount of Google results, the User Home service gets somehow broken quite often the first time it is activated, and neither is detected by some other services that use it as a dependency, nor can it be deactivated.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>If you have a Synology NAS and you are a technology enthusiast, or have some interest in using such machines as home servers, you may run into a problem that is quite common. Judging from the amount of Google results, the User Home service gets somehow broken quite often the first time it is activated, and neither is detected by some other services that use it as a dependency, nor can it be deactivated.</p>
<p>I came across the cause of the problem and its solution; keep reading to know more.</p>
<h1 id="the-symptoms">The Symptoms</h1>
<p>At some point you need to activate User Home service as per the requirements of some other package (for example, Synology Mail), or just because you want to work through SSH, or any other valid reason. Although you activate it, the dependent package keeps asking you to enable it. Or, if you just enabled it to use home folders via SSH, although you land on a home directory when you log in through SSH, you can&rsquo;t see it through DS File or File Station:</p>
<p><img alt="FileStation Not Showing Homes" loading="lazy" src="/images/20210206-filestation.png"></p>
<p>In the above picture you should see a folder for each user under <code>homes</code>, plus a <code>home</code> directory that would host your files (it&rsquo;s like a symbolic link dynamically created when you log in to the NAS through DSM or DS File).</p>
<p>If you try to disable and re-enable User Homes Service, DSM shows a sad and brief &ldquo;Operation Failed&rdquo; error pop up, and in Log Center you just see a useless message &ldquo;User home service disable failed&rdquo; like the one below:</p>
<p><img alt="Log Station Message" loading="lazy" src="/images/20210206-logcenter.png"></p>
<h1 id="the-problem">The Problem</h1>
<p>The problem is that the user homes&rsquo; hosting folder, named <code>homes</code>, should be created in one of the main volumes inside the disk array, for instance, <code>/volume1/homes</code>, and a symbolic link back should be created at <code>/var/services/homes</code>. Instead, in this case the <code>homes</code> folder was created in that location directly, as a regular folder (<code>/var/services/homes</code>). We can check it by doing SSH to the NAS:</p>
<pre><code>user@hostname:~$ pwd
/var/services/homes/user
user@hostname:~$ cd ../..
user@hostname:/var/services$ ls -lda homes
drwxr-xr-x 6 root root 4096 Feb 5 08:00 homes 
</code></pre>
<p>The expected result of a successful User Home service activation is this one instead:</p>
<pre><code>user@hostname:/var/services$ ls -lda homes
lrwxr-xr-x 6 root root 4096 Feb 5 08:10 homes -&gt; /volume1/homes 
</code></pre>
<p>Not only you can see where it points, but also the <code>l</code> flag on the folder permissions, meaning <em>link</em>, instead of a <code>d</code> from <em>directory</em>.</p>
<p>It is important to note that, although the user still has its home folder that works, <strong>the user homes created this way are outside the disk array and in the operating system&rsquo;s filesystem</strong>. This fact have several consequences, all of them dangerous for our files, for DSM&rsquo;s stability, and therefore for our NAS reliability.</p>
<p>In the first place, it causes almost every Synology package that depends on the User Home service to fail. Synology packages usually operate with directories under the volumes created inside the disk array, not under <code>/var/services/</code>, and that&rsquo;s why Synology Mail didn&rsquo;t detect the user homes directories and kept asking for User Home service to be enabled. As with Synology Mail, if the NAS is kept in this situation, the files in those directories won&rsquo;t be accessible by any backup or synchronisation service, and something as simple as updating DSM can have all the files under <code>/var/services/homes/</code> wiped, and lost forever.</p>
<p>Another consequence is that all user home directories will be lost in the event of machine upgrades or replacement, meaning that in the event of moving the disks to a new NAS, those user home directories won&rsquo;t be carried over.</p>
<p>A much worse scenario would be the one where we run out of space in the system&rsquo;s partitions because we put too many files under our home directories, phisically located under <code>/var</code>, causing DSM to crash and, probably, to have problems to boot.</p>
<h1 id="the-solution">The Solution</h1>
<p>Solving the problem is as easy as login in through SSH to back up our files and delete the <code>/var/services/homes</code> folder:</p>
<pre><code>user@hostname:~$ cd /var/services
user@hostname:/var/services$ tar cfz /volume1/[dest. folder]/homes-backup.tgz homes
user@hostname:/var/services$ sudo rm -rf homes
</code></pre>
<p>After that, we create a symbolic link to <code>/volume1/homes</code>:</p>
<pre><code>user@hostname:/var/services$ sudo ln -s /volume1/homes homes
user@hostname:/var/services$ ls -lda homes
lrwxr-xr-x 6 root root 4096 Feb 5 08:10 homes -&gt; /volume1/homes
</code></pre>
<p>Finally, we log into the DSM web interface, to disable without error and re-enable the User Home service.</p>
<p>No services should fail on activation, and the DSM File Station should show all users&rsquo; home directories; time to restore the previous users&rsquo; home folders contents if needed.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Installing Linux with Secure Boot</title>
      <link>https://gvisoc.com/en/posts/linux-secure-boot/</link>
      <pubDate>Mon, 15 Jun 2020 10:55:00 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/en/posts/linux-secure-boot/</guid>
      <description>This post is motivated by the confusion and the still prevalent recommendation of disabling Secure Boot when installing GNU/Linux, no matter what distribution we are talking about. However, many distributions do support Secure Boot since a while ago.</description>
      <content:encoded><![CDATA[<p>This post is motivated by the confusion and the still prevalent recommendation of disabling Secure Boot when installing GNU/Linux, no matter what distribution we are talking about.</p>
<p>Contrary to the mainstream trend of such a disablement and proceeding with an outdated bootstrap, security-wise, many distributions do support Secure Boot since a while ago.</p>
<p>In this post I will provide some links, references, and &ldquo;glue text to make sense&rdquo; in order to provide clarity about Secure Boot: what it is, what it provides, and what it takes from us &ndash;mostly in terms of user experience, or friction.</p>
<p>I do not want to reinvent the wheel or take credit for the existing state of the art, but to provide some insight that I hope it will be easy to understand to the Linux novel users. Or at least, to provide a lead that can be followed to read more and understand what&rsquo;s happening.</p>
<h2 id="structure">Structure</h2>
<p>You will find:</p>
<ol>
<li>What I assume you know, or a list of things for you to search about.</li>
<li>A process to install a Linux system with Secure Boot enabled.</li>
<li>Post-Install situations affected by Secure Boot</li>
<li>What is Secure Boot, and what&rsquo;s it based on.</li>
</ol>
<h2 id="what-i-assume-you-already-know-aka-what-youre-supposed-to-search-in-the-interwebs-if-not">What I assume you already know (a.k.a., what you&rsquo;re supposed to search in the interwebs if not!)</h2>
<p>I assume that you are familiar with the following concepts, which I try to summarise. But, please: use your search engine.</p>
<ul>
<li>Kernel: it&rsquo;s the hert of the operating system. It provides the applications with access to the hardware.</li>
<li>Modules: specialised code that the Kernel will load to tailor its capabilities to very specific hardware or configurations. Many times, when it allows the Kernel to understand a piece of hardware, it can be called &ldquo;a driver&rdquo; like in Windows lingo, but there are modules for many other things.</li>
<li>Root password: it&rsquo;s the password of the root user, which is the most powerful authority in a Unix or Unix-like system, as GNU/Linux for instance. Absolute privileges.</li>
<li>BIOS: stands for Basic Input and Ouput System, and it was the way that older (early 2000&rsquo;s and before) computers had to connect the Operating Systems to the hardware. This included a boot menu and a very few more options, and many specialised configurations for some hardware devices had to be done by plugging, unplugging or changing physical jumpers in the motherboard.</li>
<li>(U)EFI: stands for (Unified) Extensible Firmware Interface. It&rsquo;s the evolution of BIOS, looks after the same hardware to operating system bridge. It is much more advanced and comes with many more options, many of them enabled for modern system by default, like the GUID Partition Table for the Disks, and the Secure Boot.</li>
<li>GUID Partition Table. A modern partition schema that identifies partitions on the disk by giving them Globally Unique IDentifiers, rather than names. Amongst other things, supports much larger disk sizes.</li>
<li>Secure Boot deserves a whole section on its own. Go and check &ldquo;What is Secure Boot&rdquo; at the end of this post.</li>
</ul>
<h2 id="installation-process">Installation Process</h2>
<h3 id="check-whether-you-actually-have-uefi">Check whether you actually have UEFI</h3>
<p>First of all, have a look at what you have in your computer: whether BIOS or EFI. If you have BIOS you can skip the whole article, because Secure Boot was introduced in the UEFI.</p>
<p>If you&rsquo;re not sure which system your motherboard uses, and if you still have Windows there, check the following:</p>
<ul>
<li>Look for an EFI folder within <code>c:\windows\boot</code></li>
<li>Open the Disk Management Utility and check if you have a partition labeled EFI in your system disk, like this one:</li>
</ul>
<p><img alt="EFI Partition" loading="lazy" src="/images/20200615-diskmgrefi.png"></p>
<p>If you don&rsquo;t have Windows or you are unsure,</p>
<ul>
<li>Reboot the computer and look for a message telling you to press a key to enter setup.</li>
<li>Press that key, quick!</li>
<li>No worries, it happens to everybody. Reboot and try again.</li>
<li>Once inside, and without changing anything, look for indications of an EFI system: search for options like &ldquo;Secure Boot&rdquo;, &ldquo;Legacy/UEFI&rdquo; boot mode.</li>
</ul>
<p>If your system shows any of the above symptoms, you have an UEFI.</p>
<h3 id="choosing-a-distribution-that-supports-secure-boot">Choosing a distribution that supports Secure Boot</h3>
<p>There is a way to query distrowatch to get a list of the distributions that may support Secure Boot by searching included packages like <a href="https://distrowatch.com/search.php?pkg=shim&amp;amp;relation=lessequal&amp;amp;pkgver=1&amp;amp;distrorange=InAny"><code>shim</code></a> or <a href="https://distrowatch.com/search.php?pkg=efibootmgr&amp;amp;pkgver=0.&amp;amp;distrorange=InLatest#pkgsearch"><code>efibootmgr</code></a>, but the best way is to check your favourite distribution&rsquo;s documentation (kudos to <a href="https://firmwaresecurity.com/2019/04/29/list-of-linux-distros-support-of-trustedsecuremeasuredboot-and-fwupd-needed/">firmwaresecurity.com for the queries hint</a>).</p>
<p>The good news is that the support of Secure Boot is already in the Kernel and the base system for all of them, so it would be a matter of time and ideology for it to arrive to your computer. If you want to install a different distribution than those, you&rsquo;ll have to disable Secure Boot in your EFI.</p>
<h3 id="download-and-verify-an-iso-preferably-a-live-one-with-non-free-firmware-and-modules-included">Download and verify an ISO, preferably a Live one with non-free firmware and modules included</h3>
<p>It is advisable, always, to download an ISO installation image that offers you the possibility of trying Linux in your system without installing it first. This will give you an idea of whether or not your installation media will have the required modules for your hardware, most precisely (and critically neccessary) one module for the graphics adapter and another one for the network. Also, depending on your hardware and distribution, you may have to download specifically an ISO with <em>non-free</em> software included for it to work! This is almost always necessary (99%+ cases) in the case of Debian and most  laptops.</p>
<p>Download your distribution in ISO format, as usual, and look for a way to verify the files you download. Most every website that offers free or open source software these days will have a side or footnote telling offering you &ldquo;the hashes&rdquo; or the &ldquo;sums&rdquo;: MD5 or SHA checksum strings.</p>
<p>Checksums are strings that represent the contents of a file, much smaller than the files they represent. They are generated by a mathematical algorithm that ensures that the probability of getting the same result with different files is ridiculously small. So ridiculous that it&rsquo;s difficult to explain, but the chances are cosmically low.</p>
<p>These are techniques that allow you to check that the ISO you downloaded has not been corrupted by the download process, and more importantly, that they are authentic. It helps you know that the mirror or the server where the actual file is hosted, usually different than the server that publishes the checksums, has not been compromised: you&rsquo;re downloading an authentic image, without any malware with it. What they do is run the same procedures that you&rsquo;re about to run, in their side, and tell you to check that you get the same results.</p>
<p>If your distribution publisher offers you SHA verification sums, open Windows PowerShell and run <code>Get-FileHash</code> over the ISO you just downloaded:</p>
<p><img alt="Checking the sum!" loading="lazy" src="/images/20200615-getfilehash.png"></p>
<p>If your distribution publisher if offering MD5 sums, then open the regular command prompt and use <code>certutil -hashfile</code> over the file.</p>
<p>Whichever method you use, your local result should match with the check sums provided by the software publisher (leaving uppercase or lowercase aside).</p>
<p>If they provided some other methods, check their documentation.</p>
<h3 id="creating-a-usb-that-boots-under-uefi-conditions">Creating a USB that boots under UEFI conditions</h3>
<p>In order to create a bootable USB drive under UEFI&rsquo;s newer boot schema, that USB has to be formatted using GPT (Guid Partition Table), as the MBR (Master Boot Record) drives are considered legacy!</p>
<p>To do that, you can use Rufus to create the USB. Rufus is an open source program that you can download from its official site <a href="https://rufus.ie/">https://rufus.ie/</a>, and will offer you a simple, but powerful interface to create the bootable thumbdrive. Just make sure that you select GPT as Partition Scheme, and UEFI as Target System, leaving all other options by default (unless you wanted a persistent partition to use in a Live System):</p>
<p><img alt="Rufus" loading="lazy" src="/images/20200615-rufus.png"></p>
<h3 id="reboot-in-linux">Reboot in Linux</h3>
<ul>
<li>
<p>Reboot the computer and look for a message telling you to press a key to show the boot menu.</p>
</li>
<li>
<p>Press that key, quick!</p>
</li>
<li>
<p>No worries, it happens to everybody. Reboot and try again.</p>
</li>
<li>
<p>Search for your USB drive.</p>
</li>
<li>
<p>They are usually by the EFI the word &ldquo;USB&rdquo; and the brand of the device, plus some other model numbers and maybe the capacity.</p>
</li>
<li>
<p>Select it and press the Enter key.</p>
</li>
</ul>
<p>Select the option to <em>run</em> Linux, or to <em>try Linux</em> without installing.</p>
<p>If everything works, specially the graphics and the network, then you&rsquo;re good to go and install it.</p>
<h3 id="installing-with-secure-boot-things-that-can-happen">Installing with Secure Boot: things that can happen.</h3>
<p>In most of the cases, the installation process will be smooth and without any surprise. But, in some cases, either:</p>
<ul>
<li>The installation would remain stopped in a package for too long. If you expand the details of the installation process, you may see something like the below image.</li>
<li>You will prompted by the system that some third party software needs to be installed and you will to do some funky stuff for it to work, something similar to this:</li>
</ul>
<p><img alt="UbuntuPrompt" loading="lazy" src="/images/20200615-ubuntuprompt.png"></p>
<p>This is caused by Secure Boot, and nothing is wrong. What is happening is the following: the system found that it needs to install a package that will be loaded at boot time, but it is not signed. Secure Boot requires the software that runs at boot to be signed by a trusted key. The installation process can create a key for you, called &ldquo;Machine Owner Key&rdquo;, and sign the software with it, but in order to make the EFI trust the signature, it needs you to collaborate.</p>
<ul>
<li>Press the Enter key, or the tab key to focus OK and then Enter, or click OK if the prompt is run in a graphical environment.</li>
<li>In the next screen, you will be prompted to set a password: do it and jot it down in a paper, as you will prompted to write it in the first reboot.</li>
</ul>
<blockquote>
<p><strong>Here be dragons</strong>: if you have a non-english keyboard, <em>refrain yourself from using symbols that may be in a different key than the one in a US layout keyboard</em>, as they can cause problems when typing the password later.</p></blockquote>
<p>Once done, the installation should continue.</p>
<p>When you finish installing the system, it will reboot.</p>
<p>If you were prompted with such an ugly message, you will see a succession of screens like the following (taken from <a href="https://gist.github.com/reillysiemens/ac6bea1e6c7684d62f544bd79b2182a4">this Gist</a>, as they are the same in any case) in this first reboot:</p>
<p><img alt="1st screen" loading="lazy" src="/images/20200615-mokenroll1.png"></p>
<p>Select <strong>Enroll</strong> and press Enter.</p>
<p><img alt="2nd screen" loading="lazy" src="/images/20200615-mokenroll2.png"></p>
<p>Press <strong>Continue</strong>. Yes, it is a weird screen. If you press <code>View key 0</code> you&rsquo;ll see some information about the key you are enrolling, but it&rsquo;s quite technical and can be nonsense, specially if it was the installation program who created the MOK key.</p>
<p><img alt="3rd screen" loading="lazy" src="/images/20200615-mokenroll3.png"></p>
<p>Select <strong>Yes</strong>.</p>
<p><img alt="4th screen" loading="lazy" src="/images/20200615-mokenroll4.png"></p>
<p>Type the password you&rsquo;ve in your piece of paper and press Enter.</p>
<p><img alt="5th screen" loading="lazy" src="/images/20200615-mokenroll5.png"></p>
<p>Press Enter</p>
<p>When the system reboot, and provided that the installation program meets its quality goals, things should work.</p>
<h2 id="post-install-miscellanea">Post-Install Miscellanea</h2>
<table>
  <thead>
      <tr>
          <th>Case</th>
          <th>Solution</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>I am installing a binary package and I&rsquo;m prompted with the nefarious screen of the MOK!</td>
          <td>Repeat the process as told in the previous section. This is what will happen in many systems when you try to install third party binary packages. There are other systems, like Debian, that while supporting Secure Boot, they don&rsquo;t have an interactive process like that.</td>
      </tr>
      <tr>
          <td>I&rsquo;m trying to install a module that I know I need and it should work, but it won&rsquo;t load</td>
          <td>If you are getting a laconic <code>Permission Denied</code>, or <code>Operation not permitted</code> after trying to install a module in the Kernel, check <code>dmesg</code> after <code>modprobe module</code>, then look for something like <code>Lockdown: modprobe: Loading of unsigned module is restricted; see man kernel_lockdown.7</code>. If this is your case, you will have to create a MOK key, sign a module with it, and enroll the MOK key, <em>all manually</em>! Don&rsquo;t worry and go to the next section.</td>
      </tr>
      <tr>
          <td>I want to compile and install a module</td>
          <td>If this is your case, you will have to create a MOK key, sign a module with it, and enroll the MOK key, <em>all manually</em>! Don&rsquo;t worry and go to the next section.</td>
      </tr>
  </tbody>
</table>
<h2 id="manually-signing-binaries-eg-modules">Manually signing binaries (e.g.: modules)</h2>
<p>This is the case of a module compiled by hand, or when you install unsigned modules with Secure Boot installed, in more crude distributions like Debian.</p>
<p>The steps for Debian (credit to its official documentation and to my experience) are:</p>
<ul>
<li>Compile your software.</li>
<li><code>modprobe</code> will fail. Check that it is due to a Kernel Lockdown state imposed by the Secure Boot, to discard other errors. In <code>dmesg</code>, search for something with similar semantics to this:</li>
</ul>
<p><code>Lockdown: modprobe: Loading of unsigned module is restricted; see man kernel_lockdown.7</code></p>
<ul>
<li>If you have already enrolled a Machine Owner Key (MOK) yourself, and it is available for you, put it in your home directory and jump to step &ldquo;<strong>Open a terminal to sign the binary</strong>&rdquo;. Otherwise, continue here.</li>
<li>Install the packages <code>mokutil</code> and <code>openssl</code>.</li>
<li>Open a terminal and create a MOK (Machine Owner Key) with the following process (<code># commented</code>), documented <a href="https://wiki.debian.org/SecureBoot#Enroling_a_new_key">here</a>:</li>
</ul>
<pre tabindex="0"><code>    # Go to your home folder
    cd ~
    # Create a Machine Owner Key pair valid for 100 years. 
    # In the following, replace &#34;gabriel&#34; for your user name
    openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -days 36500 -subj &#34;/CN=gabriel/&#34; -nodes
</code></pre><ul>
<li>You will obtain two files, <code>MOK.der</code> and <code>MOK.priv</code> in your home folder. Enroll the keys in your EFI</li>
</ul>
<pre tabindex="0"><code>    # If you don&#39;t have sudo installed, run `su` and type the root password
    # before the following commands without sudo
    sudo mokutil --import MOK.der
    # This will prompt for a one time password to set up.
</code></pre><ul>
<li>Reboot the computer. You will be promted with the blue screens of section &ldquo;Installing with Secure Boot: things that can happen&rdquo;. In this case, if you select the options to <code>View Key 0</code>, you will be able to see your name and the name of your computer. In my example, I saw &ldquo;gabriel@rodas&rdquo;, and rodas is my computer named after <a href="https://en.wikipedia.org/wiki/Playa_de_Rodas">this beach</a> very close to my hometown.</li>
<li><strong>Open a terminal to sign the binary</strong>. Follow the process changing the <code>/path/to/file.ko</code> with the path to the file you need to sign.</li>
</ul>
<pre tabindex="0"><code>    # Assuming that you have kernel version X.Y.Z
    # Replace &#34;gabriel&#34; by your username.
    cd /lib/linux-kbuild-X-Y/
    sudo scripts/sign-file sha256 /home/gabriel/MOK.priv /home/gabriel/MOK.der /path/to/your/file.ko
</code></pre><ul>
<li>
<p>Try to load again the module</p>
<p>sudo modprobe /path/to/your/file.ko</p>
</li>
</ul>
<p>It should work now. This is the most common use case for this.</p>
<blockquote>
<p><strong>Here be dragons</strong>: hold your horses, one last thing before you go. Take these two files, <code>MOK.der</code> and <code>MOK.priv</code>, away from your user directory, hide them in a safe place. Personally, I keep them attached to an entry in my password manager, well encrypted. <strong>They are the door for someone to sign any malware so it can run at your computer&rsquo;s boot</strong>!</p></blockquote>
<h2 id="what-about-signing-a-custom-kernel">What about signing a custom Kernel?</h2>
<p>If you need to sign a Kernel, the <code>/path/to/your/file.ko</code> looks like <code>/boot/vmlinuz-[KERNEL-VERSION]</code>, and probably you will have to follow more steps. Although I haven&rsquo;t had the need for it, I found several forum and Stack Overflow questions that pointed to <a href="https://github.com/jakeday/linux-surface/blob/master/SIGNING.md">this document</a> as a valid process to do it.</p>
<h2 id="what-is-secure-boot">What is Secure Boot</h2>
<p>Secure Boot is a mechanism designed to protect the process of booting your computer, that is to say, making your boot secure. It is not a very creative name.</p>
<p>It was introduced at some point in the UEFI specifications, and it made a weird entrance in the scene because some poor communications skills and shady decisions from Microsoft. They told at some point that, for any PC machine to be Windows-Certified, they should pre-ship a cryptographic key (similar to the Machine Owner Key we&rsquo;ve used before in this post, but Microsoft&rsquo;s) to digitally verify the Windows bootable parts and the Kernel. They didn&rsquo;t specify at the point that they didn&rsquo;t care whether the Secure Boot could be disabled, or that many other keys should be able to be shipped or installed alonside Microsoft&rsquo;s! Thanks to that narrow statement, the community went crazy and, although they fixed the statement pretty much immediately, for many time Secure Boot was seen as a Microsoft attempt to close PC hardware to them. You can check this story <a href="https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface#Secure_boot_criticism">here</a>. It is true that the controversy continued for a while, specially related to ARM devices, but as always: technology isn&rsquo;t bad by itself, it is us who make good or bad use of it.</p>
<p>Indeed, Secure Boot is (to me) pretty awesome as it is a simple but powerful way to protect the boot sequence of your system against malware.</p>
<p>The &ldquo;Secure&rdquo; word of Secure Boot comes from Information Security, as it is based on asymmetric criptography. It works in such a way that, for the EFI to load any code at boot time, being it a Kernel, modules, or the GRUB itself, such code has to be cryptoraphically signed by a trusted key. Let&rsquo;s decypher such two sentences.</p>
<ul>
<li>
<p><strong>Asymmetric cryptography</strong> refers to a compendium of techniques that are based in a pair of keys, public key and secret key. They public key is meant to be available to everybody, while the secret key has to be kept secret to its owner.</p>
</li>
<li>
<p>That par of keys are often packed in a single software artefact called &ldquo;certificate&rdquo;, in such a way that the private part is protected by a passphrase. It can also be splitted in such a way that you can produce a certificate that will only contain the public key, to be able to share it. It provides two operations: encryption and signature.</p>
</li>
<li>
<p>Asymmetric Encryption works the following way: if I want to <strong>encrypt a message for you</strong>, so that only you are able to understand it, I will <strong>use your public key</strong> and a lot of standard maths. Once done, only your private key, plus a lot of standard maths, can decrypt it!</p>
</li>
<li>
<p>Asymmetric Signature works the opposite: if I want to prove you that <strong>it was me who wrote</strong> a message, I will <strong>sign it using my private key</strong> and a lot of standard maths. You will be able to check the signature using my public key and a lot of standard maths.</p>
</li>
<li>
<p>If someone changes a single character of that message, the signature won&rsquo;t be valid anymore.</p>
</li>
<li>
<p>The last point is great: a signature identifies the author of a message, and protects the communication against tampering.</p>
</li>
<li>
<p>We can cryptographically sign a message, or a binary file like a Kernel, or a module.</p>
</li>
<li>
<p>According to the above, when we sign some code and install it to be loaded at boot time, like a Kernel or a module, the EFI need to have available the public key to check the signatures. This defines the need of <em>enrolling public keys in the EFI</em>.</p>
</li>
<li>
<p>You can create a pair of keys, enroll the public key, and use them to sign software you create or compile, if you are the root user of a GNU/Linux system. When you create your own pair of keys, they are together called a <strong>Machine Owner Key</strong>, or MOK.</p>
</li>
<li>
<p>Enrolling a public key in the EFI is a process not only means to make available the public key to the EFI: it also makes the EFI trust that signature. Practically speaking, it will ultimately trust the software that is signed with a trusted key, and load and execute it with all the consequences.</p>
</li>
<li>
<p>Only a trusted software manudacturer, or an administrator of an operating system (root user in Linux) can enroll a key in the EFI and manually sign software.</p>
</li>
<li>
<p>Enrolling a key in the EFI is a process that requires such an administrator to collaborate and actively accept and prove his or her identity after a reboot. It cannot be automated by a malware process.</p>
</li>
</ul>
<p>A bit of recap. If you have the system bootstrap process checking signatures of the binary code that it loads, this means a lot of security.</p>
<p>Let&rsquo;s understand the two main <em>vectors of attack</em> it mitigates.</p>
<ol>
<li><strong>Only trusted signers</strong> (meaning software manufaturers, or you) <strong>can install code that runs automatically in the bootstrap of the system.</strong> That means, that if some random guy comes to your desk with a USB while you&rsquo;re away, he won&rsquo;t be able to infect your computer&rsquo;s bootstrap by putting some modules or writing code in the bootable partitions. He or she would have to enroll a key, too, and that requires (in Linux) to know the root password, which is meant to be secret and complex. They will have to be able not only to write code to the EFI, which may or may not be a challenge, but to hack the operating system they want to compromise.</li>
<li>If you accidentally allow a malware to run in your computer, that malware cannot infect the bootstrap chain even if it has the maximum privileges, as it will require active cooperation by an admin user to create and enroll its own MOK: check back the rest of the article at the point we set up a password, reboot, and type the password when enrolling the key. The only thing you have to do is to never leave your MOK private key in the computer to prevent the malware to sign itself with your own keys!</li>
</ol>
<p>I hope you didn&rsquo;t have to search many terms, and that this article was, at least, easy to follow. Feel free to send me some comments to comments (at) gvisoc (dot) com!</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
