Recently, in my efforts to increase how much I read, I recognized a need to level up my eBook game by introducing:
- A place to store and organize all my eBooks.
- A way to sync reading progress in KOReader across devices.
I didn’t want to rely on Dropbox/Google Drive, buy another subscription or change my field-tested reader app. Instead, I built my own private setup on a cheap VPS.
Here’s how you can do it too. I took some inspiration from Selfhosted eBook Library post, so you might also want to check it out.
The Goal
- calibre-web → web library for ebooks, including OPDS feed
- KOReader Sync Server → sync reading progress between devices
- Nginx + Let’s Encrypt → free SSL certificates and reverse proxy
- Cheap VPS (mine costs 1€/month + 10€ activation)
Step 1. Install Docker & Docker Compose
On your VPS (I use Ubuntu 24.04) install docker and docker-compose. Test if it works fine:
docker --version
docker-compose --version
⚠️ If you use docker-compose in version 1.29.2, you might experience some issues with ContainerConfig on the restart. I suggest updating the tool.
Step 2. Set Up Docker Compose
Create a docker-compose.yml file, with a configuration similar to:
version: "3.3"
services:
calibre-web:
image: linuxserver/calibre-web
container_name: calibre-web
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Warsaw
- DOCKER_MODS=linuxserver/mods:universal-calibre
volumes:
- ./calibre-web/config:/config
- ./calibre-web/books:/books
ports:
- 8080:8083
restart: unless-stopped
koreader-sync:
image: koreader/kosync:latest
container_name: koreader-sync
volumes:
- ./koreader-sync/data:/var/lib/redis
- ./koreader-sync/logs/app:/app/koreader-sync-server/logs
- ./koreader-sync/logs/redis:/var/log/redis
ports:
- 17200:17200
restart: unless-stopped
Start the containers:
docker-compose up -d
Check that the services are running:
docker ps
Step 3. Configure Nginx Reverse Proxy
I was thinking about using Cloudflare Tunnel, I ended up using Nginx as a reverse proxy because it allowed me to keep my domain in the current service. Assuming you create two subdomains for new services:
- books.domain.com
- sync.domain.com
Install Nginx:
sudo apt install -y nginx
Create new site configurations (2 of them, one for books, one for sync):
sudo vim /etc/nginx/sites-available/{books,sync}.domain.com
Example configurations (2 separate configuration files) :
server {
listen 80;
server_name {books, sync}.domain.com;
location / {
proxy_pass http://localhost:{for books: 8080, for sync: 17200};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Enable the sites:
sudo ln -s /etc/nginx/sites-available/{books,sync}.domain.com/etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Step 4. Secure with Let’s Encrypt
Install Certbot:
sudo apt install -y certbot python3-certbot-nginx
Request certificates:
sudo certbot --nginx -d books.domain.com -d sync.domain.com
Step 5. Test the Setup
For Calibre-Web:
curl -v http://books.domain.com
For KOReader Sync:
curl -k -H "Accept: application/vnd.koreader.v1+json" https://sync.domain.com/healthcheck
Expected JSON response: {"state":"OK"}
Step 6. KOReader configuration
OPDS Catalog
- Open KOReader
- Tap on the top and then 🔍 icon
- On the bottom, tap
OPDS catalog - Now, tap on the hamburger icon on the top left corner
- Then
Add catalog - Fill the details as below

/. admin/admin123 are default calibre-web credentials.7. Enjoy the access to your private library of books!
KOReader Sync Server
- Open a random book in KOReader
- Tap on the top and then 🛠️ icon
- Click on
Progress sync - Then tap on
Custom sync server - Type in the full address:
https://sync.domain.com/ - Click ok, and then
Register/Loginbutton below - Enter your username and password, then tap
Register - Repeat this on other devices, but instead of
Register, tapLog in. - Configure your sync settings using
Periodically sync ever # pagesoption - When all is configured correctly, when you read book on one device and open the same book on other device, you’ll see a dialog like this:

Step 6. Benefits & Lessons Learned
- Secure HTTPS via reverse proxy; apps run plain HTTP internally.
- Cheap & private: only pay for VPS, all data stays under your control.
- Docker makes management easy: restart, update, or wipe containers without losing data.
- Let’s Encrypt auto-renews certificates; no manual intervention needed.
- KOReader progress sync + ebook library is fully functional across devices.
Now you have a fully self-hosted, cheap, and secure ebook library!
Leave a Reply