Here are some notes on how to setup the main server after you've installed Debian and the usual server packages.

If you are migrating to a new server, you may be interested in the server migration plan that has been used for the last few server migrations.

Basic setup

  • Install Debian and tweak a few things
  • Install rssh and uncomment allowrsync in /etc/rssh.conf
  • Setup appropriate mail aliases

    • Add these to /etc/aliases

      root: francois
      www-data: root
      libravatar-master: root
    • Run newaliases to update /etc/aliases.db

    • Test the aliases by running mail root
  • Ensure that the only entry for localhost in /etc/hosts is for (if you leave the one for ::1, it will confuse gearman)

  • Copy the local logcheck rules from the old server and add the following to /etc/logcheck/logcheck.logfiles:

  • Create empty log files (for logcheck):

    touch /var/log/libravatar/error-{cdn,seccdn,www}.log
    chown www-data:www-data /var/log/libravatar/error-{cdn,seccdn,www}.log


  • In /etc/network/iptables.up.rules, put the following:

    # Set default policies
    :INPUT DROP [0:0]
    :FORWARD DROP [0:0]
    :OUTPUT DROP [0:0]
    # Allow unlimited outbound traffic
    # Annoying attack bots
    -A INPUT -s -j DROP
    # Accept all other traffic
  • Enable the rules using iptables-apply

  • In /etc/network/ip6tables.up.rules, put the following:

    # Set default policies
    :INPUT DROP [0:0]
    :FORWARD DROP [0:0]
    :OUTPUT DROP [0:0]
    # Allow unlimited outbound traffic
    # Allow unlimited traffic on the loopback interface
    -A INPUT -i lo -j ACCEPT
    # TODO: ban attackers!
    # Accept all other traffic
  • Enable the rules using ip6tables-apply

  • Set something like this in /etc/network/interfaces:

    auto eth0
    iface eth0 inet static
        address x.x.x.x
        gateway x.x.x.x
        pre-up iptables-restore /etc/network/iptables.up.rules
    iface eth0 inet6 static
        address x::x
        netmask 64
        gateway x::x
        pre-up ip6tables-restore /etc/network/ip6tables.up.rules


  • Install Postgres:

    • In /etc/postgresql/*/main/pg_hba.conf, change all local connections to trust
    • In /etc/postgresql/*/main/postgresql.conf, set these:

      log_min_duration_statement =  1000
      ssl = off
    • Create postgres users:

      sudo -u postgres createuser -s francois
      createuser -s root
      createuser -S -R -D djangouser
  • Install pgbouncer

    apt install pgbouncer
    • Turn it on in /etc/default/pgbouncer

    • Put the following in /etc/pgbouncer/pgbouncer.ini:

      libravatar = dbname=libravatar
      admin_users = postgres
    • Put the following in /etc/pgbouncer/userlist.txt:

      "djangouser" ""
      "postgres" ""
    • Restart the daemon:

      systemctl restart pgbouncer

