Running Calibre on a Virtual Machine with a Network Library

This article started out as just a guide on running Calibre with a network library, a difficult task at the best of times, it has since had to morph into a guide on running Calibre Web in the same way since that too is non-trivial.

Calibre

Calibre is certainly a powerful application, of that there is no doubt, but it’s also the application that I like setting up and using the least. It’s got somewhat better over the years but it’s awkward to manage and has a complex and confusing interface. The most frustrating aspect from my point of view is that it’s not a native web application which means hosting it is a painful experience. The docker container provides a sort of web application experience but it’s actually running a very cut down desktop and VNC system. Of all the containers I run this is the only one that breaks down. If that wasn’t enough Calibre is completely allergic to network shares whether they are SMB or NFS. I get why, databases have to be locked and you can’t reliably do that on a network share, but every other application can figure out how to get around that – just store the database locally. Anyway, enough complaining I just set Calibre up again and I think I’ve got it to the point where I’m sort of happy with it.

I’m using Portainer now rather than hacking on Docker manually like a caveman. I’ve recently switched over to using stacks for applications rather than the container interface. For Calibre this is actually needed because it requires seccomp to be specified and there’s no way to do that though the container form in Portainer. The stack I’m using is shown below.

version: "3"
services:
  calibre:
    image: lscr.io/linuxserver/calibre:latest
    container_name: calibre
    security_opt:
      - seccomp=unconfined
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
      - CALIBRE_OVERRIDE_DATABASE_PATH=/db/metadata.db
    volumes:
      - /data/calibre/config:/config
      - /data/calibre/db:/db
      - /data/mnt/books:/books
      - /data/mnt/scratch/piracy/calibre:/external
    ports:
      - 8080:8080
      - 8081:8081
      - 8181:8181
    restart: unless-stopped

There are a couple of interesting points that need explaining here. The first is the security_opt setting, this is marked as optional on the Docker Hub page, but I found that it doesn’t work without it. Setting PUID and PGID is a must to stop the application running as root. The most important setting though is CALIBRE_OVERRIDE_DATABASE_PATH, this tells Calibre where to look for it’s database file. Normally, Calibre will put it’s database file in the root of the directory where it expects to find books (/books in the container). This is fine if the books are stored on the same physical or virtual machine as the application but a total loss if you store your books on a NAS.

To get around this limitation I created a new configuration folder for just the database and bound it into the container. This folder is on the media server (the same server Calibre is running on) and the books folder is on a NAS. This seems to work fine. The external directory is for adding new books to Calibre. It likes to to the import itself and put the new material into the books directory, it’s very particular about naming and organizing the files. Thanks to this question for pointing me in the right direction, and here’s a bug report.

Linuxserver and PUID, PGID

Specifying UID and GID with the settings below in a compose script seems to cause the linuxserver containers to fail to launch correctly. They apparently grab a different user and then can’t switch to the user specified in the PUID and PGID environment variables. The error message given is something along the lines of s6-rc: warning: unable to start service init-adduser: command exited 127. Just use PUID and PGID for these containers.

user: 1000:1000

Calibre Web and a NAS

It is with a heavy heart that I have to write this section. I thought getting Calibre Web set up would be easy but it turns out it’s not quite as easy a I expected. I set it up as per the instructions on Docker Hub and it failed with a 500 error. It took a bit of head scratching to figure out what was wrong but eventually I had an ah-ha moment. Calibre web reads the Calibre database (metadata.db) and although I’d correctly pointed it at the folder I store my books in the database was no longer there. Pointing Calibre Web at the location of the Calibre database allowed the application to run fine but then it couldn’t find any of the books. Doh!

The solution was the following compose script

version: "3"
services:
  calibre-web:
    image: lscr.io/linuxserver/calibre-web:latest
    container_name: calibre-web

    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
      - DOCKER_MODS=linuxserver/mods:universal-calibre
    volumes:
      - /data/calibre-web/config:/config
      - /data/mnt/books:/books
      - /data/calibre/db/metadata.db:/books/metadata.db
    ports:
      - 8083:8083
    restart: unless-stopped

Notice the explicit mapping of the metadata.db file into the containers /books directory. Many thanks to the people answering in this feature request for the workaround.