ISP Mail Server HowTo: Difference between revisions

From Alpine Linux
Line 186: Line 186:
  myhostname=host.example.com                                                                   
  myhostname=host.example.com                                                                   
  mydomain=example.com                                                                         
  mydomain=example.com                                                                         
                                                                                                 
  mydestination = $myhostname, localhost.$mydomains, localhost                                 
  mydestination = localhost.$mydomains, localhost                                 
  mynetworks_style = subnet                                                                     
  mynetworks_style = subnet                                                                     
  mynetworks = 127.0.0.0/8                                                                     
  mynetworks = 127.0.0.0/8                                                                     
                                                                                                 
 
  virtual_mailbox_domains = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_domains_maps.cf               
  virtual_mailbox_domains = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_domains_maps.cf               
  virtual_alias_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_maps.cf,                     
  virtual_alias_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_maps.cf,                     
         proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_maps.cf,                           
         proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_maps.cf,                           
         proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_catchall_maps.cf                   
         proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_catchall_maps.cf                   
                                                                                                 
  virtual_mailbox_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_mailbox_maps.cf,                 
  virtual_mailbox_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_mailbox_maps.cf,                 
         proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_mailbox_maps.cf                     
         proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_mailbox_maps.cf                     
                                                                                                 
  virtual_mailbox_base = /var/mail/domains/                                                           
  virtual_mailbox_base = /var/mail/domains/                                                           
                                                                                                 
  virtual_gid_maps = static:1006                                                                     
  virtual_gid_maps = static:1006                                                                     
  virtual_uid_maps = static:1006                                                                     
  virtual_uid_maps = static:1006                                                                     
  virtual_minimum_uid = 100                                                                           
  virtual_minimum_uid = 100                                                                           
  virtual_transport = virtual     
  virtual_transport = virtual     
 
                                                                                           
  # This next command means you must create a virtual
  # This next command means you must create a virtual
  # domain for the host itself - ALL mail goes through
  # domain for the host itself - ALL mail goes through
  # The virtual transport
  # The virtual transport
 
  mailbox_transport = virtual
  mailbox_transport = virtual
  local_transport = virtual                                                                     
  local_transport = virtual                                                                     
  local_transport_maps = $virtual_mailbox_maps                                                 
  local_transport_maps = $virtual_mailbox_maps                                                 
                                                                                         
 
                                                                                           
  smtpd_helo_required = yes                                                                           
  smtpd_helo_required = yes                                                                           
  disable_vrfy_command = yes                                                                         
  disable_vrfy_command = yes                                                                         
  message_size_limit = 10240000                                                                       
  message_size_limit = 10240000                                                                       
  queue_minfree = 51200000                                                                           
  queue_minfree = 51200000                                                                           
                                                                                                 
  smtpd_sender_restrictions =                                                                         
  smtpd_sender_restrictions =                                                                         
         permit_mynetworks,                                                                         
         permit_mynetworks,                                                                         
         reject_non_fqdn_sender,                                                                     
         reject_non_fqdn_sender,                                                                     
         reject_unknown_sender_domain                                                               
         reject_unknown_sender_domain                                                               
                                                                                                 
  smtpd_recipient_restrictions =                                                                     
  smtpd_recipient_restrictions =                                                                     
         reject_non_fqdn_recipient,                                                                 
         reject_non_fqdn_recipient,                                                                 
Line 236: Line 233:
         reject_rbl_client zen.spamhaus.org,                                                         
         reject_rbl_client zen.spamhaus.org,                                                         
         reject_rbl_client bl.spamcop.net                                                           
         reject_rbl_client bl.spamcop.net                                                           
                                                                                                 
  smtpd_data_restrictions = reject_unauth_pipelining     
  smtpd_data_restrictions = reject_unauth_pipelining     
 
 
  # we will use this later - This prevents cleartext authentication
  # we will use this later - This prevents cleartext authentication
  # for relaying
  # for relaying
Line 245: Line 241:




Now we need to create a *bunch* of files so that postfix can get the delivery information out of sql. Here's a shell script to create the scripts.   
Now we need to create a *bunch* of files so that postfix can get the delivery information out of sql. Here's a shell script to create the scripts.  Change PGPW to the password for the postfix user of the postfix SQL database.
 
