Getting nginx’s wildcard-based server names to pass Exim HELO syntax checks

Many PHP-based apps, like webmails, when using SMTP functions, depends on nginx server_name value to set up the HELO sent.

But if your server_name value is wildcard-based, you’ll get “syntactically invalid argument(s)” from the SMTP server. Example with ownCloud.

Assuming that the SMTP running on the same host as your webmail is not accepting mail but from the webmail itself, you can easily work around this. You can addd


in, for example, /etc/exim4/conf.d/main/00_webmail, if your server name is something like ~^mx.



Replicating IMAPs (dovecot) mails folders and sharing (through ownCloud) contacts (kmail, roundcube, etc)

dual IMAPs servers:

Having your own server handling your mails is enabling -you can implement anti-spam policies harsh enough to be incredibly effective, place catch-alls temporary addresses, etc. It does not even require much maintainance these days, it just takes a little time to set it up.

One drawback, though, is the fact if your host is down, or simply its link, then you are virtually unreachable. So you want a backup server. The straightforward solution is to have a backup that will simply forward everything to the main server as soon as possible. But having a backup server that is a replica of the main server allows you to use one or the other indifferently, and definitely have always one up at hand.

In my case, I run exim along with dovecot.  So once exim setup is replicated,  it’s only a matter of making sure to have proper dovecot setup (in my case mail_location = maildir:~/.Maildir:LAYOUT=fs:INBOX=~/.Maildir/INBOX
and mail_privileged_group =   mail  set in /etc/dovecot/conf.d/10-mail.conf along with ssl = required in /etc/dovecot/conf.d/10-ssl.conf  – you obviously need to create a certificate for IMAPs, named as described in said 10-ssl.conf but that’s not the topic here, you can use only IMAP if you wish).

Then, for each user account (assuming we’re talking about a low number), it’s as simple as making sure SSH access with no passphrase can be achieved from one of the hosts to the other and adding a cronjob like:

# */2 * * * *     user   dsync -f mirror 2> /dev/null
*/2 * * * *     user   isync --all --create-remote --quiet 2>/dev/null
*/2 * * * *     user   mbsync --all --quiet 2>/dev/null
*/2 * * * *     user   pgrep -x "offlineimap" -u user > /dev/null || offlineimap -u quiet >/dev/null 2>/dev/null

offlineimap requires a ~/.offlineimaprc such as:

accounts = mx

[Account mx]
localrepository = mx1
remoterepository = mx2
autorefresh = 2

[Repository mx1]
type = Maildir
localfolders = ~/Maildir

[Repository mx2]
type = IMAP
ipv6 = False
preauthtunnel = ssh -q '/usr/lib/dovecot/imap'

The first run may be a bit slow but it goes very fast afterward (I do have a strict expire policy though, it probably helps). This isdone the the primitive  way, recent version of dovecot (ie: not yet in Debian stable) provides plugins to do it.

You may as well install unison on both server and synchronize things like ~/.procmailrc, /etc/aliases or whatever, for instance:

8 */2 * * *	user	unison -batch -auto -silent -log=false ~/.procmailrc ssh:// 2> /dev/null

Once you checked that you can properly login on both IMAPs, it’s just a matter of configuring your mail clients.

and many mail clients:

I use roundcube webmail whenever I have no access to a decent system with a proper mail client (kmail, gnus, etc) configured. With two IMAPs servers, there’s no benefit of not having the same webmail setup on both.

The only annoying thing is not to have common address book. It’s possible to replicate the roundcube database but it’s even better to have a cloud to share the address book with any client, not doing some rouncube-specific crap. So I went for the option of installing ownCloud on one of the hosts (so far I’ve not decided yet if there is a point in replicating also the cloud, seems a bit overkill to replicate data that is already some sort of backup or replica), pretty straight-forward since I already have nginx and php-fcgi running. And then if was just a matter of pluging roundcube in ownCloud through CardDav.

Once done, you may just want to also plug your ownCloud calendar/addressbook in KDE etc, so all your mail clients will share the same address book (yeah!). Completely unrelated, add mozilla_sync to your ownCloud is worth it too.

