Do not Panic! Remote Server (Hetzner) not rebooting any more – A Solution

I went through this experience recently. First of all, don’t panic! I panicked, and because of this, I made a mistake: I didn’t wait long enough for it to come online. Had I waited up to 60 minutes, it would probably have come online (see reason below). The story:

I had broken packages on my Ubuntu 10.04 server and decided to fix them by

apt-get update
apt-get upgrade

While updating, I noticed that the package grub-pc  also was upgraded, apparently a new bootloader (or bootloader configuration) was installed. This made me feel uncomfortable, since I didn’t know if the server would reboot after this upgrade. So, because of the saying “The devil you know is better than the devil you don’t know” (and a desire to sleep peacefully at night!) I decided to reboot the server and see what would happen. To my big dismay, it did not come online. SSH connections failed with “Port 22: Connection refused” .

I panicked and asked the Hetzner Support (which is very responsive and supportive btw!) to install a LARA Remote Console so that I could see the text output of the booting screen. After some regular startup text, the screen became blank. I panicked even more and took immediate steps to move all data to a new server. It took me 6 hours to complete the most important parts, and another full week of restless work to finish it. We will see that it was not neccessary.

Most regular servers at the Hetzner datacenter are running Software RAID. It seems that after a reboot (especially if you send a Hardware Reset) the OS needs some time to re-sync or check the file system. I am not sure what caused the delay in my case. Re-syncing the entire RAID array can take up to 1-2 hours, depending on your hardware and disc space.

So, wait at least 1 hour for it to come online, especially after a hardware reset! When you activate Hetzner’s Rescue system (which is very good btw!) it will stay active for a minimum of 1 hour, so your server will be down for 1 hour at least, in any event. So you are not losing much by waiting a bit longer.

Now, in my case, I assumed that Grub2 was broken. So I activated the Hetzner Rescue System, booted into it, and reinstalled Grub2. I have found the following method here and it worked for me. First you have to mount the regular RAID filesystem under /mnt :

mount /dev/md2 /mnt
mount /dev/md1 /mnt/boot
mount -t dev -o bind /dev /mnt/dev
mount -t proc -o bind /proc /mnt/proc
mount -t sys -o bind /sys /mnt/sys
chroot /mnt

At this point, you are in your regular root directory. To reinstall Grub2 the Debian Way, I did:

apt-get install --reinstall grub-pc

To make really sure, I reconfigured the package:

dpkg-reconfigure grub-pc

It will ask you where to install the bootloader. I selected:

[*] /dev/sda
[*] /dev/sdb

No errors were reported. I rebooted again and it did not come online immediately, for the reasons previously mentioned. I waited long enough (in my case, 15 minutes) and it did come online. So, rule number one is: Don’t panic!

A solution for MySQL Assertion failure FIL_NULL

A defective RAM module recently caused data corruption in MySQL tables. MySQL would log the following to /var/log/syslog  in regular intervals, about every few minutes:

140125 5:04:41 InnoDB: Assertion failure in thread 140046518261504 in file fut0lst.ic line 83
InnoDB: Failing assertion: == FIL_NULL || addr.boffset >= FIL_PAGE_DATA
InnoDB: We intentionally generate a memory trap.

Reading MySQL documentation and various blogs didn’t help much. I ran CHECK TABLES  on all the tables and they all reported OK. Then I ran

mysqlcheck --all-databases

and still all tables reported OK. Nevertheless the Assertion Failures continued. Then I stumbled across this excellent blog post, which suggested to dump evertying into a .sql file, wipe /var/lib/mysql (not without making a backup, mind you!), and re-import everything from scratch. This is what I did and it worked.

I recorded the passwords for each database and collected it into a SQL script like this:

GRANT ALL PRIVILEGES ON database_name1 TO 'username1'@'localhost' IDENTIFIED BY 'password1';
GRANT ALL PRIVILEGES ON database_name2 TO 'username2'@'localhost' IDENTIFIED BY 'password2';

When you dump all databases into a .sql file, it will not dump the permissions, so you will need to restore them later with this script. Next, the dumping part, then removal and reinstallation of mysql (Danger here: When you remove mysql-server, all packges which depend on it also will be removed!):

cd ~
mysqldump -u root -ppass --all-databases > alldbs.sql
cd /var/lib
cp -vpr mysql mysql-backup
apt-get remove --purge mysql-server-5.5
apt-get install mysql-server

