All you need is epub: an overengineered ebook setup

I love to read! But, I've constantly felt that I should do more of it. Getting an ereader (well, two of them) has been a gamechanger. You know how you go traveling and fill your suitcase with half your reading backlog? Then, you feel the itch to read something. Instead, you end up doomscrolling. Why? You realized that the book you actually would've wanted to read is back home, hanging out with the other books in your pile of unread books.

Don't get me wrong! I adore physical books. Nothing beats the smell of a new book, or the texture of the paper as you change pages. Well, nothing except reading something that you feel excited about. An ereader is portable and can hold a practically infinite amount of books. And, if you've read my post on self-hosting, I'm happy to share how you can set up a self-hosted ebook reader ecosystem.

Hardware

Of course, you'll need at least one proper ereader. In my case, I use two different ereaders from Boox: the Palma and the Go6. The Palma is about the size of a normal smartphone, and the Go6 is large enough to feel like a real book but still portable.

My Boox Palma and Go6 ereaders.
My Boox Palma and Go6 ereaders.

Both ereaders hit the sweet spot, for me, in terms of price, quality, and flexibility[1]. This last feature is important—these are Android devices. Because of this, they can run a wide range of apps[2]. Crucially, this includes KOReader, which is the app I'll be using in the rest of this post. If you're not using an Android ereader, KOReader does support other systems too (I just don't know how to set it up).

KOReader

There's a lot you can say about KOReader. It's unsexy, has a terrible built-in keyboard, and a confusing interface. Your typical jack-of-all-trades open source app. But you're a self-hoster, so you are used to that. As you might have guessed, KOReader is also very flexible and has a really impressive range of plugins you can use[3]. This DIY spirit makes KOReader work really well for self-hosters.

Installing a plugin is straightforward. You download the directory containing the plugin. Then, you simply add this directory under the koreader/plugins path[4]. One important caveat: the directory must be named [PLUGIN NAME].koplugin. I wasted an embarrasingly long time debugging why my plugins didn't get loaded by KOReader, only to realize that the directory name was wrong.

In this post, we'll be running KOReader with the following plugins:

  1. CWA Sync
  2. AnnotationSync

Books

First things first: you need a place to host your library. Calibre is a popular open-source tool that runs on your machine and lets you organize your books. However, you want to be able to run this headlessly on your homelab. So, instead of (or in addition to) standard Calibre, I suggest you run Calibre-Web Automated (CWA).

In my setup, I run Calibre-Web-Automated for two purposes: managing my books and making them available using OPDS and for syncing my progress between devices. As I mentioned earlier, I use two different ereaders. With KOReader + CWA Sync and a CWA server running in your homelab, you can access, upload, and sync your reading regardless of which device you're using. Both the CWA server and the KOReader sync plugin are easy to setup, and there's really not that much to explain. CWA provides a great guide to how to configure things, and the suggested docker configuration didn't need a whole lot of adjustments in my case.

Articles

(Wallabag intro w plugin for Firefox etc)

CWA allows me to access books via OPDS. KOReader has great OPDS support, and the interface is really convenient for accessing books. KOReader has a Wallabag plugin, but I find it (at the time of writing) very limiting. It only allows you to sync a fixed number of your latest saved posts, and you can't pick and choose which ones you're actually interested in. Making matters worse, I've found the plugin pretty slow? In any case, the built-in OPDS plugin is much better. Unfortunately, Wallabag doesn't natively support exposing articles via OPDS.

Here's where I got a bit creative. OPDS is a pretty simple XML-based protocol, and is a prime vibe coding target. Naturally, I made my own Wallabag OPDS proxy. Just configure the .env with your Wallabag URL and Wallabag API keys. Now you can access your Wallabag content via OPDS! I provide no guarantees that it'll be updated forever, or that it's in any way a secure solution (it's 100% vibe coded) but it works really transparently.

Annotations

Putting it all together

(Diagram)


  1. There is one big downside, though. These devices are known to phone home to Boox. Depending on how highly you value your privacy, and how dangerous your reading materials are, this might be a problem. Of course, since they are running Android, there are guides for how to root the devices and block this behavior. ↩︎

  2. In practice, I don't run that many apps on these devices. But in addition to KOReader, you have access to a fully-functional web browser, and you can also run Termux. For the tinkerer, this can prove very handy. ↩︎

  3. The app, and its plugins, are written in Lua. In an age of vibecoding, this means that you could also create your own bespoke plugins to fix any pain points you might have. In fact, I'm in the process of (slowly) creating an autocorrect feature for the clunky built-in keyboard. ↩︎

  4. If you are running Termux on your device, then you can streamline this process easily. Simply go to storage/shared/koreader/plugins, wget the appropriate Git repo, and unzip it. Bonus: you can now update the plugin with a simple git pull. ↩︎

Written on August 3, 2026.