Web server

  • Create a global TLS configuration in /etc/apache2/conf-available/tls.conf:

    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLHonorCipherOrder     on
    SSLCompression          off
    SSLUseStapling          on
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off
    SSLStaplingCache        shmcb:/var/run/ocsp(128000)
  • Enable TLS and mod_rewrite:

    a2enconf tls
    a2enmod ssl
    a2enmod rewrite
  • Setup some Apache vhosts:

    • /etc/apache2/sites-enabled/000-default.conf:

      <VirtualHost *:80>
          DocumentRoot /var/www/acme
          <Directory /var/www/acme>
              Options -Indexes
          RewriteEngine on
          RewriteCond "/var/www/acme%{REQUEST_URI}" !-f
          RewriteRule ^(.*)$ [last,redirect=301]
    • /etc/apache2/sites-available/default-ssl.conf:

      <VirtualHost *:443>
          SSLEngine on
          SSLCertificateFile /etc/libravatar/www.crt
          SSLCertificateKeyFile /etc/libravatar/www.pem
          SSLCertificateChainFile /etc/libravatar/www-chain.pem
          RewriteEngine On
          RewriteRule ^ [redirect=301,last]
    • /etc/apache2/sites-available/stats.conf:

      <VirtualHost *:443>
          DocumentRoot /var/cache/awstats
          Alias /awstats-icon/ /usr/share/awstats/icon/
          Alias /favicon.ico /usr/share/libravatar/libravatar/favicon.ico
          SSLEngine on
          SSLCertificateFile /etc/libravatar/stats.crt
          SSLCertificateKeyFile /etc/libravatar/stats.pem
          SSLCertificateChainFile /etc/libravatar/stats-chain.pem
          Header add Strict-Transport-Security: "max-age=15768000"
          <Location />
              AuthType Basic
              AuthName "Libravatar Stats"
              AuthUserFile /etc/apache2/stats.passwd
              Require valid-user
              Order allow,deny
              allow from all
              Options +indexes
      <VirtualHost *:80>
          DocumentRoot /var/www/acme
          <Directory /var/www/acme>
              Options -Indexes
    • /etc/apache2/sites-available/acme.conf:

      <VirtualHost *:80>
          DocumentRoot /var/www/acme
          <Directory /var/www/acme>
              Options -Indexes
    • /etc/apache2/sites-available/apt.conf:

      <VirtualHost *:443>
              SSLEngine On
              SSLCertificateFile /etc/libravatar/apt.crt
              SSLCertificateKeyFile /etc/libravatar/apt.pem
              SSLCertificateChainFile /etc/libravatar/apt-chain.pem
              DocumentRoot /var/www/apt
              <Directory /var/www/apt>
                      ForceType text/html
                      Options -MultiViews -Indexes
                      AllowOverride None
                      Order allow,deny
                      allow from all
              ErrorLog ${APACHE_LOG_DIR}/error.log
              # Possible values include: debug, info, notice, warn, error, crit,
              # alert, emerg.
              LogLevel warn
              CustomLog ${APACHE_LOG_DIR}/access.log combined
      <VirtualHost *:80>
          DocumentRoot /var/www/acme
          <Directory /var/www/acme>
              Options -Indexes
  • Copy the stats password file (/etc/apache2/stats.passwd).

  • Create the empty apt repo:

    mkdir /var/www/apt
    chown francois:francois /var/www/apt
    cd /var/www/apt
    ln -s /usr/share/libravatar/libravatar/favicon.ico .
    touch index.html sitemap.xml robots.txt
  • Enable the new vhosts:

    mkdir /var/www/acme
    a2ensite acme
    a2ensite apt
    a2ensite default-ssl
    a2ensite stats
  • Install certbot and then create a few certs:

    certbot certonly --webroot -w /var/www/acme -d -d -d -d
    certbot certonly --webroot -w /var/www/acme -d
    certbot certonly --webroot -w /var/www/acme -d
    systemctl restart apache2
  • Symlink the letsencrypt certs in the right place:

    cd /etc/libravatar/
    ln -s ../letsencrypt/live/ seccdn.pem
    ln -s ../letsencrypt/live/ seccdn.crt
    ln -s ../letsencrypt/live/ seccdn-chain.pem
    ln -s ../letsencrypt/live/ stats.pem
    ln -s ../letsencrypt/live/ stats.crt
    ln -s ../letsencrypt/live/ stats-chain.pem
    ln -s ../letsencrypt/live/ apt.pem
    ln -s ../letsencrypt/live/ apt.crt
    ln -s ../letsencrypt/live/ apt-chain.pem
    ln -s ../letsencrypt/live/ www.pem
    ln -s ../letsencrypt/live/ www.crt
    ln -s ../letsencrypt/live/ www-chain.pem
    chmod a+rx /etc/letsencrypt/archive /etc/letsencrypt/live
  • Install a cronjob to automatically renew these certs in /etc/cron.daily/certbot-renew-libravatar:

    /usr/bin/certbot renew --quiet --post-hook "/bin/systemctl restart apache2.service"
    pushd /etc/ > /dev/null
    /usr/bin/git add letsencrypt
    DIFFSTAT="$(/usr/bin/git diff --cached --stat)"
    if [ -n "$DIFFSTAT" ] ; then
        /usr/bin/git commit --quiet -m "Renewed letsencrypt certs"
        echo "$DIFFSTAT"
    popd > /dev/null
  • Install awstats and add this to /etc/awstats/awstats.conf.local:

  • Reduce log retention to 10 days by setting the following in /etc/logrotate.d/apache2:

    rotate 10


  • Add this script to /usr/local/sbin/libravatar_backups:

    # Perform fresh backup
    DUMP_FILE="$DUMP_DIR/`date +%Y%m%dT%H%M%S`.pg"
    pg_dump -Fc libravatar > $DUMP_FILE
    chmod 600 $DUMP_FILE
    # Encrypt backup
    gpg --recipient 007c98d1 --encrypt $DUMP_FILE
    rm $DUMP_FILE
    # Purge old backups
    find $DUMP_DIR -ctime +7 -delete
  • Create an empty /var/backups/libravatar directory

  • Install duplicity:

    apt install duplicity python-paramiko
  • Add my duplicity backup script to /home/francois/.backup/ and update:

    • GPG passhrase
  • Add the following to /home/francois/.backup/exclude:

  • Add the following to /home/francois/.backup/include:

  • Create this cronjob in /etc/cron.d/libravatar_backups:

    # Local DB backups
    4 1,13 * * *       root    ionice -c3 nice -n10 /usr/local/sbin/libravatar_backups
    # Full backups to another server
    6 14 * * *      root    /home/francois/.backup/backup-selfoss
    6 23 * * 3      root    /home/francois/.backup/backup-selfoss --full
  • Install the appropriate gpg key as root:

    gpg --keyserver --recv-key 16281F2E007C98D1
  • Mark the key as ultimately trusted by using the trust command after typing:

    gpg --edit-key 16281F2E007C98D1
  • Copy the required id_rsa key into /root/.ssh/.

  • Configure the port, hostname and username in /root/.ssh/config.

  • Run an initial backup:

    sudo /home/francois/.backup/backup-selfoss
  • Ensure the expected files have been backed up:

    sudo /home/francois/.backup/backup-selfoss --list-current-files > list.txt

