<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://ducmbui.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ducmbui.com/" rel="alternate" type="text/html" /><updated>2026-02-12T22:23:21+07:00</updated><id>https://ducmbui.com/feed.xml</id><title type="html">Duc’s website</title><subtitle>Personal website and blog of a student, lousy programmer, tooter, Redditor and YouTube addict.
</subtitle><author><name>Bùi Minh Đức</name></author><entry><title type="html"></title><link href="https://ducmbui.com/blog/2026/02/12/netnewswire-23rd-birthday.html" rel="alternate" type="text/html" title="" /><published>2026-02-12T00:00:00+07:00</published><updated>2026-02-12T00:00:00+07:00</updated><id>https://ducmbui.com/blog/2026/02/12/netnewswire-23rd-birthday</id><content type="html" xml:base="https://ducmbui.com/blog/2026/02/12/netnewswire-23rd-birthday.html"><![CDATA[<p>NetNewsWire, the RSS feed aggregator and reader program on macOS and iOS, 
<a href="https://netnewswire.blog/2026/02/11/netnewswire-turns.html">turned 23 today</a>.</p>

<p>I use it hand in hand with <a href="https://miniflux.app">Miniflux</a> to catch up on news sources, podcasts, 
subreddits and YouTube video releases. It has become an essential tool for 
helping me get through my day, and one I absolutely want to leave open in 
background on my Mac unless I need to do something memory-intensive.</p>

<p>I personally created and use a brutalist-style theme for it called <a href="https://git.sr.ht/~ducmbui/Compakt.nnwtheme">Compakt</a>.</p>

<p>Happy birthday NetNewsWire and best of wishes to the development team! Here’s 
to many more years of one of my favourite, if not my absolute number one RSS 
reader. And long live RSS.</p>]]></content><author><name>Bùi Minh Đức</name></author><category term="blockquote" /><summary type="html"><![CDATA[NetNewsWire, the RSS feed aggregator and reader program on macOS and iOS, turned 23 today.]]></summary></entry><entry><title type="html"></title><link href="https://ducmbui.com/blog/2025/11/18/B2.html" rel="alternate" type="text/html" title="" /><published>2025-11-18T00:00:00+07:00</published><updated>2025-11-18T00:00:00+07:00</updated><id>https://ducmbui.com/blog/2025/11/18/B2</id><content type="html" xml:base="https://ducmbui.com/blog/2025/11/18/B2.html"><![CDATA[<p>CloudFlare services having issues globally also knocked down ChatGPT and Claude. Coincidentally, my sibling is taking a certificate exam at this time…</p>]]></content><author><name>Bùi Minh Đức</name></author><category term="blockquote" /><summary type="html"><![CDATA[CloudFlare services having issues globally also knocked down ChatGPT and Claude. Coincidentally, my sibling is taking a certificate exam at this time…]]></summary></entry><entry><title type="html"></title><link href="https://ducmbui.com/blog/2025/11/08/B1.html" rel="alternate" type="text/html" title="" /><published>2025-11-08T00:00:00+07:00</published><updated>2025-11-08T00:00:00+07:00</updated><id>https://ducmbui.com/blog/2025/11/08/B1</id><content type="html" xml:base="https://ducmbui.com/blog/2025/11/08/B1.html"><![CDATA[<p>My entire Docker setup experienced some downtime yesterday. I did some weekly maintenance, as usual, upgrading the <code class="language-plaintext highlighter-rouge">linux-aarch64</code> kernel to 6.17.7. What I wasn’t aware however, the pre-compiled version of the new kernel omitted the <code class="language-plaintext highlighter-rouge">raw</code> table from <code class="language-plaintext highlighter-rouge">iptables</code>, preventing Docker from dropping incoming connection to the container system.</p>

<p><a href="https://archlinuxarm.org/forum/viewtopic.php?f=15&amp;t=17296">https://archlinuxarm.org/forum/viewtopic.php?f=15&amp;t=17296</a></p>

