Self-hosted eBook library with Komga
After weeks of using Audiobookshelf to listen to audiobooks daily, it dawned on me that the PDF reader was probably not the best I could be using.
Then is also dawned on me that Audible is not my only source of eBooks; I have a few from HumbleBundle deals and a few indipendent authors who sell PDF files directly, as well as a small collection of appliance manuals and electronics datasheets. All these files have been scattered all over the place, never having a common home where they could all be conveniently navigated and read.
Until now. Enter... Komga.
Komga is described as a media server for your comics, mangas, BDs, magazines and eBooks. Most importantly, for me, is that it handles individual books, file names and metadata better than a few others.
Installation
To deploy Komga in Kubernetes, the setup is essentially a fork of Audiobookshelf deployment.
A single phisical volume to store the application's databases is
needed, while the books are read from /home/depot/books/:
Once the directories and files a ready, we run Komga as the same
non-privileged user as Audiobookshelf, based on
Komga's docker-compose:
Kubernetes deployment: komga.yaml
| komga.yaml | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
$ kubectl apply -f komga.yaml
namespace/komga created
persistentvolume/komga-pv-config created
persistentvolume/komga-pv-books created
persistentvolumeclaim/komga-pvc-config created
persistentvolumeclaim/komga-pvc-books created
deployment.apps/komga created
service/komga-svc created
ingress.networking.k8s.io/komga-ingress created
$ kubectl -n komga get all
NAME READY STATUS RESTARTS AGE
pod/komga-5c865d6587-tvlt2 1/1 Running 0 28s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/komga-svc NodePort 10.103.226.126 <none> 25600:30600/TCP 8s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/komga 1/1 1 1 29s
NAME DESIRED CURRENT READY AGE
replicaset.apps/komga-5c865d6587 1 1 1 28s
Configuration
Once the application is running for the first time, register an
account (which will be the administrator) and start creating
libraries based on the files available under /data.
When creating libraries in Komga, an important step if there are individual books, is to put then under one (or more) directories that will be recognized as One-Shots.
My libray is rather small and exclusively made ouf of one-shots, although I found it useful to store a few files as a kind of series:
- Art and LEGO: eBooks from HumbleBundle deals.
- Audible: visual aids (PDF files) from Audible.
- Cosplay: books from Kamui Cosplay and Punished Props
- Including a couple of sets of templates, which make sense to store as kind of small series.
- Terry Pratchett: a small collection of Discworld Fanfics, mirrored at home just for convenience.
These are organized under the /data volume as follows:
/data/Art/books/
/data/Audible/books/
/data/Cosplay/books/
/data/Cosplay/templates/Jade Rabbit/
/data/Cosplay/templates/Ripper Axe/
/data/LEGO/books/
/data/Terry.Pratchett/books/
All individual books are stored under a books subdirectory under
each library directory, and then this name is set as the
One-Shots directory for every library:
eReaders
While Komga comes with a good web-based eBook reader, this is only good when used on a laptop or desktop PC with a big enough screen. To read books on a tablet or phone, this web UI is hard to use because once it is zoomed in enough to make the text readable turning pages is akward, confusing and sometimes frustrating. A much better experience is often available through several eReaders devices or applications.
Warning
If access to the Komga web UI is gated behind an access control layer, such as Cloudflare Tunnels or Pomerium, additional configuration will be necessary to allow unauthenticated access to Komga API endpoints (relying only on Komga's own authentication).
Kobo
Kobo eReaders may well be the best, open-source friendly eReaders out there. They can be easily tweaked to sync with a Komga server instead of the official Kobo servers, and Komga has the ability to proxy syncing on to the official Kobo servers, so the reader has access to both a private collection on a Komga server and books and audiobooks purchased from Kobo.
As anticipated in the Troubleshooting section of the Komga guide for Kobo sync,
Sync fails with Invalid character found in the request target,
which is resolved by adding an environment variable in the above deployment:
| komga.yaml | |
|---|---|
Komic for iOS
Komic seems to be the best, free to use (and not limited behind paywall or subscription) eReader iOS app for iPad. Although slightly hidden, it hes the option to filter books by library:
eReaders for Android
There are only a few eReader Android apps that are actually easy to install on a non-rooted Android phone, through the Google Play store, without side-loading an APK, and actually work. Of those few, there is maybe one that is not too annoying to use.
All of them require first that the Komga catalog is available as an OPDS feed.
Enable OPDS catalog
Komga works with OPDS eReaders, whether they use OPDS v1 or v2, but getting Komga to produce a well-formed OPDS catalog requires a few adjustments to the aboove deployment to make it use the correct URL in the ODPS feed by adding two environment variables:
-
KOMGA_SERVER_BASE_URLset to the external URL Komga is reachable at. -
SERVER_FORWARD_HEADERS_STRATEGYset toFRAMEWORKto make Komga trust the headers coming from the reverse proxy gating access to it.
Why is SERVER_FORWARD_HEADERS_STRATEGY necessary.
Even with the KOMGA_SERVER_BASE_URL set to the external URL, Komga's OPDS
generator uses dynamic link building. When unaware of a reverse proxy gating
access, Komga sees incoming requests from an internal IP address and uses that
IP to construct the "absolute" URLs found in the XML feed. Setting
SERVER_FORWARD_HEADERS_STRATEGY to FRAMEWORK tells it to "unwrap" the proxy
headers and treat komga.ssl.uu.am as its own identity.
Apply the changes to the deployment and check the variables are set:
$ kubectl apply -f komga.yaml
namespace/komga unchanged
persistentvolume/komga-pv-config unchanged
persistentvolume/komga-pv-books unchanged
persistentvolumeclaim/komga-pvc-config unchanged
persistentvolumeclaim/komga-pvc-books unchanged
deployment.apps/komga configured
service/komga-svc unchanged
$ kubectl describe pod komga -n komga | grep -A3 Environment
Environment:
KOMGA_SERVER_BASE_URL: https://komga.ssl.uu.am
SERVER_FORWARD_HEADERS_STRATEGY: FRAMEWORK
SERVER_TOMCAT_RELAXEDQUERYCHARS: [,]
Reverse proxies gating access to Komga also must be adjusted to set the required headers.
For the original Nginx ingress above, this can be done by adding these annotations:
After replacing Nginx with Pomerium, just one annotation is needed to set the required headers in the new Pomerium ingress:
Once all the above changes are applied to Komga and the relevant reverse proxy, the OPDS catalog should be available at the following URLs:
Both feeds must be using the externally facing URL rather than an internal IP address:
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>root</id>
<title>Komga OPDS catalog</title>
<updated>2026-01-04T13:55:36.737358992+01:00</updated>
<author>
<name>Komga</name>
<uri>https://github.com/gotson/komga</uri>
</author>
<link type="application/atom+xml;profile=opds-catalog;kind=navigation" rel="self" href="https://komga.ssl.uu.am/opds/v1.2/catalog"/>
<link type="application/atom+xml;profile=opds-catalog;kind=navigation" rel="start" href="https://komga.ssl.uu.am/opds/v1.2/catalog"/>
<link type="application/opensearchdescription+xml" rel="search" href="https://komga.ssl.uu.am/opds/v1.2/search"/>
<link type="application/opds+json" rel="alternate" href="https://komga.ssl.uu.am/opds/v2/catalog"/>
<entry>
<title>Keep Reading</title>
...
{
"metadata": {
"title": "All libraries - Recommended",
"modified": "2026-01-04T15:44:57.858656045+01:00"
},
"links": [
{
"rel": "self",
"href": "https://komga.ssl.uu.am/opds/v2/libraries"
},
{
"title": "Home",
"rel": "start",
"href": "https://komga.ssl.uu.am/opds/v2/catalog",
"type": "application/opds+json"
},
...
Either of these can be used to add the Komga server as a remote (network) library in eReader applications, although the v1.2 feed is recommended for maximum compatibility.
PocketBook
PocketBook seems to be the only Android eReader app that is acceptable; easy to install, actually works, and is not obnoxiously ridden by disgusting ads.
To connect the app to the Komga library:
- Tap the Menu icon () in the top-left corner.
- Tap on Network Libraries and then tap the
+icon usually found inside a folder icon () at the top of the screen. - Enter the Komga librart details:
- URL: https://komga.ssl.uu.am/opds/v1.2/catalog (for maximum compatibility).
- Catalog Name: enter a name (e.g., "My Komga").
- When prompted, enter the Komga username and password.
Once the Komga server has been added as a network library, books can be downloaded to the phone and they will later show up on the initial view when opening the app later.
| Network libraries | Komga libraries | Art library | Deck |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Discarded
The few other Android eReader apps that are actually easy to install on a non-rooted Android phone, through the Google Play store, without side-loading an APK, and actually work, fail miserably in the user experience they chose to offer; they chose to be obnoxiously annoying.
- Librera starts with the most annoying "Manage your data" dialog with a long list
of "partners" who claim to make "legitimate use" of your data (yeah, right), then
displays adds a big button blended into the ui in a blatant attempt to confuse users
into tapping on the ad when looking for the option to add a network library, which is
hidden behind a tiny
+icon on the top right, and then (disgusting) ads are displayed all the time taking away valuable screen space. - Moon+ Reader not only hides the UI controls to add a network library a few levels deep in the UI, it also makes those books not available anywhere else than in that off-the-main-track section. Not does this app contain ads, it's also quite horrible about it; upon closing a book, it displays multiple, non-skippable, disgusting ads. Being bombarded with ads from the some of the worst, beyond borderline illegal apps; the only sane way to use this app is to avoid leaving a book and instead close the app entirely each time.
Alternatives
Komga is not the only Free Software application available for this purpose, so it is worth mentioning why it was chosen over the alternatives.
Priot to setting up Komga, I spent some time trying the same with kavitareader.com. The Kubernetes deployment was essentially the same, based on linuxserver.io/images/docker-kavita. The main drawback that kept me from using this one long-term was that it really is built for series and really not for individual books.
Admitedly, that was the only one I tried among other alternatives mentioned here. Others include:
- Calibre Web, available as janeczku/calibre-web or linuxserver/calibre-web. It only supports a single library and requires using the Calibre desktop application. While this wouldn't be a problem for myself, it would prevent kids from reading the books because they only have school laptops where Calibre cannot be installed.
- Librum could be a good option, were it not for a similar requirement to install and run a client application. This is not a web app.






