<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="/index.xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>./techtipsy</title><link>https://ounapuu.ee/categories/tutorial/</link><description>Recent content on ./techtipsy, a blog written by Herman Õunapuu.</description><generator>Hugo -- gohugo.io</generator><language>en-GB</language><managingEditor>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</managingEditor><webMaster>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</webMaster><lastBuildDate>Wed, 06 May 2026 06:00:00 +0300</lastBuildDate><atom:link href="https://ounapuu.ee/categories/tutorial/index.xml" rel="self" type="application/rss+xml"/><item><title>How I self-host this blog at home with a dynamic IPv4 address, IPv6 prefix, and a dash of Wireguard</title><link>https://ounapuu.ee/posts/2026/05/06/self-host-at-home/</link><pubDate>Wed, 06 May 2026 06:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2026/05/06/self-host-at-home/</guid><description>I think I've finally figured it out. For now.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/posts/2026/05/06/self-host-at-home/media/cover_hu_a0e9c758122adadf.jpg" width="1200" height="630" alt="How I self-host this blog at home with a dynamic IPv4 address, IPv6 prefix, and a dash of Wireguard" /><p>Networking has long been my Achilles heel. I know the very basics, but the more complex areas of networking have been a
bit puzzling to me. By the time I figured out how IPv4 works, I found IPv6 and that my ISP supports it.</p>
<p>Back to square one.</p>
<p>That didn&rsquo;t stop me from learning some bits, and after 8+ years of self-hosting as a hobby, I&rsquo;ve settled on a setup that
works for me and overcomes common residential internet connection nuances, such as dynamic IPv4 addresses and changing
IPv6 prefixes. I&rsquo;m sharing these tips and tricks with the goal of helping out other hobbyists out there that happen to
share a similar stack.</p>
<h2 id="background">
  <a class="heading-anchor" href="#background">Background<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>My ISP is polite enough to provide a public IPv4 address, and allowing incoming traffic is a toggle in their online
self-service. Not perfect, but at least you can do it. However, they charge about 6 EUR a month for the static IP
address service, which I am not willing to pay out of principle.</p>
<p>They also support IPv6, which is great, and they provide you a whole <code>/56</code> slice of it to play with using IPv6 prefix
delegation. Unfortunately they have configured the lease time for the prefix to be incredibly short: 26 <strong>minutes</strong>!</p>
<p>A router reboot or short power outage usually results in the IPv4 address and IPv6 prefix changing, which is really
annoying as my services become unavailable for a short time.</p>
<h2 id="dynamic-dns">
  <a class="heading-anchor" href="#dynamic-dns">Dynamic DNS<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>A common way to overcome the dynamic IP address limitation is to sign up with a provider to set up a DNS record that
changes whenever your home IP address changes. My domain registrar does not have this as a feature, and I&rsquo;m not
interested in using a different provider, so I went in a different direction and built a home-grown script that does the
same thing.</p>
<p>Initially, this script relied on a public service that tells you what your IP address is, and based on that I could
check if things have changed and I need to update my DNS record. This approach has one glaring catastrophic failure mode
though: that provider could lie to you one day and now you&rsquo;ve pointed your DNS records at the attackers&rsquo; servers. :)</p>
<p>I ignored that failure mode for a while, but once I learned about the effectiveness of LLM-based tooling, I decided to
give it a go and to build a better solution that takes into account my setup and requirements, while at the same time
saving me from the frustration of troubleshooting and debugging this in a late evening. I&rsquo;m still very limited on
available free time, so optimizing for that is a priority for me.</p>
<p>My main networking gear runs OpenWRT, and it supports running shell scripts periodically in a crontab. The router has
two WAN interfaces, one for IPv4 and one for IPv6. It already knows what IP address and prefix have been assigned to it,
so I don&rsquo;t have to rely on an external service provider for finding this out.</p>
<p>Handling IPv4 addresses is simple: check the IPv4 address of the WAN interface. Query your existing DNS records, diff
it, and if it has changed, push an update in a separate API call. Super simple!</p>
<p>With IPv6, the approach is slightly different. Instead of the WAN interface, I have to get the IPv6 address of the
target machine, and make sure that it&rsquo;s routable over the public internet. When you&rsquo;ve checked your network settings in
an IPv6 network, you may have noticed a lot of different IP addresses there, with lots of letters thrown into the mix.</p>
<p>Here&rsquo;s an example from the machine that is serving you this blog (likely out of date though!):</p>
<pre tabindex="0"><code>    inet6 fdb3:6dad:6dce::f41/128 scope global dynamic noprefixroute 
    inet6 fdb3:6dad:6dce:0:2e0:4cff:fe0c:9ddb/64 scope global noprefixroute 
    inet6 2001:7d0:856c:4000::f41/128 scope global dynamic noprefixroute 
    inet6 2001:7d0:856c:4000:2e0:4cff:fe0c:9ddb/64 scope global dynamic noprefixroute 
    inet6 fe80::2e0:4cff:fe0c:9ddb/64 scope link noprefixroute 
</code></pre><p>The two relevant ones are the ones that start with <code>2001:</code>, others are link-local or accessible over the local network
only. The shorter one consists of the IPv6 prefix part, and then the unique bit at the end is a predictable suffix that
the host gets. The other one also works, but is as far as I understand randomly generated and more difficult to predict
when we get around to next sections.</p>
<p>I know that there is probably a better way to do this, but I wanted to keep things simple enough so that I can
troubleshoot them if needed. It may be possible to trigger this updater script on events that WAN and WAN6 interfaces
send, but I have not validated this theory.</p>
<p>There are many different ways to find the IPv6 address of a particular host, so the script I have just tries multiple
approaches to find the one that we&rsquo;re looking for.</p>
<p><a href="/posts/2026/05/06/self-host-at-home/media/ddns.sh">Here&rsquo;s the script</a> in case you&rsquo;re interested in setting up something similar. It reads credentials from
an .env file and is built around <a href="https://api.zone.eu/">the Zone API</a>. On OpenWRT, the only dependency that you need to
install is <code>curl</code>, which to my surprise was not part of the default packages list, probably to save on space.</p>
<p>One lesson I learned from a previous iteration of the script: if you trigger DNS record updates every minute, then Zone
will actually reach out to you via e-mail telling you to cut that shit out, politely. It was just one missing <code>if</code>
statement, and yet it caused some frustration to engineers far away. Sorry!</p>
<h2 id="predictable-ip-addresses">
  <a class="heading-anchor" href="#predictable-ip-addresses">Predictable IP addresses<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It&rsquo;s a good idea to set up static IP addresses for your hosts, both for IPv4 addresses and IPv6 prefix delegation via
DUID-s.</p>
<p>The OpenWRT GUI LuCI makes it quite simple, just set the addresses as static on the landing page for the hosts
that you are interested in forwarding traffic to, and you&rsquo;re done!</p>
<p>My recommendation here is to also set a predictable IPv6 suffix, otherwise all your IPv6 traffic rules may break once
again due to this nuance.</p>
<p>I like to make that host number the same for both IPv4 and IPv6, quick example:</p>
<ul>
<li><code>192.168.1.2</code></li>
<li><code>2001:7d0:854f:8e00::2</code></li>
</ul>
<p>Here&rsquo;s a configuration snippet example from <code>/etc/config/dhcp</code>, look for the <code>hostid</code> option:</p>
<pre tabindex="0"><code>config host
        option name &#39;mycoolserver&#39;
        option ip &#39;192.168.1.69&#39;
        list mac &#39;12:34:56:78:90:AB&#39;
        option duid &#39;yourduidgoeshere&#39;
        option hostid &#39;69&#39;
</code></pre><p>Apply with <code>service dnsmasq restart</code>.</p>
<p>In LuCI, as of OpenWRT 25.12, look for &ldquo;IPv6 token&rdquo;.</p>









<figure class="center">
  <a href="/posts/2026/05/06/self-host-at-home/media/ipv6token.png">
    <img src="/posts/2026/05/06/self-host-at-home/media/ipv6token_hu_556676a81dfcb972.webp"
     width="1000"
     height="103"
     loading="lazy"
     decoding="async"
     alt="Set an IPv6 token for a predictable IPv6 suffix.">

  </a>
  <figcaption class="center">Set an IPv6 token for a predictable IPv6 suffix.</figcaption>
</figure>

<p>Note that due to a bug, it doesn&rsquo;t seem to be possible to set a numeric IPv6 token via GUI, which is why you will need
to add it manually in CLI using the above approach.</p>
<h2 id="port-forwards-traffic-rules-potato-potahtoh">
  <a class="heading-anchor" href="#port-forwards-traffic-rules-potato-potahtoh">Port forwards, traffic rules, potato, potahtoh<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Whenever you want to make a local machine accessible on the internet for IPv4, the solution is simple: set up a port
forward to that particular machine, and you&rsquo;re done! It&rsquo;s a common enough flow for people who&rsquo;ve set up game servers and
the like, and well understood by more novice users.</p>
<p>With IPv6, port forwards don&rsquo;t help. You&rsquo;ll have to check one tab over at &ldquo;Traffic rules&rdquo; in OpenWRT GUI.</p>
<p>It&rsquo;s a common misconception that by using IPv6 you are exposing everything to the world as each device gets its own IPv6
address, but turns out that this is not the case in most common setups. By default, OpenWRT forwards only a few types of
traffic to IPv6 hosts, such as ICMP packets that make <code>ping</code> work between devices over IPv6 across the public internet.
If you are interested in allowing IPv6 clients to access services on your local server that has an IPv6 address, you
will have to explicitly allow it by adding a new traffic rule.</p>
<p>There&rsquo;s one issue with this approach that a lot of users seem to run into: if the IPv6 prefix changes, then all my
traffic rules that are pointing to a particular host are automatically broken!</p>
<p>Luckily there is a clever workaround implemented on OpenWRT that bypasses this issue. Assuming that you followed the
previous step and set yourself up with a predictable IPv6 suffix, when setting up a traffic rule, set the target device
up as <code>::69/-64</code>, just replace <code>69</code> with your actual suffix. The IPv6 prefix can now change, but the ports that you&rsquo;ve
made accessible on this specific host will remain working.</p>
<p>At this point, you should be all set with a reasonably well working setup where you&rsquo;ve handled the issues with dynamic
IPv4 and IPv6 prefix, and you can access your services over the public internet even when things happen.</p>
<h2 id="limitations">
  <a class="heading-anchor" href="#limitations">Limitations<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>One issue that this setup has is the fact that DNS change propagation takes time. Usually clients will pick up the new
records within 5 minutes, but in my professional career I&rsquo;ve seen some clients take up to 24 hours or longer to finally
start sending traffic to the new DNS record. Whenever your IP address changes, there will be a mini-outage. Not
catastrophic if you&rsquo;re just hosting hobby projects and personal services at home, but I wouldn&rsquo;t host anything
mission-critical in such a setup.</p>
<p>When your OpenWRT device is as underpowered as mine, then you may notice that the TLS encryption overhead when <code>curl</code>
-ing around can be significant. I have set my dynamic DNS script to run every 5 minutes, and it shows up on the CPU
usage graphs on my router.</p>









<figure class="center">
  <a href="/posts/2026/05/06/self-host-at-home/media/graph.png">
    <img src="/posts/2026/05/06/self-host-at-home/media/graph_hu_e39ff7b6e73083d4.webp"
     width="956"
     height="383"
     loading="lazy"
     decoding="async"
     alt="CPU usage graph on my router showing the scheduled dynamic DNS script doing work.">

  </a>
  <figcaption class="center">CPU usage graph on my router showing the scheduled dynamic DNS script doing work.</figcaption>
</figure>

<h2 id="wireguard-all-the-things">
  <a class="heading-anchor" href="#wireguard-all-the-things">Wireguard all the things!<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I know that Tailscale is a popular method of connecting up your devices and making your personal services privately
accessible over that, which significantly reduces your attack surface. Being behind a few updates or not being vigilant
enough is less of an issue compared to exposing your services over the public internet.</p>
<p>You don&rsquo;t necessarily need Tailscale for that though! If you just need a way to access your services over a private and
secure network, then setting up a dedicated mini PC or single-board computer is a very good starting point. Let it be
the server, allow traffic to move between the clients over the Wireguard interface, and you&rsquo;re all set!</p>
<p>Alternatively, if you have an OpenWRT router, then you can do it right there, but I found the GUI management setup to be
a bit clunky compared to deploying the plain configuration files to clients. When I <em>did</em> do that test, I discovered
quickly that my router and its single ARM CPU core with no cryptography extensions is too slow for managing my Wireguard
network, with speeds topping out at 20 Mbit/s. <strong>20.</strong> The LattePanda IOTA can easily saturate its gigabit link, as does
the ThinkPad T430, and even devices like the Orange Pi Zero can handle a theoretical maximum of about 240 Mbit/s over
Wireguard measured using <a href="https://github.com/cyyself/wg-bench">wg-bench</a>.</p>
<p>My current Wireguard host is <a href="/posts/2026/04/04/lattepanda/">the LattePanda V1, the most unstable computer in my fleet.</a>
With a USB adapter, it can push almost half a gigabit of traffic over Wireguard.</p>
<p>If you&rsquo;re like me, and you like hosting your services over Docker or Podman, then instead of listening on ports for all
interfaces on your containers (default behaviour when setting up port forwards), I recommend listening only on the
Wireguard interface. This makes the service only accessible over Wireguard, meaning that you only need to set up one
port forward and traffic rule to connect to the Wireguard network, and then you have access to all of your services. The
attack surface is significantly reduced, the whole Wireguard solution is stable and very small, and unless you leak your
private key, you are reasonably secure!</p>
<p>Here&rsquo;s a snippet from a compose file showcasing how to set this up for IPv4 and IPv6:</p>
<pre tabindex="0"><code>ports:
  - 10.69.69.12:2283:2283
  - &#34;[fded:abba:acca::12]:2283:2283&#34;
</code></pre><p>Want to make the service available over Wireguard <em>and</em> over the local network directly? Just add those to the list!
Note that if your local address changes and you don&rsquo;t update it in the compose file, your container will refuse to start
up as it cannot listen to the interface any longer, but you can mitigate that with the static IP addresses step.</p>
<p>When you are going with this route, it is unlikely but still possible that by the time the container starts up, the
Wireguard interface is not yet up. To resolve this, you can use <code>systemd</code> to set Wireguard up as a dependency that you
will have to wait for before the container starts up.</p>
<p>I manage my Wireguard connection with <code>wg-quick@interfacename</code> service. You can set up a <code>systemd</code> override for Docker,
or if you manage your Docker/Podman services via systemd, then you can set it up per-service using this pattern:</p>
<pre tabindex="0"><code># /etc/systemd/system/myimmichserver.service.d/override.conf
[Unit]
Requires=wg-quick@interfacename.service
After=wg-quick@interfacename.service
</code></pre><p>By the way, <code>systemd</code> overrides are also really useful for ensuring that your storage that your containers rely on is
properly mounted. If my service requires the path <code>/immich</code> to be available and mounted, add something like this:</p>
<pre tabindex="0"><code>BindsTo=immich.mount
After=immich.mount
</code></pre><p>If you unmount the mount point, it will also properly bring down the service. The service won&rsquo;t start if the mount point
is missing. I&rsquo;ve had the issue with containers seeing blank mount points more times than I&rsquo;d like to admit, and this has
eliminated this issue for me.</p>
<p><code>systemd</code> has received a lot of hate online, and I don&rsquo;t think it&rsquo;s fair. The ease with which you can set up
dependencies on your system, set up resource limits, make services more restricted to improve the security posture is
great and allows me to and avoid all sorts of failure modes. Production services that I&rsquo;m responsible for make use of
these <code>systemd</code> features, with great results.</p>
<p>For services that need to be public, such as Nextcloud and its public shareable links, this approach won&rsquo;t work,
obviously, but for things that only you and your family members use, this is a viable approach.</p>
<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This setup works well enough for me to confidently host my blog and self-hosted services off of it. I&rsquo;ve hit a lot of
paper cuts and frustrations along the way, but after following this guide, you don&rsquo;t have to do the same.</p>
<p>Yes, VLAN-s are intentionally missing from this guide. I&rsquo;ll get to them eventually, maybe by Q4 2037 given my lack of
free time.</p>
<p>And no, IPv6 isn&rsquo;t complicated, it&rsquo;s just different from what everyone is used to. If we started out with IPv6 right
from the get-go, <a href="https://www.ietf.org/archive/id/draft-thain-ipv8-00.html">we wouldn&rsquo;t be having dumb arguments online.</a></p>
]]></content:encoded></item><item><title>The IPv6 situation on Docker is good now!</title><link>https://ounapuu.ee/posts/2024/12/20/docker-ipv6/</link><pubDate>Fri, 20 Dec 2024 19:30:00 +0200</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2024/12/20/docker-ipv6/</guid><description>It's not often when a piece of software has genuinely improved, which is why this is worth celebrating!</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/posts/2024/12/20/docker-ipv6/media/cover_hu_2d1118bf85d813df.jpg" width="1200" height="630" alt="The IPv6 situation on Docker is good now!" /><p>Good news, everyone! Doing IPv6 networking stuff on Docker is actually good now!</p>
<p>I&rsquo;ve recently started reworking my home server setup to be more IPv6 compatible, and as part of that I learned that
during
the summer of 2024 <a href="https://docs.docker.com/engine/release-notes/27/#ipv6">Docker shipped an update</a> that eliminated a
lot of the configuration and tweaking previously necessary
to support IPv6.</p>
<p>There is no need to change the daemon configuration any longer, it just works on Docker Engine v27 and later.</p>
<h2 id="examples">
  <a class="heading-anchor" href="#examples">Examples<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>If your host has a working IPv6 setup and you want to listen to port 80 on both IPv4 and IPv6, then you don&rsquo;t
have to do anything special. However, the container will only have an IPv4 address internally.
You can verify it by listing all the Docker networks via <code>sudo docker network ls</code> and running
<code>sudo docker network inspect network-name-here</code> for the one associated with your container.</p>
<p>For services like <code>nginx</code> that log the source IP address, this is problematic, as every incoming IPv6 request will be
logged with the Docker network gateway IP address, such as <code>10.88.0.1</code>.</p>
<pre tabindex="0"><code>name: nginx
services:
  nginx:
    container_name: nginx
    ports:
      - 80:80
    image: docker.io/library/nginx
    restart: always
</code></pre><p>If you want the container to have an IPv4 <em>and</em> an IPv6 address within the Docker network, you can create a new network
and enable IPv6 in it.</p>
<pre tabindex="0"><code>name: nginx
services:
  nginx:
    container_name: nginx
    networks:
      - nginx-network
    ports:
      - 80:80
    image: docker.io/library/nginx
    restart: always
networks:
  nginx-network:
    enable_ipv6: true
</code></pre><p>There are situations where it&rsquo;s handy to have a static IP address for a container within the Docker network.
If you need help coming up with an unique local IPv6 address range, you
can <a href="https://unique-local-ipv6.com/">use this tool.</a></p>
<pre tabindex="0"><code>name: nginx
services:
  nginx:
    container_name: nginx
    networks:
      nginx-network
        ipv4_address: 10.69.42.5
        ipv6_address: fdec:cc68:5178::abba
    ports:
      - 80:80
    image: docker.io/library/nginx
    restart: always
networks:
  nginx-network:
    enable_ipv6: true
    ipam:
      driver: default
      config:
        - subnet: &#34;10.69.42.0/24&#34;
        - subnet: &#34;fdec:cc68:5178::/64&#34;
</code></pre><p>If you choose the <a href="https://docs.docker.com/engine/network/drivers/host/">host network driver,</a> your container will
operate within the same networking space as your container host. If the host handles both IPv4 and IPv6 networking, then
your container will happily operate with both. However, due to reduced network isolation, this has some security
implications that you must take into account.</p>
<pre tabindex="0"><code>name: nginx
services:
  nginx:
    container_name: nginx
    network_mode: host
    # ports are not relevant with host network mode
    image: docker.io/library/nginx
    restart: always
</code></pre><p>If you want your container to only accept connections on select interfaces, such as a Wireguard connection, then you will need
to specify the IP addresses in the <code>ports</code> section. Here&rsquo;s one example with both IPv4 and IPv6.</p>
<pre tabindex="0"><code>name: nginx
services:
  nginx:
    container_name: nginx
    networks:
      - nginx-network
    ports:
      - 10.69.42.5:80:80
      - &#34;[fdec:cc68:5178::beef]:80:80&#34;
    image: docker.io/library/nginx
    restart: always
networks:
  nginx-network:
    enable_ipv6: true
</code></pre><h2 id="what-about-podman">
  <a class="heading-anchor" href="#what-about-podman">What about Podman?<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I&rsquo;ve given up on Podman. Before doing things the IPv6 way, Podman was functional for the most part, requiring a few
tweaks to get things working.</p>
<p>I have not managed to get Podman to play fair with IPv6. No matter what I did, I could not get it to listen to certain
ports and access my services, the ports would always be filtered out.</p>
<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I&rsquo;m genuinely happy to see that the IPv6 support has gotten better with Docker, and I hope that this short introduction
helps those out there looking to do things the IPv6 way with containers.</p>
]]></content:encoded></item><item><title>How to build a fleet of networked offsite backups using Linux, WireGuard and rsync</title><link>https://ounapuu.ee/posts/2024/12/11/wireguard-backup-fleet/</link><pubDate>Wed, 11 Dec 2024 06:00:00 +0200</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2024/12/11/wireguard-backup-fleet/</guid><description>You have offsite backups of your most important data, right? Right???</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/posts/2024/12/11/wireguard-backup-fleet/media/cover_hu_79c3c1903608e4ea.jpg" width="1200" height="630" alt="How to build a fleet of networked offsite backups using Linux, WireGuard and rsync" /><p>Just like most people out there, I have some files that are irreplaceable, such as cat pictures.</p>
<p>At one point I had a few single-board computers sitting idle, namely
the <a href="http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero.html">Orange Pi Zero</a> and
the <a href="https://www.lattepanda.com/lattepanda-v1">LattePanda V1</a>, and a few
1TB SSD-s.</p>
<p>I hate idle hardware, so I did the most sensible thing and assembled a fleet of networked offsite backups for
backing up the most important data.</p>
<p>My setup is based on various flavors of Linux, but the ideas will likely translate well onto other operating systems
and solutions.</p>
<h2 id="networking">
  <a class="heading-anchor" href="#networking">Networking<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The most important part is the networking. The offsite backup endpoints connect together to my home server over a