The only thing so far that miss is the replication of your own identities – I haven’t found anything clear about that but havent looked into it seriously. I guess it’s possible to put ~/.kde/share/config/emailidentities on the cloud or use it to extract identities vcard but I’m not sure a dirty hack is worth it. It’s a pity that identities are not part of the addressbook.

(The alternative I was contemplating before was to use kolab; I needed ownCloud for other matters so I went for this option but I keep kolab in mind nonetheless)

Update 1: Stop using dsync that is tremendously unreliable as of today, use isync instead.

Update 2: Switch to mbsync, since isync was a wrapper that mbsync author recommends not to use anymore.

Update 3: Switch to offlineimap because I do not understand mbsync behavior, ignoring INBOX, etc. I cannot find a way to configure it so it works.

Release: SeeYouLater 1.2

Hi there! I’ve just released SeeYouLater 1.2 (fetch a list of IP or known spammers and to ban them by putting them in /etc/hosts.deny). It now includes seeyoulater-httpsharer, that enables to share ban list  over http instead of authenticated MySQL. It’s useful for distant hosts with unreliable link to each other/to avoid having MySQL listening on public ports.

You can obtain it on the Gna! project page using SVN or debian packages.

Avoiding Spams with SPF and greylisting within Exim

A year ago, I posted an article describing a way to slay Spams with both Bogofilter and SpamAssassin embedded in exim. This method was proven effective for my mailboxes:  since then, during a timespan of one year, Bogofilter caught ~ 85 % of actual spams, SpamAssassin (called only if mail not already flagged defavorably by Bogofilter) caught ~ 15 %. Do the math, I had almost none to flag by hand.

Why would I change such setup? For fun, obviously 🙂

Actually, I made no change, I just implemented SPF (Sender Policy Framework) and greylisting.

I noticed that plenty of spams were sent to my server @thisdomain claiming to be sent by whoever@thisdomain. These dirty spams were easily caught by the duo Bogofilter / SpamAssassin, but still, it annoyed me that @thisdomain was misused. SPF allows, using DNS records, to list which servers/computers are allowed to send mails from addresses @thisdomain.   SPF checks are predefined in Exim out of the box, so I’ll skip its configuration. The relevant DNS record (with bind9), allowing only two boxes (primary and secondary mail servers) designated by their IP to send mails @thisdomain, looks like:

thisdomain. IN  TXT  "v=spf1 -all"

Result: Since I implemented SPF on my domains, there was no change in the number of spam caughts. However, during this period, my primary server list of temporary bans dropped from 200/100 IPs to 40/20 IPs. I cannot pinpoint with certainty the cause of this evolution because the temporary bans list depends on plenty of things. But, surely, pretending to send mails @thesedomainsgrilledbySPF surely lost some interest for spambots. Implementing SPF is actually not about helping ourselves directly but indirectly: reducing effectiveness of spambots helps everybody.

I use greylisting on my secondary mail server since a while and I noticed over years that this one almost never had to ban IPs. Not that he never received spam, but that he almost never received mails from very obvious spam sources identified at STMP time.  Seems that most very obvious spam sources never insist enough to pass through greylisting. I guess that most spambots are coded to skip any mail server that does not immediatly accept a proper SMTP transaction, because it has no time to waste, considering how little is the percentage of spams sent actually reaching someone real.

This greylisting use the following files (an assumes memcached and libcache-memcached-perl are properly installed):

So I gave a try using greylist my primary mail server, but with a very short waiting time, because 5 minutes, for example, to receive mail from a not-yet-known  source is not acceptable. So I edited the relevant conf.d/main/ file to GREY_MINUTES = 0.5 and GREY_TTL_DAYS = 25.

Result: no changes regarding the number of caught spams. However, like on the secondary mail server, the number of banned IPs is near to none. Looks like most obvious spam sources don’t wait even only 30 seconds – actually, it’s a very acute choice as they would be anyway banned if they did.

Slaying Spams with both Bogofilter and SpamAssassin embedded in exim

Ads are spam. Good thing with the internet’s ads is that you can set up countermeasures.

(Disclaimer: yes, there is nothing new here, just an example of setup)

I have plenty of email addresses from different providers, some are definitely history. I could go through the websites of all of these and set up forwarding for the one I no longer use but still want to be able to get mail from, just in case. Well, I would do that if I was using my mail client to fetch mails – because otherwise fetching mails would actually take ages.