Here, I had to reset the MySQL admin password because it didn’t work any more, so I ran:

dpkg-reconfigure mysql-server-5.5

Then, I re-imported all databases from the dump file:

cd ~
mysql -u root -ppass < alldbs.sql

Then I run the SQL permission script that I mention above.

For me, this resulted in no more Assertion Failures. Yay!



Adventures with various Segfaults due to defective RAM

If you get various segfaults on your Linux server, like these:

spamd child[2656]: segfault at 200251c208 ip 00007fa039223684 sp 00007fff77953680 error 4 in[7fa03916a000+177000]


clamd[3311]: segfault at 1000000008 ip 00007f00200b3751 sp 00007fff3e2cef60 error 4 in[7f001fff1000+988000]


php5[14914]: segfault at 7fff7d2939c8 ip 00000000006bf04d sp 00007fff6d293860 error 6 in php5[400000+6f3000]


PassengerHelper[11644]: segfault at ffffffffca4ef420 ip 0000000000492fea sp 00007f5b81e991d0 error 7 in PassengerHelperAgent[400000+203000]

etc. etc., then, no, your system is not suddenly crazy. Nor are you. It is highly likely that you RAM is defective. You should reboot your server and run the  RAM test from your boot manager (Grub always has such a test) to see if it can detect faulty RAM.

If you are operating a server that you can’t reboot because you can’t tolerate downtime, there is an excellent tool calledmemtester , which is a memory test for a running system. It is part of the Debian distribution, installit with apt-get install memtester  Check top to see how much free RAM there is available. Say you have 10GB RAM free, then ask memterst to test 8GB of it (so that 2GB are remaining free for the running system to operate). In my case, memtester indeed detected faults.

I ran

memtester 8000 3

It outputted stuff like this:

Loop 1/3:
Stuck Address : ok 
Random Value : ok
Compare XOR : ok
Compare SUB : ok
Compare MUL : ok
Compare DIV : ok
Compare OR : ok
Compare AND : ok
Sequential Increment: ok
Solid Bits : testing  30FAILURE: 0xffffffffffffffff != 0xfffffffbffffffff at offset
Block Sequential : ok 
Checkerboard : ok 
Bit Spread : ok 
Bit Flip : ok 
Walking Ones : ok 
Walking Zeroes : ok 
8-bit Writes : ok
16-bit Writes : ok

So, when I replaced the RAM, the Segfaults stopped. You can runmemtester  regularly to make sure the RAM is okay. Healty RAM is a very crucial part of your successful hosting operation!

In my case however, the segfaults corrupted MySQL tables, which I had to clean up. All’s well that ends well!


How to install Guest Additions with Folder Sharing on VirtualBox – The Debian Way

Debian Wheezy as guest Operating System with Folder Sharing

I always forget where to download the proper version of the Virtualbox GuestAdditions, so here is a short tutorial about how to do it quickly and easily in the Debian way. I always need folder sharing between the guest and host OS, so you will see how this is done also. I will be using the current stable distribution Debian Wheezy as host system (without a running display manager, just the console), and  as the guest system also Debian Wheezy. It turns out that Debian has even packaged the Guest Additions for virtualbox.

First, install Virtualbox and the Guest Additions:

apt-get install virtualbox virtualbox-guest-additions

Then install Debian Wheezy as a guest system. Next, mount the Guest Additions ISO file by navigating through the menu system of Virtualbox:

  • Devices -> CD/DVD Drives -> Coose a virtual CD/DVD disk file …

Choose the ISO from this path:


Next, in your guest OS, mount the virtual CD, and run the installer:

mount /dev/cdrom /mnt
cd /mnt

Next shut down your guest OS (don’t to this in your host OS 😉 ):


Now set up the shared folder in the menu system of Virtualbox:

  • Settings -> Shared Folders -> +
  • Select Folder
  • Check “Auto-mount”

Re-start your guest OS, and you will have the shared folder auto-mounted in /media/sf_Public . Voila!

File permissions for successful SSH login via authorized_keys

If you want to ssh into your server without being repeatedly prompted for the password you can copy your public ssh key into a file called authorized_keys  in the .ssh subdirectory of the home directory of the remove server account. However, this works only if the permissions for this file are set correctly.