WireGuard network. The home server is, well, <em>the server</em>, and backup endpoints are clients.</p>
<p>I like <a href="https://github.com/linuxserver/docker-WireGuard">this WireGuard Docker image</a> a lot because it generates
the server and client configurations automatically, but you can use plain WireGuard or a completely different networking
solution to connect all the devices together. Some use Tailscale to make the setup process easier, but I like to keep
things as self-hosted as possible.</p>
<p>I&rsquo;m not a networking expert, but here&rsquo;s how I&rsquo;ve set up my network. For this example, the WireGuard network operates in
the <code>10.13.69.0/24</code> range.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>To only allow traffic between the devices and avoid tunneling everything through the home server, set the <code>AllowedIPs</code>
setting to <code>AllowedIPs = 10.13.69.0/24,10.13.69.1</code>. We want to be able to access the backup endpoints, and nothing more.</p>
<p>All the devices have a static IP address in that network, such as <code>10.13.69.1</code> for the home server, <code>10.13.69.2</code> for a
backup endpoint and so on.</p>
<p>The <code>PersistentKeepalive = 25</code> option is present in the client configurations so that I don&rsquo;t lose the ability to access
the backup endpoints. With it, all the backup endpoints call back to the home server from time to time. The
aforementioned Docker image automatically adds it to the generated configuration using
the <code>PERSISTENTKEEPALIVE_PEERS=all</code> option.
This setting is <em><strong>crucial.</strong></em> Without it, I sometimes ran into problems trying to connect from my home server to the
backup endpoint, and that&rsquo;s something you can&rsquo;t easily alleviate without having physical access to the backup endpoints,
which are offsite.</p>
<p>Remove the DNS configuration from generated WireGuard client configurations, as you don&rsquo;t need it for this purpose.</p>
<p>Optionally, edit the <code>/etc/hosts</code> file for the home server and backup endpoints so that you can access your backup
endpoints using simple hostnames, like <code>orangepizero</code>. Example row can look like this: <code>10.13.69.6 orangepizero</code>.</p>
<p>if your WireGuard server operates in a network with a dynamic external IP address, as is common with many home internet
connections, I recommend getting yourself a domain name that you can update whenever your IP address changes and using
that in your WireGuard client configurations. Without this, an IP address change will result in your backup endpoints
being inaccessible.</p>
<p>You&rsquo;ll also likely need to set up port forwarding and/or traffic rules for your backup endpoints to be able to connect
back to your WireGuard server.</p>
<p>Once you have the WireGuard connection set up and SSH running on the backup endpoints, you should be able to drop the
backup endpoints into any network that you have permission for. Ask your friends and family, and sweeten the deal by
offering free technical support or help in some other area in return. The cost of running a single-board computer 24/7
is minuscule with the typical power consumption being 1-3W, so that won&rsquo;t be much of a concern.</p>
<h2 id="making-backups">
  <a class="heading-anchor" href="#making-backups">Making backups<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>For making the actual backups themselves, you have all sorts of options.</p>
<p>I rely on <code>rsync</code> to copy the data over. It&rsquo;s simple and it works, that&rsquo;s all I expect from it.
Example command: <code>rsync -aAXvz /folder/to/back/up/ backupuser@backupendpoint:/backup/ --delete</code>.
The files will be compressed during transit with the <code>-z</code> option, and with <code>--delete</code> you&rsquo;ll ensure that the target
folder has all the files from the source, and nothing else.</p>
<p>The backup storage is specified in <code>/etc/fstab</code> with the <code>nofail</code> option present. This ensures that in case the disk
dies, the backup endpoint will still boot properly, allowing me to access the machine to troubleshoot the issue and/or
force a desperate reboot to try to fix things. A good alternative approach is to mount/unmount the remote disk manually
as part
of the backup script.</p>
<p>The backup storage uses the <code>btrfs</code> filesystem, and I use <code>btrbk</code> to take snapshots of the contents. If I accidentally
delete all the files on the backup endpoint, then I can still recover from that situation because the data is still
present in snapshots. 30 days is a good retention period: enough time to save the data in case of an accidental
deletion, but short
enough to avoid the backup disk getting full.</p>
<p>If you don&rsquo;t want to use filesystem-level snapshots, then tools like <code>restic</code> are a good alternative. It can also
operate
over SSH and you can configure snapshot retention policies in your backup script. Just make sure to not lose the
encryption password, and
verify the backups once in a while.</p>
<h2 id="deployment">
  <a class="heading-anchor" href="#deployment">Deployment<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I manage my backup endpoints using some cobbled-together Ansible roles. I&rsquo;ve perfected it to the point where the only
manual
steps are flashing the OS and setting up the storage, the rest is handled via Ansible.</p>
<p>I&rsquo;d like to share my work here, but it will make Jeff Geerling cry. Maybe one day I&rsquo;ll take the time to improve
things&hellip;</p>
<h2 id="maintenance">
  <a class="heading-anchor" href="#maintenance">Maintenance<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>All the backup endpoints update and reboot themselves regularly. It&rsquo;s just the sensible thing to do.</p>
<p>Every 6-12 months I also do major OS version updates. It&rsquo;s risky because of the whole offsite aspect of the solution,
but so far I haven&rsquo;t been burned yet.</p>
<h2 id="monitoring">
  <a class="heading-anchor" href="#monitoring">Monitoring<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Monitoring is an area where I have some room for improvement. So far, I&rsquo;ve set up Prometheus node-exporter to all of
the backup endpoints, and my home server keeps track of how the backup endpoints are doing.</p>
<p>This allows me to check once in a while if any of the backup endpoints has fallen off the network, or if the backup disk
is getting full.</p>
<h2 id="issues-ive-faced">
  <a class="heading-anchor" href="#issues-ive-faced">Issues I&rsquo;ve faced<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I&rsquo;ve had this system running for a few years now, and it&rsquo;s mostly stable! There have been some issues I&rsquo;ve faced as
well,
though. Some are very specific to certain hardware, but I think there&rsquo;s value in mentioning them.</p>
<p><a href="/posts/2023/06/10/how-i-blew-up-my-backup-server/">I once blew up a backup server because of an Ansible configuration issue.</a>
That meant that I had to physically go pick up the server to re-image it.</p>
<p>The Orange Pi Zero was running quite hot, resulting in stability issues, so I put together a really janky cooling
solution.</p>









<figure class="center">
  <a href="/posts/2024/12/11/wireguard-backup-fleet/media/orangepizero.jpg">
    <img src="/posts/2024/12/11/wireguard-backup-fleet/media/orangepizero_hu_689cb39c9001c4e2.webp"
     width="750"
     height="1000"
     loading="lazy"
     decoding="async"
     alt="Cooling. It works.">

  </a>
  <figcaption class="center">Cooling. It works.</figcaption>
</figure>

<p>Hell, I did the same for the LattePanda as well.</p>









<figure class="center">
  <a href="/posts/2024/12/11/wireguard-backup-fleet/media/lattepanduh.jpg">
    <img src="/posts/2024/12/11/wireguard-backup-fleet/media/lattepanduh_hu_b5634f62aec46ed4.webp"
     width="1000"
     height="750"
     loading="lazy"
     decoding="async"
     alt="First version of the cooling upgrade on the LattePanda.">

  </a>
  <figcaption class="center">First version of the cooling upgrade on the LattePanda.</figcaption>
</figure>

<p>It might look horrific but the extra cooling has fixed all the stability problems on both boards.</p>
<p>The lack of a real-time clock on the LattePanda has required me to make its backup script a bit special. I can&rsquo;t rely on
a systemd timer that automatically reboots the machine once in a while, so instead that part is present in the backup
script. The issue is that the LattePanda boots up with the time being set in the past, and once it gets the actual time
from the
network, it will run all sorts of tasks because enough time has passed!
This included the reboot timer as well.</p>
<p>At one point, the power supply on the LattePanda just died, and it was very visible on my graphs. That required a
replacement.</p>









<figure class="center">
  <a href="/posts/2024/12/11/wireguard-backup-fleet/media/lattepanda-psu-failure.png">
    <img src="/posts/2024/12/11/wireguard-backup-fleet/media/lattepanda-psu-failure_hu_83ab55cb07768116.webp"
     width="1000"
     height="725"
     loading="lazy"
     decoding="async"
     alt="Signs that you might have a failing power supply.">

  </a>
  <figcaption class="center">Signs that you might have a failing power supply.</figcaption>
</figure>

<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>That&rsquo;s how I back up the most important data. I hope that this has given you inspiration to take your own backup
approach to the next level!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>yes, I do plan to move this setup to IPv6 eventually.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>The Fedora Linux starter pack: everything you need for a smooth experience</title><link>https://ounapuu.ee/posts/2024/10/14/fedora-starter-pack/</link><pubDate>Mon, 14 Oct 2024 06:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2024/10/14/fedora-starter-pack/</guid><description>Fedora Linux is a great Linux distribution, but it has a few quirks that can impact your experience. Here's how to fix them.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/posts/2024/10/14/fedora-starter-pack/media/cover_hu_a4c43ff367b3786d.jpg" width="1200" height="630" alt="The Fedora Linux starter pack: everything you need for a smooth experience" /><p>I like <a href="https://fedoraproject.org/">Fedora Linux.</a></p>
<p>It&rsquo;s the Linux distro that stopped my habit of <a href="https://en.wiktionary.org/wiki/distro-hopping">distro-hopping.</a> Big
deal? Ooh, big deal!</p>
<p>It&rsquo;s stable in day-to-day use, ships with up-to-date software, and the software selection is adequate out of the box.</p>
<p>It also ships with a fresh Linux kernel version<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, resulting in a good experience even on modern hardware.</p>
<p>I&rsquo;ve been happily using it for about 4 years at this point, both on personal and work computers.</p>
<p>However, every time I recommend it to my friends, family and colleagues, I have to mention a few things that a new
Fedora Linux user might want to do first so that the experience is as smooth as possible.</p>
<p>If it weren&rsquo;t for those aspects, Fedora would be pretty much perfect.</p>
<h2 id="set-up-rpm-fusion">
  <a class="heading-anchor" href="#set-up-rpm-fusion">Set up RPM Fusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>There are some packages that are not available on Fedora by default, likely as a result of copyright laws, lawyers and
Red Hat (IBM) not having the appetite to fight it out in the courts.</p>
<p>This is why <a href="https://rpmfusion.org/">RPM Fusion</a> exists:</p>
<blockquote>
<p>RPM Fusion provides software that the Fedora Project or Red Hat doesn&rsquo;t want to ship.</p>
</blockquote>
<p>The installation instructions are <a href="https://rpmfusion.org/Configuration">here</a>, and I personally prefer this one-liner
setup:</p>
<pre tabindex="0"><code>sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
</code></pre><p>This step is a prerequisite to the next one.</p>
<h2 id="enable-hardware-accelerated-video-playback">
  <a class="heading-anchor" href="#enable-hardware-accelerated-video-playback">Enable hardware accelerated video playback<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This is the part where I blame lawyers.</p>
<p>To have a good chance at smoothly playing back videos in a browser or using VLC, you have to do a few extra steps,
because someone fucked up.</p>
<p><a href="https://rpmfusion.org/Howto/Multimedia">Check this guide for up-to-date information.</a></p>
<p>Switch to the full version of <code>ffmpeg</code>:</p>
<ul>
<li><code>sudo dnf swap ffmpeg-free ffmpeg --allowerasing</code></li>
</ul>
<p>AMD GPU users:</p>
<ul>
<li><code>sudo dnf swap mesa-va-drivers mesa-va-drivers-freeworld</code></li>
<li><code>sudo dnf swap mesa-vdpau-drivers mesa-vdpau-drivers-freeworld</code></li>
</ul>
<p>Intel GPU users (Broadwell and newer, 2014+):</p>
<ul>
<li><code>sudo dnf install intel-media-driver</code></li>
</ul>
<p>Old Intel GPU users (Ivy Bridge and older, &lt;=2013):</p>
<ul>
<li><code>sudo dnf install libva-intel-driver</code></li>
</ul>
<p>NVIDIA GPU users: good luck.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>You can verify the enabled profiles using <code>vainfo</code>.</p>
<p>Here&rsquo;s the output on my machine before completing the steps (AMD GPU).</p>
<p>Note the lack of H.264 and HEVC profiles.</p>
<pre tabindex="0"><code>me@mymachine:~$ vainfo
Trying display: wayland
libva info: VA-API version 1.21.0
libva info: Trying to open /usr/lib64/dri-nonfree/radeonsi_drv_video.so
libva info: Trying to open /usr/lib64/dri-freeworld/radeonsi_drv_video.so
libva info: Trying to open /usr/lib64/dri/radeonsi_drv_video.so
libva info: Found init function __vaDriverInit_1_21
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.21 (libva 2.21.0)
vainfo: Driver version: Mesa Gallium driver 24.1.7 for AMD Radeon 780M (radeonsi, gfx1103_r1, LLVM 18.1.6, DRM 3.57, 6.10.8-200.fc40.x86_64)
vainfo: Supported profile and entrypoints
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileVP9Profile0            :	VAEntrypointVLD
      VAProfileVP9Profile2            :	VAEntrypointVLD
      VAProfileAV1Profile0            :	VAEntrypointVLD
      VAProfileAV1Profile0            :	VAEntrypointEncSlice
      VAProfileNone                   :	VAEntrypointVideoProc
</code></pre><p>Here&rsquo;s what it looks like after the tweaks are applied.</p>
<pre tabindex="0"><code>me@mymachine:~$ vainfo
Trying display: wayland
libva info: VA-API version 1.21.0
libva info: Trying to open /usr/lib64/dri-nonfree/radeonsi_drv_video.so
libva info: Trying to open /usr/lib64/dri-freeworld/radeonsi_drv_video.so
libva info: Trying to open /usr/lib64/dri/radeonsi_drv_video.so
libva info: Found init function __vaDriverInit_1_21
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.21 (libva 2.21.0)
vainfo: Driver version: Mesa Gallium driver 24.1.7 for AMD Radeon 780M (radeonsi, gfx1103_r1, LLVM 18.1.6, DRM 3.57, 6.10.8-200.fc40.x86_64)
vainfo: Supported profile and entrypoints
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSlice
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSlice
      VAProfileHEVCMain               :	VAEntrypointVLD
      VAProfileHEVCMain               :	VAEntrypointEncSlice
      VAProfileHEVCMain10             :	VAEntrypointVLD
      VAProfileHEVCMain10             :	VAEntrypointEncSlice
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileVP9Profile0            :	VAEntrypointVLD
      VAProfileVP9Profile2            :	VAEntrypointVLD
      VAProfileAV1Profile0            :	VAEntrypointVLD
      VAProfileAV1Profile0            :	VAEntrypointEncSlice
      VAProfileNone                   :	VAEntrypointVideoProc
</code></pre><h2 id="enable-flathub">
  <a class="heading-anchor" href="#enable-flathub">Enable Flathub<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This step is only necessary if you did not enable <a href="https://github.com/minosimo">third-party repositories</a> during the
inital setup of your Fedora Linux installation.</p>
<p>Setting up Flathub is just one command:</p>
<pre tabindex="0"><code>flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
</code></pre><p>Check <a href="https://flathub.org/setup/Fedora">the Flathub setup instructions for Fedora</a> for up-to-date info.</p>
<h2 id="-specific-to-estonia-id-card-support">
  <a class="heading-anchor" href="#-specific-to-estonia-id-card-support">🇪🇪 Specific to Estonia: ID card support<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Estonia has <a href="https://www.id.ee/en/">an ID Card system</a> (<em>Eesti ID kaart</em>), and the desktop application is
also officially supported on Linux. <em><strong>Ubuntu</strong></em> Linux.</p>
<p>To use the ID card in Fedora, you&rsquo;ll need to install the necessary packages:</p>
<p><code>sudo dnf install -y open-eid</code></p>
<p>Firefox users will need to make sure that the Web eID extension is installed. If
it wasn&rsquo;t installed with the above
command, <a href="https://addons.mozilla.org/en-US/firefox/addon/web-eid-webextension/">you can also get it here.</a></p>
<p>The desktop application used for opening and digitally signing documents, DigiDoc4, has a bad habit of breaking
sometimes due to changes. Luckily there exists an unofficial version of DigiDoc4 as a Flatpak
and <a href="https://flathub.org/apps/ee.ria.qdigidoc4">it&rsquo;s available on Flathub.</a></p>
<p>It&rsquo;s mentioned
in <a href="https://github.com/open-eid/linux-installer/wiki/Linux-Packages">the official open-eid/linux-installer repo</a> as
well, which lends some credibility (plus I know
the person that built it).</p>
<p>As of 2024-10-14, ID card works on Firefox and the DigiDoc4 client from the Fedora official repository does not crash
and burn.</p>
<h3 id="gnome-fix-the-alttab-behaviour">
  <a class="heading-anchor" href="#gnome-fix-the-alttab-behaviour">GNOME: fix the &ldquo;Alt+Tab&rdquo; behaviour<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>GNOME is a great desktop environment, but it, too, has its quirks.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>If you&rsquo;re used to &ldquo;Alt+Tab&rdquo; keyboard shortcut simply switching windows, then you&rsquo;ll have to tweak it in settings.</p>
<ul>
<li>Open &ldquo;Settings&rdquo;</li>
<li>Navigate to &ldquo;Keyboard&rdquo;</li>
<li>Click on &ldquo;View and Customize shortcuts&rdquo;</li>
<li>Use the search bar to:
<ul>
<li>disable &ldquo;Switch applications&rdquo; shortcut</li>
<li>set the &ldquo;Switch windows&rdquo; shortcut to &ldquo;Alt+Tab&rdquo;</li>
</ul>
</li>
</ul>
<p>Here&rsquo;s what it looks like on GNOME 46.</p>









<figure class="center">
  <a href="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-1.png">
    <img src="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-1_hu_6f7375171fc4c57d.webp"
     width="979"
     height="642"
     loading="lazy"
     decoding="async"
     alt="Navigate to &#39;Keyboard&#39; and click on &#39;View and Customize shortcuts&#39;">

  </a>
  <figcaption class="center">Navigate to &#39;Keyboard&#39; and click on &#39;View and Customize shortcuts&#39;</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-2.png">
    <img src="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-2_hu_77f97c17c799a6fb.webp"
     width="979"
     height="642"
     loading="lazy"
     decoding="async"
     alt="Select &#39;Navigation&#39;">

  </a>
  <figcaption class="center">Select &#39;Navigation&#39;</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-3.png">
    <img src="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-3_hu_6e48f954c4c4565b.webp"
     width="979"
     height="642"
     loading="lazy"
     decoding="async"
     alt="Disable &#34;Switch applications&#34; shortcut.">

  </a>
  <figcaption class="center">Disable &#34;Switch applications&#34; shortcut.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-4.png">
    <img src="/posts/2024/10/14/fedora-starter-pack/media/shortcuts-4_hu_bb17f5e558874f8a.webp"
     width="979"
     height="642"
     loading="lazy"
     decoding="async"
     alt="Set the &#34;Switch windows&#34; shortcut to &#34;Alt&#43;Tab&#34;.">

  </a>
  <figcaption class="center">Set the &#34;Switch windows&#34; shortcut to &#34;Alt&#43;Tab&#34;.</figcaption>
</figure>

<h3 id="gnome-minimize-maximize-buttons-on-windows">
  <a class="heading-anchor" href="#gnome-minimize-maximize-buttons-on-windows">GNOME: minimize, maximize buttons on windows<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>By default, you&rsquo;ll only see the &ldquo;Close&rdquo; button on windows, but it is possible to also show minimize and maximize
buttons.</p>
<p>Install GNOME tweaks with <code>sudo dnf install -y gnome-tweaks</code>.</p>
<p>Open it, navigate to <code>Windows</code>, and toggle <code>Maximize</code> and <code>Minimize</code> settings.</p>









<figure class="center">
  <a href="/posts/2024/10/14/fedora-starter-pack/media/min-max.png">
    <img src="/posts/2024/10/14/fedora-starter-pack/media/min-max_hu_bdeba6f163b4dd79.webp"
     width="984"
     height="647"
     loading="lazy"
     decoding="async"
     alt="GNOME tweaks settings as of GNOME 40.">

  </a>
  <figcaption class="center">GNOME tweaks settings as of GNOME 40.</figcaption>
</figure>

<h3 id="gnome-app-status-indicators">
  <a class="heading-anchor" href="#gnome-app-status-indicators">GNOME: app status indicators<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>Some apps, such as Solaar, like to run in the background and show you a status indicator on your taskbar.
This functionality is not present on GNOME by default, but you can easily fix it with
the <a href="https://extensions.gnome.org/extension/615/appindicator-support/">AppIndicator and KStatusNotifierItem Support</a>
extension.</p>









<figure class="center">
  <a href="/posts/2024/10/14/fedora-starter-pack/media/appindicator.png">
    <img src="/posts/2024/10/14/fedora-starter-pack/media/appindicator_hu_104aeeaf3327e956.webp"
     width="525"
     height="262"
     loading="lazy"
     decoding="async"
     alt="I used to install a handful of extensions in the past to &#34;fix&#34; GNOME, but in 2024 this is the only one I actually need.">

  </a>
  <figcaption class="center">I used to install a handful of extensions in the past to &#34;fix&#34; GNOME, but in 2024 this is the only one I actually need.</figcaption>
</figure>

<h3 id="gnome-corner-tiling">
  <a class="heading-anchor" href="#gnome-corner-tiling">GNOME: corner tiling<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>As of GNOME 46, you cannot do corner tiling out of the box. The best you can do is split windows horizontally, which
is fine for single ultra-wide monitor setups. There are situations where corner tiling comes in really handy.</p>
<p>The best solution I have found so far seems to
be the <a href="https://extensions.gnome.org/extension/3733/tiling-assistant/">Tiling Assistant</a>
extension. It&rsquo;s configurable and will probably suit your workflow well.</p>
<p>At the time of writing, it does have a few small but annoying enough bugs that are a show-stopper for me, but compared
to other solutions this one at least works.</p>
<h3 id="optional-disable-selinux">
  <a class="heading-anchor" href="#optional-disable-selinux">Optional: disable SELinux<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>There are two types of people: those that swear by <a href="https://github.com/SELinuxProject">SELinux</a>, and those that swear
<em>due to</em> SELinux.</p>
<p>If you&rsquo;re running into weird issues and you don&rsquo;t know why, then see if SELinux is to blame.</p>
<p>I run into issues with SELinux every time I try to move files around with <code>rsync</code>, resulting in a simple
<code>rsync -aAXv source/ destination/</code> command becoming <code>rsync -aAXv --filter='-x security.selinux' source/ destination/</code>.
It&rsquo;s frustrating.</p>
<p>To fix this, I simply disable SELinux. Open up <code>/etc/selinux/config</code>, find the line <code>SELINUX=enforcing</code> and change it to
<code>SELINUX=disabled</code>.</p>
<p>You&rsquo;ll need to restart your machine for it to take effect.</p>
<h3 id="dont-use-zfs">
  <a class="heading-anchor" href="#dont-use-zfs">Don&rsquo;t use ZFS<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p><a href="https://github.com/openzfs/zfs">ZFS</a> is a great filesystem, but not on distros that ship new kernel versions.</p>
<p>This is due to OpenZFS needing to be built against the Linux kernel, and new kernel releases often break compatibility.
Those breakages may lead to your ZFS pools not being imported at boot as a result.</p>
<p>You <em>can</em> use ZFS if you use LTS kernels built by someone else, or if you simply don&rsquo;t update your system, but I don&rsquo;t
recommend either approach.</p>
<p>Use a different distribution, such as Debian, if you really need to use ZFS daily.</p>
<p>If you don&rsquo;t care for ZFS but like data integrity checks, snapshots and don&rsquo;t use a lot of disks in an array, then
<code>btrfs</code> <a href="/posts/2023/10/09/zimaboard/#fedora-server-and-btrfs">is totally fine.</a></p>
<h3 id="dont-use-nvidia-gpu-s">
  <a class="heading-anchor" href="#dont-use-nvidia-gpu-s">Don&rsquo;t use NVIDIA GPU-s<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>I&rsquo;ve never had a good experience with the open source driver <code>nouveau</code>, and the proprietary drivers are a headache and