<p>6.18rc seems to have reverted this, but with the move from legacy <code class="language-plaintext highlighter-rouge">iptables</code> to <code class="language-plaintext highlighter-rouge">nftables</code> I decided to replace <code class="language-plaintext highlighter-rouge">iptables</code> with <code class="language-plaintext highlighter-rouge">iptables-nft</code> and restarted the Docker service. All good now.</p>

<p>Maybe I shouldn’t live life on the bleeding edge…</p>]]></content><author><name>Bùi Minh Đức</name></author><category term="blockquote" /><summary type="html"><![CDATA[My entire Docker setup experienced some downtime yesterday. I did some weekly maintenance, as usual, upgrading the linux-aarch64 kernel to 6.17.7. What I wasn’t aware however, the pre-compiled version of the new kernel omitted the raw table from iptables, preventing Docker from dropping incoming connection to the container system.]]></summary></entry><entry><title type="html">the trouble of dealing with my ISP</title><link href="https://ducmbui.com/blog/2025/11/07/the-trouble-of-dealing-with-my-isp.html" rel="alternate" type="text/html" title="the trouble of dealing with my ISP" /><published>2025-11-07T00:00:00+07:00</published><updated>2025-11-07T00:00:00+07:00</updated><id>https://ducmbui.com/blog/2025/11/07/the-trouble-of-dealing-with-my-isp</id><content type="html" xml:base="https://ducmbui.com/blog/2025/11/07/the-trouble-of-dealing-with-my-isp.html"><![CDATA[<p>Part 2: I got nervous getting a public IPv4 address from my <abbr title="Internet Service Provider">ISP</abbr>, and protecting my Pi from the port attackers out there.</p>

<p>This year, I decided to purchase a domain to, maybe, have a nice little corner on the Internet. I chose this .com domain and paid a little over 11 U.S. bucks (around 270.000 VND at the time, more on this later). At first, I set the domain to point to my GitHub Pages (and later Sourcehut Pages) as I was scared to embrace the idea of getting a public IP address at the time.</p>

