Setting Up A Spam-Proof Home Email Server (The Somewhat Alternate Way) (Debian Squeeze) - Page 3
On this page
- Set Up Dovecot
- Set Up Email Address Management
- (1) Install packages
- (2) Create SSL certificate for Apache
- (3) Create the email webfolder
- (4) Edit /var/www/email/.htaccess and add
- (5) Edit /var/www/email/index.php and add
- (7) Enable apache modules
- (8) Extend apach2 config
- add at the end of the file the following
- (11) Add yourself to authdigest
- (12) Restart Apache
- and add:
- (14) Make it executable
- (15) Add the script to the cron.txt
- (16) Load the new cron.txt
- (17) Display current crons
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:
[email protected] SYSUSER
In that case incoming email to the "[email protected]" 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 "[email protected]" then I would have an entry like this:
[email protected] testuser
If only that would be in the virtual table and an email with recipient address "[email protected]" 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