break things.</p>
<p><a href="https://developer.nvidia.com/blog/nvidia-transitions-fully-towards-open-source-gpu-kernel-modules/">This might be about to change,</a>
but I&rsquo;ll believe it when I see it.</p>
<h3 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>I hope that this has made your Fedora Linux experience just a little bit better.</p>
<p>Here&rsquo;s to hoping that IBM does not fuck up Fedora
Linux. <a href="https://www.redhat.com/en/blog/message-red-hat-associates-today">My expectations are low.</a></p>
<p>If you have any other tips to share then please contact me! You can find the contact details below.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>one thing that I appreciate with Fedora is that the kernel versions are ever-so-slightly lagging behind the likes
of Arch Linux, meaning that you&rsquo;ll be less likely to hit any kernel bugs, and yet you don&rsquo;t have to worry about being
too far behind (like on Ubuntu or Debian).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>no, seriously, I wish you all the luck in the world. I have never managed to have a good experience with NVIDIA on
Linux. I&rsquo;ve completely given up.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>use whatever desktop environment floats your boat, I don&rsquo;t judge!&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>How to copy media off of an iPhone the hard way (using Linux)</title><link>https://ounapuu.ee/posts/2024/09/02/iphone-media-recovery/</link><pubDate>Mon, 02 Sep 2024 06:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2024/09/02/iphone-media-recovery/</guid><description>If your iPhone doesn't show any photos when connected to a PC, then this guide may help you out.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/posts/2024/09/02/iphone-media-recovery/media/cover_hu_e9b0badd6a9c5a39.jpg" width="1200" height="630" alt="How to copy media off of an iPhone the hard way (using Linux)" /><p>I helped a family member upgrade to a newer iPhone and make some room so that the internal storage does not run out.</p>
<p>They had <a href="https://nextcloud.com/">Nextcloud</a> installed on the current phone, but due to limitations of the Nextcloud iOS
app, the backups only take place if the app itself is open, meaning that we had hundreds of photos and videos that were
not yet backed up.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>The network was slow and I was in a time crunch, so I opted to copy the media off of the phone by connecting the iPhone
to my laptop over
a Lightning cable. After entering the PIN on the phone again and approving the connection, I could see the iPhone
in my file manager, but opening it would show nothing at all. This was very unusual as other iPhones I used in the past
just worked on my laptop.</p>









<figure class="center">
  <a href="/posts/2024/09/02/iphone-media-recovery/media/happypath.png">
    <img src="/posts/2024/09/02/iphone-media-recovery/media/happypath_hu_c02c82f42067017e.webp"
     width="482"
     height="378"
     loading="lazy"
     decoding="async"
     alt="This is what you&#39;d expect to see when connecting an iPhone to a PC.">

  </a>
  <figcaption class="center">This is what you&#39;d expect to see when connecting an iPhone to a PC.</figcaption>
</figure>

<p>Rebooting the phone and connecting it again did nothing. Different known good Lightning cables did not improve things,
either.
Even a separate Windows 10 machine could not see any images, so it wasn&rsquo;t a Linux thing.</p>
<p>Various Apple-related posts online were devoid of useful advice.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>I was not ready to give up just yet and I finally stumbled
upon <a href="https://askubuntu.com/a/1159559">this Ask Ubuntu answer</a>.
This had potential, so I gave it a go, and I&rsquo;m happy to report that it worked on my Fedora Linux machine!</p>
<p>These are the steps that I took. The commands need to be run in a terminal window.</p>
<p>Tested with Fedora Linux 40.</p>
<ul>
<li>install the necessary packages
<ul>
<li>on Fedora, run <code>sudo dnf install -y ifuse libimobiledevice libimobiledevice-utils</code></li>
</ul>
</li>
<li>connect your iPhone to your PC
<ul>
<li>if your phone is not yet paired, then run <code>idevicepair pair</code></li>
<li>if it&rsquo;s already paired, verify the connection by running <code>idevicepair validate</code></li>
</ul>
</li>
<li>mount your phone to an empty folder of your choice
<ul>
<li>if an empty folder does not exist, run <code>mkdir ~/my-iphone</code> (use any folder name that you want)</li>
<li>to mount the phone, run <code>ifuse ~/my-iphone</code></li>
</ul>
</li>
<li>you can now browse your media via your file manager or terminal by navigating to <code>~/my-iphone</code>
<ul>
<li>photos and videos taken by the camera will be in the <code>DCIM</code> folder</li>
<li>other folders, such as <code>Photos</code> and <code>Downloads</code> may also interest you</li>
<li>to make a full copy of your phone to a folder named <code>iphone-backup</code>, run <code>cp -r ~/my-iphone ~/iphone-backup</code></li>
<li>alternative way to create a full backup: <code>rsync -aAXv ~/my-iphone ~/iphone-backup</code></li>
</ul>
</li>
<li>once you&rsquo;re done, unmount the iPhone by running <code>umount ~/my-iphone</code></li>
<li>it is now safe to disconnect your iPhone from the PC</li>
</ul>









<figure class="center">
  <a href="/posts/2024/09/02/iphone-media-recovery/media/iphone-contents.png">
    <img src="/posts/2024/09/02/iphone-media-recovery/media/iphone-contents_hu_ab4faea4df55ae20.webp"
     width="556"
     height="515"
     loading="lazy"
     decoding="async"
     alt="The directory listing of an iPhone.">

  </a>
  <figcaption class="center">The directory listing of an iPhone.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2024/09/02/iphone-media-recovery/media/iphone-photos.png">
    <img src="/posts/2024/09/02/iphone-media-recovery/media/iphone-photos_hu_f0e63d72cd9690cb.webp"
     width="556"
     height="515"
     loading="lazy"
     decoding="async"
     alt="Photos are located under DCIM folder, nested into a bunch of subfolders.">

  </a>
  <figcaption class="center">Photos are located under DCIM folder, nested into a bunch of subfolders.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2024/09/02/iphone-media-recovery/media/iphone-transfer.png">
    <img src="/posts/2024/09/02/iphone-media-recovery/media/iphone-transfer_hu_a53310547121c017.webp"
     width="593"
     height="252"
     loading="lazy"
     decoding="async"
     alt="Ah yes, USB 2.0 speeds.">

  </a>
  <figcaption class="center">Ah yes, USB 2.0 speeds.</figcaption>
</figure>

<p>If you have copied everything over and want to make more space on your phone using this method, then you need to delete
files under
the <code>DCIM</code> folder <em><strong>and</strong></em> the cached thumbnails under the <code>PhotoData</code> folder. iOS seems to generate thumbnails for
the photos you take and even if you delete all the actual photos off of the device, then the photo thumbnails will still
show up in the Photos app and elsewhere. This confused the hell out of me after I deleted the backed up photos off the phone the first time.</p>









<figure class="center">
  <a href="/posts/2024/09/02/iphone-media-recovery/media/iphone-thumbnails.png">
    <img src="/posts/2024/09/02/iphone-media-recovery/media/iphone-thumbnails_hu_2ff5b8bcd23711f9.webp"
     width="800"
     height="235"
     loading="lazy"
     decoding="async"
     alt="Thumbnails are in a separate folder.">

  </a>
  <figcaption class="center">Thumbnails are in a separate folder.</figcaption>
</figure>

<p>Alternatively, you can just delete files from the Photos app on the phone itself to avoid this nuance.</p>
<p>Linux has its flaws, but at least it provides you with the power and tools needed to get you out of tricky situations.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I can&rsquo;t wait for <a href="https://immich.app/">Immich</a> to get a stable release&hellip;&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Apple and Microsoft related forums are <em>the worst</em> for getting an actual solution to your problem, which is in stark
contrast to FOSS/Linux related discussions.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>How to save an old printer from the e-waste pile with a Raspberry Pi</title><link>https://ounapuu.ee/posts/2024/06/12/save-old-printer/</link><pubDate>Wed, 12 Jun 2024 06:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2024/06/12/save-old-printer/</guid><description>Turning a 15-year-old Canon PIXMA MP250 printer into a network printer was much easier than I initially thought.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/posts/2024/06/12/save-old-printer/media/cover_hu_8b18de1695374b7c.jpg" width="1200" height="630" alt="How to save an old printer from the e-waste pile with a Raspberry Pi" /><p>A family member has a Canon PIXMA MP250 printer, originally released in 2009.
It has been a very reliable piece of hardware, especially for a printer.</p>
<p>Then came Windows 10. The printer would not work out of the box with it and
the official drivers got stuck during installation. Fiddling with the printer
in device manager, trying to install drivers via Windows Update and stars
aligning
got the printer to work again.</p>
<p>Then came Windows 11. Nothing I did could get it working now, and the printer
is not even officially supported by Canon on this version of Windows.</p>
<p>This printer works out of the box on any mainstream Linux distribution, and
the family member had been using the printer with Ubuntu for years,
but <a href="https://www.id.ee/en/article/install-id-software/">a certain piece
of important software in Estonia</a>
was not working properly a lot of the time, which triggered a switch to Windows.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>Quick searches online suggested that I could turn this printer into a network
printer, as long as I had some patience and a spare computer.</p>
<p>The idea is simple: take a spare computer, hook it up to the printer, install
CUPS on it, configure it and you&rsquo;re good to go!</p>
<p>I initially tested this setup with a Zimaboard running Fedora Server, but the
final solution used an old Raspberry Pi B+ running the latest version of
Raspberry Pi OS.</p>
<h2 id="how-to-set-it-up">
  <a class="heading-anchor" href="#how-to-set-it-up">How to set it up<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The steps will be similar with other pieces of hardware and Linux distributions,
you may just need to adjust a few commands and package names.</p>
<p>The steps are roughly based on these two guides:</p>
<ul>
<li><a href="https://m-hussainul-islam.medium.com/setting-up-network-printer-with-raspberry-pi-and-cups-d5a18e91b1f3">Setting up Network Printer with Raspberry Pi and CUPS</a></li>
<li><a href="https://pimylifeup.com/raspberry-pi-print-server/">Raspberry Pi Print Server: Setup a Network Printer</a></li>
</ul>
<p>If you&rsquo;re following along with a Raspberry Pi, set up your OS first. A minimal
installation with no graphical interface will be just fine.</p>
<p>Next, install <a href="https://www.cups.org/">CUPS</a> and optionally the right printer
drivers for your printer. The Canon PIXMA MP250 requires the
package <code>printer-driver-gutenprint</code>.</p>
<pre tabindex="0"><code>sudo apt install -y cups printer-driver-gutenprint
</code></pre><p>Make sure that CUPS is running.</p>
<pre tabindex="0"><code>sudo systemctl enable --now cups.service
</code></pre><p>Next, allow your user to manage printing. In this example, the username is <code>pi</code>.</p>
<pre tabindex="0"><code>sudo usermod -a -G lpadmin pi
</code></pre><p>Next, make sure that CUPS allows connections from other machines in your
network, and then restart it.</p>
<pre tabindex="0"><code>sudo cupsctl --remote-any
sudo systemctl restart cups
</code></pre><p>Find out the IP address of the Pi and navigate to it in your browser.
It will look something like <code>https://192.168.0.49:631</code>. The browser will likely
warn you about a self-signed certificate. It&rsquo;s safe to proceed.</p>
<p>If you haven&rsquo;t already connected your printer to the Raspberry Pi via USB, then
do so now.</p>
<p>Use the graphical interface to add a new printer under the <code>Administration</code>
section.
You&rsquo;ll need to enter the username and password for your user here. It&rsquo;s the same
user we used earlier, so in this example it&rsquo;s <code>pi</code>.</p>
<p>If you can&rsquo;t find your printer model listed in the <code>Add printer</code> view, then you
are probably missing the proper driver package, or your printer simply isn&rsquo;t
supported.</p>









<figure class="center">
  <a href="/posts/2024/06/12/save-old-printer/media/add-printer.png">
    <img src="/posts/2024/06/12/save-old-printer/media/add-printer_hu_6f3d551a1ca09828.webp"
     width="800"
     height="780"
     loading="lazy"
     decoding="async"
     alt="You should be able to find your printer in this view.">

  </a>
  <figcaption class="center">You should be able to find your printer in this view.</figcaption>
</figure>

<p>After adding your printer, you can use the CUPS web interface to print a test
page.</p>
<p>If that worked, then you should now be able to use any other device on the
network
to print!</p>
<p>On Linux and Windows, open the settings section that handles printing, and add a
new printer.
This networked printer should appear automagically, no additional configuration
required.</p>
<p>I also did testing using a Fairphone 5 running Android 13, and an iPhone X
running iOS 16. In both
cases the printing just worked.</p>









<figure class="center">
  <a href="/posts/2024/06/12/save-old-printer/media/test-page-windows.jpg">
    <img src="/posts/2024/06/12/save-old-printer/media/test-page-windows_hu_1a44a0e7cfd60776.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Test page printed using Windows 11.">

  </a>
  <figcaption class="center">Test page printed using Windows 11.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2024/06/12/save-old-printer/media/test-page-fedora.jpg">
    <img src="/posts/2024/06/12/save-old-printer/media/test-page-fedora_hu_686fc992f2a4cbdf.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Test page printed using Fedora. Yes, most of the colors in the colored ink
cassette have run out.">

  </a>
  <figcaption class="center">Test page printed using Fedora. Yes, most of the colors in the colored ink
cassette have run out.</figcaption>
</figure>

<p>I&rsquo;ve used the scanning functionality of this particular printer on Linux and it
has worked, however I forgot to test this out using this setup. I&rsquo;ll try to
test that out once I get the chance to try the printer out again.</p>
<h2 id="hardware-tech-tips">
  <a class="heading-anchor" href="#hardware-tech-tips">Hardware tech tips<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I first ran this setup with a Zimaboard to test the idea out. It worked very
well,
but as a simple print server it is a bit overkill.</p>
<p>I then replaced it with a Raspberry Pi B+, and while the printing works, I
discovered that a single ARM CPU core is apparently a limiting factor during
printing. A simple test page print pegged the CPU at 100%, and that&rsquo;s with the
700-&gt;1000 MHz overclock applied.</p>









<figure class="center">
  <a href="/posts/2024/06/12/save-old-printer/media/cups-high-cpu.png">
    <img src="/posts/2024/06/12/save-old-printer/media/cups-high-cpu_hu_dd8b775751f19ff5.webp"
     width="800"
     height="435"
     loading="lazy"
     decoding="async"
     alt="Raspberry Pi B&#43; struggling during printing.">

  </a>
  <figcaption class="center">Raspberry Pi B&#43; struggling during printing.</figcaption>
</figure>

<p>If you don&rsquo;t mind a slower printing speed, then any Raspberry Pi will be
absolutely OK.
More performant versions of Raspberry Pi will likely fare even better.</p>
<p>If you already have a small home server running, then you may want to hook the
printer up to that and set up the printer there. It&rsquo;s already running 24/7, so
it would be a perfect match.</p>
<p>One useful aspect of this setup is that you can queue up print jobs even when
the printer itself is powered off. Once you turn it on, the print jobs will
start, assuming that you have enough paper and ink.</p>
<p>Free open source software prolongs the useful life of hardware once again.
<a href="https://www.canalys.com/insights/end-of-windows-10-support-could-turn-240-million-pcs-into-e-waste">See y&rsquo;all in October 2025!</a></p>
<h2 id="2024-06-15-update">
  <a class="heading-anchor" href="#2024-06-15-update">2024-06-15 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This post got featured on:</p>
<ul>
<li><a href="https://www.xda-developers.com/raspberry-pi-unsupported-printer-on-windows/">XDA Developers</a></li>
<li><a href="https://www.hackster.io/news/herman-ounapuu-brings-an-abandoned-printer-back-from-the-brink-with-a-raspberry-pi-90701ccb1ab9">hackster.io</a></li>
<li><a href="https://hackaday.com/2024/06/13/raspberry-pi-saves-printer-from-junk-pile/">Hackaday</a></li>
<li><a href="https://news.ycombinator.com/item?id=40657753">Hacker News</a></li>
</ul>
<p><a href="https://ubuntu.social/@till/112616367405119050">And even the leader of OpenPrinting, Till Kamppeter, chimed in!</a>
They also held a talk about <a href="https://fosdem.org/2024/schedule/event/fosdem-2024-1930-openprinting-we-make-printing-just-work-/">OpenPrinting at FOSDEM 2024.</a></p>
<p>Regarding scanning, seems like there&rsquo;s a separate project for that called <a href="http://www.sane-project.org/">SANE - Scanner Access Now Easy.</a></p>
<p><a href="https://openprinting.github.io/">Find out more about OpenPrinting here.</a></p>
<h2 id="2024-11-14-update">
  <a class="heading-anchor" href="#2024-11-14-update">2024-11-14 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>A reader shared with me the <a href="https://github.com/kenyapcomau/p910nd">p910nd</a> project that can be used for a similar
purpose. I have not yet tried this myself.</p>
<p>There&rsquo;s even
an <a href="https://openwrt.org/docs/guide-user/services/print_server/p910ndprinterserver">OpenWRT page that describes its use on a router!</a></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>that might be about to change as there is an <a href="https://flathub.org/apps/ee.ria.qdigidoc4">unofficial Flatpak version</a> out there.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>What changing the CPU on a laptop looks like</title><link>https://ounapuu.ee/posts/2022/12/09/changing-cpu-in-a-laptop/</link><pubDate>Fri, 09 Dec 2022 07:00:00 +0200</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2022/12/09/changing-cpu-in-a-laptop/</guid><description>Quick demonstration of a CPU replacement in a ThinkPad T430.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="What changing the CPU on a laptop looks like" /><p>This post illustrates something that is not common on modern laptops:
changing the CPU.</p>









<figure class="center">
  <a href="/posts/2022/12/09/changing-cpu-in-a-laptop/media/0-cover.jpg">
    <img src="/posts/2022/12/09/changing-cpu-in-a-laptop/media/0-cover_hu_4c83819246e9e445.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The CPU we&#39;re replacing in the T430: a 45W Intel i7-3820QM.">

  </a>
  <figcaption class="center">The CPU we&#39;re replacing in the T430: a 45W Intel i7-3820QM.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/12/09/changing-cpu-in-a-laptop/media/1-unscrew.jpg">
    <img src="/posts/2022/12/09/changing-cpu-in-a-laptop/media/1-unscrew_hu_9919a14cced4cfe2.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Loosen the CPU by turning the screw with a flathead screwdriver.">

  </a>
  <figcaption class="center">Loosen the CPU by turning the screw with a flathead screwdriver.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/12/09/changing-cpu-in-a-laptop/media/2-socket.jpg">
    <img src="/posts/2022/12/09/changing-cpu-in-a-laptop/media/2-socket_hu_b741f6f45086469.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="A CPU socket in a laptop.">

  </a>
  <figcaption class="center">A CPU socket in a laptop.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/12/09/changing-cpu-in-a-laptop/media/3-replacement.jpg">
    <img src="/posts/2022/12/09/changing-cpu-in-a-laptop/media/3-replacement_hu_4b76c681c5159ef6.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Make sure the golden triangle aligns with the marking on the socket, and pop that new CPU in.">

  </a>
  <figcaption class="center">Make sure the golden triangle aligns with the marking on the socket, and pop that new CPU in.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/12/09/changing-cpu-in-a-laptop/media/4-cleaned-up.jpg">
    <img src="/posts/2022/12/09/changing-cpu-in-a-laptop/media/4-cleaned-up_hu_bd97f26bd4d33882.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="A bit of 98% alcohol goes a long way.">

  </a>
  <figcaption class="center">A bit of 98% alcohol goes a long way.</figcaption>
</figure>

<h2 id="background">
  <a class="heading-anchor" href="#background">Background<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>One of the modifications that you can do to a ThinkPad T430 laptop is changing
the CPU to a more powerful quad core model. That&rsquo;s exactly what I did back in 2017,
but due to the poor availability of compatible CPU-s in my region I went for
one with a 45W TDP, which is a bit much for a laptop designed for CPU-s with a
35W TDP.</p>
<p><a href="/posts/2022/09/26/minimum-viable-fan-control-script/">You could work around this issue with software</a>,
and that&rsquo;s what I also did for a long time. Since I now own two T430-s and the
availability of 35W parts is better now, I decided to go for one to see how
well these two options compare (result: it doesn&rsquo;t overheat as often, but it
managed to do it once anyway).</p>
<p>Unlike my T430, most modern laptops come with a soldered CPU.
<a href="https://www.tech-critter.com/review-level51-forge-15r/">There do exist laptops that come with a socketed CPU</a>,
but those are not that common and are designed for very specific use cases.</p>
<p>Soldering the CPU right to the board has its benefits, such as the machine
being thinner, and CPU-s don&rsquo;t really die all that often. However, what we have
lost out on is the option to upgrade older machines with more powerful
components, extending the useful lifetime of the device.</p>
<p>Yes, you <em>can</em> replace soldered CPU-s, but that requires a skillset and
equipment that few people have.</p>
]]></content:encoded></item><item><title>Recovering a password-protected ThinkPad T60</title><link>https://ounapuu.ee/posts/2022/10/13/recovering-password-locked-thinkpad-t60/</link><pubDate>Thu, 13 Oct 2022 08:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2022/10/13/recovering-password-locked-thinkpad-t60/</guid><description>An illustrated overview about the process of clearing the supervisor password from a ThinkPad T60, based on guides that some smart and persistent people have written.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="Recovering a password-protected ThinkPad T60" /><p>A couple of years ago, I worked on a ThinkPad T60. That ThinkPad had been in use
by a family member before that, and I started its cleanup by disassembling the
whole machine and making sure that it was pristine. However, once I put it all
back together, I saw that it was password protected. I wasn&rsquo;t even able to access
the BIOS. After repeatedly asking for hints for the password and trying some
simple cases myself, I never cracked it.</p>
<p>Not too long ago I got curious and looked for a way to overcome this issue.
That&rsquo;s when I stumbled upon <a href="https://superuser.com/questions/393922/how-to-remove-the-supervisor-bios-password-for-an-ibm-thinkpad">this SuperUser post about resetting the supervisor password on a ThinkPad.</a></p>
<p>Once my to-do list was down to a reasonable size, I decided to finally give this
a go, since it didn&rsquo;t seem that difficult. Here&rsquo;s an illustrated guide on how
I approached this task.</p>
<p>Sources that are relevant to this topic:</p>
<ul>
<li>
<p><a href="https://superuser.com/questions/393922/how-to-remove-the-supervisor-bios-password-for-an-ibm-thinkpad">How to remove the Supervisor BIOS password for an IBM ThinkPad</a></p>
</li>
<li>
<p><a href="http://www.ja.axxs.net/t60_t60p.htm">www.ja.axxs.net</a></p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=FW-RLkzjAS8">&ldquo;How to unlock BIOS Supervisor Password from Lenovo Thinkpad Laptop (no damage to laptop)&rdquo; by Arpan Dubey</a></p>
</li>
</ul>









<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/0-cover.jpg" aria-label="View full-size image">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/0-cover_hu_e7878d9bc5fd3e19.webp"
     width="1280"
     height="753"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<h2 id="setup">
  <a class="heading-anchor" href="#setup">Setup<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>What you&rsquo;ll need to pull this off:</p>
