<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:webfeeds="http://webfeeds.org/rss/1.0"><author><name>Marko Korhonen</name><uri>https://korhonen.cc/</uri></author><generator uri="https://gohugo.io">Hugo 0.154.5</generator><id>urn:uuid:341a0375-31e6-47e9-a19f-f8e9a0436977</id><link rel="self" type="application/atom+xml" href="https://korhonen.cc/feed.xml" hreflang="en"/><link rel="alternate" type="text/html" href="https://korhonen.cc/" hreflang="en"/><link rel="alternate" type="application/json" href="https://korhonen.cc/index.json" hreflang="en"/><icon>https://korhonen.cc/favicon.png</icon><logo>https://korhonen.cc/images/marko.jpeg</logo><title>Korhonen.cc Blog</title><subtitle>This blog explores open-source tools, self-hosted services, and the daily life of a developer.</subtitle><updated>2026-03-12T14:12:40+00:00</updated><entry><author><name>Marko Korhonen</name></author><id>tag:korhonen.cc,2024:/posts/firewall_rules_openwrt_ipv6_dynamic_prefix/</id><link rel="alternate" href="https://korhonen.cc/posts/firewall_rules_openwrt_ipv6_dynamic_prefix/"/><title>OpenWRT firewall rules with dynamic IPv6 prefix</title><published>2024-06-10T00:00:00-05:00</published><updated>2025-12-29T03:01:31+00:00</updated><summary type="text">Easier firewall rules in OpenWRT when you have a dynamic IPv6 prefix.</summary><content type="html" xml:base="https://korhonen.cc/posts/firewall_rules_openwrt_ipv6_dynamic_prefix/" xml:lang="en"><![CDATA[
        <img src="hero.jpg" alt="Featured image"></img>
        
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>I recently got IPv6 connectivity at my house, so naturally I wanted to add IPv6 support for my server. I ran into some difficulties that I didn’t find documented in a single place so here is the solution I came up with.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_problem">The problem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I quickly discovered that my ISP is not doing the IPv6 support &#34;right&#34;, they are not giving me a /56 prefix with prefix delegation but instead a /64 prefix that cannot be further divided into subnets. This is true for all mobile operators in Finland and I cannot get anything else in my current address so this will have to do.</p>
</div>
<div class="paragraph">
<p>The lack of prefix delegation means that I have to set RA and NDP to relay mode in OpenWRT and I have no control over the IPv6 addresses that are assigned to my devices. That in turn means I cannot create static firewall rules based on those addresses because they can change any time.</p>
</div>
<div class="paragraph">
<p>For a few weeks I got by with manually changing the firewall rules every time the prefix changed but that was not sustainable because I have a lot of firewall rules.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_turning_off_ipv6_slaac_privacy_extensions">Turning off IPv6 SLAAC Privacy Extensions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>While I couldn’t have a predictable prefix, I can have a predicatble suffix by turning off the IPv6 SLAAC <a href="https://www.internetsociety.org/resources/deploy360/2014/privacy-extensions-for-ipv6-slaac/">Privacy Extensions</a> on my server. This way the suffix (the host part) is derived from the MAC address of the device and it will always stay the same.</p>
</div>
<div class="paragraph">
<p>Privacy Extensions exist for a reason. It increases privacy by generating the host part of the IP randomly and changing the address from time to time. I don’t think that is a problem for my server because it is open to the public anyway. The main reason for Privacy Extensions is so that mobile devices can’t be tracked across networks and my server obviously stays in the same network all the time. It’s good to acknowledge that this effectively makes your MAC address public, but I don’t personally see an obvious risk in that.</p>
</div>
<div class="paragraph">
<p>I’m using NetworkManager on my server. You can turn off Privacy Extensions by locating your interface configuration under <code>/etc/NetworkManager/system-connections/</code>. On my server it was in the file <code>Wired connection 1.nmconnection</code>. Add/change the following lines in the <code>[ipv6]</code> section:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="config">[<span class="n">ipv6</span>]
<span class="n">addr</span>-<span class="n">gen</span>-<span class="n">mode</span>=<span class="n">eui64</span>
<span class="n">method</span>=<span class="n">auto</span>
<span class="n">ip6</span>-<span class="n">privacy</span>=<span class="m">0</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>After this, you can either restart NetworkManager or reboot the whole computer. Then your computer should have a new IPv6 address.</p>
</div>
<div class="paragraph">
<p>The logic by which the IPv6 address is calculated now is called EUI-64. I found a great tool to test and better understand it: <a href="https://eui64-calc.princelle.org/">the EUI-64 Calculator</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_dynamic_prefix_forwarding">Dynamic prefix forwarding</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I discovered that in OpenWRT firewall rules, part of the target address can be dynamic. This technique is called dynamic prefix forwarding. As I understand it, it is specific to OpenWRT, so this syntax doesn’t probably work in other firewalls. With this technique we can use the static host part we set for the server in the previous part as the firewall rule’s target IP address.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;"/>
<col style="width: 50%;"/>
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Server IPv6 address</strong></p></td>
<td class="tableblock halign-right valign-top"><p class="tableblock"><strong><code>2001:14bb:8ad:6b:f279:59ff:fe65:f9e4</code></strong></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Firewall rule target address</strong></p></td>
<td class="tableblock halign-right valign-top"><p class="tableblock"><strong><code>::f279:59ff:fe65:f9e4/-64</code></strong></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Here you can see the current IPv6 address of my server and the resulting firewall rule target address. The <code>/-64</code> tells the firewall to ignore the first 64 bits of the address and only look at the 64 bits at the end, which is the host part.</p>
</div>
<div class="paragraph">
<p>For more information about the firewall configuration, you can refer to the <a href="https://openwrt.org/docs/guide-user/firewall/fw3_configurations/fw3_ipv6_examples#dynamic_prefix_forwarding">OpenWRT wiki</a></p>
</div>
</div>
</div>

      ]]></content></entry><entry><author><name>Marko Korhonen</name></author><id>tag:korhonen.cc,2023:/posts/migrate_misskey_root_account/</id><link rel="alternate" href="https://korhonen.cc/posts/migrate_misskey_root_account/"/><title>Migrate Misskey root account</title><published>2023-12-10T11:41:08+02:00</published><updated>2025-12-29T03:01:31+00:00</updated><summary type="text">A solution for an issue I found when migrating from Misskey to Firefish</summary><content type="html" xml:base="https://korhonen.cc/posts/migrate_misskey_root_account/" xml:lang="en"><![CDATA[
        <img src="hero.jpg" alt="Featured image"></img>
        
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>I recently migrated my single user Fediverse server from  <a href="https://misskey-hub.net">Misskey</a> to <a href="https://joinfirefish.org">Firefish</a>.
During the migration I encountered an issue that I did not find documented elsewhere.
I thought I’d write down the solution I found, in case anyone would benefit from it and save some time in the future.</p>
</div>
<div class="paragraph">
<p>I decided to migrate to a new domain at the same time, so the easiest way was just to create a new server and migrate my account and not fuss about migrating the Misskey instance itself.</p>
</div>
<div class="paragraph">
<p>Being a single user instance, my account was also the &#34;root&#34; account of Misskey.
Misskey does not allow migrating the root account, if trying to do so, you will just get an error along the lines of &#34;root cannot migrate&#34;.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_solution">Solution</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I took to the database to find out what I can do bypassing the UI, and lo and behold, I found an <code>isRoot</code> column in the <code>user</code> table.
I didn’t want to end up without a root account on my old instance however, so I went to the Misskey control panel and created a new account, simply called &#34;root&#34;.</p>
</div>
<div class="paragraph">
<p>Misskey seems to save all of it’s known users to the <code>user</code> table, not only the actual local accounts.
To find the local accounts only, you can use the following query</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sql"><span class="n">misskey</span><span class="o">=#</span> <span class="k">SELECT</span> <span class="n">id</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="nv">&#34;isRoot&#34;</span> <span class="k">from</span> <span class="nv">&#34;user&#34;</span> <span class="k">WHERE</span> <span class="k">host</span> <span class="k">IS</span> <span class="k">NULL</span><span class="p">;</span>
     <span class="n">id</span>     <span class="o">|</span>  <span class="n">username</span>   <span class="o">|</span> <span class="n">isRoot</span> 
<span class="c1">------------+-------------+--------</span>
 <span class="mi">98</span><span class="n">wzsyrur6</span> <span class="o">|</span> <span class="n">relay</span><span class="p">.</span><span class="n">actor</span> <span class="o">|</span> <span class="n">f</span>
 <span class="mi">9</span><span class="n">n1njqolcd</span> <span class="o">|</span> <span class="n">root</span>        <span class="o">|</span> <span class="n">f</span>
 <span class="mi">9</span><span class="n">n342nasd3</span> <span class="o">|</span> <span class="n">marko</span>       <span class="o">|</span> <span class="n">t</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Now you can simply make your new root account’s <code>isRoot</code> column <code>true</code> and your actual user account <code>false</code>.
After that, the migration will work.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sql"><span class="n">misskey</span><span class="o">=#</span> <span class="k">BEGIN</span><span class="p">;</span>
<span class="k">UPDATE</span> <span class="nv">&#34;user&#34;</span> <span class="k">SET</span> <span class="nv">&#34;isRoot&#34;</span> <span class="o">=</span> <span class="k">true</span> <span class="k">WHERE</span> <span class="n">id</span> <span class="o">=</span> <span class="s1">&#39;9n1njqolcd&#39;</span><span class="p">;</span>
<span class="k">UPDATE</span> <span class="nv">&#34;user&#34;</span> <span class="k">SET</span> <span class="nv">&#34;isRoot&#34;</span> <span class="o">=</span> <span class="k">false</span> <span class="k">WHERE</span> <span class="n">id</span> <span class="o">=</span> <span class="s1">&#39;9n342nasd3&#39;</span><span class="p">;</span>
<span class="k">COMMIT</span><span class="p">;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>You should probably check that you only modified 2 rows before committing the transaction.</p>
</div>
<div class="paragraph">
<p>I would imagine that this solution should work for the numerous Misskey forks around, but I have not tested it so your results may vary.</p>
</div>
<div class="paragraph">
<p>If you found this post useful, make sure to share, tweet, toot, bleep and bloop this on your social media service of choice.
If you have any issues with this process, you can leave a comment below and I will try to help you out.</p>
</div>
</div>
</div>

      ]]></content></entry><entry><author><name>Marko Korhonen</name></author><id>tag:korhonen.cc,2022:/posts/creating_this_site/</id><link rel="alternate" href="https://korhonen.cc/posts/creating_this_site/"/><title>Creating this site</title><published>2022-09-14T00:00:00-05:00</published><updated>2025-12-29T03:01:31+00:00</updated><summary type="text">My journey with AsciiDoc and Hugo, and how we got here</summary><content type="html" xml:base="https://korhonen.cc/posts/creating_this_site/" xml:lang="en"><![CDATA[
        <img src="hero.jpg" alt="Featured image"></img>
        
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>As seems to be customary on technology related blogs, the first post is about creating the blog itself.
So here we are, this is the first post in my blog, detailing the steps I took to arrive here.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_assessing_the_options">Assessing the options</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I first got interested in static site generators years ago when my friend Fatih built <a href="https://teaddict.net">his site</a> with <a href="https://jekyllrb.com">Jekyll</a>.
It felt very refreshing at the time since I was hosting my homepage on WordPress, which always seemed a little too bloated and overkill for my needs.</p>
</div>
<div class="sect2">
<h3 id="_jekyll">Jekyll</h3>
<div class="paragraph">
<p>I tried setting up Jekyll multiple times during 2021 but got discouraged by the build process which involved specifying all sorts of bundles and gems for just for building the site (I never was very into Ruby to begin with).
I also got to debug all sorts of build problems which were a result of my very specific requirements for the blog.
I added multiple plugins which didn’t work together very well.
The biggest hurdle to overcome was the fact that I wanted to use <a href="https://en.wikipedia.org/wiki/AsciiDoc">AsciiDoc</a> as the mark-up language.
Jekyll doesn’t natively support this so I had to use a <a href="https://github.com/asciidoctor/jekyll-asciidoc">plugin</a> to bring in the functionality.
This plugin specifically didn’t seem to work very well with the other plugins I required and the theme I had selected.</p>
</div>
<div class="paragraph">
<p>Anyways, I never got further with setting up the site so I put the project on the backburner.
From the inception of the my current domain <a href="https://korhonen.cc">korhonen.cc</a> in late 2020 until summer 2022 the main domain just showed a 404 error.
I had a lot of self-hosted applications only on subdomains.</p>
</div>
</div>
<div class="sect2">
<h3 id="_hugo">Hugo</h3>
<div class="paragraph">
<p>After discovering <a href="https://gohugo.io">Hugo</a> I got very exited immediately.
It seemed to be an answer to all of my problems. The main benefits were</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Single binary</p>
</li>
<li>
<p>Support for AsciiDoc out of the box</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Because of this, I got a basic site setup within a matter of minutes.
No more fiddling with bundles and gems.
I also didn’t require any other plugins since Hugo seemed to support everything I wanted natively.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_configuration">Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I opted to use the <a href="https://github.com/hossainemruz/toha">Hugo Toha</a> theme for my site since it seemed to do well all of the things I wanted to accomplish with this site</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A website where I can add any number of static pages (not blog posts)</p>
<div class="ulist">
<ul>
<li>
<p><a href="/pgp">Information page about my PGP key</a></p>
</li>
<li>
<p><a href="/korhonen_aur">Information page about my Arch Linux repository</a></p>
</li>
</ul>
</div>
</li>
<li>
<p><a href="/">Introduction and portfolio</a></p>
</li>
<li>
<p><a href="/posts">A blog</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The configuration of Hugo and the theme took quite a while but was well worth it.
I now have a beautiful multipurpose site which is easy to maintain and expand.</p>
</div>
<div class="sect2">
<h3 id="_commenting_system">Commenting system</h3>
<div class="paragraph">
<p>I wanted to add support for users to add comments on the blog.
While I usually self-host everything I can, this time I landed with <a href="https://giscus.app">Giscus</a>.
It’s built upon the GitHub discussions platform so all I needed to do was to create a repository in GitHub with the discussions feature enabled and configure it in Toha (the Hugo theme I selected).</p>
</div>
<div class="paragraph">
<p>I went through all of the options that Toha supported but none of them were self-hostable and I didn’t feel like implementing support for a different platform myself.
This might be a cool future project at some point though.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_automating_the_build_process">Automating the build process</h2>
<div class="sectionbody">
<div class="paragraph">
<p><em>Update 2022-12-17: I have switched from Drone CI to Woodpecker CI. Woodpecker is a FOSS fork of Drone as Drone has moved to a proprietary license.</em></p>
</div>
<div class="paragraph">
<p><em>Update 2022-12-17 part 2: I have switched from Gitea to Forgejo. Forgejo is a FOSS fork of Gitea as Gitea seems to be moving towards a closed business model.</em></p>
</div>
<div class="paragraph">
<p><em>Update 2025-08-15: I have switched Woodpecker CI to Forgejo Actions. I actually switched a lot earlier but only now thought to update this site.</em></p>
</div>
<div class="paragraph">
<p>Over the years I have moved to different CI systems. The current system is <a href="https://forgejo.org/docs/latest/user/actions/reference/">Forgejo Actions</a>.
It’s basically the open source equivalent of GitHub actions and I really enjoy using it.</p>
</div>
<div class="paragraph">
<p>Relevant configuration files</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://git.korhonen.cc/FunctionalHacker/korhonen.cc/src/branch/main/.forgejo/workflows/deploy_site.yaml">Pipeline for building this website</a></p>
</li>
<li>
<p><a href="https://git.korhonen.cc/FunctionalHacker/dotfiles/src/branch/main/docker/forgejo/docker-compose.yaml">Forgejo server configuration</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_future_plans">Future plans</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I don’t plan to become a regular blogger any time soon but if I find something that I think would be of value to other people, I will write about it here if I find the time and energy.</p>
</div>
<div class="paragraph">
<p>I really enjoy tinkering with Linux and self-hosting applications on my server so I might write some tutorials about these topics in the future.
I’m also a passionate <a href="https://neovim.io">NeoVim</a> user so I might write a post about <a href="https://git.korhonen.cc/FunctionalHacker/dotfiles/src/branch/main/home/.config/nvim">my configuration</a> sometime soon.</p>
</div>
<div class="paragraph">
<p>Just for fun, here is a screenshot of me writing this blog post. How meta of me 😃</p>
</div>
<div class="imageblock">
<div class="content">
<img src="assets/writing_blogpost_neovim_hugo.png" alt="Me writing this blog post"/>
</div>
<div class="title">Figure 1. A screenshot of me writing a blog post about this blog</div>
</div>
</div>
</div>

      ]]></content></entry></feed>