But, as I have a local home underclocked 🙂 server, I find way easier and potent to, instead, use ESR’s fetchmail to download them all to a single account that is accessed by my mail client through IMAPS. I have a /etc/fetchmailrc like:

poll with proto POP3
user 'XXX' there with password 'XXX' is 'localuser' here
poll with proto IMAP
user '' there with password 'XXX' is 'localuser' here with ssl
user '' there with password 'XXZ' is 'localuser' here with ssl

Fetchmail download mails than then relies on the installed SMTP, which is Exim, to deliver it to end user account mailbox accessible through IMAPS.

What’s so nifty nifty about? Well, mails will also be filtered for spam. As it happens on the local home server, it will be unnoticeable for the end user that is me. We’ll use several anti-spam tools, not caring about redundancy and time-consumption: DNSBLs, Bogofilter, SpamAssassin, razor2.

So, here we go. Note that Exim (exim4) in Debian use the user Debian-exim. localuser is the recipient end-user, it belongs to the group localuser name after himself.
We will add Debian-user to the group localuser and create a system group dedicated to spamchecking to easily share bayesian databases.:

# addgroup --system spamslayer
# adduser Debian-exim spamslayer
# adduser Debian-exim localuser
# adduser localuser spamslayer

* Bogofilter is a bayesian spam filter . It is said to be faster and lesser time consuming than the SpamAssassin’s own bayesian filter so will run mails through it first. It is installed with the debian package.

Edit /etc/ as follows:


The bayes directory must be created by hand:

# mkdir /var/lib/bogofilter
# chgrp spamslayer /var/lib/bogofilter
# chmod 2777 /var/lib/bogofilter

* SpamAssassin is a powerful, at the cost of time-consumption, spam-killer. It is installed with the debian package.

In the following site-wide config /etc/spamassassin/, I use bayesian filters, razor2, several DNSBLs and I adjust some tests according to my needs:

# Save spam messages as a message/rfc822 MIME attachment instead of
# modifying the original message (0: off, 2: use text/plain instead)
# Keep as it is because bogofilter would not learn properly otherwise,
# as it cannot distinguish report from the spam.
report_safe 0
# Set which networks or hosts are considered 'trusted' by your mail
# server (i.e. not spammers)
trusted_networks 192.168.1.
# Locales
# (I only receive mails in English or French)
ok_locales en fr
# Set the threshold at which a message is considered spam (default: 5.0)
required_score 3.3
# Use Bayesian classifier (default: 1)
# (I created the relevant directory)
use_bayes 1
bayes_file_mode 0777
bayes_path /var/lib/spamassassin-bayes/bayes
score BAYES_20 0.3
score BAYES_40 0.5
score BAYES_50 0.8
score BAYES_60 1
score BAYES_80 2
score BAYES_95 2.5
score BAYES_99 6
# Bayesian classifier auto-learning (default: 1)
# (I may change that, not sure about it)
bayes_auto_learn 1
# Set headers which may provide inappropriate cues to the Bayesian
# classifier
bayes_ignore_header X-Bogosity
bayes_ignore_header X-Spam-Flag
bayes_ignore_header X-Spam-Status
# use razor
# (/etc/razor is the standard debian path)
use_razor2 1
razor_config /etc/razor/razor-agent.conf
score RAZOR2_CF_RANGE_51_100 3.2
# some rbl checks are already made by exim, at RCPT time, not all.
skip_rbl_checks 0
rbl_timeout 30
score RCVD_IN_SBL 15
score RCVD_IN_XBL 15
# adjust some tests scores: lower DUL test
# lower stupid test
# adjust some tests scores
score HTML_FONT_BIG 2.4
score NO_REAL_NAME 2
score SUBJ_ALL_CAPS 2.6
# increase all scores related to drugs: what do I care, duh
score DRUGS_DIET 5
score DRUGS_PAIN 5
score DRUGS_SMEAR1 5
# same goes for porn
score BEST_PORN 5
score FREE_PORN 5
score LIVE_PORN 5
score PORN_15 5
score PORN_16 5
score PORN_URL_SEX 5

The bayes directory must be created:

# mkdir /var/lib/spamassassin-bayes
# chown Debian-exim /var/lib/spamassassin-bayes
# chmod 0777 /var/lib/spamassassin-bayes