<p>Because of <a href="https://en.wikipedia.org/wiki/Internet_of_things">Internet of Things</a> and every Internet-connected appliance having to be assigned an IP address, companies around the world have bought every public-facing IPv4 address blocks available from ICANN (public-facing, accounting about 580 million reserved addresses.) IPv4 addresses, the ones with four blocks of 0 through 255, <a href="https://en.wikipedia.org/wiki/IPv4_address_exhaustion">have pretty much run out</a>. To combat this issue, ISPs have been placing people behind what are called Carrier-Grade <abbr title="Network Address Translation">NAT</abbr>s (<a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT">CG-NAT</a>). Think of them as massive routers: each group of devices is only assigned a public-facing IP address.</p>

<p>(I know I did some massive simplification there, because often companies don’t reserve IP address blocks directly from ICANN but from their regional Internet address registries, such as APNIC. Also, people are embracing the IPv6 address standard, which holds a serviceable, virtually infinite number of IP addresses to assign to devices.)</p>

<p>Almost everyone is fine behind CG-NATs as long as they have access to the Internet. For those who want to host things online, they rely on companies providing centrally managed servers (cloud services) such as Amazon Web Services (AWS), Google Cloud, Microsoft Azure, Cloudflare, Netlify, Vercel, and the like. For self-hosting purposes, as I’m about to do, however, it means no one would be able to reach my Pi.</p>

<p>Most ISPs around the world provide a fixed IP rent service for businesses, and ours do too. Our government restricts the external IP addresses that can reach its databases, for security purposes, so companies would rent IP addresses to register with the National Tax Department. The problem is, the monthly rate (600,000 VND/month, or over 22 USD) is too costly for an individual to rent one, you have to be a legal business entity and file papers stating your purposes for getting a static IP address; not to mention getting approval from the ISP itself.</p>

<p>I turned to seek some advices from the Vietnamese home network community, who certainly has more experience in self-hosting and dealing with ISPs than me.</p>

<figure class="figure-caption " style="max-width:414px">
    <img src="/assets/images/blog/2025-10-01-threads-post.jpeg" alt="A screenshot of a Threads post in Vietnamese, in which I sought some advices on getting a static IP from ISPs. The post received 33 comments, along with likes, reposts and shares." title="" />
    
        <figcaption><a href="https://www.threads.com/@ducmbui2/post/DNfaul0R34Z">Original post</a>; the Vietnamese home network community even has <a href="https://voz.vn/t/tat-ca-cac-van-%C4%91e-mang-fpt-viettel-vnpt-nem-het-vao-%C4%91ay-lap-thread-ngoai-xoa-an-warn.51987/">an active forum thread</a> discussing bad practices of local ISPs</figcaption>
    
</figure>

<p>Many comments suggested using a middle-man service, such as CloudFlare Tunnel, which assigns a public IP address for my Pi on CloudFlare’s servers. As it turns out, CloudFlare Tunnel doesn’t support <a href="https://github.com/juanfont/headscale/issues/1468">WebSocket POST calls</a>, which I would later need to self-host one of the services.</p>

<p><a href="https://www.threads.com/@realrookie001/post/DNgQTCJyaUr">One comment from @realrookie001</a>, however, pointed out an alternative, yet quite more advanced solution: enable port forwarding in the dashboard of my ISP’s modem, which routes all Internet traffic to my home IP address directly to the Pi. Then, as the ISP updates my public IP address, I could use a tool on my Pi, such as <code class="language-plaintext highlighter-rouge">ddclient</code> to get the new address and send that to my domain provider.</p>

<p><a href="https://www.threads.com/@ducmaster01/post/DNfb7wCzwSj">@ducmaster01 assured me</a> that ISPs are more open to requests for assigning a public IP address, and perhaps I could call their support number and ask if they can move me away from their CG-NATs.</p>

<h2 id="time-to-port-forward">Time to port forward</h2>

<p>Eventually I got to work. By sheer luck (and definitely not just looking at the default username and password printed on the back), I was able to guess my way into my ISP’s modem. I decided to get my Pi’s MAC address and configure the modem to forward all traffic on port 80 (for HTTP) and port 443 (for HTTPS) to the Pi.</p>

<p><img src="/assets/images/blog/2025-10-01-modem-config.png" alt="A screenshot of the Port Forwarding configuration page on the dashboard of my modem, where I forward all traffic to port 80 through port 443 of the modem's IP address to my Pi. Later this changed to port 80 and 443 only." /></p>

<p>I knew that I was behind a carrier-grade NAT, because the WAN IP address that the ISP gave to my modem and the public IP address when I ran <code class="language-plaintext highlighter-rouge">curl ifconfig.me</code> on my Pi were’t the same. So I had to call their support number and request to be moved to the public address pool.</p>

<p>I was nervous. I’ve worked as a customer support representative at a call centre before, and I knew the pressure of taking the next call right after getting yelled at by a customer for their dissatisfaction with the service, and the urge to vent the anger; having to forward customer requests to the upper departments, or deny requests outright even when they were technically feasible, because a representative doesn’t have the authority to do things by themselves.</p>

<p>Then my phone rang.</p>

<blockquote>
  <p>“Hello, is this Mr. Duc? I saw your service request on our support app, you want to be assigned a public IP address to your modem, on the contract number […]?”</p>
</blockquote>

<p>I was too nervous to call their support number, so I opened a service support ticket in the app in the hope that they would understand the situation.</p>

<blockquote>
  <p>“I’ve assigned a new IP address to your modem. Please hold for a minute or two and check if you’re on the new public IP address.”</p>
</blockquote>

<p>That was quick. Maybe I’m just an introvert guy who was shy to take calls from strangers, and I was overthinking for a bit. Or I was making a request at 11:30 in the night and the support man wanted to get things done as quick as possible.</p>

<p>But as I refreshed the modem dashboard and ran the command again on my Pi, the IP addresses became matching with each other. I jumped. I couldn’t think it was as simple as that.</p>

<h2 id="shell-my-pi-securely-from-port-22-and-other-port-attack">Shell my Pi securely from port 22 and other port attack</h2>

<p>I remember watching a YouTube video on finding Chinese scam websites and attacking common open ports of their servers. Unfortunately I wasn’t able to trace back that video to link here (possibly from <a href="https://www.youtube.com/@_JohnHammond">John Hammond</a>?)</p>

<p>It’s not difficult, nonetheless, to find incidents where hackers gain unauthorised access to servers, as the maintainers of those servers did little to no effort to implement any protective measures, such as closing port 22, which is often exposed for remote access over SSH, or only locking SSH access behind a layer of password.</p>

<p>Keeping that in mind, on the Pi, I installed Uncomplicated Firewall (<code class="language-plaintext highlighter-rouge">ufw</code>) and configured it to block all external access into all ports, except port 22 for SSH, which I restricted access to devices within my local network only, port 80 and 443 for the Nginx web server; and set up SSH to authenticate using public-private key verification.</p>

<p><code class="language-plaintext highlighter-rouge">ufw</code> acts as an abstraction layer and uses either <code class="language-plaintext highlighter-rouge">iptables</code> or <code class="language-plaintext highlighter-rouge">nftables</code> as the back-end firewall.</p>

<p>I made sure to disable any other firewall services in place, then followed the <a href="https://wiki.archlinux.org/title/Uncomplicated_Firewall">ArchWiki entry for <code class="language-plaintext highlighter-rouge">ufw</code></a>, which instructed me to install the <code class="language-plaintext highlighter-rouge">ufw</code> package, enable the <code class="language-plaintext highlighter-rouge">systemd</code> service, and enable the firewall.</p>

<h2 id="i-got-lucky">I got lucky</h2>

<p>I can now rest easy knowing I can start building my presence on the web. But another day I shared this story on a call with a fellow developer, who lives in a shared apartment. And for him, things didn’t turn out as easy as I thought they would be.</p>

<p>In shared apartments, an ISP usually signs a contract with the construction project owner to provide their Internet service for the entire apartment. He’s stuck with whichever ISP providing the service there. It took a lot of time before he was given the credential to access the modem by a service repairman, and he was denied permission to have a public IP address, due to the way it was set up that could affect the Internet security of the entire apartment.</p>

<p>You might have better chance at this if you live in a house, I guess.</p>]]></content><author><name>Bùi Minh Đức</name></author><category term="article" /><summary type="html"><![CDATA[Part 2: I got nervous getting a public IPv4 address from my ISP, and protecting my Pi from the port attackers out there.]]></summary></entry><entry><title type="html">the tale of my Raspberry Pi</title><link href="https://ducmbui.com/blog/2025/10/01/the-tale-of-my-raspberry-pi.html" rel="alternate" type="text/html" title="the tale of my Raspberry Pi" /><published>2025-10-01T00:00:00+07:00</published><updated>2025-11-08T00:00:00+07:00</updated><id>https://ducmbui.com/blog/2025/10/01/the-tale-of-my-raspberry-pi</id><content type="html" xml:base="https://ducmbui.com/blog/2025/10/01/the-tale-of-my-raspberry-pi.html"><![CDATA[<p>Part 1 of a three-plus-part story on my experience of getting a Raspberry Pi and setting it up to be my personal server for self-hosting services.</p>

