MoreRSS

site iconArne BahloModify

a developer, podcaster & dad based near Frankfurt, Germany.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of Arne Bahlo

I built a NAS

2026-02-07 08:00:00

Without going too deep into it, in light of our late-stage surveillance capitalism and political escalations, I do not want to depend on tech companies for my personal data, especially those from the United States.

In lieu of that, I’ve decided to take matters into my own hands and build a NAS.

Table of contents

History

I’ve been hosting my own music since 2024, and I moved my personal data to a hosted NextCloud on Hetzner shortly after. Cryptomator helped me end-to-end encrypt my files on the Hetzner servers, and while I would recommend this, the workflow is a bit convoluted—for example, on macOS it mounts a volume that is harder to access.

The biggest problem for me was photos—I was using iCloud photos, and even though something like Immich get’s really close to the functionality I’m interested in, it’s not automatically end-to-end encrypted.

Hardware

Let’s talk about constraints:

  • No pre-built, closed-source solution (Synology, QNAP, etc.): If I do this, I’m going to do it the right way.
  • Ideally SSD-only: Using HDDs is cheap (see next point), but they’re more prone to fail and wayyy slower.
  • Enough power: Because I wanted to run apps like Immich or NextCloud, I needed a fast-enough processor and enough memory, at least 8 GB.
  • Reasonably priced: My budget was around 700 €.

Things I considered:

  • Old QNAP stations: Some of these come with SATA slots that also support SSD, but ultimately the processors of the ones I looked at were too weak.
  • Framework/Intel NUC/whatever with an external NVMe/M.2 case for my storage SSDs: There aren’t a lot of external NVMe RAID cases out there that look trustworthy, plus it felt wrong to have them connected over USB; it’s probably a lot slower as well.

At this point, I felt like there was no good solution, until I found the Intel NUC NUC6i7KYK, a.k.a. Skull Canyon. It has:

  • Intel Core i7 (6MB cache, up to 3.5 GHz)
  • 16 GB memory (at least the one I got on eBay)
  • 2 internal M.2 SSD slots

This sounded perfect, and I got it used for around 200 €, with an internal 500 GB SSD already built in, which I used to test the setup.

My plan is to then get 2× 4 TB SSDs and mirror them for maximum security. This is more than enough storage for our family for the next few years. Also have you looked at SSD prices lately? 100 €/TB is a good deal.

System

From my research, these were the three top options:

  • TrueNAS Community Edition (Scale): Open-source NAS system based on ZFS, with support for many apps using Docker.
  • Unraid: Closed source; supports ZFS; BTRFS and XFS; needs a license ($249 for Lifetime)
  • Handrolled: Build everthing myself using Arch/NixOS w/ Docker

While Unraid looked promising, I did not want any closed-source software. I thought about hand-rolling, but since I wanted this setup to be as stable as possible and I have very little experience with ZFS, I eventually decided on TrueNAS Scale.

One annoyance with TrueNAS1 was that the installation could not be on a drive used for data. After some research, I decided to install on an SSD in a SATA case connected via USB. Booting from an external drive is not great and should be avoided if possible, but this is a common setup for people building NAS systems using mini-computers.

One problem I encountered was that initramfs failed to find the boot pool on boot because the (external) SSD was not discovered when it tried. I solved this problem by running this on the TrueNAS shell:

midclt call system.advanced.update '{"kernel_extra_options": "rootdelay=20"}'

This pauses the boot process for 20s, giving the USB controller time to set up the SSD.

Security

Security is all about attack vectors. My setup is meant to protect against theft and automated attacks. There is room to tighten this up even more, but this is more than good enough for me.

ZFS encryption

TrueNAS supports ZFS-native encryption. You can choose to encrypt the root pool, which I did; the encryption key is stored on the system itself for auto-unlock. This is great, but it offers no protection against the whole system being stolen.

Because of this, I have a top-level dataset under tank called encrypted, which is encrypted with a password. This means the system boots, but no data (including app data) is accessible until I log in and decrypt the dataset.