Obviously, it implies that razor2 must be properly installed. We install the debian package then set it up. Remember it must run with user Debian-exim, so we do:

# chown -R Debian-exim:spamslayer /etc/razor
# su Debian-exim
$ razor-admin -home=/etc/razor -register
$ razor-admin -home=/etc/razor -create
$ razor-admin -home=/etc/razor -discover

To save ressources, we start SpamAssassin as a daemon (spamd), that will be called using its specific client (spamc). Before using the initd script, edit as follows /etc/defaut/spamassassin:

# Change to one to enable spamd
# SpamAssassin uses a preforking model, so be careful! You need to
# make sure --max-children is not set to anything higher than 5,
# unless you know what you're doing.
OPTIONS="--create-prefs --max-children 5 --helper-home-dir -u Debian-exim -g spamslayer"
# Cronjob
# Set to anything but 0 to enable the cron job to automatically update
# spamassassin's rules on a nightly basis

All that being do, you’ll want to (re)start the daemon with the relevant initd script (/etc/init.d/spamassassin restart here).

* Now we’ll tune Exim to call all by himself first Bogofilter and then SpamAssassin, if necessary only. We use splitted configuration in /etc/exim4/conf.d/. That is debian-specific I think but it does make any difference anyway.

First we define useful transports in /etc/exim4/conf.d/transport/35_spamblock (the name 35_spamblock is arbitrary and the number does not matter here):

driver = pipe
command = /usr/sbin/exim4 -oMr spamslayed-bogofilter -bS
use_bsmtp = true
transport_filter = /usr/bin/bogofilter -l -p -e
home_directory = "/tmp"
current_directory = "/tmp"
# must use a privileged user to set $received_protocol
# on the way back in!
user = Debian-exim
group = spamslayer
log_output = true
return_fail_output = true
return_path_add = false
message_prefix =
message_suffix =
driver = pipe
command = /usr/sbin/exim4 -oMr spamslayed-spamd -bS
use_bsmtp = true
transport_filter = /usr/bin/spamc
home_directory = "/tmp"
current_directory = "/tmp"
# must use a privileged user to set $received_protocol
# on the way back in!
user = Debian-exim
group = spamslayer
log_output = true
return_fail_output = true
return_path_add = false
message_prefix =
message_suffix =

Second we define routers, here in /etc/exim4/conf.d/router/450_spamblock – the order matters, here it is just after 400_exim4-config_system_aliases and before 500_exim4-config_hubuser:

# spam checking
# first bogofilter
debug_print = "R: bogofilter for $local_part@$domain received with protocol $received_protocol with X-Spam-Flag=$h_X-Spam-Flag and X-Bogosity=$h_X-Bogosity"
# When to scan a message :
# - it isn't already flagged as spam
# - it has not yet been spamslayed at all
# - it isn't local ($received_protocol eq "" or local)
condition = "${if and{ {!eqi{$h_X-Spam-Flag:}{yes}} {!eq{$received_protocol}{spamslayed-bogofilter}} {!eq{$received_protocol}{spamslayed-spamd}} {!eq{$received_protocol}{local}} {!eq{$received_protocol}{}} }}"
driver = accept
transport = spamslay_bogofilter
# second spamd
debug_print = "R: spamd for $local_part@$domain received with protocol $received_protocol with X-Spam-Flag=$h_X-Spam-Flag and X-Bogosity=$h_X-Bogosity"
# When to scan a message :
# - it isn't already flagged as spam
# - it has not yet been spamslayed with SA
# - it isn't local ($received_protocol eq "" or local)
condition = "${if and { {!eqi{$h_X-Spam-Flag:}{yes}} {!match{$h_X-Bogosity:}{^Spam}} {!eq {$received_protocol}{spamslayed-spamd}} {!eq{$received_protocol}{local}} {!eq{$received_protocol}{}} }}"
driver = accept
transport = spamslay_spamd
# This route will send any mail that got here to the devnull alias, that
# should be configured in /etc/aliases to be a real link to /dev/null.
# This route should get only mails that have spam score higher than 14.
# This will affect users mails!
condition = "${if ge{$h_X-Spam-Level:}{\*\*\*\*\*\*\*\*\*\*\*\*\*\*} {1}{0} }"
driver = redirect
data = spam
file_transport = address_file
pipe_transport = address_pipe