<ul>
<li>your ThinkPad T60 laptop that has a supervisor password enabled</li>
<li>a screwdriver</li>
<li>anything that conducts electricity and can be used to short two pins</li>
<li>a steady hand</li>
<li>a magnifier, if your eyesight isn&rsquo;t that great</li>
</ul>









<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/1-the-big-short.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/1-the-big-short_hu_ab68aee36d70d2b3.webp"
     width="922"
     height="800"
     loading="lazy"
     decoding="async"
     alt="For shorting pins, I came up with this contraption.">

  </a>
  <figcaption class="center">For shorting pins, I came up with this contraption.</figcaption>
</figure>

<p>To begin the process, you need to remove the palm rest of the ThinkPad. Follow
the service manual if needed. Removing the keyboard screws is optional, but
it might help you access the correct pins better.</p>









<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/2-disassembly.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/2-disassembly_hu_48b0223a797b6e0c.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="T60, slightly disassembled.">

  </a>
  <figcaption class="center">T60, slightly disassembled.</figcaption>
</figure>

<h2 id="the-process">
  <a class="heading-anchor" href="#the-process">The process<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The steps for performing the supervisor password clearing:</p>
<ul>
<li>turn on the laptop</li>
<li>when you see the ThinkPad logo, short two specific pins</li>
<li>keep shorting those pins!</li>
<li>press F1 to go to the BIOS</li>
<li>navigate to the section in BIOS where you can set the Supervisor Password</li>
<li>enter the supervisor password setting prompt and enter a blank password in
the first field</li>
<li>stop shorting the pins, and then enter an empty password to the second field</li>
<li>save settings and restart</li>
<li>after rebooting, you should be able to boot without having to enter a password</li>
</ul>
<p>What follows is an illustrated guide of the process.</p>









<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/3-pins.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/3-pins_hu_74ffbfde9c6e201d.webp"
     width="1103"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The pins you need to short are located on the left side of the laptop, under the palmrest.">

  </a>
  <figcaption class="center">The pins you need to short are located on the left side of the laptop, under the palmrest.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/4-startup.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/4-startup_hu_5a1a5f4a00212719.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Once you see this, short those pins!">

  </a>
  <figcaption class="center">Once you see this, short those pins!</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/5-short.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/5-short_hu_b2486b50ca7b7282.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Just apply pressure to those pads and make sure the contact is solid.">

  </a>
  <figcaption class="center">Just apply pressure to those pads and make sure the contact is solid.</figcaption>
</figure>

<p>This is the step where I messed up initially. The contact between the pins was
not good and I got prompted with the supervisor password prompt. Power the machine
off and try again if you face the same issue.</p>
<p>Once the pins are shorted, you should be able to access the BIOS with a little
bit of F1 key spamming.</p>









<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/6-bios.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/6-bios_hu_c8c5216d8283d52d.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="While the pins are still shorted, you should be able to get access to the BIOS.">

  </a>
  <figcaption class="center">While the pins are still shorted, you should be able to get access to the BIOS.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/7-password.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/7-password_hu_627c5b3973c8cc7c.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Leave the first field blank, stop shorting the pins, and leave the other field blank as well.">

  </a>
  <figcaption class="center">Leave the first field blank, stop shorting the pins, and leave the other field blank as well.</figcaption>
</figure>

<p>After saving the settings and rebooting, you should be greeted with a successful
boot.</p>









<figure class="center">
  <a href="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/8-its-booting.jpg">
    <img src="/posts/2022/10/13/recovering-password-locked-thinkpad-t60/media/8-its-booting_hu_33261b36e6e8f758.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="It&#39;s booting! Not into Linux, since the SSD is removed, but still, it works!">

  </a>
  <figcaption class="center">It&#39;s booting! Not into Linux, since the SSD is removed, but still, it works!</figcaption>
</figure>

<p>Once you&rsquo;ve confirmed that everything&rsquo;s OK, assemble the machine again and enjoy
the laptop that you just saved from becoming e-waste.</p>
<h2 id="caveats">
  <a class="heading-anchor" href="#caveats">Caveats<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This guide might not be terribly relevant in 2022. I still remember starting
my software development career in 2016 with a ThinkPad T60 and it was painful
even back then. These laptops are classics, but they are really starting to show
their age. I&rsquo;ve even encountered issues like the WiFi chip causing lots of
trouble, with the connection being very spotty and borderline unusable.</p>
<p>But hey, at least it&rsquo;s not completely unusable any more!</p>
]]></content:encoded></item><item><title>The minimum viable fan control script</title><link>https://ounapuu.ee/posts/2022/09/26/minimum-viable-fan-control-script/</link><pubDate>Mon, 26 Sep 2022 08:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2022/09/26/minimum-viable-fan-control-script/</guid><description>Some assembly required. No, not _that_ one.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="The minimum viable fan control script" /><p>I&rsquo;ve always been a fan of tinkering with cooling setups on my computers.
I&rsquo;ve even went as far as writing <a href="https://github.com/Hermanio/linux-cpu-manager">crappy</a>
<a href="https://github.com/Hermanio/linux-gpu-manager">solutions</a> to make up for
deficiencies on the hardware level. After years of dumb experiments I&rsquo;ve seen
how little you can get away with in cooling and how to run your machines as
quietly as possible without giving up too much performance.</p>
<p>I also appreciate simplicity, which is why I&rsquo;m currently running the simplest
damn solution you can imagine to control how my ThinkPad T430 and ASRock
DeskMini X300 run: a shell script.</p>
<p>It also comes with some added benefits:</p>
<ul>
<li>self-documenting</li>
<li>highly customizable</li>
<li>low resource usage</li>
</ul>
<p>These scripts are not &ldquo;battle-hardened&rdquo; and using them incorrectly may or
may not result in hardware failure. Use at your own risk. The only guarantee
I can give is that <em>it works on my machine™</em>.</p>
<p>If you&rsquo;re someone who doesn&rsquo;t like tinkering with their computers and wants
their machines to &ldquo;just work&rdquo;, then this article likely isn&rsquo;t for you.</p>









<figure class="center">
  <a href="/posts/2022/09/26/minimum-viable-fan-control-script/media/image.png" aria-label="View full-size image">
    <img src="/posts/2022/09/26/minimum-viable-fan-control-script/media/image_hu_cf274236fe7bd4f.webp"
     width="473"
     height="209"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<h2 id="thinkpad-t430">
  <a class="heading-anchor" href="#thinkpad-t430">ThinkPad T430<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>With the ThinkPad T430, the script does two things:</p>
<ul>
<li>control the fan speed</li>
<li>preemptively throttle the CPU and GPU</li>
</ul>
<p>This type of behaviour is optimized for mostly quiet operation. The fan is
running at its lowest speed when under a small load, and the CPU/GPU throttling
has an added benefit of reducing the overall power usage, too. The difference
between non-turbo and turbo speeds on the Intel i7-3820QM can be as much as
13-15 watts.</p>
<p><a href="https://wiki.archlinux.org/title/fan_speed_control#ThinkPad_laptops">To enable fan control on ThinkPads</a>,
you need to have a file at <code>/usr/lib/modprobe.d/thinkpad_acpi.conf</code> with the
following contents:</p>
<pre tabindex="0"><code>options thinkpad_acpi fan_control=1
</code></pre><p>Reboot, and you can now have full control over the fan speed in your ThinkPad!</p>
<p>The script itself looks like this:</p>
<pre tabindex="0"><code>#!/bin/bash

set -e

while true; do

  temp=$(cat /sys/class/thermal/thermal_zone1/temp)

  if ((temp &gt; 90000)); then
    echo level 7 &gt;/proc/acpi/ibm/fan
  elif ((temp &gt; 75000)); then
    echo level 5 &gt;/proc/acpi/ibm/fan
  elif ((temp &gt; 60000)); then
    echo level 3 &gt;/proc/acpi/ibm/fan
  elif ((temp &gt; 30000)); then
    echo level 1 &gt;/proc/acpi/ibm/fan
  else
    echo level 0 &gt;/proc/acpi/ibm/fan
  fi

  if ((temp &gt; 97000)); then
    echo 350 &gt;/sys/class/drm/card*/gt_max_freq_mhz
    echo 350 &gt;/sys/class/drm/card*/gt_boost_freq_mhz
  elif ((temp &gt; 90000)); then
    echo 650 &gt;/sys/class/drm/card*/gt_max_freq_mhz
    echo 650 &gt;/sys/class/drm/card*/gt_boost_freq_mhz
  else
    echo 1250 &gt;/sys/class/drm/card*/gt_max_freq_mhz
    echo 1250 &gt;/sys/class/drm/card*/gt_boost_freq_mhz
  fi

  if ((temp &gt; 70000)); then
    echo 1 &gt;/sys/devices/system/cpu/intel_pstate/no_turbo
  else
    echo 0 &gt;/sys/devices/system/cpu/intel_pstate/no_turbo
  fi

  sleep 0.5
done
</code></pre><p>What we&rsquo;re doing is reading the temperature of the CPU package and then setting
the fan speed and throttling based on that. Note that the temperatures are
represented without any decimal places. A reading of 78000 means that the chip
is running at 78 °C.</p>
<p>On my ThinkPad T430, the fan speed levels can be roughly described as such:</p>
<ul>
<li>level 1: lowest speed, barely audible</li>
<li>level 3: audible, but tolerable</li>
<li>level 5 and above: it&rsquo;s probably loud enough to bother you</li>
</ul>
<p>The second section controls the integrated GPU. What I&rsquo;ve found in my testing
is that a weak integrated GPU can still chug up to 20 watts, which is a
considerable amount, especially on a laptop. The <code>card*</code> wildcard is there
because the integrated GPU may change between <code>card0</code> and <code>card1</code>, and I&rsquo;m too
lazy to make the script any smarter.</p>
<p>The values written there correspond to the maximum GPU clock speed. <code>1250</code> happens
to be the max clock speed (in MHz) and at that speed the GPU is using a lot of
power. <code>650</code> is the speed at which the integrated GPU is running most
efficiently. <code>350</code> is the lowest speed, and you will notice it due to the
performance being extra crappy.</p>
<p>With the CPU, I chose to just turn the turbo boost on or off. With turbo boost
off, the CPU will top out at 2.7 GHz and around 22 watts of power usage. With
turbo boost, the CPU can run anywhere between 3.4-3.7 GHz, depending on the number
of cores under load. You&rsquo;ll likely notice much higher CPU temperatures and power
usage climbing to around 35 watts. Fast at short and bursty workloads, and yet
efficient and relatively cool at sustained loads.</p>
<p>And at the very end, you have a simple <code>sleep</code> statement. I&rsquo;ve set it to half a
second, but feel free to set it as you see fit. Higher intervals might not be
that good of an idea because the script may not be able to respond quickly enough
to changing thermals, just keep that in mind.</p>
<h2 id="asrock-deskmini-x300">
  <a class="heading-anchor" href="#asrock-deskmini-x300">ASRock DeskMini X300<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Although I&rsquo;ve opted for a more experimental setup with my home server and the
ASRock DeskMini X300 is no longer running as one, I think it&rsquo;s still worthwhile
to share how I configured the fan control logic on this machine.</p>
<p>With the ASRock DeskMini X300, my goal was simple: let it run as quietly as
reasonably possible without losing too much performance.</p>
<p>This machine was running 24/7 as a server and has a powerful 8-core AMD Ryzen 7
5700G CPU in it. One thing this script is heavily relying on is the fact that Ryzen
CPU-s have well-engineered boosting logic in them, meaning that they&rsquo;re already
designed to run at the highest speed possible and only limit their speed if they
hit power or thermal limits.</p>
<p>One thing you may need to do first is installing <code>lm-sensors</code> and running
<code>sudo sensors-detect</code>. By default the CPU fan speed controls were not properly
exposed, but after running <code>sensors-detect</code> and saying yes at every prompt,
they were picked up.</p>
<p>The script looks like this:</p>
<pre tabindex="0"><code>#!/bin/bash

set -e

# /sys/devices/platform/nct6775.656/hwmon/hwmon3

echo 1 &gt;/sys/devices/platform/nct6775.656/hwmon/hwmon3/pwm2_enable

while true; do

  temp=$(cat /sys/class/hwmon/hwmon4/temp1_input)

  if ((temp &gt; 94000)); then
    echo 170 &gt;/sys/devices/platform/nct6775.656/hwmon/hwmon3/pwm2
  elif ((temp &gt; 90000)); then
    echo 140 &gt;/sys/devices/platform/nct6775.656/hwmon/hwmon3/pwm2
  elif ((temp &gt; 70000)); then
    echo 120 &gt;/sys/devices/platform/nct6775.656/hwmon/hwmon3/pwm2
  elif ((temp &gt; 40000)); then
    echo 30 &gt;/sys/devices/platform/nct6775.656/hwmon/hwmon3/pwm2
  else
    echo 0 &gt;/sys/devices/platform/nct6775.656/hwmon/hwmon3/pwm2
  fi

  sleep 5
done
</code></pre><p>The <code>hwmon</code> values and which fan you&rsquo;re controlling is likely different on your
own PC. Take a look at the paths found in the script and poke around while also
physically looking at your PC. Try enabling PWM control by writing to <code>pwm*_enable</code>
handles and then setting the fan speed. As a result of your poking, you should
see the CPU fan change its speed. If it doesn&rsquo;t, try another value.</p>
<p>The values you can write are in the range 0-255, where the higher value corresponds
to a higher speed.</p>
<p>I&rsquo;ve limited the TDP of my CPU to 35 watts using a setting found in UEFI
settings. This results in the CPU running cool and quiet even under a full load.</p>
<h2 id="systemd-service">
  <a class="heading-anchor" href="#systemd-service">systemd service<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>To run your fan control script as a systemd service, drop the script to your
preferred location (I placed it in <code>/root/.local/bin/fancontrol</code>), then create
a file <code>/etc/systemd/system/fancontrol.service</code> with the following contents:</p>
<pre tabindex="0"><code>[Unit]
Description=Quick fan control software

[Service]
ExecStart=/root/.local/bin/fancontrol

[Install]
WantedBy=multi-user.target
</code></pre><p>And once that is done, enable and start your fan control service with
<code>sudo systemctl enable --now fancontrol.service</code>.</p>
<p>If you encounter issues or something isn&rsquo;t working right, check the status of
the service with <code>systemctl status fancontrol.service</code> or full logs with
<code>journalctl -u fancontrol.service</code>.</p>
<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>If you want something that works out of the box and does the smart stuff for you,
then <a href="https://wiki.archlinux.org/title/fan_speed_control">give this Arch Linux wiki page a look</a>.
If you&rsquo;re not into that and want to easily tune the behaviour of your machine,
then feel free to use these scripts as a baseline for your own experimentation.</p>
]]></content:encoded></item><item><title>Overcoming hardware limitations: the time-to-sleep script</title><link>https://ounapuu.ee/posts/2022/08/26/the-time-to-sleep-script/</link><pubDate>Fri, 26 Aug 2022 08:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2022/08/26/the-time-to-sleep-script/</guid><description>Sometimes the least technical solutions end up being the ones that I'm the most proud of. This is probably one of them.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="Overcoming hardware limitations: the time-to-sleep script" /><p>As some of you might own, <a href="/posts/2022/01/09/why-i-went-back-to-using-a-thinkpad-from-2012/">I&rsquo;m still rocking a ThinkPad T430, a laptop model
originally released in 2012.</a>
It&rsquo;s not the fastest laptop out there, but it is plenty fast for a number of
tasks, even most software development work.</p>
<p>I also try to keep my machines up to date and properly backed up. On my laptop,
this means having around a couple of scheduled tasks, such as <code>restic</code> backups.
They don&rsquo;t really take up a lot of time, but if an intensive scheduled task
starts while you&rsquo;re having a video call over Google Meet while also sharing
the screen, things can get a bit slow, ruining the experience.</p>
<p>After a couple of these instances, I started thinking about finding a solution.</p>
<h2 id="scheduled-tasks">
  <a class="heading-anchor" href="#scheduled-tasks">Scheduled tasks<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Here&rsquo;s a quick rundown of regular tasks that I like to run on my laptop.</p>
<p><strong>Backups using <code>restic</code></strong>: hourly backups to my home server. The file scanning
process of the backup is quite intense, eating up a lot of my CPU time.</p>
<p><strong>System updates using <code>dnf</code> and <code>flatpak</code></strong>: usually run daily, because I&rsquo;m too
lazy to install the updates using a GUI, and at the same time I cannot afford
to run out of date software.</p>
<p><strong>Backups of critical files from my server to my laptop</strong>: there are some files
I just cannot afford to lose. For this reason, I make a daily backup of the
files to my laptop.</p>
<p><strong>Filesystem maintenance</strong>: I don&rsquo;t trust my storage devices (and neither should
you), which is why I run a weekly scrub on my SSD that&rsquo;s running the <code>btrfs</code>
filesystem. If there are errors detected, I will know as soon as possible.</p>
<p>These tasks can be quite intensive, especially on hardware that&rsquo;s a bit older.</p>
<p>With some tasks, such as system updates, you may also run into random
issues. Updating Mozilla Firefox while it&rsquo;s actively running results in the
browser requiring a restart immediately after opening a new tab. This is very
annoying and inconvenient when you&rsquo;re in the middle of your work.</p>
<h2 id="the-time-to-sleep-script">
  <a class="heading-anchor" href="#the-time-to-sleep-script">The &ldquo;time-to-sleep&rdquo; script<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>To avoid intensive scheduled tasks running while I&rsquo;m doing actual work, I tried
rescheduling these tasks to a more quiet time. All I needed to do was to edit
the <code>systemd</code> timers so that the jobs start after midnight and leave the laptop
running.</p>
<p>This solution has quite an obvious downside: my laptop will be powered on
pretty much 24/7, and since electricity is super expensive and laptop
maintenance a bit of a pain, I&rsquo;d be wasting resources, time and eventually
money.</p>
<p>I <em>could</em> make the last scheduled task make the machine shut down, but what if I
have a long-running file copy operation running? It would be interrupted, unless
I specifically disabled the scheduled task.</p>
<p>Then it clicked for me.</p>
<p>I know when I&rsquo;m planning on going to sleep. Sleeping also has a regular cycle
as it happens daily. Why not just put all the scheduled daily tasks into one
script that I can run whenever I intend to shut down my laptop?</p>
<p>And thus, the <code>time-to-sleep</code> script was born. It&rsquo;s a simple Bash script that
lives in <code>/root/.local/bin/time-to-sleep</code>. To make sure I can also reasonably
observe the behaviour of the script, I&rsquo;ve implemented it as a simple <code>systemd</code>
service that lives in <code>/etc/systemd/system/time-to-sleep.service</code>. It&rsquo;s
disabled by default, but can be started manually.</p>
<pre tabindex="0"><code>[Unit]
Description=Run maintenance tasks

[Service]
ExecStart=/root/.local/bin/time-to-sleep
</code></pre><p>I have an alias in <code>~/.bashrc</code> that I use to start the service.</p>
<pre tabindex="0"><code>alias time-to-sleep=&#34;sudo systemctl start time-to-sleep.service&#34;
</code></pre><p>Whenever the time comes to go to sleep, or when I&rsquo;m just going to do something
else and can leave the laptop running at my desk, I just open a terminal window,
type <code>time-to-sleep</code> and I&rsquo;m good to go. If I&rsquo;m somewhere with a very poor
internet connection or need to conserve battery power, I can opt to not run that
script.</p>
<p>Going with this approach also saves me a lot of trouble on the technical side
as well. I don&rsquo;t need to think of a magical way to automatically detect if I&rsquo;m
working at the moment, or if I&rsquo;m running on battery, or if I&rsquo;m behind a limited
internet connection. Sometimes your job becomes so much easier if you make some
assumptions about when and where the script runs. You&rsquo;re in control of choosing
when to run it, after all.</p>
<p>In case something goes wrong, I can rely on the <code>set -e</code> line in my script to
fail hard. When I come back to my machine, it will be quite noticeable that
something has gone wrong, as the laptop will still be running. Who needs a
fancy monitoring setup when you have visual evidence of failure?</p>
<p>As for the hourly backups, I solved that problem by only making backups of
more important files. It takes much fewer resources compared to the full <code>/home</code>
folder backup that runs as part of the <code>time-to-sleep</code> script.</p>
<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>After all this work, I don&rsquo;t have to worry about any scheduled tasks hogging
up all the resources while working. At the same time, I still get all the
benefits that the scheduled tasks bring.</p>
<h2 id="example">
  <a class="heading-anchor" href="#example">Example<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>In case you need it: here&rsquo;s an example of the script that I&rsquo;m running, with all
the personal details scrubbed out. Feel free to use it as inspiration for your
own <code>time-to-sleep</code> script!</p>
<pre tabindex="0"><code>#!/bin/bash

set -e

echo &#34;Restic full home folder backup.&#34;
export RESTIC_REPOSITORY=&#39;sftp:backupuser@backupserver.lan:/path/to/repo/&#39;
export RESTIC_PASSWORD=&#39;someverysecurepasswordgoeshere&#39;

restic unlock

restic backup --verbose --exclude-caches --cleanup-cache \
  --iexclude=/home/*/downloads \
  --exclude=/home/*/.cache \
  --exclude=/home/*/.gradle \
  --exclude=/home/*/.local/share/Trash \
  /home

restic forget --prune \
  --keep-hourly 0 \
  --keep-daily 7 \
  --keep-monthly 0

echo &#34;Restic full home folder backup done.&#34;

echo &#34;Backing up important data from the server.&#34;

rsync -az --delete-before \
  user@myserver.lan:/path/to/nextcloud/ \
  /storage/backups/nextcloud/

chown -R localuser:localuser /storage/backups/nextcloud/

echo &#34;Backing up important data from the server done.&#34;

echo &#34;Updating system.&#34;

dnf update -y

flatpak update -y &amp;&amp; flatpak uninstall --unused -y

echo &#34;Updating system done.&#34;

echo &#34;Scrubbing disk.&#34;
btrfs scrub start -B /
echo &#34;Scrubbing disk done.&#34;

echo &#34;All done! Going to sleep.&#34;

shutdown now
</code></pre>]]></content:encoded></item><item><title>Disabling the crappy Broadcom Bluetooth adapter in your ThinkPad T430 running Linux</title><link>https://ounapuu.ee/posts/2022/06/01/thinkpad-t430-bluetooth-shenanigans/</link><pubDate>Wed, 01 Jun 2022 12:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2022/06/01/thinkpad-t430-bluetooth-shenanigans/</guid><description>If you have ever felt frustated with the Bluetooth experience that your ThinkPad T430 offers you, especially after upgrading the WiFi adapter to one that also has Bluetooth capabilities, then this article might help you out.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="Disabling the crappy Broadcom Bluetooth adapter in your ThinkPad T430 running Linux" /><p>You&rsquo;ve disabled the boneheaded Lenovo WiFi adapter whitelist using a tool like
<a href="https://github.com/n4ru/1vyrain">1vyrain</a>, installed a better adapter like the
<a href="https://ark.intel.com/content/www/us/en/ark/products/75439/intel-dual-band-wirelessac-7260.html">Intel Dual Band Wireless-AC 7260</a>,
and found that Bluetooth is not working as intended on your ThinkPad T430
running Linux?</p>
<p>Here&rsquo;s a guide on what you can try to resolve some issues you may encounter.</p>
<h2 id="the-integrated-bluetooth-adapter">
  <a class="heading-anchor" href="#the-integrated-bluetooth-adapter">The integrated Bluetooth adapter<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The ThinkPad T430 comes with Bluetooth out of the box. Mine is this one:</p>