For this reason, I’m also not using the built-in backup solution; I don’t want the encryption key and password to be accessible on boot. More about backups further down.

I disabled the text console without a password prompt to prevent someone with physical access to the running, decrypted system from extracting data.

Headscale

There’s no way I’m exposing this system to the public internet. This is far too dangerous, even if you know what you’re doing. I still want to be able to access all my data from on the go, so I set up Headscale, an open-source, self-hosted version of Tailscale and compatible with the Tailscale apps. With this, I can access my NAS from anywhere via a self-hosted VPN.

SSL

But what if a machine in the VPN or on my local Wi-Fi gets compromised? The attacker would be able to sniff all HTTP traffic, extract credentials, and access all my data. This is why we encrypt our HTTP traffic.

For the TrueNAS system, I forward HTTP to HTTPS and use the self-signed certificate that comes pre installed.

But most TrueNAS apps expose ports without SSL, which means we need a reverse proxy. While TrueNAS supports the option to expose ports for inter-container communication, each app gets its own Docker network, which means a reverse proxy can’t access other apps by default2. To fix this, I use Dragonify (which I forked for security reasons). It connects all apps to a single network, so I can use Nginx Proxy Manager3 to serve apps with SSL on a subdomain.

I bought a domain solely for this setup and use deSEC with an account created specifically for this domain. This means when a token gets compromised, only that single domain is affected. But that token lives on the encrypted dataset, soo it’s unlikely.

Backups

Because I don’t want any encryption keys or access credentials on the system partition, I’m not using the native TrueNAS backup systems. After some research, I’ve landed on Backrest, a configuration interface for Restic.

Here’s what Filippo Valsorda has to say about Restic encryption:

“The design might not be perfect, but it’s good. Encryption is a first-class feature, the implementation looks sane and I guess the deduplication trade-off is worth it. So… I’m going to use restic for my personal backups.”

For storage, I’m using Hetzner Object Storage, mostly because it’s environmentally friendly and hosted in the EU.

Apps

We already talked about Tailscale, Dragonify, Nginx Proxy Manager, and Backrest.

Here are the apps I’m using

Conclusion

So that’s my setup. It works really well, and I’m happy. I’ll try to edit this post in six months to give an update.

Am I missing something? Let me know: [email protected]

Thanks to Eric & Jan for proof-reading this post and listening to my ramblings!

  1. Not sure if this restriction also applies to Unraid/other systems.

  2. Apparently this was possible with 24.04 (Dragonfish)

  3. I might switch to a boring Caddy configuration soon.

  4. E.g. syncing my Obsidian vault or Steamdeck screenshots

Brené Brown on productivity and self-worth

2025-07-21 08:00:00

I’m currently reading Dare to Lead (Brown, 2018) and this made me think:

When worthiness is a function of productivity, we lose the ability to pump the brakes. The idea of doing something that doesn’t add to the bottom line provokes stress and anxiety. It feels completely contrary to what we believe we want to achieve in life—we convince ourselves that downtime, like playing with our kids, hanging out with our partners, napping, tooling around in the garage, or going for a run is a waste of precious time. Why sleep when you can work?

Although I’m not a workaholic, I do see myself in some of these points.
I need to work on that.

Reclaiming my attention

2025-07-05 08:00:00

“Like fingers pointing to the moon, other diverse disciplines from anthropology to education, behavioral economics to family counseling, similarly suggest that the skillful management of attention is the sine qua non of the good life and the key to improving virtually every aspect of your experience.” — Winifred Gallagher

Our attention is being stolen.
We’re slowly losing the ability to concentrate, not only because of TikTok, but also because we constantly have access to easy consumption. It’s digital fast food.

When I started to notice this on myself, I started with the naïve approach and deleted all time sink1 apps like YouTube or Instagram. This worked for a day or two until I either got bored or found another reason to re-install.

Then I moved to Apple Screen Time. This works for a bit, but that “15 minutes more” button starts to become muscle memory very quickly. Even apps like one sec got deleted because they’re annoying (that’s the idea, I know).