* Next step, now that spams are flagged, it makes sense to put them apart in the Maildir that will be accessed through IMAPS. I do this with procmail. We set umask for procmail (the IMAP server is configured as such too) to make sure Debian-exim can access stored mails (we want mode 0640, group read access, so the umask is 666-640=026). Here’s the relevant bit of /home/localuser/.procmailrc:

* ^X-Spam-Status: Yes
* ^X-Spam-Flag: YES
* ^X-Bogosity: Spam

At the same time, we make sure Debian-exim can access mails already there (so not affected by umask):

# cd /home/localuser
# chmod 750 -Rv .Maildir
# chmod 0640 -v `find .Maildir -type f`

(PS: you may want to enforce a more restrictive policy, depending on how your server is accessed – but, anyway, Debian-exim is by essence able to tamper with mails you receive, so it won’t make a big difference)

* Training bayesian filters.

Now that spam ended up in a specific Maildir, both SpamAssassin and Bogofilter bayesians filters must be trained to be effective.

We add the following in /etc/cron.d/bayes:

# trains bayesian filters
SPAMDIR="/home/localuser/.Maildir/.Poubelle.Spam/cur/ /home/localuser/.Maildir/.Poubelle.Spam/new/"
# spamd: can handle by itself bogofiltered headers
25 * * * * Debian-exim /usr/bin/sa-learn --spam $SPAMDIR
# bogofilter: not able to clean inappropriate cues from spamd, will do it
# by removing:
# - informational SpamAssassin headers
# - SpamAssassin score and decision (irrelevant)
# (-u was not set as it is discouraged perf-wise in bogofilter's manual)
28 * * * * Debian-exim for file in `find $SPAMDIR -type f`; do cat $file; done | grep -v -E "^X-Spam-(Checker|Flag|Level|Report)" | sed s/"^X-Spam-Status.*score.*required.*tests="//g | /usr/bin/bogofilter --register-spam

Obviously, if you want it to learn from plenty of different users, you’ll have to think of something more elaborated 🙂
Anyway, regarding plenty of users, it would actually probably wise to think twice about the whole concept of sharing bayesian filters that may not at all be accurate for very differents users.

One alternative would have been to avoid meddling with Exim and to run both bogofilter and spamd via procmail. Sure, it would not have been site-wide setup but for a few users, ~/.procmailrc can be replicated easily. But actually I enjoy messing with Exim, that’s kind of a hobby. I skipped here the part where we call DNSBLs in Exim (working out-of-the-box anyway). And on a production server, with the SMTP wide opened to the web, it is possible to follow this approach just to shut off spammers at SMTP-time -which induces a huge resources gain- and even ban them.

Securing and improving internet services, including SSH and SMTP, using xinetd

As stated by its manpage, xinetd performs the same function as inetd: it starts programs that provide Internet services. Instead of having such servers started at system initialization time, and be dormant until a connection request arrives, xinetd is the only daemon process started and it listens on all service ports for the services listed in its configuration file. When a request comes in, xinetd starts the appropriate server. Because of the way it operates, xinetd (as well as inetd) is also referred to as a super-server.

The X in the name stands for extended. Which means the following is really for xinetd, not openbsd-inetd 🙂

Still according to its manpage, so far, the only reason for the existence of a super-server was to conserve system resources by avoiding to fork a lot of processes. While fulfilling this function, xinetd takes advantage of the idea of a super-server to provide features such as access control and logging. Some people will say, and they’ll be right, that running all services through a wrapper implies, instead of conserving resources, somekind of overhead: in conserves resources since it avoids running concurrently as many services as available on the server, right, but this makes no sense on a server with a wide audience that actually have enough users so all services are anyway almost always running concurrently. In this case, some people would be correct to assume more efficient to use standalone servers for each service .

But, and that’s the point, access control makes a difference. Sure, standalone servers have also access control. OpenSSH does ; and using OpenSSH via xinetd should not discourage to look into /etc/ssh/sshd_config. Nonetheless, xinetd access control applies to any service running through it. And that’s prett-ay, pretty good. For instance, you do not need to configure each standalone server to be hardened enough against DDoS, if xinetd is, you should be fine.