<p>I was on top of the world when I got my first Raspberry Pi about three years ago.</p>

<p>Probably because the Pis were (and still are) ever so costly to buy here with our current exchange rate, to the point that I had to save up my allowance to get one. Or perhaps there were no micro-electronic hardware stores on Tran Dai Nghia St. that were selling genuine Pis at the time, and mine had to be delivered from one of the approved distributors in Ho Chi Minh City. Or maybe I was getting a Pi at <a href="https://www.raspberrypi.com/news/production-and-supply-chain-update/">the worst time of the global Pi supply shortage</a>.</p>

<p>But most importantly, I was watching <a href="https://www.youtube.com/playlist?list=PLRiHAWwt3g5Nz9Vv0Nd6VbSsiPfQccOPA">Rob’s YouTube videos</a> on using a Raspberry Pi as a companion computer for the iPad. Rob was able to power his Raspberry Pi 4 with his iPad Pro and a Thunderbolt USB-C cable, and open a <abbr title="Secure Shell">SSH</abbr> on the Pi over that USB-C connection. I dreamed of a day when I can carry my iPad and the Pi around and work anywhere I want.</p>

<p>It was until I realised that I should’ve got a personal laptop instead of having my goldfish memory remember to bring the USB-C cable.</p>

<p>Alas, since then I used the Pi for other things than I intended: <a href="https://konstakang.com/devices/rpi4/">converting it into what’s basically an Android set-top-box</a> so I can watch YouTube on my LG TV full of crappy bloatware, <a href="https://linuxhint.com/install-kde-plasma-raspberry-pi/">installing KDE on Raspberry Pi OS</a> and use it as a computer, or <a href="https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-4">replacing Raspberry Pi OS with Arch Linux ARM</a>. But I just left it running, messing around whenever I want to be in a Linux environment.</p>