In January 2024 I went 7 days with only my Apple Watch, leaving my iPhone at my desk at all times. It was doable, but very impractical.

None of this worked

In early 2025 I sold my Apple Watch and bought a Casio DW-5600BB-1. This had a large impact as I would no longer get buzzed on my wrist for every notification2.

Then I deleted my Instagram account and the YouTube, Mastodon and Bluesky apps. Yes, a lot of my friends are on Instagram—but I mostly watched Reels anyway! I do miss Mastodon. I now use YouTube in Safari with shorts blocked. This creates enough friction for me to watch videos intentionally (most of the time). It also lets me use cool extensions like SponsorBlock and DeArrow.

And when Apple Intelligence (if you can call it that) got to Europe, I turned on the new Reduce Interruptions focus and never turned it off. This works great because it randomly lets things through, but blocks most of it.

I tried a dumb phone3, but this was way too much friction—I need a usable phone for renting a bike, getting my parcels, etc.

In March I bought a Bullet Journal and started tracking my tasks there instead of my phone. I also started journalling and tracking my habits and I love the analog lifestyle—even my running plan is analog!

The combination of all of this is working out pretty well so far: My phone is mostly boring. It doesn’t have any exciting apps. It doesn’t spark joy. Because of this, I’m spending my time a lot more intentional.

That being said, sometimes I spend a little too much time on YouTube (at least that’s longform content) and I should probably delete the Slack app to not check the work chat when I’m not at my desk.

We deserve more humane tech

I’m happy to see the first smartphone vendors start to add physical switches to their phones to disable connectivity or limit apps4 and maybe I’ll switch to one of them one day.

This is not a political post, but if it was, it would talk about the obscene power of big tech and the necessity to regulate and break up. It would appeal on you to rethink your investment into these services, services that are actively spying on you, services that exploit your mental health for the sake of raising shareholder value.

Now go, touch some grass5. 🌱

  1. Knapp, J. & Zeratsky, J. (2018). Make Time: How to focus on what matters every day.

  2. Yes, you can turn all notifications off. I didn’t.

  3. Punkt MP02

  4. Fairphone 6, Mudita Kompakt

  5. Apparently there’s an app for that

My favorite things of 2024

2024-12-22 08:00:00

Here are my favorite things, digital and physical, of 2024!

Music

Books

These links go to my reviews (no spoilers):

Apps

  • Manet: I’ve started buying my music and hosting it myself this year1, this app makes it a joy to listen to music.
  • CouchTimes: The best TV show tracker in the App Store, period. It doesn’t have feature bloat and it respects your privacy.
  • Ghostty: A super fast, new Terminal emulator for the Mac.
  • Halide: This camera app has been around for a while, but this year they released Process Zero, a mode that applies minimal corrections and makes photos look more like digital camera photos.

Goods

  • aranet4: There are cheaper options, but a CO2 monitor for my home office has helped me keep the air at good levels.
  • heat-it: This tiny tool draws power from your phone to relieve itch & pain from insect bites.
  • Leatherman 2H Wave+: The only big Leatherman that’s legal to carry in Germany, super versatile and handy to have around.

What were your favorites?

  1. I even wrote a blogpost about it.

Jujutsu in practice

2024-10-21 08:00:00

This post is not about the Japanese martial arts Jiu-jitsu, it’s about a new VCS, or version control system. There are some great tutorials and introductions for Jujutsu, short jj, so I want to give some insight in how I use it day to day for this website.

Initialize a repository

You can initialize jj in an existing git repository like this:

$ jj git init --git-repo .

This will create a .jj directory next to .git. You can now use both git and jj, although I wouldn’t recommend it. There’s a work-in-progress native storage backend, but since all my projects are git repositories anyway, this works great for me.

Note that this is non-destructive; if you want to go back to git, all it takes is a rm -r .jj.

Get an overview

Running jj log in the repository for this very website gives this output:

$ jj log
@  qzsvtxpv [email protected] 2024-10-21 09:58:06 e18f7532
  Add blog/jj-in-practice
 ○  yoxxsupn [email protected] 2024-10-20 22:55:03 ae5d9109