<pre tabindex="0"><code>Bus 001 Device 004: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad]
</code></pre>








<figure class="center">
  <a href="/posts/2022/06/01/thinkpad-t430-bluetooth-shenanigans/media/image.jpg">
    <img src="/posts/2022/06/01/thinkpad-t430-bluetooth-shenanigans/media/image_hu_7f58e7068cea5d7a.webp"
     width="1280"
     height="775"
     loading="lazy"
     decoding="async"
     alt="And it looks something like this.">

  </a>
  <figcaption class="center">And it looks something like this.</figcaption>
</figure>

<p>I run Fedora Linux and frankly the experience with the stock adapter is horrible.
Getting stuck while pairing a device or the GNOME Bluetooth settings GUI hanging
isn&rsquo;t a rare sight. Sometimes I&rsquo;ve had to run a script to reset all USB devices
to get things sorted out, or restart the machine altogether. This is not fun
when a work call started 3 minutes ago and your Bluetooth headset is just not
working.</p>
<p>After installing the new Intel WiFi adapter, I thought that I&rsquo;d just disable the
integrated Bluetooth controller via the UEFI settings. That should do the trick,
right?</p>
<p>Nope. Apparently this disabled ALL bluetooth devices, including the one provided
by the Intel adapter.</p>
<p>Well, no problem, I&rsquo;ll just physically remove the Broadcom device and that
should force the ThinkPad to use the Intel adapter, right?</p>
<p>Nope. Now the machine just shows no Bluetooth devices.</p>
<h2 id="udev-to-the-rescue">
  <a class="heading-anchor" href="#udev-to-the-rescue">udev to the rescue<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>If you install the Intel adapter and don&rsquo;t touch any of the settings, you&rsquo;ll have
two Bluetooth adapters. On my laptop, the OS used the Broadcom adapter by default,
which was evident by all GUI interactions interfacing with the Broadcom one and
throwing out errors in <code>dmesg -w</code> as a result.</p>
<p>Since disabling the Broadcom bluetooth adapter via other means did not work, I
had to look for some solutions. One that I stumbled upon relied on <code>udev</code> rules.</p>
<p>Essentially, what you want to do is drop a file in <code>/etc/udev/rules.d/</code>, name it
something like <code>81-bluetooth-hci.rules</code> and make the contents something like
this:</p>
<pre tabindex="0"><code>SUBSYSTEM==&#34;usb&#34;, ATTRS{idVendor}==&#34;0a5c&#34;, ATTRS{idProduct}==&#34;21e6&#34;, ATTR{authorized}=&#34;0&#34;
</code></pre><p>Make sure to replace the <code>idVendor</code> and <code>idProduct</code> with the correct values for
your Bluetooth adapter. Output of <code>lsusb</code> will likely contain those values.</p>
<p>In my case, the output of <code>lsusb</code> is</p>
<p><code>Bus 001 Device 004: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad]</code></p>
<p>The <code>idVendor</code> and <code>idProduct</code> info is in this string: <code>ID 0a5c:21e6</code>.</p>
<p>After making this change and restarting, you should see that<code>bluetoothctl list</code>
outputs only one Bluetooth device.</p>
<pre tabindex="0"><code>[host@T430 ~]$ bluetoothctl list
Controller AC:FD:CE:30:EB:BA T430 [default]
</code></pre><p>Because Bluetooth is still a hot mess in 2022, I still have to occasionally beat
it with a hammer. However, the experience with the Intel adapter is much better
and a simple &ldquo;turn the adapter off and on again in the GUI&rdquo; solved 99% of the
issues I&rsquo;ve encountered since then.</p>
<h3 id="have-you-tried-turning-it-off-and-on-again">
  <a class="heading-anchor" href="#have-you-tried-turning-it-off-and-on-again">&ldquo;Have you tried turning it off and on again?&rdquo;<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>If for whatever reason this solution does not apply to you, and you feel like
you want to hit your machine with a big hammer without having to restart it, then
<a href="https://askubuntu.com/a/290519">here&rsquo;s a script</a> that resets all the USB
devices on your machine. I&rsquo;ve observed that most Bluetooth adapters run over USB,
which is why this script works with those as well.</p>
<p>It has helped me countless times when desperate for a quick Bluetooth fix on
various desktops and laptops that I&rsquo;ve used.</p>
<p>Run it at your own risk.</p>
<pre tabindex="0"><code>#!/bin/bash

for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do
  [ -e &#34;$i&#34; ] || continue
  echo &#34;${i##*/}&#34; &gt; &#34;${i%/*}/unbind&#34;
  echo &#34;${i##*/}&#34; &gt; &#34;${i%/*}/bind&#34;
done
</code></pre>]]></content:encoded></item><item><title>Oversimplified guide into snapshots on the btrfs filesystem</title><link>https://ounapuu.ee/posts/2022/04/05/btrfs-snapshots/</link><pubDate>Tue, 05 Apr 2022 06:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2022/04/05/btrfs-snapshots/</guid><description>Oh, snap(per)!</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="Oversimplified guide into snapshots on the btrfs filesystem" /><p><em><strong>Update:</strong></em> I&rsquo;ve switched to <a href="/posts/2022/07/09/btrbk-is-awesome/">btrbk</a> for managing btrfs snapshots due to certain
deficiencies that I had with <code>snapper</code>. Those may have been fixed since then, but <code>btrbk</code> has served me very well, and
I&rsquo;m sticking with it in the foreseeable future.</p>
<p>Friday afternoon. You&rsquo;re trying out a script that you wrote to mass-rename and
move some files around. You finish the script and test it out.</p>
<p>Oops.</p>
<p>All the files now have all the wrong names, and some have been randomly moved
10 folders deep. It&rsquo;s a mess.</p>
<p>And you didn&rsquo;t make a backup of your files right before this step because
you thought that you wouldn&rsquo;t need it. <em>It&rsquo;s just a simple script, after all&hellip;</em></p>
<p>If you&rsquo;ve found yourself in a similar situation and want to know how to avoid
problems in the future, then this article is for you</p>
<h2 id="btrfs-overview">
  <a class="heading-anchor" href="#btrfs-overview">btrfs: overview<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>









<figure class="center">
  <a href="/posts/2022/04/05/btrfs-snapshots/media/btrfs.png" aria-label="View full-size image">
    <img src="/posts/2022/04/05/btrfs-snapshots/media/btrfs_hu_6d2804214375925e.webp"
     width="593"
     height="328"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p><a href="https://btrfs.wiki.kernel.org/index.php/Main_Page">btrfs</a>
(<em>butter-fs, bee-tee-arr-eff-ess</em>) is a modern filesystem present in the Linux
kernel that has a lot of great features:</p>
<ul>
<li>different RAID levels: RAID0, RAID1, RAID10&hellip;</li>
<li>data integrity guarantees</li>
<li>snapshots</li>
<li>and many more!</li>
</ul>
<p><code>btrfs</code> does have some downsides and has had its fair share of issues and
controversy in the past, but at least during the last couple of years it&rsquo;s been
fine in my simple RAID1 + snapshots use cases.</p>
<p>In this post, we&rsquo;ll focus on the snapshots feature that <code>btrfs</code> offers.</p>
<p>If you&rsquo;re not sure what snapshots are, then you can think of them as a still
image of the state of your filesystem at a certain point in time. You can create
a snapshot of the filesystem, delete all your files, and still be able to get
your files back just like you left them.</p>
<p>If you&rsquo;re a developer who has used <code>git</code> and doesn&rsquo;t mind oversimplified (and
probably incorrect) explanations: you can think of snapshots like <code>git</code> commits.
You can take snapshots (commit), roll back to a previous snapshot (reset/revert)
or view the contents of a previous snapshot (checkout commit).</p>
<p>One thing to keep in mind with snapshots is that they will take up space,
especially if you make a lot of them and move files around a lot.</p>
<p>There are many tools available to manage <code>btrfs</code> snapshots. The one I&rsquo;ve opted
for is <a href="http://snapper.io/">snapper</a>.</p>
<h2 id="snapper-quick-start">
  <a class="heading-anchor" href="#snapper-quick-start">Snapper quick-start<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Here&rsquo;s a quick guide on how to get started with snapshotting your <code>btrfs</code>
filesystem. The example is based on a system with a <code>btrfs</code> filesystem mounted
on <code>/home</code></p>
<ul>
<li>Install <code>snapper</code>
<ul>
<li>Ubuntu/Debian: <code>sudo apt install snapper</code></li>
<li>Fedora: <code>sudo dnf install snapper</code></li>
</ul>
</li>
<li>Setup the configuration: <code>sudo snapper -c home create-config /home</code></li>
<li><code>/etc/snapper/configs</code> now has a text file named <code>home</code> that you can configure
to your liking. My personal recommendation is to use the <code>TIMELINE</code> snapshots
configuration to configure the maximum number of hourly and daily snapshots.</li>
<li><code>snapper</code> ships with two systemd timers that automatically take new snapshots
and remove old ones. Make sure that they are enabled:
<ul>
<li><code>sudo systemctl enable --now snapper-timeline.timer snapper-cleanup.timer</code></li>
</ul>
</li>
<li>After a while, you should be able to see snapshots appear in the output of
<code>sudo snapper -c home list</code>.</li>
<li>If you want to browse the files for the old snapshots, go to <code>/home/.snapshots</code>.</li>
</ul>
<p>Example output of <code>sudo snapper -c home  list</code> on my machine:</p>
<pre tabindex="0"><code>&gt; sudo snapper -c home list

    # | Type   | Pre # | Date                     | User | Cleanup  | Description | Userdata
------+--------+-------+--------------------------+------+----------+-------------+---------
   0  | single |       |                          | root |          | current     |         
   1  | single |       | K 16 märts 2022 08:12:01 | root | timeline |             |         
 242  | single |       | K 16 märts 2022 13:00:16 | root | timeline |             |         
 302  | single |       | K 16 märts 2022 14:00:05 | root | timeline |             |         
 362  | single |       | K 16 märts 2022 15:00:10 | root | timeline |             |         
 422  | single |       | K 16 märts 2022 16:00:19 | root | timeline |             |         
 461  | single |       | K 16 märts 2022 17:20:29 | root | timeline |             |         
 501  | single |       | K 16 märts 2022 18:00:02 | root | timeline |             |
...         
</code></pre><p>That&rsquo;s it!</p>
<h2 id="snapper-tech-tips">
  <a class="heading-anchor" href="#snapper-tech-tips">Snapper tech tips<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>If you&rsquo;re new to snapshots, then I recommend keeping an eye on your disk usage
and tuning the <code>snapper</code> timeline related configurations to your liking. For my
<code>/home</code> folder, my configuration looks like this:</p>
<pre tabindex="0"><code># create hourly snapshots
TIMELINE_CREATE=&#34;yes&#34;

# cleanup hourly snapshots after some time
TIMELINE_CLEANUP=&#34;yes&#34;

# limits for timeline cleanup
TIMELINE_MIN_AGE=&#34;300&#34;
TIMELINE_LIMIT_HOURLY=&#34;48&#34;
TIMELINE_LIMIT_DAILY=&#34;7&#34;
TIMELINE_LIMIT_WEEKLY=&#34;0&#34;
TIMELINE_LIMIT_MONTHLY=&#34;0&#34;
TIMELINE_LIMIT_YEARLY=&#34;0&#34;
</code></pre><p>With this configuration, I can undo my screw-ups for up to 7 days, with more
granular control for changes done within the last 48 hours.</p>
<p>If you have data that changes more often than other data on the same filesystem,
then I recommend utilizing <code>btrfs</code> subvolumes and creating separate <code>snapper</code>
configurations for each.</p>
<p>For example: a folder containing gigabytes of cat pictures is unlikely to change
all that often, so a longer snapshot retention policy of 24 hourly/30 daily
snapshots is a sensible one.</p>
<p>However, the contents of my <code>downloads</code> folder changes more frequently and may
contain bigger files that I need temporarily, such as the ISO file for the
latest Fedora/Debian release. In a situation like that, having a 6 hourly/7
daily snapshots policy will make more sense, especially if I don&rsquo;t want to run
out of space due to excessive number of snapshots taken for that filesystem.</p>
<h2 id="further-reading-zfs-snapshots">
  <a class="heading-anchor" href="#further-reading-zfs-snapshots">Further reading: ZFS snapshots<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p><a href="https://zfsonlinux.org/">ZFS</a> is a fantastic filesystem that offers many of
the features boasted by <code>btrfs</code>, and some that <code>btrfs</code> doesn&rsquo;t have. ZFS also
supports snapshots. To set up automatic snapshot creation and pruning on ZFS,
I can recommend <a href="https://github.com/jimsalterjrs/sanoid">sanoid</a>.</p>
]]></content:encoded></item><item><title>Self-hosting Wikipedia using Kiwix</title><link>https://ounapuu.ee/posts/2021/12/09/self-hosting-wikipedia/</link><pubDate>Thu, 09 Dec 2021 06:00:00 +0200</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2021/12/09/self-hosting-wikipedia/</guid><description>Hosting your own Wikipedia instance has never been this easy!</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="Self-hosting Wikipedia using Kiwix" /><p>Do you have a need to host Wikipedia on your computer?</p>
<p>Or a StackExchange site, like <a href="https://superuser.com/">Super User</a>?</p>
<p>It&rsquo;s easier than you think!</p>









<figure class="center">
  <a href="/posts/2021/12/09/self-hosting-wikipedia/media/image.jpg" aria-label="View full-size image">
    <img src="/posts/2021/12/09/self-hosting-wikipedia/media/image_hu_735508aea9ceb050.webp"
     width="920"
     height="518"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<h2 id="step-1-download-stuff">
  <a class="heading-anchor" href="#step-1-download-stuff">Step 1: download stuff!<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The <a href="https://www.kiwix.org/en/">Kiwix project</a> provides ZIM files for many popular websites, including Wikipedia.
These files can be downloaded <a href="https://wiki.kiwix.org/wiki/Content_in_all_languages">over at Kiwix wiki.</a></p>
<p>Take a look at the content packages available and download those that you are interested in.</p>
<h2 id="step-2-install-kiwix">
  <a class="heading-anchor" href="#step-2-install-kiwix">Step 2: install Kiwix<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Kiwix provides <a href="https://www.kiwix.org/en/download/">all sorts of clients for different operating systems</a>. If you don&rsquo;t
want to go crazy with setting up a server and you just want to browser your offline copy of Wikipedia or any other
resource, then go ahead and use that.</p>
<p>However, if you want to make the resources available for other people as well, then you need to install <code>kiwix-serve</code>.
On Debian and Ubuntu systems, this is just a <code>sudo apt install kiwix-tools</code> in your terminal.</p>
<p>Once you have it installed, all you have to do is to run <code>kiwix-serve -p 8080 your-file-here.zim</code> and your content
package is served to anyone who can connect to your machine with a browser over port 8080.</p>
<p>If you have multiple ZIM files in the same folder, then you can serve all of them at once with something like
<code>kiwix-serve -p 8080 *.zim</code>.</p>
<h2 id="step-3-enjoy">
  <a class="heading-anchor" href="#step-3-enjoy">Step 3: enjoy!<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>You should now be up and running with your very own hosted Wikipedia instance!
Just keep in mind that your copy might not be 100% up to date. The Kiwix project does repackage these sites quite
regularly so keep an eye out for updates.</p>
<h2 id="tips-and-tricks">
  <a class="heading-anchor" href="#tips-and-tricks">Tips and tricks<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I have set up my own Kiwix instance and the way it works is quite simple.</p>
<p>I use <a href="https://deluge-torrent.org/">Deluge</a> to download and seed the content packs that I have downloaded.</p>
<p>Then I have also set up a <code>systemd</code> service that automatically starts Kiwix on boot. It is located at
<code>/etc/systemd/system/kiwix-serve.service</code> and looks like this:</p>
<pre tabindex="0"><code>[Unit]
Description=Serve all the ZIM files loaded on this server

[Service]
Restart=always
RestartSec=15
User=kiwix
ExecStart=/usr/bin/bash -c &#34;/usr/bin/kiwix-serve -p 8080 /path/to/your/files/*.zim&#34;

[Install]
WantedBy=network-online.target
</code></pre><p>Note that I have set up a separate non-interactive user for this purpose. The path to the ZIM files simply refers to
the download folder of the Deluge torrent client.</p>
<p>Making this available to the world is simply a matter of either exposing the selected port to the world, or using <code>nginx</code>
as a reverse proxy. There are plenty of guides available on how to achieve the latter so I won&rsquo;t go into detail about
that here.</p>
<p>That&rsquo;s it!</p>
<h2 id="2024-09-05-update">
  <a class="heading-anchor" href="#2024-09-05-update">2024-09-05 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It&rsquo;s been a fun experiment, but LLM-bots are overwhelming my Kiwix instance and I can&rsquo;t be bothered with setting up
any protections right now, so the <code>kiwix.ounapuu.ee</code> instance is shut down for now.</p>
]]></content:encoded></item><item><title>Testing GPU passthrough on AMD Ryzen 7 5700G APU</title><link>https://ounapuu.ee/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/</link><pubDate>Sat, 28 Aug 2021 10:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/</guid><description>A quick overview of my experience with setting it up on a small PC box and things to consider when attempting this yourself.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="Testing GPU passthrough on AMD Ryzen 7 5700G APU" /><h2 id="introduction">
  <a class="heading-anchor" href="#introduction">Introduction<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Before we jump into all the nitty-gritty details, I&rsquo;d like to go over what we are dealing with here since these topics
may be unfamiliar to you. VFIO is quite a niche topic and not everyone knows about it.</p>
<p><a href="https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF">GPU passthrough</a>: the process of allowing a VM (virtual
machine) to use a dedicated GPU. This allows you to run GPU-heavy workloads inside the VM, such as gaming or anything
that benefits from GPU compute power.</p>
<p><a href="https://www.kernel.org/doc/Documentation/vfio.txt">VFIO</a>: the framework that allows us to perform this operation.</p>
<p><a href="https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit">IOMMU</a>: hardware feature that supports all
of this.</p>
<p><a href="https://virt-manager.org/">virt-manager</a>: GUI application that I use to manage VM-s.</p>
<p>Reasons why you may want to go through all the hassle and use this approach:</p>
<ul>
<li>you&rsquo;re on Linux but want to play games occasionally without rebooting into Windows</li>
<li>you want to do all your work, gaming and server workloads on one machine</li>
<li>you simply don&rsquo;t want to build a dedicated PC for playing games and would like to utilize the existing resources on
your main machine</li>
<li>you want more control over the Windows installation because you simply don&rsquo;t trust Microsoft</li>
<li>you want to have more control over the Windows installation and the ability to revert the installation to an earlier
point in time using a filesystem that supports snapshots (BTRFS, ZFS)</li>
<li>you have multiple separate VM-s for different purposes, but you would like to use one single GPU for all of them</li>
</ul>
<p>One thing to keep in mind is that the hardware you use matters a lot here as that provides the foundation for getting
this solution working. Here are some of the requirements you should know about:</p>
<ul>
<li>The GPU you want to pass through has to support UEFI. GPU-s from the past 5 years should be good on that, but if you
have a really old GPU that you want to use for testing, then that might not work out that well.</li>
<li>You need to have a good-enough CPU and plenty of RAM. After all, you&rsquo;re essentially running a full PC within another
PC.</li>
<li>Your motherboard has to support IOMMU and have IOMMU groups that allow you to isolate the GPU and only pass the GPU to
the VM. <a href="https://www.youtube.com/user/teksyndicate">Level1Techs</a> does quite a few motherboard reviews and Wendell goes
over the IOMMU groups and suitability for VFIO in them. It also helps if you look around the internet for enthusiasts
that have already bought the same motherboard, they may have posted information about the groups. Here&rsquo;s
a <a href="https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF#Ensuring_that_the_groups_are_valid">handy script that allows you to check your IOMMU groups.</a></li>
<li>Some games may ban you if they detect that you are running the game inside a VM. It&rsquo;s great that they&rsquo;re trying to do
something against cheaters, but unfortunately VFIO users get unfairly treated here. Please do some research beforehand
if you play competitive multiplayer games a lot!</li>
</ul>
<p>I hope that this introduction helped you understand the basics. Now, let&rsquo;s just jump right into it.</p>
<h2 id="setup">
  <a class="heading-anchor" href="#setup">Setup<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>We&rsquo;re going to test this setup
on <a href="/posts/2021/08/07/amd-ryzen-7-5700-first-impressions/">hardware that I have covered previously</a>. What makes this
setup a bit special is that we&rsquo;re using an AMD Ryzen 7 5700G APU on an mITX motherboard and a single dedicated GPU,
allowing us to do big things in a small package. Yes, there are setups where you can do VFIO with a single GPU and pass
it between the host OS and the VM, but that setup might be a bit tricky to use.</p>
<p>The OS is Fedora 34. To get this working, I&rsquo;ve used various resources:</p>
<ul>
<li><a href="https://forum.level1techs.com/t/the-vfio-and-gpu-passthrough-beginners-resource/129897">beginners guide on Level1Techs forums</a></li>
<li><a href="https://forum.level1techs.com/t/fedora-33-ultimiate-vfio-guide-for-2020-2021-wip/163814">Fedora-specific guide by Wendell from Level1Techs</a></li>
<li><a href="https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF#Ensuring_that_the_groups_are_valid">this brilliant Arch Wiki guide that covers most of what you need to know about setting this up.</a>
It&rsquo;s not only useful for Arch, a lot of what is written here applies for any distro.</li>
</ul>
<h2 id="testing">
  <a class="heading-anchor" href="#testing">Testing<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I decided to do the initial testing with the Nvidia GT 710. It&rsquo;s slow, buggy on Linux on Nouveau open source drivers,