First, if you have not done so already, generate the public key for your local user:



This will create a file ~/.ssh/

Append the only line in this file into the file ~/.ssh/authorized_keys  of the remote user account. Create the directory and file if it does not exist.

Now try to ssh into your remote account. If ssh is still asking for the remote user’s password, check the permissions of the following files and directories:

  • The permissions of the home directory of the remote user must be 755
  • The permissions of the remote .ssh directory must be 700
  • The permissions of the remote authorized_keys file must be 600

… of course all of those must be owned by the remote user, and not by root.

Now, you should be able to ssh into the remote account without being asked for the password!

How to set up audio streaming (internet radio) in Linux

This tutorial will show you how you can go live with your own internet radio station in a few minutes.

Demystifying “streams”

There is a lot of information, disinformation and irrelevant information about this in the internet. When you listen to internet radio, and you inspect the network requests in your Google Chrome Developer Tools (yes, you should use Chrome anyway), you will discover that a ‘magickal’ stream is nothing else than a blatantly simple HTTP download of a regular file which never finishes. Yup, jawdroppingly simple.

What do you need?

In order to broadcast audio (e.g. internet radio) into the internet, you need

  1. a remote streaming server with high bandwidth to which many clients can collect
  2. a local stream generator, which is sending a single stream to the streaming server

The following tutorial shows how you can easily achieve this with free and open source tools which are part of the Debian (Ubuntu) distributions. It will take you 15 minutes to start your first rudimentary broadcast.

We will use Icecast2 as a streaming server, simply for the reason that it is part of the Debian distribution and that I got it to work immediately. As the local stream generator we will use darkice, for the same reasons.

Why not Windows? Well, since the majority of remote servers are running Linux distributions, you can use Icecast2 anyway. If you want to use a different stream generator for Windows, you can do so. This screencast shows you how it’s done.


Is Icecast a professional-grade solution? According to a blog,

Very much so. ICEcast is an industry standard platform used by thousands and thousands of radio stations all over the world. Its wide compatibility means people can listen with most players and operating systems.

Listeners will be able to connect to your MP3 stream from all over the world, with all the popular media players including Windows Media Player, iTunes, Winamp, Realplayer, XMMS, and many more media players besides.

Although incredibly simple, it can cope with even the heaviest demands and will not break under pressure. Its simplicity works to the broadcaster and listeners favor.

According to Wikipedia,

Version 2 [of Icecast] was started in 2001, a ground-up rewrite aimed at multi-format support (initially targeting Ogg Vorbis) and scalability.

A ground-up rewrite for scalability certainly sounds like good news! So, let’s dive in!

You would do the following steps on a server which is located at a large internet node with enough bandwidth to serve all your audience. To install, simply type

apt-get install icecast2

During the installation you will be asked if you want to configure Icecast2. Answer yes. You will be asked the hostname. Here simply leave the default “localhost”. Next, you will be asked for source, relay and administration passwords. For testing, leave “hackme”. If you want to change the configuration at a later point, edit the configuration file /etc/icecast2/icecast.xml

Next, you have to enable the Icecast2 server by setting ENABLE  in the configuration file /etc/default/icecast2  to true .

Now, start the server by typing

service icecast2 start

You now can access the web admin interface on port 8000 of your machine:

Icecast2 web-based admin interface
Icecast2 web-based admin interface

The log file is in /var/log/icecast2/error.log  and access.log  . Best to tail -f  both files to observe what is going on.


Darkice is a stream generator. It encodes audio into various formats (e.g. ogg, mp3, etc.) from various inputs (e.g. microphone jack, line-in jack, or the stereo mix of your operating system) and sends a single stream to our Icecast2 server, which in turns re-broadcasts it to all connected clients.

To install, simply type:

apt-get install darkice

By default it does not install a configuration file. But there is an example one in the documentation. Copy this to the /etc directory:

cp /usr/share/doc/darkice/examples/darkice.cfg /etc

You will need to edit this file according to your needs. Here is an example that worked for me:

# this section describes general aspects of the live streaming session
duration = 0
bufferSecs = 5
reconnect = yes

device = default
sampleRate = 44100
bitsPerSample = 16
channel = 2

bitrateMode = abr
format = vorbis
bitrate = 96
server =
port = 8000
password = hackme
mountPoint = example1.ogg
name = DarkIce trial
description = This is only a trial
url =
genre = my own
public = yes
localDumpFile = dump.ogg

