Setting Up A Spam-Proof Home Email Server (The Somewhat Alternate Way) (Debian Squeeze) - Page 3

Set Up Dovecot

(1) Install the packages

apt-get install dovecot-imapd

The Dovecot config file is located at /etc/dovecot/dovecot.conf. Edit it and make following changes:

 

(2) Add Maildir

Search for

#mail_location = 

and add below

mail_location = maildir:~/Maildir 

 

(3) Add authentication

Search for

auth default { 

rename it to

auth default2 { 

and add above

auth default {
	mechanisms = plain login
	passdb pam {
	}
	userdb passwd {
	}
	socket listen {
		client {
			path = /var/spool/postfix/private/auth
			mode = 0660
			user = postfix
			group = postfix
		}
	}
}

 

(3) Restart Dovecot

/etc/init.d/dovecot restart

By default only IMAP and IMAPs is enabled on dovecot. I don't see any point nowadays in POP3 hence the according daemon is not being installed and activated.

 

Set Up Email Address Management

Now we actually have a fully functioning mail server. The only problem is, the mailserver does not yet know what to do with incoming email.

When we added this "virtual_maps = hash:/etc/postfix/virtual" to the postfix config we told the server, that the incoming email address and their destination is to be found in this file. This file has a very simple structure:

USER@MYDOMAIN.COM		SYSUSER 

In that case incoming email to the "USER@MYDOMAIN.COM" email address will be put into the Maildir of the system user "SYSUSER".

Assuming my username on the system is "testuser" and I setup a recipient address for my buddy John Doe like "from.john.doe@testuser.com" then I would have an entry like this:

from.john.doe@testuser.com		testuser 

If only that would be in the virtual table and an email with recipient address "really.from.john.doe@testuser.com" would arrive, then Postfix can't find a match and it will reject it. The sender will get an according notice, that this email address does not exist.

This means we can easily just add hundreds and thousands of email addresses there and tell they should all go to the "testuser" account. When I then notice, I get spam to specific incoming email address, I can simply remove that one.

HOWEVER, just creating that file doesn't do the job. There are two more steps required after each edit:

postmap /etc/postfix/virtual
/etc/init.d/postfix reload

The first one converts the virtual file into a hashed virtual.db file which makes it faster for postfix to process and the second command reloads the file.

Always editing this by hand is cumbersome. Hence I created myself a little PHP script which makes it simple. It only has two options:

- adding new incoming email addresses

- remove existing entries

In order to prevent any abuse, a few precautions have to be taken. Namely:

- According access to the script is only possible with HTTPS

- Username and password are required to login

- virtual file is not directly altered but updated with cron

 

(1) Install packages

apt-get install libapache2-mod-php5

This will install Apache, PHP5, PHP5 Module and PHP5 Cli.

 

(2) Create SSL certificate for Apache

openssl req $@ -new -x509 -days 3650 -nodes -out /etc/apache2/apache.pem -keyout /etc/apache2/apache.pem

 

(3) Create the email webfolder

mkdir -p /var/www/email

 

(4) Edit /var/www/email/.htaccess and add

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

 

(5) Edit /var/www/email/index.php and add

<?php
$sysuser = 'USERNAME';
$domain = 'MYDOMAIN.COM';
#######################################################################################################
#                                                                                                     #
#                                                                                                     #
#                        DO NOT EDIT BELOW                                                            #
#                                                                                                     #
#                                                                                                     #
#######################################################################################################

$email = $_POST['email'];
$pg = $_POST['submit'];
if($pg == '') {  $pg = $_GET['pg']; }

switch ($pg) {
    case 'Add':
        $output = add_email($email, $domain, $sysuser);
        break;
    case 'Remove':
        $output = remove_email($email);
        break;
    case 'RemoveForm':
        $output = remove_form();
        break;
    default:
        $output = add_form();
}
$output = f_header() . $output . f_footer();
echo $output;

function f_header() {
	$output = "<html>\n<head>\n<title>Email Management</title>\n</head>\n
			<body>\n
			<a href='?pg=AddForm'>Add Email</a> | <a href='?pg=RemoveForm'>Remove Email</a><br><br>
			<form name='input' action='" . $PHP_SELF . "' method='POST'>\n
	";	
	return($output);
}
function f_footer() {
	$output = "</form>\n</body>\n</html>";
	return($output);
}

function add_form($added) {
	$output = "$added<br>
			<br>Domain '@$domain' will be automatically added.<br>
			<input type='text' name='email' value='' size='30'>\n
			<input type='submit' name='submit' value='Add'>\n
	";
	return($output);
}
function remove_form($added) {
	$output = "$added<br>
			<br>Only enter the 'left' part of the '@'<br>
			<input type='text' name='email' value='' size='30'>\n
			<input type='submit' name='submit' value='Remove'>\n
	";
	return($output);
}

function add_email($email, $domain, $sysuser) {
        $myFile = "add.txt";
		$write_block = $email . '@' . $domain ."\t\t\t" .$sysuser . "\n";
        $fh = fopen($myFile, 'a') or die("can't open file");
        fwrite($fh, $write_block);
        fclose($fh);
        $added = $email . "@" . $domain . " - marked for addition";
        $output = add_form($added);
        return($output);	
}
function remove_email($email) {
        $myFile = "remove.txt";
		$write_block = $email . "\n";
        $fh = fopen($myFile, 'a') or die("can't open file");
        fwrite($fh, $write_block);
        fclose($fh);
        $added = $email . " - marked for removal";
        $output = remove_form($added);
        return($output);
}
?>

Replace at the beginning the USERNAME with your system user name and MYDOMAIN.COM with your actual domain name.

 

(6) Chown /var/www/email

chown -R www-data:www-data /var/www/email

 

(7) Enable apache modules

a2enmod ssl auth_digest rewrite

 

(8) Extend apach2 config

echo "servername localhost" >> /etc/apache2/apache2.conf

 

(9) Edit /etc/apache2/sites-enabled/000-default

Insert after

        <Directory /var/www/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

this

        <Directory /var/www/email/>
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>

 

(10) Still editing the /etc/apache2/sites-enabled/000-default add at the end of the file the following

<VirtualHost *:443>
        ServerAdmin webmaster@localhost
        SSLEngine on
        SSLCertificateFile /etc/apache2/apache.pem
        DocumentRoot /var/www/
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /var/www/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>
        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>
        ErrorLog /var/log/apache2/error.log
        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn
        CustomLog /var/log/apache2/access.log combined
    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>
    <Location /email>
        AuthType Digest
        AuthName "email"
        AuthDigestDomain /var/www/email/ http://MYDOMAIN.COM/email
        AuthDigestProvider file
        AuthUserFile /etc/apache2/passwords
        Require valid-user
        SetEnv R_ENV "/var/www/email"
     </Location>
</VirtualHost>

 

(11) Add yourself to authdigest

htdigest -c /etc/apache2/passwords email USERLOGIN

Enter a desired username for USERLOGIN and enter twice the desired password.

 

(12) Restart Apache

/etc/init.d/apache2 restart

What we have now is an auto-redirect to SSL version of the email management script. When successfully logged in, the script will create an "add.txt" and "remove.txt" file when email addresses should be added/removed.

The missing piece now is to communicate those changes with postfix. For this, we just add another small shell script and add that one to cron.

 

(13) Edit /root/email_virtual.sh and add:

#!/bin/bash
ADD="/var/www/email/add.txt"
REMOVE="/var/www/email/remove.txt"
DEST="/etc/postfix/virtual"
if [ -f $ADD ] 
then 
        while read CURLINE; do
#               echo $CURLINE
                echo $CURLINE >> $DEST
        done < $ADD
        rm $ADD
fi 
if [ -f $REMOVE ]
then
        while read CURLINE; do
#               echo $CURLINE
                sed -i "/$CURLINE/ d" $DEST
        done < $REMOVE
        rm $REMOVE
fi
postmap /etc/postfix/virtual 
/etc/init.d/postfix reload 

 

(14) Make it executable

cd /root
chmod 0700 email_virtual.sh

 

(15) Add the script to the cron.txt

echo "*/2 * * * * virtual_email.sh >/dev/null 2>&1" >> cron.txt

 

(16) Load the new cron.txt

crontab cron.txt

 

(17) Display current crons

crontab -l

Share this page:

6 Comment(s)

Add comment

Comments

From: Anonymous at: 2011-05-17 08:01:14

You do need DNS resolution if you are NATed.... and if you are using multiple networks at once, you really, really need it.

 If you're just on at home, you can easily set the dns resolution in the hosts file. But if it's a notebook that you use at home, at work or other places.... you'll need a better option ;=

From: JohnP at: 2011-05-16 18:17:54

DNS services support wildcard redirection like *.domain.org, so you don't need to run BIND locally - or anywhere on your systems.

This has been working here for over a decade.

Bind is often hacked, so don't run it unless you really need it. If you do need to run it, use chroot.

DynDNS.org's DNS service supports wildcard redirection, MX and all the other things you need from a DNS service. ddclient is the dynamic IP tool, assuming your router doesn't support them already. Most current routers seem to support dyndns and a few other DNS providers.

From: Samat at: 2011-05-19 01:02:38

Nice idea: but what I don't like about this, you're on that Thunderbird extension setting sender e-mail address for you.

What if someone stops maintaining the extension, or you want to switch to another e-mail client or webmail?

From: KBurger at: 2011-05-22 04:01:12

The dynamic IP address problem can easily be overcome with DDclient.  I think it's in the repositories.  If not you can get it here -  http://sourceforge.net/apps/trac/ddclient

With this you don't need a static IP address.

From: fossala at: 2011-09-18 12:45:07

I have followed your guide (very good btw) and I cannot send things with smtp. It just says "login to server *mymailserver*.com failed."

Any ideas where to start to look where I went wrong? 

From: at: 2012-01-28 19:36:14

I noticed a little error. On page 2 it says to run:

echo 'mech_list: plain login' >> /etc/postfix/sasl/smtpd.config

 but it should be smtpd.conf

 

Maybe that's the reason why you can't login.