So let’s get to business. We assume here you have xinetd up an running. Shouldn’t be a big deal, xinetd is standard on many GNU/Linux systems.

Normally, you should have a /etc/xinetd.d where you can add bits of config for xinetd (if it does not exists, well, you could still use the default config file /etc/xinetd.conf).

There you have basic standard stuff: chargen, daytime, discard, echo, time. If you do not want to provide these, sure make sure each entry in these files got the line:

disable = yes

For each following example to work, you must indeed shut down the standalone server, otherwise the service port won’t be available to xinetd. Also, in the following examples, you’ll have to edit the IPs according to your network.

This is for OpenSSH, with a specific port for root login (probably a nuisance on a distant server supposed to be frequently accessed as root – but a safe pick for a local network server rarely accessed as root from the web):

# To work, sshd must not run by itself,
# so /etc/ssh/sshd_not_to_be_run
# should exists

# allows unrestricted SSH only to local network
service ssh
socket_type = stream
protocol = tcp
wait = no
user = root
bind =
only_from =
server = /usr/sbin/sshd
server_args = -i

# allows SSH from the web but restricted to users listed
# (root being forcefully disallowed)
# restrict also to only 5 connections per IP (per-source)
# and limit the rate of incoming connections (cps)
service ssh
socket_type = stream
protocol = tcp
port = 22
wait = no
user = root
bind = 88.???.???.???
server = /usr/sbin/sshd
server_args = -i -o PermitRootLogin=no -o AllowUsers=thisuser
cps = 30 10
per_source = 5
log_on_success = HOST USERID

# allow SSH from the web only for root, on port 33333
# requires /etc/services to include lines:
# rootexternalssh 33333/tcp
# rootexternalssh 33333/udp
service rootexternalssh
socket_type = stream
protocol = tcp
port = 33333
wait = no
user = root
server = /usr/sbin/sshd
server_args = -i -p 33333 -o AllowUsers=root
cps = 30 10
per_source = 3
log_on_success = HOST USERID

This is for Dovecot, an IMAPS server. This setup listen on the local network. You can easily tune it following the example given above:

service imaps
socket_type = stream
protocol = tcp
wait = no
user = root
bind =
only_from =
server = /usr/lib/dovecot/imap-login
flags = IPv4
server_args = --ssl

I won’t provide an exhaustive list of services that you can run with xinetd. You can surely find for yourself what suits you best! 🙂 But the presentation wouldn’t be complete if I missed traps. Yes, you can set up traps with xinetd. For instance if you do not use ftp, irc, telnetd, etc, you can safely assume that someone trying to connect on these services ports is trying to do something he shouldn’t. And you can then decide to disallow further connections.

# bind must be set so we do not shut off clients from the
# local network that made dumb scan
service ftp
socket_type = stream
wait = no
user = root
bind = 88.???.???.???
flags = SENSOR
log_on_success = HOST PID
deny_time = 1440

service sftp
socket_type = stream
wait = no
user = root
bind = 88.???.???.???
flags = SENSOR
log_on_success = HOST PID
deny_time = 1440

service irc
socket_type = stream
wait = no
user = root
bind = 88.???.???.???
flags = SENSOR
log_on_success = HOST PID
deny_time = 1440

service telnet
socket_type = stream
wait = no
user = root
bind = 88.???.???.???
flags = SENSOR
log_on_success = HOST PID
deny_time = 1440

These are basic examples. You can do more.

For instance, years ago, I wrote SeeYouLater, denying access to spammers with hosts.deny, a production-ready software that looks in the SMTP daemon logs for identified spam sources IPs and then ban them via /etc/hosts.deny (which xinetd handles).
With the SMTP daemon run through xinetd, any identified spam source will no longer even be able to connect (which presents plenty of advantages, as it is costless by comparison to discarding the spam sources during SMTP transaction).
SeeYouLater depends on perl and MySQL, the debian apt source is

deb ./

and there is a cookbook entry covering setup with Exim.

I’d like to mention that I ran xinetd on Gna! main servers (for mail with exim, or for CVS/SVN/Arch, etc – mail server was moved and I did not follow the way it is set up) and the overhead mentioned above was unnoticeable while the number of connections per minutes was quite higher than what you would expect on a small business network server or whatever.