Configure Doorman Server

Quickstart

As a first and very basic scenario, just let's get started by setting up Doorman with three simple modules to explain you the actual usage and show how module order in your configuration matters.

We will use DNSBL (a DNS Blackhole List), Basic (validity checks) and Greylist (well, a greylist), because they are simple but provide extend configuration as well to be good for an example. Also, using those three modules can be enough for a simple SPAM defense.

The Doorman config file

I assume you've used the standard configuration directories, so you'll find the Doorman config file in /etc/decency/doorman.yml

It is already filled with some stuff, but to get you started, just remove it and begin with a blank slate.

First, you should set the environment stuff. This includes logging, database and cache.

One thing: All the config snippets are YAML. So DONT use TABS! I use 4 spaces, you can go with two if you are a lazy typer - as long as you stay consistent.

Database

I am going to use a SQLite database, cause it's either already installed or you can install it quite simple (via your distribution installer).

Insert into the (empty) configuration file the following:

---

# Using SQLite database
database:
    type: DBD
    args:
        - 'dbi:SQLite:dbname=/var/spool/decency/database.db'

I think it's quite readable. The 'dbi:SQLite:dbname=' gibberish is a Perl Data Source Name (DSN) - don't bother. You can edit the path to the database if you wish.

Cache

Having this done, let's use a cache. For the example, we'll got with the simplest one: a memory cache. The downside of this cache is, that i will be wiped on server restart and also it can grow large over time. For production i'd rather go with FastMmap or even Memcached.

So, add the following under the database configuration:

# Using Memory cache
cache:
    class: Memory

Logging

Lets use directory logging for the example. Normally, decency writes directory logs in /var/log/decency/, but you can change this as you like. Just make sure the decency user can write to the directory.

Here we go, add the following below the cache settings:

# Directory logging
logging:
    log_level: 1
    directory: /var/log/decency

Server settings

This part sets up the server itself, where it listens, how many mails it can work on in parallel and so on.

Here we go:

server:
    host: 127.0.0.1
    port: 15000
    instances: 3

Modules

The last part is setting up the modules. You could write the module configuration inline, but i am not a big fan of huge config files (better more, each short).

Announcing modules in the server config

The order of the modules is important. So we begin with the Basic checks, then the DNSBL and at last the Greylist.

modules:
    - Basic: /etc/decency/doorman/basic.yml
    - DNSBL: /etc/decency/doorman/dnsbl.yml
    - Greylist: /etc/decency/doorman/greylist.yml

One thing, while we're at the last config entry in the server config file: It should end with a blank link, or the Perl YAML parser will complain..

Basic-Module config

Ok, to the Basic module. If you are familiar with postfix basic validations, you will recognize them here. If not: all checks consider the validy of either the HELO name the connecting mail server has provider, the sender domain, the recipient domain oder the client's hostname. I will not go in depth, that you can find in the module description, so here are the settings for /etc/decency/doorman/basic:

---

weight_invalid_helo_hostname: -100
weight_non_fqdn_helo_hostname: -100
weight_non_fqdn_recipient: -100
weight_non_fqdn_sender: -100
weight_unknown_helo_hostname: -50
weight_unknown_recipient_domain: -50
weight_unknown_sender_domain: -50
weight_unknown_reverse_client_hostname: -25

Again, don't miss the last empty line..

DNSBL-Module config

DNSBL in short: check the connecting mailserver IP against a blackhole list. If it is on the list, it get's scored negatively. Which lists you use is your choice. The following are an example /etc/decency/doorman/dnsbl.

---

blacklist:
    -
        host: ix.dnsbl.manitu.net
        weight: -80
    -
        host: bl.spamcop.net
        weight: -80
    -
        host: dnsbl.sorbs.net
        weight: -60

Empty line ..

Greylist-Module config

Here is the last module for our example: the Greylist. It basicially reject any "first-contact" deliver attempt with a temporary error. If the sender is a real mailserver, it will queue the mail and try again later. Later the mail is accepted and everybody is happy. Here you go /etc/decency/doorman/greylist.yml :

---

recipient_domain_threshold: 5
sender_domain_threshold: 10

Empty line ..

Setup the database

Your Greylist module requires a database. Also you could enable later on statistics for your Doorman. So, assuming you have the sqlite commandline tools installed (if not: do now), open an empty file (eg /tmp/tables.sql) and add the SQL syntax:

-- TABLE: greylist_recipient (SQLITE):
CREATE TABLE GREYLIST_RECIPIENT ("to_domain" varchar(255),
    "from_address" varchar(255), "last_update" integer, "ip" varchar(39),
    "data" integer, id INTEGER PRIMARY KEY);
CREATE INDEX GREYLIST_RECIPIENT_LAST_UPDATE ON
    GREYLIST_RECIPIENT ("last_update");
CREATE UNIQUE INDEX GREYLIST_RECIPIENT_FROM_ADDRESS_IP_TO_DOMAIN ON
    GREYLIST_RECIPIENT ("from_address", "ip", "to_domain");

-- TABLE: greylist_sender (SQLITE):
CREATE TABLE GREYLIST_SENDER ("to_domain" varchar(255),
    "from_domain" varchar(255), "last_update" integer, "ip" varchar(39),
    "data" integer, id INTEGER PRIMARY KEY);
