Monday, June 11, 2012

Setting up a headless Calibre server

My wife and I like to read books on the go, and we use an Android app called Aldiko (it's great) to read epubs. I have loads of epubs on my computer, and I have traditionally used Calibre's server feature to share them with our phones. In the past, I've kind of clobbered together things on an Ubuntu box that also served as my main desktop computer. That worked well in the past, but I've recently set up a headless Debian Squeeze server, and I decided to migrate my Calibre server there. I had some setbacks, and thought it would be worth it to document the process here, and how I got things to work successfully.

My server runs headless, and that's the first problem with Calibre. The version of it in the Debian Squeeze repositories doesn't have a standalone server mode that is configurable without using the graphical UI. I can't have that, so I decided to get newer binaries installed. Ordinarily, I wouldn't recommend this, especially on a system like Debian whose community prides itself on the stability of their software packages, but this is a functional necessity, so I'll take it. This command, ripped straight from the official Calibre website, worked for me:

sudo python -c "import sys; py3 = sys.version_info[0] > 2; u = __import__('urllib.request' if py3 else 'urllib', fromlist=1); exec(u.urlopen('http://status.calibre-ebook.com/linux_installer').read()); main()"

When prompted, I told it to install to ''/opt/calibre'' so it wouldn't conflict with any system libs or binaries.

That means that ''/opt/calibre/calibre-server'' is the standalone daemon for serving e-books.

I wanted to servicize it, so I wrote this init script and placed it at ''/etc/init.d/calibre-server'':

#!/bin/bash

CALIBRE_LIBRARY_PATH="/home/shared/Calibre Library"
PIDFILE=/tmp/calibre-server.pid
USER=calibre
PORT=8081

start() {
        echo "Starting Calibre server..."
        su -c "calibre-server --with-library=\"$CALIBRE_LIBRARY_PATH\" -p $PORT --pidfile=$PIDFILE --daemonize" & 
        if [ $? -ne 0 ]; then
                echo "Could not start calibre-server."
        fi
}

stop() {
        echo "Stopping Calibre server..."
        if [ -e $PIDFILE ]; then
                read PID < $PIDFILE
                ps aux | grep "$PID" | grep 'calibre-server' > /dev/null
                RUNNING=$?
                if [ $RUNNING -eq 0 ]; then
                        kill $PID
                        if [ $? -eq 0 ]; then
                                rm $PIDFILE
                        fi
                else
                        echo "Could not find a calibre-server process with PID $PID."
                fi
        else
                echo "Could not find pidfile: $PIDFILE"
        fi
}

restart() {
        stop
        start
}

status() {
        if [ -e $PIDFILE ]; then
                read PID < $PIDFILE
                echo "calibre-server is running with PID $PID."
        else
                echo "calibre-server is not running."
        fi
}

unknown() {
        echo "Unrecognized command: $1"
        echo "Try one of the following: (start|stop|restart|status)"
}

case $1 in
        start ) 
                start
                ;;
        stop )
                stop
                ;;
        restart )
                restart
                ;;
        status )
                status
                ;;
        * )
                unknown
                ;;
esac

You can change the variables at the top to run the server differently. Once this is given execute permissions, you can start the server with:

/etc/init.d/calibre-server start

And stopped with

/etc/init.d/calibre-server stop

It looks like the ''service'' command works, too:

service calibre-server start

I know there are some other problems I need to work out (how to import new books, for example), but this seems like a good start. Anyone have any tweaks or additions to note?

6 comments:

  1. It would be nice if calibre could be started on another computer and remote into your server, but if it can't (I haven't looked this up), than what about installing something like nx and remoting in. Granted you would need to install X, but with a windows manager like fluxbox or icewm it would be really lite.

    ReplyDelete
  2. My solution is to simply have the library stored on a NAS. I can import books via my workstation as long as the service isn't running. It's not the most elegant solution, but does save you from having to install all of the X dependencies on a server.

    ReplyDelete
  3. Hi Ryan,

    thanks a lot for your post.

    I have installed an apache proxy with authentication in front of Calibre-server and it works fine.

    I put my config file in case anyone is interested:
    VirtualHost *:80
    ServerAdmin xxxx@xxx.com
    ServerName ebooks.xxx.org
    ErrorLog /var/log/apache2/error-calibre-xx.log
    CustomLog /var/log/apache2/access-calibre-xx.log combined

    #ProxyPreserveHost On
    ProxyPass / http://x.x.x.x:8080/
    ProxyPassReverse / http://x.x.x.x:8080/
    Proxy *
    Allow from all
    AuthType Basic
    AuthName "Calibre-auth"
    AuthUserFile /etc/apache2/password
    Require user myuser
    /Proxy
    /VirtualHost

    Cotolo

    ReplyDelete
  4. hm, still some questions left, how to backup or move to a new environment ? did anybody test the redbeam project for calibre (www.redbeam.com)? it is open source on github ( https://github.com/tomschlenkhoff/ReadBeam )

    ReplyDelete
  5. You could add LSB headers to the init script so that on Debian apt-get doesn't break with "insserv: there is a loop between service...":

    ### BEGIN INIT INFO
    # Provides: calibre-server
    # Required-Start: $remote_fs $syslog
    # Required-Stop: $remote_fs $syslog
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: Start calibre-server at boot time
    # Description: Enable service provided by calibre-server.
    ### END INIT INFO

    ReplyDelete
  6. You could eliminate the "when prompted" portion of the instruction by changing the install command to

    sudo python -c "import sys; py3 = sys.version_info[0] > 2; u = __import__('urllib.request' if py3 else 'urllib', fromlist=1); exec(u.urlopen('http://status.calibre-ebook.com/linux_installer').read()); main(install_dir='/opt/calibre')"

    ReplyDelete