Make sure that the password and the IP address of the Icecast2 server (which we installed earlier on the other machine) match. Also, remember the mountPoint of this stream. This is simply a label, in my case it is “example1”. Then you simply run as normal user


It is a console-only application and you will see some messages. This is what I get:

DarkIce 1.0 live audio streamer,
Copyright (c) 2000-2007, Tyrell Hungary,
Copyright (c) 2008-2010, Akos Maroy and Rafael Diniz
This is free software, and you are welcome to redistribute it 
under the terms of The GNU General Public License version 3 or
any later version.

Using config file: /etc/darkice.cfg
Using ALSA DSP input device: default
Could not set POSIX real-time scheduling, this may cause recording skips.
Try to run darkice as the super-user.

The note about the realtime stuff is just a warning, it works for me nevertheless. It would be easy to run it as superuser.

Making a simple stream player

We will simply make a small website with one <audio> element. That is enough to play streams. Create an empty file called streamtest.html  with the following contents:

    <audio controls>
      <source src="" />

Make sure that the IP address corresponds to the server where the Icecast2 server is running on. Open this html file in a browser and click the play button. Now you should hear the same audio that the darkice client has as its input.

Changing the audio input for darkice

In case you don’t have the Pulse Audio Volume control installed, install it with

apt-get install pavucontrol

Then run it. As soon as you have darkice running, the “Recording” tab will show the text “ALSA plug-in [darkice]: ALSA Capture from …” From the drop down you can select the input source. The text is a bit misleading. In my case “Monitor” means the stereo-mix of the entire computer (e.g. all system sounds, all played back audios). “Built-in Analog Stereo” means the microphone / line-in jack.

Pulse Audio volume control pavucontrol
Pulse Audio volume control pavucontrol

For professional radio applications you of course would not use such a simple software mixer, but have an external hardware-based mixer to which all the microphones and the line-out of your computer are attached. Then you would connect the final output of the hardware mixer to your computer line-in and select “Built-in Analog Stereo” for darkice’s input.

Linux has a more professional audio system called Jack as a replacement for the standard system Pulse Audio (we were using Pulse Audio in the above tutorial, which is similar to what Windows uses). Both are running on the Linux Kernel’s sound system called ALSA.


In the face of tons of documentation and blogs in the internet it is surpirisingly easy to set up your own, simple internet radio station with zero investment, all thanks to the Open Source movement.




Citations within footnotes in LaTeX

Writing a tutorial on programming, I needed citations within footnotes. Luckily, the biblatex package added support (see first comment on the sourceforge page of biblatex) for citations within footnotes in 2011. Apparently, this is not straightforward, since a low-level citation command has to be used to satisfy LaTeX. Anyway, this is now done automatically by thebiblatex  package, so I didn’t have to make any changes.

In my document, I only use the LaTeX command \autocite  which behavior I can define in the document preamble. In my preamble I have:


Now, with the following TeX code…

\chapter{My chapter}

This is a test\footnote{TeX is awesome \autocite[see][p. 120]{Knuth}. I agree.} for a citation within a footnote. However, this is a citation\autocite[]{Ritchie75} in normal text.

… you get the following output:

LaTeX citation within footnote on HTML and Kindle output
LaTeX citation within footnote on HTML and Kindle output


You will notice that footnote 2 is a citation from within the normal text. Since I’ve specified autocite=footnote  in the preamble, this is rendered as a footnote. However, the citation from within the footnote 1 is rendered in-line.


Removing millions of files in a directory