CREATE INDEX GREYLIST_SENDER_LAST_UPDATE ON GREYLIST_SENDER ("last_update");
CREATE UNIQUE INDEX GREYLIST_SENDER_FROM_DOMAIN_IP_TO_DOMAIN ON
    GREYLIST_SENDER ("from_domain", "ip", "to_domain");

-- TABLE: greylist_address (SQLITE):
CREATE TABLE GREYLIST_ADDRESS ("from_address" varchar(255),
    "last_update" integer, "ip" varchar(39), "data" integer,
    "to_address" varchar(255), id INTEGER PRIMARY KEY);
CREATE INDEX GREYLIST_ADDRESS_LAST_UPDATE ON GREYLIST_ADDRESS ("last_update");
CREATE UNIQUE INDEX GREYLIST_ADDRESS_FROM_ADDRESS_IP_TO_ADDRESS
    ON GREYLIST_ADDRESS ("from_address", "ip", "to_address");


-- TABLE: stats_doorman_results (SQLITE):
CREATE TABLE STATS_DOORMAN_RESULTS ("calls" integer, "period" varchar(10),
    "last_update" integer, "status" varchar(32), "module" varchar(32),
    "start" integer, id INTEGER PRIMARY KEY);
CREATE INDEX STATS_DOORMAN_RESULTS_START ON STATS_DOORMAN_RESULTS ("start");
CREATE UNIQUE INDEX STATS_DOORMAN_RESULTS_MODULE_PERIOD_STATUS_START
    ON STATS_DOORMAN_RESULTS ("module", "period", "status", "start");

-- TABLE: stats_doorman_performance (SQLITE):
CREATE TABLE STATS_DOORMAN_PERFORMANCE ("calls" integer, "period"
    varchar(10), "last_update" integer, "score" integer, "runtime" real,
    "module" varchar(32), "start" integer, id INTEGER PRIMARY KEY);
CREATE INDEX STATS_DOORMAN_PERFORMANCE_START ON
    STATS_DOORMAN_PERFORMANCE ("start");
CREATE UNIQUE INDEX STATS_DOORMAN_PERFORMANCE_MODULE_PERIOD_START
    ON STATS_DOORMAN_PERFORMANCE ("module", "period", "start");

-- TABLE: stats_doorman_final_state (SQLITE):
CREATE TABLE STATS_DOORMAN_FINAL_STATE ("amount" integer,
    "period" varchar(25), "status" varchar(10), "start" integer,
    id INTEGER PRIMARY KEY);
CREATE INDEX STATS_DOORMAN_FINAL_STATE_START ON
    STATS_DOORMAN_FINAL_STATE ("start");
CREATE UNIQUE INDEX STATS_DOORMAN_FINAL_STATE_PERIOD_STATUS_START
    ON STATS_DOORMAN_FINAL_STATE ("period", "status", "start");

Then create your database out of it:

$ sqlite3 /var/spool/decency/database.db < /tmp/tables.sql

Substitute /var/spool/decency/database.db with the path to your database. Also assure the Decency user has write access to the database:

# assuming your user and group are called "decency"
chown decency:decency /var/spool/decency/database.db

Start the Doorman

Thats it! You can now start the Doorman. For the first run, it's a good idea not to use the init.d-scripts or daemonize the server, because you will see all errors directly.

# direct
$ /opt/decency/bin/decency.pl -u decency -g decency -a doorman -l 6

You can stop the server by pressing "Ctrl+c".

Running as daemon

If everything works well, you can run the Doorman as daemon. Either use the init.d scripts or append the "-d" parameter:

# init scripts
$ /etc/init.d/decency-doorman start

# direct
$ /opt/decency/bin/decency.pl -u decency -g decency -a doorman -d

Connect to Postfix

To connect the Doorman to Postfix, you have to add a check-directive at a convenient point in your postfix config. If you configured config with smtpd_delay_reject = yes you can put it in any restriction class. If not, it should be placed in smtpd_recipient_restrictions. Here you go (in /etc/postfix/main.cf):

smtpd_recipient_restrictions =
    # .. something before
    check_policy_service inet:127.0.0.1:15000
    # .. something after

Of course: restart Postfix.

Why module-order matters

In the above example, we used Basic -> DNSBL -> Greylist. What, if we'd just reversed that order? Well, it would probably work the same, at least with the same accuracy .. BUT: your greylist database would grow enormously. From my experience, Basic and DNSBL will filter out about 90-95% of all SPAM beforehand (they are probably the most effective modules), so the Greylist has to deal with about 5-10% of the actual spams. If you reversed the order, Greylist has to cope with 10 to 20 times of the amount and will write about 10-20 times more database entries.

What if you'd put DNSBL before Basic? That will also work, but DNSBL has to query external blacklists, whereas Basic just does "local" validity checks. So you'd slow down your server, due to the more queries to external DNS servers. Basic would filter out somthing in the range of 50-70% beforehand, so DNSBL has to check less IPs if it runs after Basic.

Finetunting

You should familiarize yourself with the modules and the concepts they implement. Here is a list of all currently available modules:

What's next ?

Also read the Doorman configuration, where you can find out about fine tuning your scoring, default responses and so on.

In the cache and database documentation you can read about the pros and cons about the supported databases and caches (and how to configure them).

Then of course go to the Detective tutorial, setup your Detective and understand how Doorman and Detective interact.