├─╯  Add library/calibans-war
 ○  tvkvwslw [email protected] 2024-10-20 22:49:54 5e4dee1f
├─╯  Add library/the-posthumous-memoirs-of-bras-cubas
 ○  pywmtrys [email protected] 2024-10-20 21:20:11 7bda14b7
 │  Add atoms/1
 ○  xnlzypwn [email protected] 2024-10-20 21:20:10 8a004404
├─╯  Add atoms functionality
  wxxtrmqk [email protected] 2024-10-20 16:18:15 main HEAD@git 1eb46c81
  Add weekly/166
~

This already shows one of the biggest differences, compared to git: There’s no branches, other than main. You can create branches, which are called bookmarks in jj, but you don’t need to. Instead, you work mostly with changes1.

The terminal above shows the change w (you can use the first letter to reference changes; on your terminal it’ll be highlighted as well) as a parent to x, t, y and q. All these child-revisions don’t have a branch/bookmark, but they don’t need one. You can see what’s in-flight at this repository better than with any git repo, especially if branches haven’t been cleaned up in a while.

Create a revision

My usual flow with git is to leave changes in the staging area until I’m ready to commit. Sometimes, if I have to switch branches or want to save my work, I’ll stash or create a WIP commit.

In jj, there is no staging area—everything is a revision. Let’s create a new revision on top of my revisions where I add atoms functionality:

$ jj new -r p

Running git log again:

$ jj log
@  kxqvnxnw [email protected] 2024-10-21 10:03:20 22c020cf
  (empty) (no description set)
  pywmtrys [email protected] 2024-10-20 21:20:11 HEAD@git 7bda14b7
  Add atoms/1
  xnlzypwn [email protected] 2024-10-20 21:20:10 8a004404
  Add atoms functionality
 ○  qzsvtxpv [email protected] 2024-10-21 10:03:18 27229dca
├─╯  Add blog/jj-in-practice
 ○  yoxxsupn [email protected] 2024-10-20 22:55:03 ae5d9109
├─╯  Add library/calibans-war
 ○  tvkvwslw [email protected] 2024-10-20 22:49:54 5e4dee1f
├─╯  Add library/the-posthumous-memoirs-of-bras-cubas
  wxxtrmqk [email protected] 2024-10-20 16:18:15 main 1eb46c81
  Add weekly/166
~

You’ll notice that our active revisions are now left-aligned, and the one to add this very blog post has moved to the right. There’s no hierarchy, they’re all descendants of Add weekly/166.

After doing some work, e.g. adding a new atom, I can describe that revision with jj describe. This is comparable to git commit, but it doesn’t actually create a commit or a revision, it only describes the current one.

Sometimes I want to update a previous revision, in this case Add atoms/1. I can run jj squash to merge the current one with its parent.

Push and pull

To fetch new revisions, I run jj git fetch; to push branches/bookmarks, I run jj git push. This uses the same git server it was using before.

Before pushing, I need to move my bookmark to the revision I want to push. I push the main branch to deploy my website, so if I wanted to publish my atoms functionality (should I?), I would run jj bookmark set main -r p before pushing.

Rebase and split

Sometimes I need to rebase. Fortunately that’s a lot simpler than it is in git: I can run jj rebase -s <source> -d <destination> to move revisions around. If I wanted support for atoms for this blog post, I would run jj rebase -s q -d p and it would move the revision for this blog post on top of “Add atoms/1”.

jj also does automatic rebasing, e.g. if you squash changes into a revision that has descendants.

And if I have a revision that I’d like to be two, I run jj split and interactively select what belongs to which revision.

Undo

Undoing an (interactive) rebase in git is not fun. jj undo undoes the last jj operation, doesn’t matter if it’s abandoning (deleting) a revision or doing a rebase. This is a life saver! You can also run jj op log to display your last jj operations.

Things I stumble upon

