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

Want to support HowtoForge? Become a subscriber!
 
Submitted by guestwriter (Contact Author) (Forums) on Mon, 2011-05-16 17:39. ::

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


Please do not use the comment function to ask for help! If you need help, please use our forum.
Comments will be published after administrator approval.