Update - eLibrary Setup

The setup I will present has gone through many iterations and changes. The main application has changed so many times that it would seem ridiculous. Testing has included Calibre-Web, Kavita, Koodo Reader, and OPDShelf. There are a few other apps in between that weren’t able to spin up even locally or with more than half of the capabilities I was looking for.

What I Use

My setup is fairly straightforward with only a handful of applications needed to get it working. It is deployed on a 1 CPU / 1 GB RAM server that is also running other setups. The only part of the setup that I would not classify as simple is the integration of Caddy to handle basic authentication for OPDS feed traffic.

Authentication and Library System

I deployed 2 pods for Tinyauth and OPDShelf using podman with minimal environment setup, specifically with only defining a set of users to populate TINYAUTH_AUTH_USERS and pointing where the OPDS server could find my library content mounted at /app/books.

# create each user
podman run -i -t --rm ghcr.io/steveiliop56/tinyauth:v5 user create --interactive

# start Tinyauth
podman run -d --name tinyauth -e TINYAUTH_AUTH_USERS=<user:hash_list> -e TINYAUTH_APPURL=tinauth.sub.domain ghcr.io/steveiliop56/tinyauth:v5

# start up OPDShelf
mkdir -p /path/to/library

podman run -p 8080:3000 -v /path/to/library:/app/books koalilla/opds-server:latest

I was very partial to Kavita beacuse it didn’t require any external database configuration, but there was a lot of container bloat from unused software features and small issues I ran into when trying to import files from directories with unique structures. OPDShelf, on the other hand, auto scans whatever is mounted at /app/books.

Content

The content of the shelf was populated using filen.io, WebDAV, and a simple non-permanent mount. I enjoy using the Filen CLI, but I was not able to get anything mounted with it or even rclone.

To mount a read-only filesystem, I spun up a small local WebDAV server with a systemd service. The local server was able to mount the content and sync the changes from cloud storage. In contrast, I use Koofr to host my FLAC files, which are also mounted as a read-only filesystem using rclone directly.

# mount command for WebDAV
mount -t davfs2 http://localhost:<webdav_port> /path/to/library

Running the podman run command with --restart always and adding the mount to /etc/fstab would make sure that the mount stays in place with reboots.

Routing

The most difficult part of this setup was the Caddyfile configuration. In previous deployment setups, I used Nginx but decided to migrate everything over to Caddy. Since I have domains through PorkBun, GoDaddy, etc. the Caddy binary needed to be modified to support certain DNS plugins. xcaddy is the best tool for this, but can be a very manual process.

I created a subdomain for Tinyauth, then required all requests to first be forwarded and authenticated through it. I configured the Caddyfile to exclude all traffic to /opds because those feed requests would use basic auth. OPDShelf points its root to the feed and the actual UI points to /admin. I think that this should be reversed, and configured my application to have the root domain point to the UI and the path /opds point to the feed. Caddy has extensive documentation that covers configurations for many different domain registrars.

# sample Caddyfile
(tinyauth_forwarder) {
        forward_auth localhost:3000 {
                uri /api/auth/caddy
                copy_headers Authorization Remote-User Remote-Groups Remote-Email Remote-Name
        }
}
some.domain {
        tls {
                dns godaddy <api_key>:<api_secret>
                propagation_timeout 60m
                propagation_delay 5m
                resolvers 8.8.8.8 8.8.4.4
        }
        @opds path /opds*
        handle @opds {
                basic_auth {
                        <basic_auth_user> <basic_auth_password_hash>
                }
                rewrite * /
                reverse_proxy localhost:8080
        }
        handle {
                import tinyauth_forwarder
                @root path /
                redir @root /admin

                reverse_proxy localhost:8080
        }
}
tinyauth.some.domain {
        tls {
                dns godaddy <api_key>:<api_secret>
                propagation_timeout 60m
                propagation_delay 5m
                resolvers 8.8.8.8 8.8.4.4
        }
        reverse_proxy localhost:3000
}

What Next

I have macOS devices that use the Books app, which works as a way to read downloaded content, but I have not found a similar tool for any of my Android devices, nor have I found out if the basic auth works with my e-reader. I will be testing a lot of free apps, and will share what works or what offers the best features on the free tier.

Since user authentication configuration is manual and Tinyauth has no dependencies, I am slow to automate user creation. Eventually, this will become automated, but to keep it secure, each user would need to be added to some maintained allow list to limit bot access.

The easiest upgrade to the current setup would be to add the mount to /etc/fstab, and this will most likely be completed first.

Many people online have begun speaking out about data retention and privacy, and I believe that fellow readers, digital archivist and the like will find use in this solution. Purchased Kindle books being removed from user libraries and “updates” made to already purchased content raises the question of who really owns digital content.

What are actions that can be taken today to help people learn how to host their own data? What are some tools that can be used that are free or low cost with minimal effort to implement for the everyday person?