<p>More recently, I stumbled across <a href="https://news.ycombinator.com/item?id=44877724">this Hacker News comment</a> about using <a href="https://wiki.archiveteam.org/index.php/ArchiveTeam_Warrior">ArchiveTeam’s Warrior tool</a> to preserve links on the Internet from being inaccessible (called link rot). My interest suddenly got piqued by supporting the team’s effort and running a version of Warrior on a spare computer at home. The Pi came to my mind first, but I soon came aware that <a href="https://wiki.archiveteam.org/index.php/ArchiveTeam_Warrior#Can_I_run_the_Warrior_on_ARM_or_some_other_unusual_architecture?">the Warrior tool is preserved for <code class="language-plaintext highlighter-rouge">amd64</code> desktop computers</a> and I cannot run it on my Pi.</p>

<p>Nonetheless, I learned about Docker and the self-hosting community, the people who don’t want to be bounded by the Terms of Services placed upon by some massive companies.</p>

<p>I had been hosting my website on GitHub Pages, before moving it to Sourcehut. However, having the website on a third-party service meant I’m limited to what that service allows me to do. <a href="https://srht.site/limitations/">Sourcehut, for example</a>, prohibits loading scripts and styles from <abbr title="Content Delivery Networks, a.k.a. centrally hosted files">CDNs</abbr> or having the content of the site over 1GB in size. <em>(well, I try not to use JavaScript on this website, nor is it that big now… anyway)</em></p>

<p>And so begins my journey of moving my personal website to a self-hosted web server of my own, plus maybe a password manager and an internal VPN between my devices.</p>

<h2 id="notes-on-installing-64-bit-arch-linux-arm-on-pi-4-and-overclocking">Notes on <a href="https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-4">installing 64-bit Arch Linux ARM on Pi 4</a> and overclocking</h2>

<p>Once I followed the instructions to install the <code class="language-plaintext highlighter-rouge">aarch64</code> version of Arch Linux ARM, my Pi 4 kept running into kernel panics as it went through the boot process with the generic U-Boot loader. I kept around a spare USB stick with a Raspberry Pi OS installation on it so I can investigate the filesystem.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mmc1: error -5 whilst initialising SD card
</code></pre></div></div>