Since my Exim email server wan’t configured for Spam detection, it became blacklisted and was storing literally millions of Spam emails in the mail queue (which are stored as regular files in the directories `/var/spool/exim4/input` and `/var/spool/exim4/msglog`. There were so many files that I could not remove them with the `rm ./*` command any more, nor even with `find . -type f -delete`, as some tutorials suggested. The reason is that all those commands first collect file names which are then passed as arguments. You quickly can eat up your RAM with these methods and you literally can wait dozens of hours before these commands even start deleting files. The solution was to bypass Bash entirely and delete it with Perl. This is the command that started deleting files only after 1 minute startup time:

cd directoy/to/be/emptied
perl -e 'opendir D, "."; while ($n = readdir D) { print $n; unlink $n }'

According to my subjective estimation, it deleted about 200 files per second.

Setting up Exim4 Mail Transfer Agent with Anti-Spam, Greylisting and Anti-Malware

Recently my Exim mail server was hopelessly spammed to such an extent that I wasn’t even able to clear the mail queue with `rm ./*`, nor even list the files, nor even count the files with `ls`.  How still I managed to delete probably millions of mail files in one folder can be read in my post “Removing a million files in a directory“.

After this shock, I decided to integrate Anti-Spam and Anti-Malware systems into my Exim MTA, and within a few hours my server was back up and running, and this time, bouncing spam emails back to where they belong (hell). I did this in Ubuntu 10.04 LTS, but I know it also works in Debian 7 Wheezy, as I’ve recently used my own tutorial.

My own knowledge about Exim comes from the excellent Official Guide to Exim by Exim’s author, Philip Hazel. Email servers are very complex. You won’t be able to go very far with ‘duct tape’ administration, nor come up with a good fix in a case of emergency. With a misconfigured email server, is very easy to get your IP address blacklisted in the entire internet. Therefore I would suggest you grab your own copy of the Official Guide to Exim from Amazon.


How to install Exim

I already was running Exim, but still, if you are interested, here is what to do. First, you can install Exim by running

apt-get install exim4

but by default, this installs the package `exim4-daemon-light`, which does not have advanced capabilities compiled in. Since we want to do spam filtering, we need to install `exim4-daemon-heavy`:

apt-get install exim4-daemon-heavy

This will remove `exim4-daemon-light` automatically.

We have to enable Exim for internet communications, since the default is only localhost communications. In /etc/exim4/update-exim4.conf.conf  change the line dc_eximconfig_configtype=’local’  to


Enter the domains you want to receive emails for to the line:


Make exim listen to all interfaces by emptying the following config line:


Enable TLS for Exim by running the script


… and add the following line somewhere at the top of Exim’s configuration template file /etc/exim4/exim4.conf.template .


Every time you modify /etc/exim4/exim4.conf.template , you have to run update-exim4.conf  and do service exim4 restart .

Next, we will install and configure Spamassassin for Exim. Luckily, it is a Debian package.

Spam Assassin


You can find instructions in this Debian Wiki, but you will find all commands here for convenience.

apt-get install spamassassin

This starts a daemon calledspamd  automatically. However, it is disabled by default. Enable it by changing the following line in /etc/default/spamassassin :


Debian-specific modification: In the same file, change this line

OPTIONS="--create-prefs --max-children 5 --helper-home-dir"

to this:

OPTIONS="--create-prefs --max-children 5 --helper-home-dir -u debian-spamd"

This instructs the spamd daemon to run as the user debian-spamd  which is created when you install spamassassin. Its home directory is /var/lib/spamassassin . I had to do this because the following error messages was regularly logged into /var/log/syslog :

config: cannot create user preferences file /nonexistent/.spamassassin/user_prefs: No such file or directory
spamd: failed to create readable default_prefs: /nonexistent/.spamassassin/user_prefs
spamd: failed to create readable default_prefs: /var/spool/exim4/.spamassassin/user_prefs

Also, enable the cronjob to automatically update the spamassassin’s rules:


The conjob file in question is /etc/cron.daily/spamassassin , which in turn calls sa-update .

Next, you can configure the behaviour of spamassassin in the config file /etc/spamassassin/ . Especially the entries “rewrite_header” and “required_score” are interesting, but later we will configure Exim to do these jobs for us directly.

Restart the daemon to make the changes effective:

service spamassassin restart

Integration into Exim

All of following modifications have to take place in `/etc/exim4/exim4.conf.template`.

Now we have to enable `spamd` in Exim’s configuration file. Search for the line containing `spamd_address` and uncomment it like this:

spamd_address = 783

It is a good idea to add special headers to each processed email which specify the spam score. The configuration is alredy there, we just have to uncomment it (see also official documentation of this here):

    spam = debian-spamd:true
    add_header = X-Spam_score: $spam_score\n\
              X-Spam_score_int: $spam_score_int\n\
              X-Spam_bar: $spam_bar\n\
              X-Spam_report: $spam_report

Note that I have replaced spam = Debian-exim:true  with spam = debian-spamd:true to match the user of the spamd daemon. If you want to know what the :true  part means, study this section of the official Exim documentation.

At this point, emails which are definitely spam will still be delivered. This is not good, since when a mail client of one of your customers is compromised, it could send thousands of spam emails per day, which still would cause your server and IP to be blacklisted. If you want to bounce emails that are over a certain spam point threshold, add the following lines directly below. In this case, the threshold is 12.0 (but you have to enter it without the comma):

    message = This message scored $spam_score spam points.
    spam = debian-spamd
    condition = ${if >{$spam_score_int}{120}{1}{0}}

Generate the real Exim4 configuration from /etc/exim4/exim4.conf.template  that we’ve just edited by running

service exim4 restart


Now, let’s test if our spamassassin setup was successful. Send an email to your Exim server that contains the following line. This code is taken from Spamassassin’s GTUBE (the Generic Test for Unsolicited Bulk Email):


The email should bounce back immediately and contain the message that we’ve entered above:

SMTP error from remote server after transfer of mail text:
This message scored 1000.0 spam points.

Now, send yourself a normal email. After you have received it, in your mail client (I’m using Icedove) inspect the mail source by pressing Ctrl + U. It should contain the following special header lines:

X-Spam_score: 2.7
X-Spam_score_int: 27
X-Spam_bar: ++
X-Spam_report: snip

So far, so good.


Next, let’s set up Greylisting, another spam defense measure. The tool of my choice was greylistd because Debian has its own package greylistd.


apt-get install greylistd

You will be shown a configuration notice, instructing you how to enable `greylistd` in the Exim configuration. The following will show you what to do.

Integration into Exim

greylistd-setup-exim4 add

As far as I could determine, this automatically adds some lines in the already existing Exim configuration templates `exim4.conf.template` and inside of the directory `/etc/exim4/conf.d`. It adds it right after `acl_check_rcpt:`.

At this point, `greylistd` is already running. In case you want to restart the service, run

service greylist restart

Of course, we have to restart Exim again so that our new configuration becomes active:

service exim4 restart


Observe the contents of the Exim log file

tail -f /var/log/exim4/mainlog

and send yourself a regular email. You will see a line in the logfile similar to this:

F=<> temporarily rejected RCPT <>: greylisted.

When it says “temporarily rejected RCPT” and “greylisted” it means that `greylistd` is working.


Anti-Malware and Anti-Virus

As an email provider you certainly want to have some anti-malware and anti-virus measures in place. My choice was ClamAV, since it’s part of Debian and rather easy to integrate with Exim. The following instructions are loosely based on the Ubuntu Wiki EximClamAV, but it contains one step too much which seems to be no longer neccessary (the part about creating a new file). In any case, here are my working steps.


First, install the daemon:

apt-get install clamav-daemon

It will output the following failures, but don’t worry, they are harmless:

[FAIL] Clamav signatures not found in /var/lib/clamav ... failed!
[FAIL] Please retrieve them using freshclam ... failed!
[FAIL] Then run '/etc/init.d/clamav-daemon start' ... failed!

To get rid of the messages, you have to run


This command updates your virus databases from the internet. You should create a cronjob to run it regularly. Now you are able to restart the daemon without failure messages:

service clamav-daemon restart

Next, add the `clamav` daemon user to the `Debian-exim` group, so that it can access the spool files:

usermod -a -G Debian-exim clamav

Integration into Exim

Locate the line in `/etc/exim4/exim4.conf.template` which contains `av_scanner`, uncomment it, and change it to the following (as the Ubuntu Wiki correctly says, the default value does not work):

av_scanner = clamd:/var/run/clamav/clamd.ctl

Next, uncomment the following lines in `/etc/exim4/exim4.conf.template` (this is where the Ubuntu Wiki says that you should create a new file, but it’s already there):

    malware = *
    message = This message was detected as possible malware ($malware_name).

As we have done before, we have to restart Exim so that our new configuration becomes active:

service exim4 restart


There is a special string that you can use to test Anti-Malware programs. It is taken from the eicar website.  At the bottom of the linked page you will find it:


Send an email to Exim which contains this string in a separate line. It should bounce immediately. The bounced message will contain:

SMTP error from remote server after transfer of mail text:
This message was detected as possible malware (Eicar-Test-Signature).

When you get this, ClamAV is working correctly.


Setting up Exim with DKIM (DomainKeys Identified Mail)

Google Mail suggests using DKIM for ISP providers. When you are signing outgoing messages with DKIM, you are reducing the chance that Google thinks you are a spammer. See also Google’s Bulk Senders Guidline as to how Google judges the Anti-Spam qualities of your mails. DKIM is not a strong Anti-Spam indicator, it only ensures (due to private/public key encryption) that an email was actually sent from the server it claims it was sent. Anyhow, here is how to do it (based on the articles here and here):

Generate a private key with openssl:

cd /etc/exim4
openssl genrsa -out dkim.private.key 1024

Extract the public key:

openssl rsa -in dkim.private.key -out dkim.public.key -pubout -outform PEM

Change permissions and ownership to make it readable for Exim and for security reasons:

chmod 640 dkim.p*
chown root:Debian-exim dkim.p*

Next add the following to exim4.conf.template  (or to your split-configuration files if you use that method), right before the line remote_smtp: 

DKIM_PRIVATE_KEY = CONFDIR/dkim.private.key
DKIM_CANON = relaxed

More information about these parameters see this section of the official Exim documentation.

Update the configuration and restart Exim:

service exim4 restart

Now send a test email to some address (e.g. free mail provider) which is not handled by your email server and inspect the sources of the received email. It should contain a line DKIM-Signature . To avoid confusion: If you are sending an email to yourself, which is received by the same server which you are configuring, no DKIM Signature is added (since not neccessary).

Next, you have to add the DKIM public key as a TXT “selector record” to the DNS zone of For DKIM_DOMAIN  and DKIM_SELECTOR  you have specified above, you have to add the following entry:

TXT  |  exim._domainkey  |  v=DKIM1; k=rsa; p=MIGfMA...;

where p=  gives the public key from /etc/exim4/dkim.public.key  without headers and without line breaks.

You also should add a “DKIM policy record” for the subdomain _domainkey to state that all emails must be signed with DKIM. Otherwise, DKIM could simply be omitted by a spoofer without consequences. Again, this is a simple TXT entry in the DNS:

TXT  |  _domainkey  |  o=~;

You can use this tester to check the policy record:

However, this “o” policy record does not seem to be documented in any RFC (I found it on various blog posts), and it is superseded by RFC5617 (DKIM ADSP Author Domain Signing Practices). For ADSP you would have to add:

TXT  |  _adsp._domainkey  |  dkim=all

Similar in function to ADSP seems to be DMARC. I’ll write about this in a future blog post.

For details on DKIM see: RFC specification


Now check if your zone records have been saved and taken:

dig TXT

It should output the contents of the TXT zone entry which you’ve made above. If you can see them, send an email to the excellent SMTP tester email

If it responds with

DKIM check:         pass

Then the DKIM set-up was successful.


Additional Anti-Spam measures

A characteristic behaviour of malicious Spam senders is that they send a Spam Flood (as many messages as possible in the least time possible).  If possible, they will send many messages in just one SMTP connection (i.e. several MAIL commands in one session). If that happens, you will be blacklisted very soon, and with tens of thousands of send Spam emails, it will be very difficult to re-gain a good reputation for email providers like Google or Yahoo. Legitimate senders however will only send a few single messages, one message per SMTP connection, and it reasonably will take them at least 10 seconds to write a short email. So, we can rate-limit the submission of messages, having a great impact on Spammers, but little impact on legitimate senders. Exim has a rate-limiting feature, but since it’s a science to configure Exim properly, I decided for an easier, more robust, low-level approach using the iptables firewall.

First, we will lock Exim down to just allow one MAIL command per SMTP session. From the Exim Main Configuration Documentation, we can write somewhere in /etc/exim4/exim4.conf.template

smtp_accept_max_per_connection = 1

Next, we are going to limit the number of parallel SMTP connections per sending host to 1:

smtp_accept_max_per_host = 1

And we will limit the maximum SMTP connections which Exim will allow. You can set this to the approximate number of clients you have, plus a margin:

smtp_accept_max = 100

Now that we know that there only can be 1 message per SMTP connection, we limit the SMTP connection frequency in our firewall:

iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 60 --hitcount 6 -j DROP

This will limit incoming SMTP connections to 6 in 1 minute, which is one connection per 10 seconds in average — enough for private or business emails, not enough for spammers.

SMTP banner delay

(inspiration from here and here) Exim drops the connection if a SMTP client attempts to send something before the SMTP banner is displayed, this is already spam protection built into Exim:

SMTP protocol synchronization error (input sent without waiting for greeting): rejected connection

To further slow down Spam we simply delay this banner. Somewhere at the beginning of the Exim config file, write:

acl_smtp_connect = acl_check_connect

In layman’s terms, this tells Exim which ACL to execute when a connection is initiated. Then, after begin acl  add it:

    delay = 10s

You can test this by telnet’ing to your server. The banner should appear only after 10 seconds.

More Anti Spam measures (not tested)




If you have succeeded so far, test your new Exim installation with the great tool at:

Exim is a very complex program (the most complex one I’ve encountered so far) and you can literally spend a lifetime studying it. The complexity seems to stem from the complexity of the email delivery process itself. Despite that fact, this tutorial will enable you to set up Exim with Anti-Malware and Anti-Spam measures in less than 1 hour of work. It is by no means exhaustive, but it at least bounces Spam emails above a certain threshold which is the most important thing when you don’t want your server and IP address to be blacklisted all over the internet for all eternity. It also adds value to your customers when you are operating Exim as a business.

But: Anyone who would like to operate Exim for customers, to be a professional email hosting company, should not think twice, but ten times if it’s really worth it. Things do go wrong all the time, and if you don’t have an exhaustive knowledge about what exactly to do in case of a failure — immediately, right there and then — you could upset all your customers pretty quickly. So, my advice would be: “hands-off” unless you know what you are doing. As I like to say: “No funny stuff!”

Follow up:

Exim and Spamassassin: Rewriting Subject lines, adding SPAM and Score

Home Entertainment goes GNU/Linux!

Since our old TV died, today our family bought a new flat-screen for the living room from Amazon: LG Electronics 55LN5700 55-Inch 1080p 120Hz LED-LCD HDTV with Smart TV (2013 Model)

I’m an Open Source advocate, so I was happy to learn that LG uses Open Source software for this particular TV family, since the User Manual contained a legal hint about Open Source Software.

This TV is pretty good, the installation is very easy. It comes with a quite advanced and progressive onscreen menu. This menu actually was the decisive factor for buying it. The best part is that it has a built-in browser (it seems to be webkit-based) and supports regular keyboard and mouse via a bluetooth dongle connected to one of the 3 available USB ports (I’m using a combined keyboard and mouse dongle from Logitech). The mouse cursor is attractive. The browser works fine for YouTube too. This is our Logitech wireless set from Amazon: Logitech Wireless Combo Mk520 With Keyboard and Mouse

There also is an LG App-Store for Games and other funny stuff, but since it requires a registered account, I haven’t tried that yet.

This TV also supports Media sharing from various PCs in the intranet via the DLNA system. Initially afraid that this would be all proprietary Windows stuff, it turned out that there are at least two good Open Source DLNA servers are part of the Debian distribution.

The first one I tried is rygel, but had medium successes with it. It worked when I ran it as root, but failed for some reason when I wanted to run it as an unprivileged user. Also, it didn’t come with an init.d script. Since I’m generally very busy, I immediately looked for an alternative.

The second server is minidlna, and I had immediate success with it. It is very thin and does an excellent job at serving media, all that is needed, and et even comes with an init.d script. Just do:

apt–get install minidlna

and the server is up and running. Then I tweaked /etc/minidlna.conf in the following way:

  • point media_dir to the folder where your media (pictures, videos, music) lives on your hard drive. In my case, this is also a folder shared by Samba, so that everyone in the house can copy media there and immediately watch it on the TV.
  • Uncommented log_dir and db_dir, but left the default values
  • As root_container I selected B, so that you can browse the acutal directory structure
  • set inotify=yes
  • set notify_interval=60

Then restart the minidlna service. Browse to port 8200 of your server to see a short HTML status message about the number of indexed files.

Then I ran into a problem: Moving a new media file into the folder wasn’t recognized by minidlna. It is supposed to be informed by new media by inotify, but it wasn’t. I found the fix here. Stop the service, delete /var/lib/minidlna/files.db, then start the service again. Now minidlna is immediately informed about new media files.

Considering that most of the entertainment technologies out there are proprietary and closed, the chance of success was extremely slim, but here it is anyway: GNU/Linux media server on a mainstream TV!