I’ve been using git for a long, long time. My brain assumes that after a commit, I’m working on the next one. It also assumes that jj describe does the same as git commit (it does not). I often describe a revision and continue editing files, which then erroneously get added to the current revision. I’m not saying this is wrong, it makes sense in the jj world, but I keep tripping over that and have to run jj split to pull changes out again.
alterae on Lobste.rs pointed out that you can describe and immediately create a new revision on top of it with jj commit. Thanks!

One other thing is that you cannot check out a revision directly (or maybe I just don’t know how to), so when I’ve moved to a different revision and want to move back, I run jj new <revision>, which creates an empty revision on top of it. This means that if I’m not done with the revision, I have to keep running jj squash to move changes into it.
gecko on Lobste.rs pointed out that you can check out a revision directly with jj edit <revision>. Thanks!

Why it works for me

A week ago, I removed jj from my website’s repository, to see if I’d miss it. I added it back the same day. Jujutsu feels lighter than git, while at the same time giving you a full overview of what’s in-flight right now2. Having no staging area means I only need to worry about revisions (see caveat above).

If trying new things sounds fun to you, give Jujutsu a spin!

Further reading

  1. What’s cool about a jj change, is that updating it doesn’t change its ID.

  2. If you work in large projects with many contributors, you can tune your jj log to only your revisions.

We need more zero config tools

2024-10-01 08:00:00

It just works. — Steve Jobs

If you follow this blog, you’ll know that I’m doing a series called “Emacs Config From Scratch”1. Emacs is an editor operating system, where you can configure and customize literally everything. I like that you can truly make it yours, but it’s a lot of work to get there.

Recently, I’ve become fond of (command line) tools that just work, out of the box2. This blogpost is an ode to them.

Fish

Julia Evans recently posted Reasons I still love the fish shell, and the first point she makes is “no configuration”.

Things that require plugins and lots of code in shells like ZSH, like autosuggestions, are included and configured by default in fish. At the time of writing this, my fish config has less than 31 loc, most of which are abbreviations.

I have two fish plugins configured: z for jumping to a directory, and hydro as my shell prompt. Neither need configuration.

Helix

My Neovim config had 21 external plugins. Making LSP, tree-sitter and formatting work took a while (LSP alone needs 3 plugins) and in the end there were still things that didn’t work.

I’ve switched to Helix, which can do so much out of the box, here’s a non-exhaustive list:

  • LSP (including autocompletion, show signature, go to definition, show references, etc.) just works
  • Tree-sitter is built in, you can even do selections on tree-sitter objects
  • A file picker and global search
  • Pressing a key in normal mode shows subsequent keys you can press, and what they do
  • You can jump to any visible word, add/remove/replace quotes or other characters
  • … and so much more

The config for the code editor I use all day is 5 loc. Here it is:

theme = "kanagawa"

[editor]
line-number = "relative"
cursorline = true
rulers = [80]

I will say that it takes some getting used to as it folows the selection -> action model, i.e. you need to run wd instead of dw to delete the next word.

Lazygit

After raving about Magit in London, my team showed me Lazygit and I’ve been using it ever since—it’s really good and it does exactly what you want it to do, without configuration3.

You can toggle different screen modes, panes adjust in size when active and pretty much everything you want to do is only a few keystrokes away.

Zellij

A batteries-included Tmux alternative, Zellij doesn’t need any configuration to work well. You can set up Layouts without additional plugins (although there is a plugin system) and I’m generally not missing anything from my Tmux configuration.

My favorite feature is the floating panes. Press Ctrl + p, w to toggle a pane floating on top of everything else—I often use this for Lazygit.

What else?

Here are some tools you have sent me that are zero/minimal config:

  • Matthew shared Broot, a new way to see and navigate directory trees
  • Ilija shared k9s, a CLI to maange Kubernetes clusters
  • Alexander shared Orbiton, a text editor they built

Do you have a tool that requires no (or minimal) configuration? Send me an email and I’ll add it to the list!

And if you’re building something, please strive to make the default experience work really well for most people.

  1. Check it out

  2. I’m starting to feel the same about programming languages and external dependencies, but that’s a different post.

  3. You can configure almost everything—but you don’t need to.