and I had it available. I also recently heard that Nvidia stopped being hostile towards their customers in one aspect
by <a href="https://www.nvidia.com/en-us/geforce/news/outriders-game-ready-driver/">allowing GeForce GPU-s to be used in a Windows 10 VM without having to resort to workarounds.</a></p>
<p>The testing itself was relatively straightforward. The only issues I had
were <a href="https://en.wiktionary.org/wiki/PEBCAK">PEBCAK</a> issues, possibly related to me performing this testing after work.
The main issues I ran were either small typos in dracut configuration or the wrong device ID-s being added to kernel
boot parameters. Once I discovered and fixed those, it was all smooth sailing.</p>
<p>I&rsquo;m not going to rewrite a full guide here, please refer to the previously linked resources if you need more details
than that. Those resources are also much more likely to receive updates about new finds and features.</p>
<p>The steps I took were roughly these:</p>
<ul>
<li>Make sure that IOMMU was enabled in UEFI settings. It&rsquo;s probably set to <code>auto</code> by default, make sure to set it
to <code>enabled</code>.</li>
<li>Install the GPU that I want to pass through and connect it to a monitor.</li>
<li>Install virtualization packages on Fedora: <code>sudo dnf install @virtualization</code></li>
<li>Enable IOMMU and preload the VFIO kernel module by adding <code>amd_iommu=on rd.driver.pre=vfio-pci</code> to Linux kernel
parameters.
<ul>
<li>I use GRUB2, these parameters live in <code>/etc/sysconfig/grub</code>.</li>
<li>To apply these changes, you have to regenerate the GRUB configuration. Under Fedora, this is done
using <code>grub2-mkconfig -o /etc/grub2-efi.cfg</code></li>
</ul>
</li>
<li>Get the device ID-s for the GPU and the related audio device that you&rsquo;re planning on passing through
<ul>
<li>To see the devices and ID-s, run <code>lspci -nnk</code>. The ID-s look something like <code>1002:aaf0</code>.</li>
</ul>
</li>
<li>Bind the GPU to <code>vfio-pci</code> to avoid the GPU driver from taking control of the GPU, otherwise you cannot pass it to the
VM.
<ul>
<li>I opted to go for the simple approach and added the device ID-s to kernel
parameters: <code>vfio-pci.ids=1002:67df,1002:aaf0</code></li>
<li>Since I went with this approach, then I have to regenerate GRUB configuration again.</li>
</ul>
</li>
<li>Make sure that the initramfs loads the necessary vfio drivers early in the boot.
<ul>
<li>With Fedora 34, this means creating a file <code>/etc/dracut.conf.d/10-vfio.conf</code> with
contents <code>add_drivers+=&quot; vfio_pci vfio vfio_iommu_type1 vfio_virqfd &quot;</code>.</li>
<li>Make sure that you don&rsquo;t have any typos in that.</li>
<li>Regenerate the initramfs: <code>dracut -f</code></li>
</ul>
</li>
<li>Reboot!</li>
<li>Using <code>virt-manager</code>, select the VM you want to pass the GPU through and add two PCIe devices: the GPU and its
associated audio device.
<ul>
<li>If you don&rsquo;t have the VM set up yet, then proceed with the normal installation without the GPU passed through yet.
Make sure to create an UEFI VM, otherwise you might run into issues. This can be configured in <code>virt-manager</code> _
Overview_ section by selecting the Q35 chipset and setting the firmware to <code>OVMF_CODE.df</code>.</li>
<li>If you have passed through the GPU, then make sure to remove the <code>Display Spice</code> device from the VM.</li>
<li>If you want to also control the VM, you need to also pass through your USB devices, such as a Logitech wireless
receiver.</li>
</ul>
</li>
<li>Start the VM and cheer once you notice TianoCore appearing on the monitor that&rsquo;s connected to the passed through GPU!</li>
</ul>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/vfio-success.jpg">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/vfio-success_hu_199212126e9325b5.webp"
     width="1107"
     height="800"
     loading="lazy"
     decoding="async"
     alt="If you see this, then you&#39;ve just successfully passed the GPU to the VM. Congratulations!">

  </a>
  <figcaption class="center">If you see this, then you&#39;ve just successfully passed the GPU to the VM. Congratulations!</figcaption>
</figure>

<h2 id="results-nvidia-gt-710">
  <a class="heading-anchor" href="#results-nvidia-gt-710">Results: Nvidia GT 710<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Initial testing with Nvidia GT 710 was successful. By successful, I mean that the GPU displayed an image and did not
install GPU drivers automatically.</p>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/nvidia-error-43.jpg">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/nvidia-error-43_hu_326f276537db01bf.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The infamous Nvidia error code 43.">

  </a>
  <figcaption class="center">The infamous Nvidia error code 43.</figcaption>
</figure>

<p>To overcome that last issue, I downloaded the latest official Nvidia GPU drivers and was good to go. The news were true,
error code 43 was no longer an issue!</p>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/nvidia-postinstall.jpg">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/nvidia-postinstall_hu_42e3d99bf6c38aba.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="If your GPU shows up like this in Device Manager, then it should work properly.">

  </a>
  <figcaption class="center">If your GPU shows up like this in Device Manager, then it should work properly.</figcaption>
</figure>

<p>Things got a bit less exciting when I got reminded that this GPU is weak. Very weak. Regardless, I decided to
demonstrate its computing prowess by downloading the <a href="https://funselektor.itch.io/art-of-rally">art of rally demo</a>. Side
note: it&rsquo;s a great game, go try it out!</p>
<p>The demo ran! Not well, but it still ran!</p>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/nvidia-artofrally.jpg">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/nvidia-artofrally_hu_b26dfefd5196674e.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Not pictured: the horrible framerate.">

  </a>
  <figcaption class="center">Not pictured: the horrible framerate.</figcaption>
</figure>

<p>Satisfied with the results, I decided to go for gold and replace this GPU with the AMD RX 570 that I &ldquo;borrowed&rdquo;
from <a href="/posts/2021/08/21/turning-leftover-parts-into-a-decent-gaming-pc/">this PC I built recently</a>.</p>
<h2 id="results-amd-rx-570">
  <a class="heading-anchor" href="#results-amd-rx-570">Results: AMD RX 570<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>After switching the GPU, I replaced the device ID-s with the new values and continued with the VFIO adventure. This
time, the GPU drivers were automatically installed by Windows and everything just worked. That&rsquo;s not supposed to happen,
at least in my experience <em>something</em> always goes wrong. Always.</p>
<p>I installed the latest drivers from AMD-s website and continued with testing.</p>
<p>Furmark? Runs as expected.</p>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/amd-furmark.jpg">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/amd-furmark_hu_27a05e2f78a7e673.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="VM on the left, VM performance stats on the right, mess of cables everywhere.">

  </a>
  <figcaption class="center">VM on the left, VM performance stats on the right, mess of cables everywhere.</figcaption>
</figure>

<p>GTA IV? A stuttery mess, so yeah, runs as expected.</p>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/amd-gta-iv.jpg">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/amd-gta-iv_hu_64a674dc7b9cffa9.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="On the left: GTA IV, straight from the GPU. On the right: GTA IV, streamed via Parsec.">

  </a>
  <figcaption class="center">On the left: GTA IV, straight from the GPU. On the right: GTA IV, streamed via Parsec.</figcaption>
</figure>

<p>At this point the VM was assigned 4 CPU cores and I had performed no CPU pinning or optimizations of any kind, so the
results were pretty good.</p>
<h2 id="storage">
  <a class="heading-anchor" href="#storage">Storage<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Because I built this setup on my current workstation/server machine, the storage situation is a bit tricky. The other VM
that runs all the services has full access to the two 12TB hard drives and I wasn&rsquo;t interested in setting up a networked
storage setup. The only free spots I had were as follows:</p>
<ul>
<li>120GB partition from the NVMe SSD. Good enough for storing the Windows 10 system files.</li>
<li>2x 250GB partitions on the Samsung SATA 1TB SSD-s. Just enough to hold my recently played games, but not much more.
Running in striped configuration under Windows.</li>
</ul>
<p>I later opted to expand the game storage partitions to 375GB, which meant that I had to get rid of the extra
overprovisioning space that I had left aside. This setup is fine, but I&rsquo;m losing out on some of the benefits that come
with a virtualized Windows setup.</p>
<p>With regards to passing this storage to the VM, I had two options:</p>
<ul>
<li>keep using the SATA virtual disk: works out of the box, but might not perform as well.</li>
<li>use <code>virtio</code>: you need to manually load and install the drivers for Windows to recognize these disks, but allegedly
this has better performance than the SATA implementation.</li>
</ul>
<p>I started off with SATA and did a comparison against <code>virtio</code> using CrystalDiskMark.</p>









<figure class="center">
  <a href="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/crystaldiskmark.png">
    <img src="/posts/2021/08/29/testing-gpu-passthrough-on-amd-ryzen-5700g/media/crystaldiskmark_hu_71252985bd8c9ed3.webp"
     width="1280"
     height="467"
     loading="lazy"
     decoding="async"
     alt="Left: SATA. Right: virtio.">

  </a>
  <figcaption class="center">Left: SATA. Right: virtio.</figcaption>
</figure>

<p><code>virtio</code> did come ahead in these comparisons, but I would probably have been fine with the SATA performance as well.</p>
<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion">Conclusion<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>One of the main reasons I do these kinds of setups is the technical challenge. It sounds weird, but sometimes I am
happier after having completed something technical and novel compared to actually using the setup.</p>
<p>Previously I&rsquo;ve had mixed results with GPU passthrough,
with <a href="https://www.reddit.com/r/linuxmasterrace/comments/7ry4jr/gta_v_on_arch_linux_how_i_managed_to_get_gpu/">ThinkPad T430 and eGPU somehow managing to run GTA V in a VM</a>
, while in another testing session I ran into issues which turned out to be related to the CPU being faulty (lots of
PCIe errors).</p>
<p>I do have more practical future plans with this. The plan is to use this VM as a gaming VM that I can stream games from
using <a href="https://parsec.app/">Parsec</a>
to any device that I wish. One idea is to use the <a href="https://www.nvidia.com/en-us/shield/shield-tv/">Nvidia Shield TV</a> as
a low-power box that is capable of performing streaming. Alternatively, I could also get a super tiny form factor
Dell/Lenovo/HP PC that has plenty of power to drive a 4K display and uses a reasonable amount of power. More on that in
a future post.</p>
<p>Regarding storage I foresee an upgrade coming soon, either to the drives themselves or the whole setup since ATX
motherboards support more SATA ports and expansion cards. If you also pair that up with a case
like <a href="https://www.coolermaster.com/catalog/cases/mid-tower/masterbox-q500l/">Masterbox Q500L</a> with a good power supply
placement, then you&rsquo;d still have a relatively small setup.</p>
]]></content:encoded></item><item><title>How to mess up a simple ThinkPad X230 BIOS flash and how to recover from it</title><link>https://ounapuu.ee/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/</link><pubDate>Mon, 28 Jun 2021 07:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/</guid><description>At least it won't end up in a landfill!</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="How to mess up a simple ThinkPad X230 BIOS flash and how to recover from it" /><h2 id="background">
  <a class="heading-anchor" href="#background">Background<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I have a Lenovo ThinkPad X230. It&rsquo;s a small and good laptop that I&rsquo;ve used as my main laptop and a server as well.</p>
<p>A couple of years ago I messed around with flashing alternative BIOS implementations on the X230, such
as <a href="https://github.com/merge/skulls">the skulls project</a>, which made installing prebuilt coreboot images very simple. Of
course, before doing any testing, I made backups of the stock BIOS implementation (ooh, foreshadowing!).</p>
<p>Skulls was nice, it booted fast, but changing the boot order likely required modifications and rebuilding the coreboot
image (I wanted to set the mSATA SSD as the first bootable device). It was also not UEFI-compatible, which could have
probably been solved with something like TianoCore, but I didn&rsquo;t feel like messing with that too much. Eventually I
flashed the original UEFI implementation back and went on with my life.</p>
<p>Then I stumbled upon <a href="https://1vyra.in/">the 1vyrain project</a> project, which allows you to &ldquo;jailbreak&rdquo; your BIOS. This
modification also enables a lot more bells and whistles in the BIOS under the <em>Advanced</em> menu option, plus it also gets
rid of the WiFi adaptor whitelist that Lenovo has put in place, allowing you to now use any adaptor that&rsquo;s compatible
with the form factor.</p>
<p>The mod was very easy to install and had no issues, until I got myself a DDR3 SODIMM RAM kit. One of the sticks was not
working properly, showing up with graphical glitches and failing a memtest run. To troubleshoot it, I decided to change
the speed at which the memory runs from DDR3-1600 to DDR3-1333. It booted, and still had the issues.</p>
<p>Then I changed it to DDR3-1066.</p>
<p>Black screen. Uh-oh.</p>
<h2 id="initial-troubleshooting">
  <a class="heading-anchor" href="#initial-troubleshooting">Initial troubleshooting<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Thinking that this is just a simple issue that I could get fixed by clearing the BIOS settings and starting fresh, I
looked up some basic instructions on doing so.</p>
<p>Things I tried:</p>
<ul>
<li>remove the battery (even if it is completely dead, like mine), and hold the power button for 60 seconds, then attach
the battery and turn it on again.</li>
<li>remove both the battery and disconnect the internal CMOS battery that sits under the palmrest and hold the power
button for 60 seconds again.</li>
<li>disconnect all the batteries and leave the laptop sitting on a shelf, then try again.</li>
<li>try <a href="http://www.masnick.com/2007/09/07/the-secret-thinkpad-powerbutton-code-to-bring-dead-laptops-back-to-life/">&ldquo;the secret ThinkPad power button combo&rdquo;</a>:</li>
</ul>
<blockquote>
<p>&hellip; unplug the AC adapter and take out the battery. Then, you push the power button 10 times in a row at one second intervals.
Next, you push and hold the power button for 30 seconds. Then you put the battery back in and push the power button…
and she lives. The computer came back, good as ever.</p>
</blockquote>
<p>After all of that, the laptop was still as good as dead. You could see the light turn on, the fan starts spinning, but
nothing shows up on the screen. At that point I knew that the BIOS reflash was probably my only choice.</p>
<h2 id="flashing-the-bios">
  <a class="heading-anchor" href="#flashing-the-bios">Flashing the BIOS<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>To fix the issue, I had to flash the BIOS externally. Luckily I still had the original BIOS backup images available.</p>
<p>With the help of a good friend, we set everything up and did some tests to ensure that the connection is good and that
read/write operations on the chips return consistent results.</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/bios-chips-2.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/bios-chips-2_hu_82eb324a42c768d5.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The chips that we&#39;re going to flash sit behind the left side of the palmrest, making them quite easy to access.">

  </a>
  <figcaption class="center">The chips that we&#39;re going to flash sit behind the left side of the palmrest, making them quite easy to access.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/bios-chips-1.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/bios-chips-1_hu_989137a4e63602da.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Left one is generally referred to as the bottom chip and the right one is the top one.">

  </a>
  <figcaption class="center">Left one is generally referred to as the bottom chip and the right one is the top one.</figcaption>
</figure>

<p>Once we had specified the correct chip type by looking at what was written on the chip package itself, we flashed both
the top and bottom chips with the original images that were once made as a backup. After reading the chips back and
comparing checksums using <code>md5sum</code>, it all looked good.</p>
<p>We disconnected the SOIC clip, attached the power cable and tried turning the laptop on. Power button light comes up for
1 second and then turns off. Not a good sign.</p>
<p>We flashed both chips again and made sure that everything is in order. No dice, the symptoms are the same.</p>
<h2 id="a-closer-look">
  <a class="heading-anchor" href="#a-closer-look">A closer look<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It didn&rsquo;t take too long for me to start thinking about what I could use all these extra laptop parts for. After all, the
screen was good, it had 16GB DDR3 RAM, two SSD-s, a screen assembly in good condition etc. I was stopped in my tracks
when my friend noticed something.</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/something-missing.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/something-missing_hu_4572e9842f6a6cc6.webp"
     width="967"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Find the missing resistor.">

  </a>
  <figcaption class="center">Find the missing resistor.</figcaption>
</figure>

<p>It turns out that during this flashing process, we (probably me) had managed to get rid of a resistor that sat next to
the top flash chip. Whoops. Turns out that it was an important one, because over at
Reddit, <a href="https://old.reddit.com/r/coreboot/comments/dhwdss/did_i_just_brick_my_x230/">someone else also ran into this issue and had similar symptoms</a>
.</p>
<p>To resolve this, my friend had the idea of putting a 10K resistor in there to see if it fixes things. The issue was that
the only one available right from the get-go was a very big one, so he had to be clever with it. He ended up positioning
it upright with a piece of wire handling the other side.</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/resistor-hackjob.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/resistor-hackjob_hu_34d3505e3b9f8a42.webp"
     width="700"
     height="372"
     loading="lazy"
     decoding="async"
     alt="Isn&#39;t it beautiful?">

  </a>
  <figcaption class="center">Isn&#39;t it beautiful?</figcaption>
</figure>

<p>This, however, didn&rsquo;t improve the situation much.</p>
<h2 id="schematics-to-the-rescue">
  <a class="heading-anchor" href="#schematics-to-the-rescue">Schematics to the rescue<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>To understand the role of the missing resistor better, we started looking for schematics online. I managed to find an OK
looking one from a random forum and started browsing through it. The keyword of the day was &ldquo;SPI&rdquo; and when searching for
it, we found some promising results. My friend found the resistor and found that we could just short it, since the
resistor used to be between two wires. And that he did.</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/schematics.png">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/schematics_hu_e238f6bcdf0bfede.webp"
     width="1280"
     height="401"
     loading="lazy"
     decoding="async"
     alt="The missing resistor, as shown on the schematic.">

  </a>
  <figcaption class="center">The missing resistor, as shown on the schematic.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/the-big-short.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/the-big-short_hu_ea2fb8942d0aab25.webp"
     width="1250"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The big short.">

  </a>
  <figcaption class="center">The big short.</figcaption>
</figure>

<p>We attempted to power on the machine again and this time the error sequence was different as the laptop went into some
sort of a party mode with lights flashing. The usual troubleshooting steps didn&rsquo;t work that well here, either, so it&rsquo;s
possible that the stock BIOS image did not like something here.</p>
<p>What we did have was the option of flashing the known-good skulls image on. I handled that part quite OK, since all the
commands were in my bash history anyway. The excitement, however, got the best of me and I managed to repeat the
original mistake and I bumped the soldered piece of wire off of the board, putting us back to the original issue.</p>
<p>After another session of carefully connecting the two wires, we repeated the steps and after the flash, we finally saw
the Skulls splash screen.</p>
<p>It works!</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/it-works-1.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/it-works-1_hu_42b508142a55117a.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Picture taken after the fact, because I forgot to do it initially.">

  </a>
  <figcaption class="center">Picture taken after the fact, because I forgot to do it initially.</figcaption>
</figure>

<p>After booting into a Fedora 34 liveusb environment with <code>iomem=relaxed</code>, I grabbed the latest release of skulls (
released on 4/20 🔥) and used the internal flashing method to update.</p>
<p>Reboot, and we saw party mode again. Having used skulls in the past, I knew that this was likely down to skulls (or
coreboot) being very picky about RAM. The solution here is to reseat the RAM modules and turn it on again. Why does that
work? Not sure, but it did.</p>
<p>To make this solution more resistant to my unintentional attempts of breaking things, I added a glob of hot glue next to
the top chip to make sure that I don&rsquo;t knock anything off of the board again.</p>
<h2 id="testing">
  <a class="heading-anchor" href="#testing">Testing<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Once the laptop was assembled again, I did some testing to see if everything still works as intended.</p>
<p>Fedora 34 liveusb boot resulted in a black screen once, but on the second try, it worked again.</p>
<p>Windows 10 installed fine on the machine and while some functions don&rsquo;t work as well (TrackPoint and touchpad being the
prime examples here), it was still usable. Unfortunately I did not manage to write down the original Windows 10 key that
is embedded to the stock BIOS image, so I could not activate it. But hey, at least it works.</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/it-works-2.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/it-works-2_hu_fc2369c02a72eb2f.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Windows 10 also works.">

  </a>
  <figcaption class="center">Windows 10 also works.</figcaption>
</figure>

<h2 id="lessons-learned">
  <a class="heading-anchor" href="#lessons-learned">Lessons learned<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Even though this adventure started with a self-inflicted wound, I still consider it a success, as I learned a couple of
things.</p>
<ul>
<li>It&rsquo;s very easy to get confused when reviewing how the wires should be set up on the SOIC test clip and the device
that&rsquo;s actually performing the flashing.</li>
<li>If a piece of software exposes a bunch of knobs and levers and warns you about catastrophic failures that might occur
as a result, then trust it and don&rsquo;t mess with things that you have no clue about. With this example case, though, I
didn&rsquo;t expect a memory speed change to result in such a catastrophic failure in the first place&hellip;</li>
<li>Developers that know hardware are worth their weight in gold.</li>
<li>Access to schematics is very valuable when fixing hardware.</li>
</ul>
<p>And on the final note, I would like to give a shout-out to <a href="https://zirk.me/">Arti Zirk</a>, the guy who helped fix the
mess I created. If you need someone who is well-versed in anything related to software development, Linux and embedded
systems, then he is your guy.</p>









<figure class="center">
  <a href="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/the-setup.jpg">
    <img src="/posts/2021/06/28/breaking-and-fixing-thinkpad-x230/media/the-setup_hu_324bc408874b6fe3.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Genius at work.">

  </a>
  <figcaption class="center">Genius at work.</figcaption>
</figure>

<h2 id="flashrom-references">
  <a class="heading-anchor" href="#flashrom-references">flashrom references<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This section has some commands that might be useful to you. Unless you&rsquo;re using the exact same flasher, you will probably
need to specify a different programmer with the <code>-p</code> flag.</p>
<p>The names and extensions for the input-output files are arbitrary. A file is a file.</p>
<h3 id="readingwriting-the-top-chip">
  <a class="heading-anchor" href="#readingwriting-the-top-chip">Reading/writing the top chip.<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>Note that I had to specify the chip type, otherwise <code>flashrom</code> would complain.</p>
<p>The top chip is 4MB and the bottom chip is 8MB. This should also be reflected in any output that you get.</p>
<p><code>--verify</code> option is also useful for checking if the results are OK. I also recommend reading the image from the chip
after a write and comparing its checksum using <code>md5sum</code>, just to be extra safe.</p>
<pre tabindex="0"><code># Read the existing image on the chip
flashrom -p ft2232_spi:type=2232H,port=B,divisor=4 -r top.bin -c MX25L3206E/MX25L3208E 

# Write the specified image to the chip
flashrom -p ft2232_spi:type=2232H,port=B,divisor=4 -w top_backup.bin -c MX25L3206E/MX25L3208E 
</code></pre><h3 id="readingwriting-the-bottom-chip">
  <a class="heading-anchor" href="#readingwriting-the-bottom-chip">Reading/writing the bottom chip<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<pre tabindex="0"><code># Read
flashrom -p ft2232_spi:type=2232H,port=B,divisor=4 -r bottom.bin -c MX25L6406E/MX25L6408E

# Write
flashrom -p ft2232_spi:type=2232H,port=B,divisor=4 -w bottom_backup.bin -c MX25L6406E/MX25L6408E
</code></pre>]]></content:encoded></item><item><title>How to start your self-hosting adventure: a high-level overview</title><link>https://ounapuu.ee/posts/2021/03/17/how-to-start-your-self-hosting-adventure/</link><pubDate>Wed, 17 Mar 2021 15:00:00 +0200</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2021/03/17/how-to-start-your-self-hosting-adventure/</guid><description>Getting started is probably the hardest step.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="How to start your self-hosting adventure: a high-level overview" /><p>Reddit is a great starting point for getting new ideas for your homelab: racks full of machines
in <a href="https://www.reddit.com/r/homelab/">/r/homelab</a>, storage measured in terabytes (or even petabytes) over
at <a href="https://www.reddit.com/r/DataHoarder/">/r/datahoarder</a>, all the different services that people host over at
<a href="https://www.reddit.com/r/selfhosted/">/r/selfhosted</a>. This can be a bit overwhelming for someone just starting out in
this area, which is why I decided to write a small guide on how to start off on your self-hosting adventure.</p>
<h2 id="why-self-host-in-the-first-place">
  <a class="heading-anchor" href="#why-self-host-in-the-first-place">Why self-host in the first place?<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Hobbyists and professionals have a lot of different reasons for self-hosting services. These include (but are not
limited to):</p>
<ul>
<li>it&rsquo;s an excuse to play around with computer hardware and rationalize the purchase of thousands of dollars of hardware</li>
<li>reduce reliance on <a href="https://en.wikipedia.org/wiki/Big_Tech">&ldquo;big tech&rdquo;</a></li>
<li>the services solve an actual problem for the user (home automation, secure file storage, backups etc.)</li>
<li>learning new tech and solutions that otherwise have not come up during their day-to-day work</li>
</ul>
<p>Regardless of the specifics, the main part of the self-hosting experience is to just have fun and work on challenges
that you find interesting.</p>
<h2 id="step-0-find-a-problem-to-solve">
  <a class="heading-anchor" href="#step-0-find-a-problem-to-solve">Step 0: find a problem to solve<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>One of the best motivators for setting up your homelab/self-hosting setup is to solve a real problem that you have.</p>