<p>After doing some research, <a href="https://archlinuxarm.org/forum/viewtopic.php?f=67&amp;t=15422&amp;start=20#p67299">as a member pointed out on the Arch Linux ARM forum</a>, it turned out the <code class="language-plaintext highlighter-rouge">boot.txt</code> in the boot partition of the new system was using the memory address variable <code class="language-plaintext highlighter-rouge">fdt_addr_r</code> instead of <code class="language-plaintext highlighter-rouge">fdt_addr</code>. <code class="language-plaintext highlighter-rouge">fdt_addr_r</code> doesn’t seem to exist on newer revisions of the Pi 4 than 1.4.</p>

<p>I was able to correct the variables in the <code class="language-plaintext highlighter-rouge">/boot/boot.txt</code> file, install <code class="language-plaintext highlighter-rouge">u-boot-tools</code> in Raspberry Pi OS and run the <code class="language-plaintext highlighter-rouge">./mkscr</code> executable:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">@@ -1,16 +1,16 @@</span>
  # After modifying, run ./mkscr
<span class="err">
</span>  # Set root partition to the second partition of boot device
  part uuid ${devtype} ${devnum}:2 uuid
<span class="err">
</span>  setenv bootargs console=ttyS1,115200 console=tty0 root=PARTUUID=${uuid} rw rootwait smsc95xx.macaddr="${usbethaddr}"
<span class="err">
</span>  if load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} /Image; then
  	if load ${devtype} ${devnum}:${bootpart} ${fdt_addr_r} /dtbs/${fdtfile}; then
   	  if load ${devtype} ${devnum}:${bootpart} ${ramdisk_addr_r} /initramfs-linux.img; then
<span class="gd">-       booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
</span><span class="gi">+       booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr};
</span>      else
<span class="gd">-       booti ${kernel_addr_r} - ${fdt_addr_r};
</span><span class="gi">+       booti ${kernel_addr_r} - ${fdt_addr};
</span>      fi;
    fi;
  fi
</code></pre></div></div>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /dev/mmcblk0p1/boot/
<span class="nb">sudo chmod</span> +x ./mkscr <span class="o">&amp;&amp;</span> <span class="nb">sudo</span> ./mkscr
<span class="c"># OR</span>
<span class="nb">cd</span> /dev/mmcblk0p1/boot/
<span class="nb">sudo </span>mkimage <span class="nt">-A</span> arm <span class="nt">-T</span> script <span class="nt">-O</span> linux <span class="nt">-d</span> boot.txt boot.scr
</code></pre></div></div>

<p>In addition to that, I was able to follow <a href="https://magazine.raspberrypi.com/articles/how-to-overclock-raspberry-pi-4">the overclocking instructions on Raspberry Pi Official Magazine</a> and boost the CPU clock of my Pi 4 to 2.1GHz. Overclocking probably wouldn’t hurt since the Pi 400 and the Compute Module were also overclocked, and that I have a fan (it didn’t show any temperature warnings when I ran Raspberry Pi OS overclocked.)</p>

<p>Since the <code class="language-plaintext highlighter-rouge">/boot/config.txt</code> file of the U-Boot bootloader is the same as the one on the Raspberry Pi OS, basically I had to add the boot flags in <code class="language-plaintext highlighter-rouge">/boot/config.txt</code>:</p>

<div class="language-config highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">over_voltage</span>=<span class="m">6</span>
<span class="n">arm_freq</span>=<span class="m">2100</span>
<span class="n">gpu_freq</span>=<span class="m">750</span>
</code></pre></div></div>

<hr />

<p>If you have any ideas on running ArchiveTeam’s Warrior tool on a Raspberry Pi (I’d rather not go through emulation), or just want to correct my use of the word “but”, feel free to send me an e-mail, discuss on GitHub or mention me on Mastodon!</p>]]></content><author><name>Bùi Minh Đức</name></author><category term="article" /><summary type="html"><![CDATA[Part 1 of a three-plus-part story on my experience of getting a Raspberry Pi and setting it up to be my personal server for self-hosting services.]]></summary></entry></feed>