cd /etc/postfix
mkdir sql
PGPW="ChangeMe"                                                             
                                                                                                                            cat - <<EOF >sql/pgsql_virtual_alias_domain_catchall_maps.cf
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix
query = Select goto From alias,alias_domain where alias_domain.alias_domain = '%d' and alias.address = '@' || alias_domain.target_domain and alias.active = true and alias_domain.active= true
EOF                                                                                                                                                                                                     
cat - <<EOF >sql/pgsql_virtual_alias_domain_mailbox_maps.cf                                                                                                                                             
user=postfix                                                                                                                                                                                            
password = $PGPW                                                                                                                                                                                         
hosts = localhost                                                                                                                                                                                       
dbname = postfix                                                                                                                                                                                         
query = Select maildir from mailbox,alias_domain where alias_domain.alias_domain = '%d' and mailbox.username = '%u' || '@' || alias_domain.target_domain and mailbox.active = true and alias_domain.active
EOF                                                                                                                                                                                                     
cat - <<EOF >sql/pgsql_virtual_alias_domain_maps.cf                                                                                                                                                     
user=postfix                                                                                                                                                                                             
password = $PGPW                                                                                                                                                                                         
hosts = localhost                                                                                                                                                                                       
dbname = postfix                                                                                                                                                                                         
query = select goto from alias,alias_domain where alias_domain.alias_domain='%d' and alias.address = '%u' || '@' || alias_domain.target_domain and alias.active= true and alias_domain.active= true     
EOF                                                                                                                                                                                                     
cat - <<EOF >sql/pgsql_virtual_alias_maps.cf                               
user=postfix                                                                                                                                                                                             
password = $PGPW                                                                                                                                                                                         
hosts = localhost                                                                                                                                                                                       
dbname = postfix                                                                                                                                                                                         
query = Select goto From alias Where address='%s' and active ='1'                                                                                                                                       
EOF                                                                                                                                                                                                     
cat - <<EOF >sql/pgsql_virtual_domains_maps.cf                                                                                                                                                           
user=postfix                                                                                                                                                                                             
password = $PGPW                                                                                                                                                                                         
hosts = localhost                                                                                                                                                                                       
dbname = postfix                                                                                                                                                                                         
query = Select domain from domain where domain='%s' and active='1'                                                                                                                                       
EOF                                                                                                                                                                                                     
cat - <<EOF >sql/pgsql_virtual_mailbox_limit_maps.cf                                                                                                                                                     
user=postfix                                                                                                                                                                                             
password = $PGPW                                                                                                                                                                                         
hosts = localhost                                                                                                                                                                                       
dbname = postfix 
query = Select quota from mailbox where username='%s' and active='1'                                                                                                                                     
EOF                                                                                                                                                                                                     
cat - <<EOF >sql/pgsql_virtual_mailbox_maps.cf                                                                                                                                                           
user=postfix                                                                                                                                                                                             
password = $PGPW                                                                                                                                                                                         
hosts = localhost                                                                                                                                                                                       
dbname = postfix                                                                                                                                                                                         
query = Select maildir from mailbox where username='%s' and active=true                                                                                                                                 
EOF     
 
 
 


cd /etc/postfix
mkdir sql
PGPW="ChangeMe"                                                             
                                                                                                                              cat - <<EOF >sql/pgsql_virtual_alias_domain_catchall_maps.cf
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix
query = Select goto From alias,alias_domain where alias_domain.alias_domain = '%d' and alias.address = '@' ||  alias_domain.target_domain and alias.active = true and alias_domain.active= true
EOF
cat - <<EOF >sql/pgsql_virtual_alias_domain_mailbox_maps.cf                 
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix                                                           
query = Select maildir from mailbox,alias_domain where alias_domain.alias_domain = '%d' and mailbox.username = '%u' || '@' || alias_domain.target_domain and mailbox.active = true and alias_domain.active
EOF
                                                                         
cat - <<EOF >sql/pgsql_virtual_alias_domain_maps.cf                         
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix                                                           
query = select goto from alias,alias_domain where alias_domain.alias_domain='%d' and alias.address = '%u' || '@' || alias_domain.target_domain and alias.active= true and alias_domain.active= true
EOF
cat - <<EOF >sql/pgsql_virtual_alias_maps.cf                               
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix                                                           
query = Select goto From alias Where address='%s' and active ='1'           
EOF
                                                                           
cat - <<EOF >sql/pgsql_virtual_domains_maps.cf                             
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix                                                           
query = Select domain from domain where domain='%s' and active='1'
EOF
                                                                           
cat - <<EOF >sql/pgsql_virtual_mailbox_maps.cf                             
user=postfix                                                               
password = $PGPW                                                           
hosts = localhost                                                           
dbname = postfix                                                           
query = Select maildir from mailbox where username='%s' and active=true     
EOF