<p>Do you want to automate your home with <a href="https://www.home-assistant.io/">HomeAssistant</a>?</p>
<p>Or do you want your family to be able to back up their valuable photos and videos to your server
using <a href="https://nextcloud.com/">Nextcloud</a>?</p>
<p>Or do you want to share your media collection with your family and friends using <a href="https://jellyfin.org/">Jellyfin</a>?</p>
<p>It doesn&rsquo;t really matter what solution you end up using or how you do it, as long as it is a secure solution and that
solves your original problem without creating 10 additional ones.</p>
<h2 id="step-1-find-a-place-for-running-your-software">
  <a class="heading-anchor" href="#step-1-find-a-place-for-running-your-software">Step 1: find a place for running your software<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Once you have a problem that you are going to solve, you will need to also find a home for your project to live in. For
this, you have a lot of different options:</p>
<ul>
<li>using a virtual machine at a cloud service provider (DigitalOcean, Linode etc.). Performance is not the best and
beefier configurations can be quite expensive, but this is a reliable option with a fast network.</li>
<li>renting a server from a service provider (example: Hetzner). More performant than a virtual machine at most cloud
service providers, but probably more expensive as well. Usually comes with a fast network.</li>
<li>an old laptop that you have collecting dust on your shelf. Not the fastest or the quietest option, but it does not use
a lot of power.</li>
<li>an old desktop PC. Probably plenty fast for any task that you can throw at it, but its power usage is higher compared
to laptops.</li>
<li>a tiny desktop PC. Low power usage, but can pack quite a punch. For inspiration, check
out <a href="https://www.servethehome.com/introducing-project-tinyminimicro-home-lab-revolution/">Project TinyMiniMicro</a>
by ServeTheHome.</li>
<li>a single-board computer, such as a Raspberry Pi or alternatives. Plenty of performance for most workloads, uses very
little power (5-15W generally) and silent as well.</li>
<li>a second-hand rack-mounted server. Probably quite performant, but uses a lot of power and is very noisy.</li>
<li>a NAS box from one of the more popular providers (Synology, QNAP, TerraMaster etc.). Useful for when you need a lot of
storage on your machine or something that <em>just works</em>.</li>
</ul>
<p>Your choice will likely be affected by other factors as well:</p>
<ul>
<li>your home internet connection. If your ISP does not allow opening ports or if your upload/download speeds are not that
great, then using a cloud service provider or renting a server might be a better option for you.</li>
<li>living in a small apartment will likely rule out noisy solutions, such as full-blown rack-mounted servers or powerful
desktop PC-s.</li>
<li>if all you want to do is local testing, then a virtual machine on your already existing desktop/laptop PC might be a
better fit, as it does not require you to buy any new/used hardware.</li>
<li>reliability and price of electricity. In some countries, running a server in your home might result in a huge power
bill or might not be possible at all due to the power grid being unreliable.</li>
</ul>
<p>The workloads that you plan on running will also have an effect on your chosen approach. You will need to take into
account the resources that your workload requires. It does not make much sense to get a rack-mount server for hosting
your Wordpress blog if a Raspberry Pi can do the same job just as well. On the other hand, running a CPU-heavy service
like Jellyfin on a Raspberry Pi will be a painful experience when compared to running it on a desktop PC or an
enterprise-grade server. If your service will be used by a high number of users, then you might want to opt for a more
powerful machine.</p>
<p>Some solutions may also benefit from faster, SSD-based storage. Loading a lot of smaller files or running a big database
off of hard drives will be noticeably slower than running them off of fast SSD-s.</p>
<p>There is no <em>one size fits all</em> solution. It&rsquo;s better to do a little bit of initial research and use the right tool for
the job. If in doubt, ask for help from someone more experienced.</p>
<h2 id="step-2-find-the-software-solution-that-fits-your-use-case-the-best">
  <a class="heading-anchor" href="#step-2-find-the-software-solution-that-fits-your-use-case-the-best">Step 2: find the software solution that fits your use case the best<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Just like with hardware, there is also a lot of choice when it comes to software.</p>
<p>Some solutions are pretty low-level and require setting up the OS and the services manually. This is not very
user-friendly, but it offers the most potential for learning about your system and how to manage it. This approach will
likely require you to learn new things and pay more attention to automating common tasks (updates, monitoring, backups)
and making sure that everything is secure (no weak passwords, services properly isolated, regular and frequent updates
etc.). If something goes wrong, then you will need to fix it yourself, but at least you have all the tools and knowledge
to do so.</p>
<p><strong>Example:</strong> Debian with ZFS for your main storage and services running using Docker or Podman (my personal preference).</p>
<p>There are also solutions that cater to people who just want to get work done. These solutions usually provide the user
with a web-based user interface that can manage the system and any services that run on it. Do you want to set up your
very own Wordpress blog? Just click this button and you will soon be set up with one without having to even know what
the hell a &ldquo;Docker&rdquo; is. The downside of this approach is that when things go wrong, you will still need to familiarize
yourself with the inner workings of the system. Troubleshooting issues with no preparation and learning new things under
stressful circumstances is not very fun.</p>
<p>Cloud service providers have also started offering <em>one-click</em> solutions to setting up the more popular services. your
very own Minecraft server is just a click away!</p>
<p><strong>Examples:</strong></p>
<ul>
<li>a NAS box from Synology that is aimed towards consumers</li>
<li>VM provided and set up by Linode using a one-click solution in their web UI.</li>
</ul>
<p>And then there are solutions that fit in somewhere in-between. Solutions
like <a href="https://www.truenas.com/">TrueNAS (formerly FreeNAS)</a>
and <a href="https://www.openmediavault.org/">OpenMediaVault</a> are made for users that can probably set things up themselves as
well, but are just too lazy to do it. Using these solutions is not in any way worse than the alternatives. If it solves
a problem and fits your use case, then go ahead and use it! Just keep in mind that you might need to peek under the hood
when there are issues where the GUI cannot help you out.</p>
<p>As always, if in doubt, ask for assistance. It is perfectly fine for you to pick one of the user-friendlier options
first and dig deeper once you feel more comfortable. Self-hosting is not a race, you can do everything at your own pace.</p>
<h2 id="step-3-managing-your-setup">
  <a class="heading-anchor" href="#step-3-managing-your-setup">Step 3: managing your setup<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Once you have everything up and running, there are some topics that you really should pay attention to in order to avoid
big problems down the line.</p>
<h3 id="backups">
  <a class="heading-anchor" href="#backups">Backups<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>If the only copy of your files lives on your NAS and something should happen to them (accidental delete, hard drives
suddenly die, you get hit by ransomware etc.), then you are in a world of hurt. Having backups is a mandatory part of
your self-hosting adventure. A mix of automated and manual backups is better than having no backups at all.</p>
<p>Some ideas for backups:</p>
<ul>
<li>
<p>external hard drive attached to your server that receives automated backups that run on an schedule. Just make sure
that any failures during the backup will be communicated to you (over e-mail, for example). It&rsquo;s also a good idea to
occasionally check if the last backup was successful or not. Downside of this approach is that since this drive is
still connected to the server, it is subject to other events that can shred your data (ransomware, power surges etc.).</p>
</li>
<li>
<p>offline backups that you will manually run on a regular schedule. Example: copying all files from the server to an
external hard drive on the 1st day of each month. If you accidentally delete all files on your server or a piece of
malware does this for you, or if your server is toast due to a power surge, you will still have a copy of the data
that cannot be affected by those kinds of issues.</p>
</li>
<li>
<p>snapshots. While technically not a backup, snapshots do help against accidental deletes. Depending on your setup, you
might be able to retrieve files deleted a week ago if you keep snapshots of your data for the last 30 days.</p>
</li>
<li>
<p>a hard drive at your friends house. Helps protect against the worst case scenario where your house burns down.</p>
</li>
<li>
<p>(encrypted) backups to cloud storage providers, such as Backblaze, OneDrive or Google Drive. It will require a monthly
subscription, but at least you will likely have a copy of the file <em>somewhere</em>. Just keep in mind that if you should
get locked out of the service or fail to pay for it, then you might not be able to access the data hosted at that
service.</p>
</li>
</ul>
<h3 id="security">
  <a class="heading-anchor" href="#security">Security<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>If you are exposing a service to the wild wild west that is the internet, then you will be a target. Automated scanners
will poke your services and if they find a vulnerability, they will use it. To prevent the worst, consider the
following:</p>
<ul>
<li>
<p>keep everything up to date. Don&rsquo;t forget that for some updates to apply (example: kernel updates), you <em>need</em> to
restart the machine. For other services (example: ssh), they can be restarted without restarting the whole machine.
Regular updates will help prevent most security issues.</p>
</li>
<li>
<p>only expose services that you absolutely need to expose. With something like a web server, you really don&rsquo;t have a lot
of choice here, but with services aimed towards a known set of users, you can limit the exposed surface area by using
a VPN or enforcing other restrictions (whitelisted IP addresses, fail2ban to block most intrusion attempts, etc.).</p>
</li>
<li>
<p>make sure that your configuration is correct. A lot of intrusions are caused by configuration issues that usually end
up with a service being exposed to the web without any passwords or other protections set up. It&rsquo;s a good idea to
check if you are accidentally exposing too much by checking what others are seeing when they try to connect to your
service.</p>
</li>
<li>
<p>try to set up your services so that you are prepared for an intrusion. If the attacker is able to take control of
service X, but it is completely isolated from other services and devices on the network, then the damage they can do
is likely limited.</p>
</li>
</ul>
<h3 id="monitoring">
  <a class="heading-anchor" href="#monitoring">Monitoring<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>Your setup will likely have issues. Hard drives might die, or the CPU might be overheating due to years of dust
accumulation, or one service might be using up all the available resources, causing others to slow down as well. A
better understanding of what your system is doing will help out a lot here.</p>
<p>Cloud hosting service providers usually provide at least a basic level overview of your resource usage: CPU, RAM, disk,
network etc. If you are running your own machine, then you will need to figure this out on your own.</p>
<p>To understand what your system is doing, a tool like <a href="https://www.netdata.cloud/">Netdata</a> is a good starting point. If
your server slows down, then you can most likely pinpoint the reason by looking at the resource indicators.</p>
<p>It is not realistic for you to keep an eye on all the indicators all the time, so having some kind of alerting set up is
also a great idea. Events, such as a hard drive starting to throw errors, the CPU usage being at 100% for more than an
hour, or a service not being reachable, are all something that you might be interested in hearing about.</p>
<p>You don&rsquo;t have to monitor everything and have alerts set up to catch everything, but it is a great starting point for
responding to issues proactively. Ending up with all your data lost because you did not hear about hard drive failures
is not a great situation to be in.</p>
<h2 id="what-next">
  <a class="heading-anchor" href="#what-next">What next?<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>If you have reached this point, then you are probably aware of most of the topics that will come up during your
self-hosting adventure. You will encounter issues that will be specific to the approach that you have chosen at the
hardware and software steps, but that&rsquo;s perfectly normal. Most of these issues have solutions that are one search away,
and if you have trouble figuring something out, then feel free to ask for help!</p>
<p>If you need new ideas, then check out the subreddits mentioned at the start of this post, you might find some gems in
there! Do keep in mind that you will likely end up in an endless loop of building something, being happy with it for a
week and finding something else to try out. It&rsquo;s really fun, though.</p>
]]></content:encoded></item><item><title>My attempt at archiving nfscars.net</title><link>https://ounapuu.ee/posts/2021/03/01/my-attempt-at-archiving-nfscars.net/</link><pubDate>Mon, 01 Mar 2021 09:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2021/03/01/my-attempt-at-archiving-nfscars.net/</guid><description>Nostalgia is one hell of a drug.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="My attempt at archiving nfscars.net" /><p>2025 June update: the contents of my archive are now easily accessible over
at <a href="https://www.nfs-cars.com/">nfs-cars.com, a read-only static website that hosts content that was previously on nfscars.net.</a>
I&rsquo;m not affiliated with that website, but I&rsquo;m very happy that it exists!</p>
<h2 id="background">
  <a class="heading-anchor" href="#background">Background<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>My mother once had a laptop: the Compaq Armada 1592DT. It came with Windows ME which later got &ldquo;upgraded&rdquo; to Windows 98
SE
after I managed to completely screw up the OS, a whopping 96MB of RAM and a hard drive that probably wasn&rsquo;t much larger
than 1-3GB. It wasn&rsquo;t powerful or anything, but some of my earliest memories of playing video games on that thing were
related to Sports Car GT and Need for Speed III Hot Pursuit. Yes, both were demos, and the performance was probably in
the 10-20FPS range, but it was still great for a younger me. That laptop eventually got replaced by a Windows 98 based
desktop which wasn&rsquo;t a lot better with its 64MB of RAM, but it could play RuneScape (barely) and also Need for Speed
III.</p>
<p>Need for Speed III Hot Pursuit holds a very special place in my heart. It looked great at the time, the police chases
were
fun and challenging, the soundtrack was fantastic and the track featured in the demo (Rocky Pass) is still something I
could probably draw up from memory, assuming that I could draw. At some point I discovered that it is possible to mod
the game to include new cars and tracks, which resulted in ridiculous speeds, cars that could absolutely destroy the
police cars, and lots and lots of game crashes. One of the sources for these mods
was <a href="https://www.nfscars.net/">nfscars.net</a>.</p>
<h2 id="nfscarsnet">
  <a class="heading-anchor" href="#nfscarsnet">nfscars.net<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Depending on when you will be reading this, nfscars.net is/was a website that hosts/hosted thousands cars, tracks and
other
mods for various Need for Speed titles. In 2020, I decided to check this site out again to see if it is still
operational.</p>
<p>The last post referred to an &ldquo;upcoming&rdquo; NFS title that was already released a year ago.</p>
<p>The link to the forums resulted in an error page being shown.</p>
<p>Should the site suddenly disappear without any warning, all the content would be lost. Since I have a small datahoarding
bug, I decided to take matters into my own hands and do my best to archive the contents of the site. That, and nostalgia
for the old Need for Speed titles was what pushed me to start this archiving adventure.</p>
<h2 id="initial-efforts">
  <a class="heading-anchor" href="#initial-efforts">Initial efforts<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Before trying any fancy technical solutions to crawl the site and get all of the assets that way, I decided to start
from
the source and tried contacting the site owner to arrange the download of the assets. That did not work out at all,
since the contact e-mails were either not active or the inboxes were full.</p>
<p>I signed up for the site and tried to message some user accounts which hopefully were related to someone who was in
charge.
No dice.</p>
<p>There is a small chatroom on the site named &ldquo;Shoutbox&rdquo;, so I tried asking about the site owners there. It seems that a
couple of users are still occasionally chatting there, mainly about random topics and spammy users. Unfortunately none
of the users there - even the moderators - could not assist with setting up a backup of the site.</p>
<p>With the domain (potentially) expiring on 2021-05-02, I felt like I had to act now, because the site was probably
running
on borrowed time.</p>
<h2 id="technical-solutions">
  <a class="heading-anchor" href="#technical-solutions">Technical solutions<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I checked a selection of solutions for performing a crawl on the site and decided
on <a href="https://github.com/internetarchive/heritrix3">Heritrix</a>,
mainly due to this being backed by the <a href="https://archive.org/">Internet Archive</a>.
If they cannot get archiving right, then who can?</p>
<p>Setting up Heritrix turned out to be quite a hassle. There does not seem to be a quick guide that you can follow to
get started in 5 minutes. After stumbling around, learning the config file format and understanding that the best way
to configure crawls was to do it externally with a text editor, I was set up to launch my first crawl. Even then, I hit
some roadblocks:</p>
<ul>
<li>The crawl was slow. I understand that Heritrix is just trying to be polite here, but if you have millions of URL-s to
crawl and the site might go down at any moment, then time really isn&rsquo;t on your side.</li>
<li>Checkpointing is supported, but for some reason the default configuration does not enable it. If the machine that you
are running this on should restart, then your crawl will be stopped and you cannot resume at that point, you can only
start
over.</li>
<li>Heritrix is based on Java, which means that <em>theoretically</em> it should run on anything that runs Java, such as an ARM
CPU based SBC. However, I ran into weird <code>java.nio</code> related issues with symlinking on those platforms and I just could
not get them resolved.</li>
<li>If you run too many crawls at once, then Heritrix is perfectly capable of killing your LAN by using up all the
available
connections. It managed to rack up 16000+ active connections, which hit the 16384 connection limit on my
consumer-grade
router. That was not fun to debug.</li>
<li>Automatically continuing crawls from a checkpoint on system startup requires you to use the Heritrix API, which isn&rsquo;t
too complicated, but I just wish that this was another feature that it supported out of the box.</li>
</ul>
<p>After messing up a couple of times and trying again, I finally managed to complete a crawl of the site. This only took 6
months,
where the crawl itself ran for 3 months. <strong><em>MONTHS!</em></strong></p>
<h2 id="what-the-hell-is-a-warc">
  <a class="heading-anchor" href="#what-the-hell-is-a-warc">What the hell is a WARC?<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Heritrix collects the results of the crawl into a special format
called <a href="https://en.wikipedia.org/wiki/Web_ARChive">WARC</a>,
which it then compresses, resulting in lots of little <code>.warc.gz</code> files. If you extract one of these, you will end up
with
a <code>.warc</code> file.</p>
<p>To extract files from a WARC file, you
need <a href="https://wiki.archiveteam.org/index.php/The_WARC_Ecosystem">one of these tools listed here</a>.
After trying a couple, I decided to go with <a href="https://github.com/chfoo/warcat">warcat</a> since it seemed to mostly work and
it supported combining smaller WARC files into bigger ones and extracting the contents.</p>
<p>Depending on the size of the site, the extracting process might take a while. Crawls can contain thousands or even
millions
of small little files, and if you are using hard drives for storing these, then it will be slow. I have not done testing
on an SSD, but it will probably be much faster due to its superior random I/O performance.</p>
<p>Once I had extracted the contents, I did some checking to see if the assets that I care about are present in the crawl.
Did a file search for a modded car in Need for Speed III.</p>
<p>No results.</p>
<p>Okay, that&rsquo;s odd. Tried it with another file name.</p>
<p>No results.</p>
<p>Well, what <em>do</em> we have? I checked the extracted contents using <code>ncdu</code> and found that while Heritrix managed to grab a
lot
of the webpages and the images from the galleries, it failed to download files, such as .zip and .rar files that contain
the modifications themselves.</p>
<h2 id="getting-the-final-pieces-of-the-puzzle">
  <a class="heading-anchor" href="#getting-the-final-pieces-of-the-puzzle">Getting the final pieces of the puzzle<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I started investigating the download functionality of the site. On every page load, the download link would have a new
identifier attached to it. Upon clicking on it, the download would start. If you wait too long, then the download link
would expire.</p>
<p>Firefox has a handy feature where you can copy the request into a <code>curl</code> command. I did that, added some parameters to
it
so that it would use the filename that comes from the response header and made it save the file to disk. It worked!</p>
<p>Now I had to figure out how to collect all of these download links. The site has sections for each game, which is also
reflected in the URL. However, I found that when you navigate to the page of a mod and change the numerical ID at the
end,
you could cycle through all the cars, tracks and other tools for <em>all</em> games, even if the URL was technically referring
to one game in the series.</p>
<p>After bashing around for a while, I came up with this masterpiece:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span>cd /your/download/destination <span style="color:#f92672">||</span> exit <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> index in <span style="color:#f92672">{</span>1..18050<span style="color:#f92672">}</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Index at </span>$index<span style="color:#e6db74">, starting.&#34;</span>
</span></span><span style="display:flex;"><span>  filePath<span style="color:#f92672">=(</span><span style="color:#66d9ef">$(</span>curl --silent https://www.nfscars.net/need-for-speed-hot-pursuit/1/files/view/$index/ -H <span style="color:#e6db74">&#39;Cookie: csrftoken=XXX; sessionid=YYY&#39;</span> | grep -oE <span style="color:#e6db74">&#34;files/download/send/[0-9]+/[0-9a-zA-Z]+&#34;</span><span style="color:#66d9ef">)</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;File path: </span>$filePath<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Making directory </span>$index<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>  mkdir -p <span style="color:#e6db74">&#34;</span>$index<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Going into directory </span>$index<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>  cd $index
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">for</span> path in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>filePath[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Starting download on path https://www.nfscars.net/</span>$path<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    curl --silent <span style="color:#e6db74">&#34;https://www.nfscars.net/</span>$path<span style="color:#e6db74">&#34;</span> -H <span style="color:#e6db74">&#39;User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0&#39;</span> -H <span style="color:#e6db74">&#39;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&#39;</span> -H <span style="color:#e6db74">&#39;Accept-Language: en-US,en;q=0.5&#39;</span> --compressed -H <span style="color:#e6db74">&#39;Connection: keep-alive&#39;</span> -H <span style="color:#e6db74">&#39;Referer: https://www.nfscars.net/need-for-speed-hot-pursuit/1/files/view/1/&#39;</span> -H <span style="color:#e6db74">&#39;Cookie: csrftoken=XXX; sessionid=YYY&#39;</span> -H <span style="color:#e6db74">&#39;Upgrade-Insecure-Requests: 1&#39;</span> -OJ
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Download </span>$path<span style="color:#e6db74"> done.&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  cd /your/download/destination 
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Back in home dir. Index </span>$index<span style="color:#e6db74"> end.&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p>Not the prettiest script around, but it did the trick. In a day or so the assets were downloaded and you could use the
index to connect these to a page that is contained in the crawl.</p>
<h2 id="results">
  <a class="heading-anchor" href="#results">Results<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>All this effort would be for nothing if I didn&rsquo;t share my results, so I decided to pack these up and serve them for
anyone
that wants to keep a backup of at least one part of Need for Speed history.</p>
<p>The archived content can be found <a href="https://archive.org/details/nfscars.net.2020.">on the Internet Archive</a>.
<a href="https://archive.org/details/nfscars.net.2021">Here&rsquo;s a newer crawl from 2021.</a></p>
<p>The torrent files are also mirrored here:</p>
<ul>
<li>
<p><a href="/misc/archive/torrents/nfscars.net.2020.zip.torrent">2020 crawl</a></p>
</li>
<li>
<p><a href="/misc/archive/torrents/nfscars.net.2021.zip.torrent">2021 crawl</a></p>
</li>
</ul>
<p>Pieces of history get lost all the time with sites going offline. I&rsquo;m hoping that at least with this effort I have
managed
to do my part in preserving a tiny piece of it.</p>
<h2 id="2021-03-15-update">
  <a class="heading-anchor" href="#2021-03-15-update">2021-03-15 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The site seems to be down at the moment and has been for a couple of days. Oh no.</p>
<h2 id="2021-03-20-update">
  <a class="heading-anchor" href="#2021-03-20-update">2021-03-20 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Somehow the site is alive again.</p>
<h2 id="2024-08-20-update">
  <a class="heading-anchor" href="#2024-08-20-update">2024-08-20 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It&rsquo;s dead.</p>
<p>However, I&rsquo;m delighted
to <a href="https://www.reddit.com/r/needforspeed/comments/1dc6bva/comment/l9otz0z/">find people using this archive to get their favourite mods!</a></p>
<p><a href="https://www.nfsaddons.com/forums/index.php?topic=2672.msg41002#msg41002">This post includes a guide on how to match up your favourite mod with the correct filename in my archive.</a>
I do wish that I had more time to properly organize that archive while creating it&hellip;</p>
<h2 id="2025-06-10-update">
  <a class="heading-anchor" href="#2025-06-10-update">2025-06-10 update<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>I learned that there exists a browsable mirror of the nfscars.net
archive! <a href="https://www.nfs-cars.com/">You can find it on nfs-cars.com.</a>
I&rsquo;m very happy that it exists.</p>
]]></content:encoded></item><item><title>How to fix ZFS pool not importing at boot</title><link>https://ounapuu.ee/posts/2021/02/01/how-to-fix-zfs-pool-not-importing-at-boot/</link><pubDate>Mon, 01 Feb 2021 08:45:27 +0200</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2021/02/01/how-to-fix-zfs-pool-not-importing-at-boot/</guid><description>You have probably tried Stack Exchange and reddit at this point, so what do you have to lose?</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="How to fix ZFS pool not importing at boot" /><h2 id="issue-description">
  <a class="heading-anchor" href="#issue-description">Issue description<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>You are running a Linux-based machine with an install of ZFS on Linux. Everything seems to work correctly, but
