Running Calibre as a Service with NSSM

Calibre (pronounced like the bullet) is one of my all-time favorite applications. It allows me to store, manage, and remotely access all of my ebooks in DRM-free formats, across a number of appliances, and share them with my family as well. It supports dozens of powerful community-written plug-ins, allows batch meta-data editing, has a built-in web-server, and converts books to and from multiple popular formats. But it was written as a single-user desktop application, which comes with certain limitations that are difficult to work around.

One of those limitations has to do with the file locking characteristics of various different operating systems. Because of those limitations, and the way Calibre is written, you cannot store your books in one place, and run the front-end from somewhere else. It is not a client-server application. There are people on the internet who have claimed that they have figured out how to run it that way, and they have published detailed instructions on how to do it, and I do not believe them. The author has explicitly stated that this way lies sadness and, after repeated attempts to prove him wrong, I am certain he is right. If you are going to run this thing, you are going to have to put the application, its database, and the book files all on the same machine.

That said, I would prefer not to run something like this on my primary desktop. It constantly uses memory that I might need for something else, and has (at least for me) large storage requirements. And I'm constantly doing unwise things to my desktop, which makes it a sub-optimal place to put a server my entire family accesses. So off to a server it goes.

Calibre is a GUI application. You can run the ebook server from a CLI without the GUI, but you can't manage your books from there. Since that's where at least half the utility comes from, and since the GUI has to reside with the server and the book files, you need to install it on a server with a desktop. Calibre will run on Linux, but all my Linux servers are (currently) headless, so I installed it on a Windows server.

Now, the GUI app has a cool button under the "Connect/Share" menu item that will launch a web service for your library. It's about as simple as possible. You click it, the service starts, and you can immediately access all your books from a compatible device at the server IP address on port 8080. And that's all it takes. But there is a downside to doing it that way.

First, Calibre allows you to run multiple different versions of your library. You can run one version for the kids filled with Magic Tree House and Encyclopedia Brown, and another one for the grown-ups filled with ... grown-up stuff. The "button" will only launch one version of the library.

Second, using the GUI to launch the server means you have to be running the GUI to run the server. This has performance implications. And it means you have to log in to the server in order to launch the service. This adds an annoying manual step to the process of getting this server running after planned and unplanned reboots.

My preference then is to run the server portion (when I'm not actively managing the library) without the GUI. The good news is that you can launch the server portion of Calibre from the command line. The bad news is that it doesn't run as a service, so you still have to log in. The other good news is that there is a way to get around that.

Enter NSSM ("The Non-Sucking Service Manager"). This neat little tool will package any executable, along with applicable arguments, credentials, and a few other variables, as a service. This service can be set to launch automatically on boot up, just like any other service.

To use, first go to the site page and download it. There's no install, just a couple of executables (32 and 64 bit versions), so just unzip it somewhere convenient. It's a command line tool. You can click the exe, but it will just display a window with the basic usage instructions. Feel free to poke around.

For the next step, you'll need to create a virtual library. Leave NSSM, and launch the Calibre GUI. In the upper left corner, you'll see a button labeled "Virtual Library". Click the binocular button next to that, and enter the criteria for the first slice you want to expose. For instance, you may want all the books with a tag of "Kids", or the opposite (NOT (tag:"Kids")). Fine tune it as much as you want to, then click the "Virtual Library" button, then "Create Virtual Library". This screen will allow you to review your filter criteria and Name the Virtual Library. For this example, assume we named it "Kids". Hit okay and close the Calibre GUI.

Next, we'll want to test access to the virtual library we just created. Open up a CLI and change directory to the Calibre folder.

cd C:\Program Files\Calibre2

Try to launch calibre-server with the Virtual Library filter.

calibre-server -p 8082 --username "kidz" --password "kidzB00kz" --with-library "\\ServerName\library" --restriction "Kids"

Note that the port (-p 8082), username, and password can be whatever you want. You are setting them here. "--with-library" needs to point to the UNC of the folder holding your Calibre metadata.db file (along with all your books). "restriction" is the Virtual Library you just created. The point of this exercise to is get all the parameters right. If you get a message that something is wrong (no such library, no such filter, etc.), fix it until nothing comes back. When the cursor doesn't return, it's time to test the server. Go to a browser on another machine on the network and enter in the server address (by IP is easiest) and the port you entered above.


Remember: You may need to open up a port on the server, or on your network, depending upon how you've set up your firewalls.

Once you see the Calibre home page, you know you have all the variables right. Now close the CLI to shut that down.

Now, open up a new CLI and change the directory to wherever you dropped NSSM.

cd \some\directory\nssm\nssm-2.24\win32 (or win64 if appropriate)

Launch the NSSM service installer interface:

nssm install calibre-server-kids

I'll refer you to the instructions for usage of all the tabs in the service installer.

The key fields you need here all on the first (Application) tab.
Path: The path to calibre-server.exe.
e.g. C:\Program Files\Calibre2\calibre-server.exe
Startup directory is auto filled. Leave it alone.
Arguments: This is everything you entered in the test above, right of the exe.
e.g. -p 8082 --username "kidz" --password "kidzB00kz" --with-library "\\ServerName\library" --restriction "Kids"

On the "Details" tab, this is what shows up in the Services tab of the server Task Manager. Make this as detailed as you want to.
On the "Log on" tab, I left this as "Local System Account", but YMMV.
I didn't use the "Dependencies", "Process", "Shutdown", "Exit actions", or "Environment" tabs.
If you have any problems with getting the service to run, you can set up logging with the "I/O" tab, and log rotation with the "File rotation" tab.

When everything looks good, hold your breath and hit the "Install service" button. If everything is right, you should see your service running in task manager, and the web browser test will work. If not, check your logs. To remove the service and start over, enter something like this:

nssm remove calibre-server-kids

Once everything looks good, create your next virtual library with your new filter criteria and do it again. I'm running 3 customer services in my environment, each using from 116k to 136k memory, dependent upon the size of the virtual library. When not being called, they use 0 CPU.

Obviously, NSSM has a lot more utility than just running Calibre servers, but this is as good an introduction as any. Now go forth and wrap exes.

Update: The 3.6.0 Update of Calibre significantly changes the parameters for the server piece. Now, a single server running with multiple accounts, each having their own access (set up from within the base UI), seems to be the best way to set this up. But NSSM, alas, seems to not like the new parameters. I was not able to find a way to run this as service and am now using the built in webserver initiated from the base UI.