chown -R postfix:postfix sql
chmod 640 sql/*




=== Spam Filtering ===
At this point you should be able to start up postfix
newaliases  # so postfix is happy...
/etc/init.d/postfix start
rc-service add postfix




Add the following line to /etc/postfix/main.cf
=== Create a domain in PostfixAdmin and test ===
#content_filter = scan:[127.0.0.1]:10025                                                     


create a domain for the local box (e.g. example.com)  Create the alias accounts


=== Relay for Authenticated Users ===
From the machine, send a test message:


sendmail -t root@example.com
subject: test
.
^d


# TLS Stuff -- since we allow SASL with tls *only*, we have to set up TLS first                   


smtpd_tls_cert_file = /etc/lighttpd/server-bundle.pem                                             
In /var/log/mail.log (or /var/log/messages, if you still have busybox syslogd running) you should see the message queuedThe message should be in /var/mail/domains/example.com/root/new
smtpd_tls_key_file = /etc/lighttpd/server-bundle.pem                                             
  smtpd_tls_CAfile = /etc/lighttpd/ca-crt.pem                                                       
smtpd_tls_security_level = may                                                                   
# Log info about the negotiated encryption levels                                                 
smtpd_tls_received_header = yes                                                                   
smtpd_tls_loglevel = 1                                                                           
                                                                                                 
                                                                                                 
# SASL - this allows senders to authenticiate themselves                                           
# This along with "premit_sasl_authenticated" in smtpd_recipient_restrictions above allows relaying
smtpd_sasl_type = dovecot                                                                         
smtpd_sasl_path = private/dovecot-auth.sock                                                       
smtpd_sasl_auth_enable = yes                                                                     
smtpd_sasl_authenticated_header = yes                                                             
smtpd_tls_auth_only = yes


== Install Dovecot ==
== Install Dovecot ==

Revision as of 01:22, 18 January 2010

A Full Service Mail Server

The goal of this document is to describe how to set up postfix, dovecot, clamav, dspam, roundecube, and postfixadmin for a full-featured "ISP" level mail server.

The server must provide:

  • multiple virtual domains
  • admins for each domain (to add/remove virtual accounts)
  • Quota support per domain / account
  • downloading email via IMAP / IMAPS / POP3 / POP3S
  • relaying email for authenticated users with TLS or SSL (Submission / SMTPS protocol)
  • Standard filters (virus/spam/rbl/etc)
  • Web mail client
  • Value Add services

Set up Lighttpd + PHP

PostfixAdmin needs php pgpsql and imap modules, so we do it in this step.

 apk add lighttpd php php-pgsql php-imap

Stop and remove mini_httpd, and move ACF to lighttpd; We are setting this up to be a mult-domain virtual web server:

 mkdir -p /var/www/domains/host.example.com
 mv  /usr/share/acf/* /var/www/domains/host.example.com

Edit /etc/lighttpd/mod_cgi.conf to serve haserl files by adding a "" => "" cgi handler

$HTTP["url"] =~ "^/cgi-bin/" {
    # disable directory listings
    dir-listing.activate = "disable"
    # only allow cgi's in this directory
    cgi.assign = (
		".pl"	=>	"/usr/bin/perl",
		".cgi"	=>	"/usr/bin/perl",
		"" => ""
	)
}

Edit /etc/lighttpd/mod_fastcgi.conf to serve php scripts

server.modules += ("mod_fastcgi")
fastcgi.server = ( ".php" => ((
                   "socket" =>  "/var/run/lighttpd/lighttpd-fastcgi-php-" + PID + ".socket"
                    "bin-path" => "/usr/bin/php-cgi"
                  ))
                 )
                  

Add these lines to /etc/lighttpd/lighttpd.conf to point to the new document root, and set it up to listen on port 443:


simple-vhost.server-root   = "/var/www/domains/"
simple-vhost.default-host  = "/"
simple-vhost.document-root = "www/
$SERVER["socket"] == "[ip_address_of_server]" {
ssl.engine    = "enable"
ssl.pemfile   = "/etc/lighttpd/server-bundle.pem"
ssl.ca-file   = "/etc/lighttpd/ca-crt.pem"
}


Get a web certificate, and install it. If you want to use a self-signed cert, you can use Generating SSL certs with ACF or Generating SSL certs with ACF 1.9. If you create a certificate with ACF, you can create the "server-bundle.pem" and the "ca-crt.pem" file with these commands:

 openssl x509 -nocerts -nokeys -cacert -in certificate.pfx  -out /etc/lighttpd/ca-crt.pem
 openssl x509 -nodes -in certifcate.pfx -out /etc/lighttpd/server-bundle.pem
 chown root:root /etc/lighttpd/server-bundle.pem
 chmod 400 /etc/lighttpd/server-bundle.pem


Note: The server certifcate and key are in the server-bundle.pem file, so it is critical that the file be read-only by user "root".


Stop and remove mini_httpd; start lighttpd, test

 /etc/init.d/mini_httpd stop
 rc-update del mini_httpd
 apk del mini_httpd
 rc-update add lighttpd
 /etc/init.d/lighttpd start

At this point you should be able to see ACF being served with lighttpd: https://host.example.com/


Install Postgresql

Add get and configure postgresql

 apk add acf-postgresql postgresql-client
 /etc/init.d/postgresql setup
 /etc/init.d/postgresql start
 rc-update add postgresql

At this point any user can connect to the sql server with "trust" mechanism. If you want to enforce password authentication (you probably do) edit /var/lib/postgresql/8.4/data/pg_hba.conf


 Editme: What should we recommend?


Create the postfix database:

 psql -U postgres
  create user postfix with password '******';
  create database postfix owner postfix;
  \c postfix
  create language plpgsql;
  \q

(Of course, use your selected password where ******* is shown above.)

Install PostfixAdmin

We are going to install the postfix admin web front-end before we install the mail server. This just creates an interface to populate the SQL tables that postfix and dovecot will use.

Download PostfixAdmin from Sourceforge. When these instructions were written, 2.3 was the current release, so:

wget http://downloads.sourceforge.net/project/postfixadmin/postfixadmin/postfixadmin_2.3.tar.gz
tar zxvf postfixadmin_2.3.tar.gz
mkdir /var/www/domains/host.example.com/postfixadmin
mv postfixadmin-2.3/* /var/www/domains/host.example.com/postfixadmin
rm -rf postfixadmin*

Edit /var/www/domains/host.example.com/postfixadmin/config.inc.php and modify at least these lines:

$CONF['configured'] = true;
$CONF['setup_password'] = ;  << Don't change this yet
$CONF['database_type'] = 'pgsql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = '*****';   << The password you chose above
$CONF['database_name'] = 'postfix';
$CONF['database_prefix'] = ;
$CONF['database_prefix'] = ;
$CONF['database_tables'] = array (
$CONF['admin_email'] = 'you@some.email.com';  << Your email address 
$CONF['encrypt'] = 'md5crypt';
$CONF['authlib_default_flavor'] = 'md5raw';
$CONF['dovecotpw'] = "/usr/sbin/dovecotpw";
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['aliases'] = '10';                       
$CONF['mailboxes'] = '10';
$CONF['maxquota'] = '10';
$CONF['quota'] = 'YES';
$CONF['quota_multiplier'] = '1024000';
$CONF['alias_control'] = 'YES';
$CONF['alias_control_admin'] = 'YES';
$CONF['special_alias_control'] = 'YES';
$CONF['fetchmail'] = 'NO';
$CONF['user_footer_link'] = "http://host.example.com";
$CONF['footer_link'] = 'http://host.example.com/postfixadmin/main.php';
$CONF['create_mailbox_subdirs_prefix']='INBOX.';
$CONF['used_quotas'] = 'YES';                     
$CONF['new_quota_table'] = 'YES';


Go to http://host.example.com/postfixadmin/setup.php

Create the password hash, add it to the config.inc.php file

Go back to http://host.example.com/postfixadmin/setup.php

Create superadmin, create a mail domain or other, as desired.


Install Postfix

Create a user for the virtual mail delivery, and get its uid/gid (you'll need the numeric uid/gid for postfix)

adduser vmail -H -D -s /bin/false
grep vmail /etc/passwd

(In examples below, we use 1006/1006 for the uid/gid)

Create the mail directory, and assign vmail as the owner

mkdir -p /var/mail/domains
chown -R vmail:vmail /var/mail/domains

Install postfix

apk add acf-postfix postfix-pgsql

Edit the /etc/postfix/main.cf file Here's an example:

myhostname=host.example.com                                                                  
mydomain=example.com                                                                         

mydestination = localhost.$mydomains, localhost                                 
mynetworks_style = subnet                                                                    
mynetworks = 127.0.0.0/8                                                                     
 
virtual_mailbox_domains = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_domains_maps.cf               
virtual_alias_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_maps.cf,                     
       proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_maps.cf,                           
       proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_catchall_maps.cf                   

virtual_mailbox_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_mailbox_maps.cf,                 
       proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_mailbox_maps.cf                    

virtual_mailbox_base = /var/mail/domains/                                                          
virtual_gid_maps = static:1006                                                                     
virtual_uid_maps = static:1006                                                                     
virtual_minimum_uid = 100                                                                          
virtual_transport = virtual     


# This next command means you must create a virtual
# domain for the host itself - ALL mail goes through
# The virtual transport

mailbox_transport = virtual
local_transport = virtual                                                                    
local_transport_maps = $virtual_mailbox_maps                                                 

smtpd_helo_required = yes                                                                          
disable_vrfy_command = yes                                                                         
message_size_limit = 10240000                                                                      
queue_minfree = 51200000                                                                           

smtpd_sender_restrictions =                                                                        
       permit_mynetworks,                                                                         
       reject_non_fqdn_sender,                                                                    
       reject_unknown_sender_domain                                                               

smtpd_recipient_restrictions =                                                                     
       reject_non_fqdn_recipient,                                                                 
       reject_unknown_recipient_domain,                                                           
       permit_mynetworks,                                                                         
       permit_sasl_authenticated,                                                                 
       reject_unauth_destination,                                                                 
       reject_rbl_client dnsbl.sorbs.net,                                                         
       reject_rbl_client zen.spamhaus.org,                                                        
       reject_rbl_client bl.spamcop.net                                                           

smtpd_data_restrictions = reject_unauth_pipelining    

# we will use this later - This prevents cleartext authentication
# for relaying
smtpd_tls_auth_only = yes 


Now we need to create a *bunch* of files so that postfix can get the delivery information out of sql. Here's a shell script to create the scripts. Change PGPW to the password for the postfix user of the postfix SQL database.

cd /etc/postfix
mkdir sql
PGPW="ChangeMe"                                                              
                                                                                                                             cat - <<EOF >sql/pgsql_virtual_alias_domain_catchall_maps.cf
user=postfix                                                                 
password = $PGPW                                                             
hosts = localhost                                                            
dbname = postfix
query = Select goto From alias,alias_domain where alias_domain.alias_domain = '%d' and alias.address = '@' ||  alias_domain.target_domain and alias.active = true and alias_domain.active= true 
EOF

cat - <<EOF >sql/pgsql_virtual_alias_domain_mailbox_maps.cf                  
user=postfix                                                                 
password = $PGPW                                                             
hosts = localhost                                                            
dbname = postfix                                                             
query = Select maildir from mailbox,alias_domain where alias_domain.alias_domain = '%d' and mailbox.username = '%u' || '@' || alias_domain.target_domain and mailbox.active = true and alias_domain.active
EOF
                                                                         
cat - <<EOF >sql/pgsql_virtual_alias_domain_maps.cf                          
user=postfix                                                                 
password = $PGPW                                                             
hosts = localhost                                                            
dbname = postfix                                                             
query = select goto from alias,alias_domain where alias_domain.alias_domain='%d' and alias.address = '%u' || '@' || alias_domain.target_domain and alias.active= true and alias_domain.active= true
EOF

cat - <<EOF >sql/pgsql_virtual_alias_maps.cf                                 
user=postfix                                                                 
password = $PGPW                                                             
hosts = localhost                                                            
dbname = postfix                                                             
query = Select goto From alias Where address='%s' and active ='1'            
EOF
                                                                           
cat - <<EOF >sql/pgsql_virtual_domains_maps.cf                               
user=postfix                                                                 
password = $PGPW                                                             
hosts = localhost                                                            
dbname = postfix                                                             
query = Select domain from domain where domain='%s' and active='1'
EOF
                                                                           
cat - <<EOF >sql/pgsql_virtual_mailbox_maps.cf                               
user=postfix                                                                 
password = $PGPW                                                             
hosts = localhost                                                            
dbname = postfix                                                             
query = Select maildir from mailbox where username='%s' and active=true      
EOF
chown -R postfix:postfix sql
chmod 640 sql/*


At this point you should be able to start up postfix

newaliases  # so postfix is happy...
/etc/init.d/postfix start
rc-service add postfix


Create a domain in PostfixAdmin and test

create a domain for the local box (e.g. example.com) Create the alias accounts

From the machine, send a test message:

sendmail -t root@example.com
subject: test
.
^d


In /var/log/mail.log (or /var/log/messages, if you still have busybox syslogd running) you should see the message queued. The message should be in /var/mail/domains/example.com/root/new

Install Dovecot