after restarting your machine, the ZFS pool is not visible. You can still import your pool manually using
<code>zpool import poolname</code> or <code>zpool import -a</code>.</p>
<p>In my situation, this issue does not occur with Debian 10 on an x86-based machine, but it does occur on a Raspberry Pi 4
running Ubuntu Server 20.04.1 LTS.</p>
<p>Setup:</p>
<ul>
<li>Raspberry Pi 4 (4GB)</li>
<li>Ubuntu Server 20.04.1</li>
<li>32GB microSD card for root filesystem</li>
<li>2x 8TB WD Elements external USB 3.0 drives (ZFS mirror)</li>
</ul>
<h2 id="potential-causes-and-solutions">
  <a class="heading-anchor" href="#potential-causes-and-solutions">Potential causes and solutions<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>When looking this issue up, there were many potential causes and solutions provided:</p>
<ul>
<li><a href="https://unix.stackexchange.com/a/338522">ensure that all ZFS related services are enabled</a></li>
<li><a href="https://serverfault.com/a/915191">add a startup delay in ZFS related configuration files</a></li>
<li><a href="https://serverfault.com/a/915191">just import the pools (duh)</a></li>
<li><a href="https://www.reddit.com/r/zfs/comments/9j714p/ubuntu_1804_zpool_mount_on_boot_does_not_work/e6p6zu0/">recreate the ZFS cache file</a></li>
</ul>
<p>In my specific scenario, none of these seemed to do the trick.</p>
<h2 id="investigation">
  <a class="heading-anchor" href="#investigation">Investigation<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>The ZFS pools should be automatically imported on boot by a service named <code>zfs-import-cache.service</code>. The cache file
should contain information about the imported pools.</p>
<p>Once you have started your system and don&rsquo;t see any ZFS pools available, try running <code>systemctl status zfs-import-cache.service</code>
or <code>journalctl -u zfs-import-cache.service</code>. This should show you if the automatic import succeeded or not.</p>









<figure class="center">
  <a href="/posts/2021/02/01/how-to-fix-zfs-pool-not-importing-at-boot/media/zpool-import-fail.png">
    <img src="/posts/2021/02/01/how-to-fix-zfs-pool-not-importing-at-boot/media/zpool-import-fail_hu_b0e51bb16973b5be.webp"
     width="963"
     height="285"
     loading="lazy"
     decoding="async"
     alt="In my case, the failure shows up like this.">

  </a>
  <figcaption class="center">In my case, the failure shows up like this.</figcaption>
</figure>

<p>The pool <code>tanker</code> is a ZFS mirror that is supported by two 8TB WD Elements external hard drives. They are big, loud and
require some time to spin up the platters before you can actually read data off of them. At this point in the investigation,
a good friend recommended that I check what disks were recognized by the system at the time when this import service was
starting up.</p>
<p>For that, you need to modify the systemd service by running <code>systemctl edit zfs-import-cache.service</code> and put these contents
in there:</p>
<pre tabindex="0"><code>[Service]
ExecStartPre=/usr/bin/lsblk
</code></pre><p>This addition will run the <code>lsblk</code> command before the command specified in the systemd service is actually executed.
The output of this command will be visible in the service logs. After making this addition, reboot your system and run
<code>journalctl -u zfs-import-cache.service</code> again. You should be able to see all the connected drives on the system.</p>
<p>In my case, the system recognized the microSD card and an SSD that was connected over USB, but not the hard drives. This
was a very clear indication that the system was not waiting until the drives had spun up before attempting to import the
ZFS pool.</p>
<h2 id="hacky-solution">
  <a class="heading-anchor" href="#hacky-solution">Hacky solution<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>To resolve this issue quickly and move on with more interesting things, you can use the same trick that we used for
troubleshooting this issue, but instead of listing the connected hard drives, we can make the systemd service delay its
execution by putting a <code>sleep</code> statement in there.</p>
<p>Edit the systemd service again with <code>systemctl edit zfs-import-cache.service</code> and replace the contents with this:</p>
<pre tabindex="0"><code>[Service]
ExecStartPre=/usr/bin/sleep 15
</code></pre><p>This will make the service sleep for 15 seconds before importing the ZFS pool(s). It could be 10, or 30, or whatever value
works for you, 15 seconds was chosen here because it is more than enough time for the disks to spin up.</p>
<h2 id="proper-solution-probably">
  <a class="heading-anchor" href="#proper-solution-probably">Proper solution (probably)<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>There are probably better solutions, such as messing around with udev rules or enforcing the delay somewhere else in the
ZFS pool import chain of operations, but I have not investigated them at this point. Feel free to contact me with a better
solution, and I will update the post accordingly.</p>
]]></content:encoded></item><item><title>How to make digital copies of your old video tapes</title><link>https://ounapuu.ee/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/</link><pubDate>Sun, 27 Dec 2020 18:00:00 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/</guid><description>Or 'Wow, I did not know that VLC could do _that_!'</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="How to make digital copies of your old video tapes" /><h2 id="introduction">
  <a class="heading-anchor" href="#introduction">Introduction<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This is a short overview of one way to take your old video tapes and make digital copies of their contents.</p>
<p>To get started, you will need the following:</p>
<ul>
<li>old video tapes that you want to make copies of (VHS and its variants)</li>
<li>a device that can read analog AV signals and convert them to digital signals</li>
<li>a device that can play back the tapes (VHS player, camcorder etc.)
<ul>
<li>in this example, we will be using a camcorder that has video playback capabilities.</li>
</ul>
</li>
<li>a computer with enough free space to store the digital copies
<ul>
<li>for VHS and H.264+MP3, this means roughly 1.5GB of space for 1 hour of footage</li>
</ul>
</li>
<li><a href="https://www.videolan.org/vlc/index.html">VLC media player</a></li>
<li>time and patience</li>
</ul>
<p>In this example, we will be using the <a href="https://nedis.com/en-us/product/computer/imaging/media-converters/550670251/video-grabber-av-cable-scart-software-included-usb-20">Nedis VGRRU100BK</a>.
Not because it is any good, it was just something we had access to.</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-20-00-44-47-1997.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-20-00-44-47-1997_hu_333b06cc2ed0b1d0.webp"
     width="1024"
     height="768"
     loading="lazy"
     decoding="async"
     alt="Nedis VGRRU100BK - front.">

  </a>
  <figcaption class="center">Nedis VGRRU100BK - front.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-20-00-44-57-1998.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-20-00-44-57-1998_hu_63e0303a299b57aa.webp"
     width="1024"
     height="768"
     loading="lazy"
     decoding="async"
     alt="Nedis VGRRU100BK - back.">

  </a>
  <figcaption class="center">Nedis VGRRU100BK - back.</figcaption>
</figure>

<h2 id="the-process">
  <a class="heading-anchor" href="#the-process">The process<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<h3 id="step-1-setting-up-the-physical-devices">
  <a class="heading-anchor" href="#step-1-setting-up-the-physical-devices">Step 1: setting up the physical devices<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>Set up your video playback device so that it can play the cassettes that you are planning to record.</p>
<p>Connect the AV output cables (composite or S-video) to the input of the USB device. For this specific device,
it means connecting the appropriate composite AV cables together and connecting them to the USB stick using a
proprietary connector.</p>
<p>The end result might look something like this:</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-12-06-1986.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-12-06-1986_hu_4f27c894bddbd740.webp"
     width="1024"
     height="768"
     loading="lazy"
     decoding="async"
     alt="Overview of the setup used in this example.">

  </a>
  <figcaption class="center">Overview of the setup used in this example.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-12-22-1988.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-12-22-1988_hu_b232568158040b80.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The USB capture device connected to the PC.">

  </a>
  <figcaption class="center">The USB capture device connected to the PC.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-13-58-1994.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-13-58-1994_hu_8139b292c10db2c5.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="We are using a camcorder to play back the video in this case.">

  </a>
  <figcaption class="center">We are using a camcorder to play back the video in this case.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-14-34-1995.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-14-34-1995_hu_f99d25dc65353ecb.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Video outputs on the camcorder. Yes, that is mono sound.">

  </a>
  <figcaption class="center">Video outputs on the camcorder. Yes, that is mono sound.</figcaption>
</figure>










<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-14-40-1996.jpg">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/20-12-19-18-14-40-1996_hu_1e3a52017a59b3d9.webp"
     width="600"
     height="800"
     loading="lazy"
     decoding="async"
     alt="Video output -&gt; USB capture card input.">

  </a>
  <figcaption class="center">Video output -&gt; USB capture card input.</figcaption>
</figure>

<h3 id="step-2-testing-the-initial-display-output">
  <a class="heading-anchor" href="#step-2-testing-the-initial-display-output">Step 2: testing the initial display output<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>In this example, we will be using VLC to play and record the videos. We are using Linux here, but
the process should be very similar on Windows.</p>
<p>Open up VLC.</p>
<p>In the top-left corner, click on <code>Media</code> and select <code>Open Capture device...</code>.</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-14-14.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-14-14_hu_dacb8a6af5310b07.webp"
     width="559"
     height="456"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p>You should see a screen similar to this one:</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-16-40.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-16-40_hu_b439be1dc208358f.webp"
     width="703"
     height="539"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p>Your computer probably has multiple options for selecting audio and video devices, since microphones
and webcams will likely show up here. If you are unsure which one is the correct one, go through each one-by-one
until you find the options that work.</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-16-47.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-16-47_hu_b05c7d510875730.webp"
     width="704"
     height="534"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>










<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-16-55.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-16-55_hu_3fdc2406d1bcefa8.webp"
     width="711"
     height="547"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p>In this example, our video capture device is named <code>/dev/video2</code> and the audio feed for the capture device
is <code>hw:4,0</code>.</p>
<p>In the bottom-left corner, you have the option to play back the video signal directly in VLC. You can use this to check
which video and audio device is the correct one.</p>
<p>If all goes well, you should be able to see the output in VLC:</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-17-48.png">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-17-48_hu_27f8fef6c16b1a62.webp"
     width="1280"
     height="720"
     loading="lazy"
     decoding="async"
     alt="Camcorder output being streamed to VLC using the USB capture device.">

  </a>
  <figcaption class="center">Camcorder output being streamed to VLC using the USB capture device.</figcaption>
</figure>

<h3 id="step-3-recording">
  <a class="heading-anchor" href="#step-3-recording">Step 3: recording<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>Once you have found the correct configuration, you can click on the arrow next to the <code>Play</code> button and
select the <code>Convert</code> option.</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-17-03.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-17-03_hu_86f0c824d30728f8.webp"
     width="723"
     height="686"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p>In this view, you can configure <a href="https://en.wikipedia.org/wiki/Deinterlacing">deinterlacing</a>,
select the video profile, and set where the resulting video file will be saved.</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-19-19.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-19-19_hu_1e17944a939cab5f.webp"
     width="589"
     height="564"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p>For our purposes, we have chosen to deinterlace the video, since it provided a higher quality output,
and we have stuck with MP4 as the output format because it is an acceptable default option for us.</p>
<p>Displaying the output while converting the video did not work for us and that might be related to
how VLC accesses the video feed in Linux (only one program can read the stream at a time, it seems).</p>
<p>You can now click <code>Start</code> in VLC to start recording the video. You will also need to hit <code>Play</code> on your video playback
device.</p>









<figure class="center">
  <a href="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-19-53.png" aria-label="View full-size image">
    <img src="/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/media/2020-12-19-18-19-53_hu_b6adf27f2c0540ce.webp"
     width="1280"
     height="720"
     loading="lazy"
     decoding="async"
     alt="">

  </a>
  
</figure>

<p>Wait until the VHS tape has finished playing and then hit the stop button in VLC.</p>
<h3 id="step-4-verify-results">
  <a class="heading-anchor" href="#step-4-verify-results">Step 4: verify results<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>You can now open the resulting video file and check the results.</p>
<p>If you have additional VHS tapes to record, then repeat step 3.</p>
<h2 id="troubleshooting-notes">
  <a class="heading-anchor" href="#troubleshooting-notes">Troubleshooting notes<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>There were some challenges to get this setup working.</p>
<h3 id="not-able-to-read-the-output-from-the-usb-capture-device">
  <a class="heading-anchor" href="#not-able-to-read-the-output-from-the-usb-capture-device">Not able to read the output from the USB capture device<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>Being able to read the video signal from the USB capture device turned out to be a headache.
The software that comes with the USB capture device (Arcsoft ShowBiz) had issues displaying the video signal
and was generally unreliable and crashing.</p>
<p>Other software, like OpenShot and Kdenlive video editors, could not recognize the video capture device.</p>
<p>Since we found that this USB capture device emulates an USB webcam, we tried viewing its signal using
a browser or a camera app in the OS (Cheese in Linux, Camera in Windows), but that did not work out either.</p>
<p>We eventually found success with VLC and then chose it for performing our video recording effort. It has multiple advantages
over the software shipped with the capture device itself:</p>
<ul>
<li>it just works</li>
<li>free and open source, meaning that you can do your recording on different platforms</li>
<li>no need for a license key</li>
<li>up to date (Arcsoft ShowBiz installation files were unchanged since 2012)</li>
</ul>
<p>VLC truly is a Swiss army knife for media playback and recording.</p>
<h3 id="vhs-playback-troubles">
  <a class="heading-anchor" href="#vhs-playback-troubles">VHS playback troubles<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h3>
<p>We initially tried the recording process with a proper VHS player, but while recording the footage
and reviewing it later, we noticed that at random points the VHS player had fast-forwarded
over portions of the video.</p>
<p>The camcorder did not exhibit this behaviour, so we went with that. However, with the camcorder we could only
output mono sound, which means that the resulting video file will only have one sound channel present. This will
be especially noticeable when listening to the recorded footage using headphones. To fix this, we
used <a href="https://handbrake.fr/">HandBrake</a> to copy the single audio channel to both channels, which resolved that issue for us.</p>
]]></content:encoded></item><item><title>The little Wi-Fi AP that could</title><link>https://ounapuu.ee/posts/2020/07/23/the-little-wifi-ap-that-could/</link><pubDate>Thu, 23 Jul 2020 01:17:30 +0300</pubDate><author>ihavesomethoughtsonyourblog@ounapuu.ee (Herman Õunapuu)</author><guid>https://ounapuu.ee/posts/2020/07/23/the-little-wifi-ap-that-could/</guid><description>Depends on your definition of _could_.</description><content:encoded><![CDATA[<img src="https://ounapuu.ee/media/cover_hu_4fe4cf2661554252.jpg" width="1200" height="630" alt="The little Wi-Fi AP that could" /><p>I have a bad habit of testing things whenever a &ldquo;good&rdquo; idea pops into my head. This is a short overview of one of them.</p>
<p>The <a href="http://linux-sunxi.org/Xunlong_Orange_Pi_Zero">Orange Pi Zero</a> is a SBC (single board computer) that has a slow 32-bit ARM 4 core CPU, 512MB of RAM and no display output.
It&rsquo;s actually quite OK for many tasks, such as reverse proxy (assuming 100Mbit/s is enough for you), low-performance
NAS (assuming you are fine with 10-12MB/s file transfer speeds) or a Syncthing relay. Oh, and you can also turn it into
a Wi-Fi access point.</p>









<figure class="center">
  <a href="/posts/2020/07/23/the-little-wifi-ap-that-could/media/wifi-ap.jpg">
    <img src="/posts/2020/07/23/the-little-wifi-ap-that-could/media/wifi-ap_hu_b66fbeeb649becd7.webp"
     width="1067"
     height="800"
     loading="lazy"
     decoding="async"
     alt="The Wi-Fi access point in its natural habitat.">

  </a>
  <figcaption class="center">The Wi-Fi access point in its natural habitat.</figcaption>
</figure>

<h2 id="why">
  <a class="heading-anchor" href="#why">Why?<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Because <a href="https://www.armbian.com/">Armbian</a> made it really easy to test out and I was interested in seeing what kind of
performance an old USB Wi-Fi dongle could offer. This cheap AP could also come into handy in situations where my main
access point dies for some reason.</p>
<h2 id="how">
  <a class="heading-anchor" href="#how">How?<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>Go to the <a href="https://www.armbian.com/orange-pi-zero/">Armbian device page for your SBC</a> and download the latest image, then
write it to your microSD card using the tool of your choice, start your SBC and finish the initial setup.</p>
<p>After all that is done, start <code>armbian-config</code> as root. This tool allows you to do many things over a terminal UI, including
a no-hassle method of setting up an Wi-Fi AP.</p>
<p>The option you are looking for is under <code>Network -&gt; Hotspot</code>.</p>









<figure class="center">
  <a href="/posts/2020/07/23/the-little-wifi-ap-that-could/media/armbian-config-1.png">
    <img src="/posts/2020/07/23/the-little-wifi-ap-that-could/media/armbian-config-1_hu_86a28d26c03eeca9.webp"
     width="710"
     height="403"
     loading="lazy"
     decoding="async"
     alt="This image will likely be way out of date in a couple of years.">

  </a>
  <figcaption class="center">This image will likely be way out of date in a couple of years.</figcaption>
</figure>

<p>Follow the on-screen instructions to set everything up. After the initial setup is done, make sure to navigate to the same
menu again to change the SSID and the Wi-Fi password because the defaults are horribly insecure.</p>
<p>After all this you should be good to go!</p>
<h2 id="issues-and-troubleshooting-tips">
  <a class="heading-anchor" href="#issues-and-troubleshooting-tips">Issues and troubleshooting tips<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It would not be a proper project if something didn&rsquo;t go wrong in the process.</p>
<p>Before starting this configuration, run <code>ip a</code> to see if your Wi-Fi device is present. In my case the Orange Pi Zero also
has onboard Wi-Fi, but that particular one has poor support, so I use an USB Wi-Fi dongle instead.</p>
<p>If your Wi-Fi device is not showing up, make sure that the correct firmware is present. In my case I had to install
<code>firmware-atheros</code> package so that my <code>ath9k_htc</code> based Wi-Fi adapter would start working. <code>dmesg</code> and <code>lsusb -v</code> can help determine
what chip your Wi-Fi adapter is using and what driver it needs.</p>
<p>The Orange Pi Zero that I have could set everything up, but it would crash hard with the logs not really showing much.
After testing the USB Wi-Fi adapter in all the different USB ports with no success, I opted to use <code>armbian-config</code> menu <code>System -&gt; CPU</code>
to limit the CPU clock speed to 480MHz and set the CPU governor to <code>performance</code> to rule out power delivery issues that might be caused by
variations in CPU power usage. That seems to have done the trick, because after that change the Wi-Fi AP has been rock solid.</p>
<h2 id="testing-and-conclusions">
  <a class="heading-anchor" href="#testing-and-conclusions">Testing and conclusions<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>After setting it up and tweaking it a bit I started testing this thing out. The AP had no major issues
throughout the day and did not crash.</p>
<p>The performance, however, isn&rsquo;t anything to write home about. Speed maxes out at 30Mbit/s and is generally lower than that,
especially when more than one client is connected. You can do things like Steam Remote Play (stream your game over your home network),
but the quality will suffer. It was still quite fun to mess around in GTA V regardless of the image quality and during ~1h
of play time there were only 4-5 stutters that were caused by the network.</p>









<figure class="center">
  <a href="/posts/2020/07/23/the-little-wifi-ap-that-could/media/i-am-speed.png">
    <img src="/posts/2020/07/23/the-little-wifi-ap-that-could/media/i-am-speed_hu_a2e4f1e9419a97f.webp"
     width="223"
     height="185"
     loading="lazy"
     decoding="async"
     alt="I am speed.">

  </a>
  <figcaption class="center">I am speed.</figcaption>
</figure>

<p><strong>Would I use this as my main Wi-Fi access point?</strong></p>
<p>Definitely not. Any half-decent router will out-perform this setup.</p>
<p><strong>Can it still be useful?</strong></p>
<p>Definitely. A crappy Wi-Fi AP is better than no AP.</p>
<h2 id="parts-list">
  <a class="heading-anchor" href="#parts-list">Parts list<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<ul>
<li>Orange Pi Zero SBC (512MB RAM)</li>
<li>Orange Pi Zero expansion board (adds two USB 2.0 ports)</li>
<li>Cheap case for the Orange Pi Zero</li>
<li>32GB Sandisk microSD card</li>
<li>TP-Link WN-722N USB Wi-Fi adapter</li>
<li>Official Raspberry Pi microUSB power adapter</li>
</ul>
<h2 id="update-2020-08-22">
  <a class="heading-anchor" href="#update-2020-08-22">Update (2020-08-22)<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It&rsquo;s still working and is happily serving as a <em>temporary</em> Wi-Fi access point.</p>
<p>During additional testing I could also hit 40 Mbps speeds when testing in an environment with
far fewer competing Wi-Fi access points nearby.</p>
<h2 id="update-2020-08-30">
  <a class="heading-anchor" href="#update-2020-08-30">Update (2020-08-30)<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>It&rsquo;s still running well and it seems that it won&rsquo;t be a simple temporary
solution after all.</p>
<h2 id="update-2020-11-30-approximately">
  <a class="heading-anchor" href="#update-2020-11-30-approximately">Update (2020-11-30, approximately)<svg class="heading-anchor__icon" viewBox="0 0 24 24" width="0.75em" height="0.75em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</h2>
<p>This setup has now been retired. It had 0 issues throughout its lifespan as a Wi-Fi access point, but I replaced
it with a more standard Wi-Fi access point so that this board can be used somewhere else.</p>
<p>The setup did surprisingly well and even survived nightly automated updates and restarts, which can be attributed to the good
work that <a href="https://www.armbian.com/">the Armbian project</a> has done.</p>
]]></content:encoded></item></channel></rss>