Install application

  • Install Libravatar packages

    • Start by installing the apt-transport-https package
    • Add the Libravatar repository to /etc/apt/sources.list:

      deb jessie main
    • Then install server packages:

      apt update
      apt install libravatar{,-common,-cdn,-cdn-common,-deployment,-www,-master}
    • Use the defaults for all of the debconf questions except:

      • 6432 for the database port number
      • a string from pwgen -s 50 for the Django secret
  • Install gearman-job-server:

    apt install --no-install-recommends gearman-job-server
  • Add your username to the libravatar-deployment group:

    adduser francois libravatar-deployment

Squid proxy

  • Install squid:

    apt install squid3
  • Restrict access and outgoing requests by putting the following in /etc/squid3/squid.conf:

    acl to_localnet dst
    acl to_localnet dst
    acl to_localnet dst
    acl to_localnet dst
    acl to_localnet dst
    acl to_localnet dst
    acl to_localnet dst fc00::/7
    acl to_localnet dst fe80::/10
    acl SSL_ports port 443
    acl Safe_ports port 80
    acl Safe_ports port 443
    acl CONNECT method CONNECT
    http_access deny !Safe_ports
    http_access deny CONNECT !SSL_ports
    http_access deny manager
    http_access deny to_localhost
    http_access deny to_localnet
    http_access allow localhost
    http_access deny all
  • Force all outgoing connections from Django to go through the proxy by putting the following near the end of /etc/libravatar/django.wsgi:

    os.environ['ftp_proxy'] = ""
    os.environ['http_proxy'] = ""
    os.environ['https_proxy'] = ""

Git mirrors

  • Install hg:

    apt install mercurial
  • Enable the convert mercurial extension by putting this in /etc/mercurial/hgrc:

    convert =
  • Add this script in /usr/local/bin/git-mirror:

    cd $DIR/git
    git fetch --quiet origin 2> /dev/null
    git reset --quiet --hard origin/master
    git push --quiet github master 2> /dev/null
    exit 0
  • Add this script in /usr/local/bin/hg-mirror:

    cd $DIR/git
    git fetch --quiet origin 2> /dev/null
    git reset --quiet --hard origin/master
    cd $DIR
    hg --quiet convert git libravatar-hg
    cd $DIR/libravatar-hg
    hg --quiet update
    hg --quiet push ssh:// 2> /dev/null
    exit 0
  • Add this to /home/francois/.ssh/config:

      User hg
      IdentityFile ~/.ssh/repository_mirrors
      User git
      IdentityFile ~/.ssh/repository_mirrors
      AddressFamily inet
  • Copy repository_mirrors ssh key from old server into /home/francois/.ssh/ (make sure that the private key has 600 permissions)

  • Prepare directory for git and mercurial repositories:

    mkdir -p /home/francois/git-mirrors/libravatar-hg
    cd /home/francois/git-mirrors/
    git clone git
    cd git
    git remote add github
  • Do a test run for each of them (as francois):

    /usr/local/bin/git-mirror && echo success
    /usr/local/bin/hg-mirror && echo success
  • Create the following cron jobs in /etc/cron.d/libravatar_git-mirrors:

    50 * * * *      francois        /usr/local/bin/git-mirror
    55 * * * *      francois        /usr/local/bin/hg-mirror

From the old server

If migrating from one server to another:

  • Setup the database

    • Get a DB dump from the old server:

      pg_dump -Fc libravatar >
    • Create a new database:

      createdb -O djangouser -E utf8 libravatar
    • Restore the database:

      pg_restore -d libravatar <
  • Copy the contents of /var/lib/libravatar/ from the old server and fix the file permissions:

    chown -R root:root /var/lib/libravatar/avatar/* /var/lib/libravatar/user/*