Postfix, Virtual Domain Setup

From Ubuntuwiki.net

Jump to: navigation, search

Contents

Basic LAMP environment

If you don't already have the basic Apache / MySQL / PHP environment set up, do that first:

# tasksel install lamp-server


Setting up Postfixadmin

The package did not make it to the Ubuntu repositories. But the "all .deb" from the project will work just fine, so download it from http://sourceforge.net/project/showfiles.php?group_id=191583&package_id=225300 and install it.

# dpkg -i postfixadmin_*_all.deb
# apt-get install -f

Postfixadmin will be installed in /usr/share/postfixadmin/, the configuration file will be in /etc/postfixadmin/config.inc.php, and a file /etc/apache2/conf.d/postfixadmin will be created and will set Alias /postfixadmin /usr/share/postfixadmin so that Postfixadmin will run from the URL /postfixadmin on your Apache server. (This can all be done manually if you do decide to install using the source tarball instead of the deb.)

Next, you need to configure Postfixadmin to match your setup (database user/pass, default domain, etc). Create the file /etc/postfixadmin/config.local.php and set the following:

<?php
//
// contents of this file override defaults in /etc/postfixadmin/config.inc.php
//

$CONF['configured'] = true;
$CONF['postfix_admin_url'] = 'http://change-this-to-your-domain.tld/postfixadmin';

$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'SecretPassword!';
$CONF['database_name'] = 'postfix';

$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';

// 'md5crypt' is compatible with vpopmail password databases and Dovecot's CRYPT-MD5 setting.
// 'md5' generates raw hexadecimal MD5-sums, compatible with Dovecot's PLAIN-MD5 setting.
// 'cleartext' does not encrypt user passwords at all, compatible with Dovecot's PLAIN setting.
//
// For new installs, only use 'cleartext' if you have users who want you to be able to tell
// them explicitly what their password is - and if you want to support that.  Otherwise 
// 'md5crypt' is probably a better idea.
//
$CONF['encrypt'] = 'md5crypt';

$CONF['admin_email'] = 'postmaster@change-this-to-your-domain.tld';

$CONF['default_aliases'] = array (
    'abuse' => 'abuse@change-this-to-your-domain.tld',
    'hostmaster' => 'hostmaster@change-this-to-your-domain.tld',
    'postmaster' => 'postmaster@change-this-to-your-domain.tld',
    'webmaster' => 'webmaster@change-this-to-your-domain.tld'
);

$CONF['vacation_domain'] = 'autoreply.change-this-to-your-domain.tld';
$CONF['user_footer_link'] = "http://change-this-to-your-domain.tld/main";
$CONF['footer_text'] = 'Return to change-this-to-your-domain.tld';
$CONF['footer_link'] = 'http://change-this-to-your-domain.tld';

You can quickly change the default domain to your own:

# replace "change-this-to-your-domain.tld" "yourdomain.com" -- /etc/postfixadmin/config.local.php

Have a look at /etc/postfixadmin/config.inc.php if you want to see the default settings you're overriding with that config.local.php you just created.

Create the database and user in mysql:

# mysql -u root -p
mysql> create database postfix;
mysql> grant all privileges on postfix.* to 'postfix'@'localhost' identified by 'SecretPassword!';
mysql> flush privileges;
mysql> quit;

Now restart apache with /etc/init.d/apache2 restart, then browse to "http://yourdomain.com/postfixadmin/setup.php" or "http://yourip/postfixadmin/setup.php". Make sure the Setup Checker says 'OK' for everything.

Then browse to http://yourdomain.com/postfixadmin/admin. You should get prompted. Login with the admin email you registered earlier in the setup page. From here you can add domains, mailboxes, etc. But Postfix won't see these yet. We need to install Postfix, and configure it.

Install Postfix with MySQL support

# apt-get install postfix-mysql libsasl2-modules-sql libsasl2-modules

Now you MUST RUN the newaliases command, to generate an /etc/aliases.db:

# newaliases

OK, before we can proceed editing main.cf, we need to know what the Postfix uid and gid are on your system. Grep /etc/passwd to find out:

# grep postfix /etc/passwd
postfix:x:105:114::/var/spool/postfix:/bin/false

So the uid is 105 on my server, and the gid is 114. Again, you need to double-check uid and gid for your server and use them in the step below.

Add the following to /etc/postfix/main.cf: (the "proxy" bits are to allow MySQL connection pooling)

virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_gid_maps = static:CHANGE_ME_TO_YOUR_POSTFIX_GID
virtual_mailbox_base = /data/postfix
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_minimum_uid = CHANGE_ME_TO_YOUR_POSTFIX_UID
virtual_transport = virtual
virtual_uid_maps = static:CHANGE_ME_TO_YOUR_POSTFIX_UID

broken_sasl_auth_clients = yes
smtpd_recipient_restrictions =
  permit_mynetworks,
  permit_sasl_authenticated,
  reject_unauth_destination,
  reject_unauth_pipelining

smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_security_options = noanonymous

WORD OF WARNING: do not set reject_non_fqdn_sender or reject_non_fqdn_recipient, as many guides will advise you to, if you don't want to have a lot of problems with Outlook clients! The FQDN checks in these settings WILL process whatever's in the HELO/EHLO string - even when you have smtpd_helo_restrictions set to empty.

Note: the syntax for the following files is based on the postfix mysql_table(5) manual as per http://www.postfix.org/mysql_table.5.html

Create the following files in /etc/postfix/:

mysql_virtual_alias_maps.cf

user = postfix
password = SecretPassword!
hosts = 127.0.0.1
dbname = postfix
table = alias
select_field = goto
where_field = address

The alternative syntax for that file is:

user = postfix
password = SecretPassword!
hosts = 127.0.0.1
dbname = postfix
query = SELECT goto FROM alias WHERE address = '%s'

The same can be applied for the rest of these files.

mysql_virtual_domains_maps.cf

user = postfix
password = SecretPassword!
hosts = 127.0.0.1
dbname = postfix
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '0' and active = '1'

mysql_virtual_mailbox_maps.cf

user = postfix
password = SecretPassword!
hosts = 127.0.0.1
dbname = postfix
table = mailbox
select_field = maildir
where_field = username

If you want to be be able to relay mail through your server with SMTP AUTH, you'll need to configure SASL. Since we need to get Dovecot's authentication against our db working anyway for IMAP, the easiest way to do this is just to go ahead and use Dovecot SASL support as well.

Dovecot installation, and SASL configuration for the Postfix SMTP server

Dovecot SASL support is available in Postfix 2.3 and later. On the Postfix side you need to specify the location of the Dovecot authentication daemon socket. We use a pathname relative to the Postfix queue directory, so that it will work whether or not the Postfix SMTP server runs chrooted.

In /etc/postfix/main.cf, add the following:

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

On the Dovecot side you also need to specify the Dovecot authentication daemon socket. In this case we specify an absolute pathname. In the example we assume that the Postfix queue is under /var/spool/postfix/.

Install Dovecot with MySQL support:

# apt-get install dovecot-common dovecot-imapd dovecot-mysql dovecot-pop3d

Configure the Dovecot/MySQL setup in /etc/dovecot/dovecot-mysql.conf using these settings:

/etc/dovecot/dovecot-mysql.conf

driver = mysql
connect = dbname=postfix user=postfix host=localhost password=SecretPassword!

# if passwords are stored in the mysql db in plaintext, use PLAIN: 
# but we used 'md5crypt' in postfixadmin, so the correct setting in 
# Dovecot-ese is MD5-CRYPT.
#
# note that this encryption setting is directly compatible with  
#  vpopmail password databases, making migration from Qmail/Vpopmail
# setups possible.
#
default_pass_scheme = MD5-CRYPT
password_query = SELECT password FROM mailbox WHERE username = '%u'

####
#### CHANGE THE UID AND GID below to match those for Postfix in your
#### system!  grep postfix /etc/passwd to find them!
####
user_query = SELECT maildir, CHANGE_ME_TO_YOUR_POSTFIX_UID AS uid, CHANGE_ME_TO_YOUR_POSTFIX_GID AS gid FROM mailbox WHERE username  = '%u'

Then configure Dovecot to use MySQL by setting these options in /etc/dovecot/local.conf (these will override settings in /etc/dovecot/dovecot.conf):

/etc/dovecot/local.conf

auth_mechanisms = digest-md5 plain login
disable_plaintext_auth = no
first_valid_uid = CHANGE_ME_TO_YOUR_POSTFIX_UID
first_valid_gid = CHANGE_ME_TO_YOUR_POSTFIX_GID

log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_access_groups = mail
mail_location = maildir:/data/postfix/%d/%n

passdb {
  args = /etc/dovecot/dovecot-mysql.conf
  driver = sql
}

protocols = imap
 service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  unix_listener /var/spool/postfix/private/dovecot-auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  user = root
}

ssl = yes
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem

userdb {
  args = /etc/dovecot/dovecot-mysql.conf
  driver = sql
}

NOTE: be sure you've enabled the LOGIN mechanism above, or Outlook clients WILL NOT authenticate properly! (Outlook doesn't bother reading the list of server capabilities; it just uses LOGIN no matter what.)


/etc/dovecot/conf.d/auth-system.conf.ext

You need to disable PAM authentication in this file; otherwise every time you authenticate, it has to fail PAM before it tries your SQL authentication as a "fallback". This, obviously, sucks rocks - in particular it'll make a webmail client like roundcube seem PAINFULLY slow.

# PAM authentication. Preferred nowadays by most systems.
# PAM is typically used with either userdb passwd or userdb static.
# REMEMBER: You'll need /etc/pam.d/dovecot file created for PAM
# authentication to actually work. <doc/wiki/PasswordDatabase.PAM.txt>
#passdb {
  # driver = pam
  # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=<n>]
  # [cache_key=<key>] [<service name>]
  #args = dovecot
#}

Just make sure this entire block is commented out, just as above. Note that dovecot configuration files and syntax tend to evolve disturbingly quickly, so if this article isn't seriously shiny new... you may need to go hunting elsewhere to find where PAM passdb is configured.

(More information about the dovecot configuration can be found in http://wiki.dovecot.org/AuthDatabase/SQL and http://wiki.dovecot.org/Variables if you need it. See Dovecot, enforcing retention policy if you want to keep users from deleting email completely.)

Now, create the directory structure, including a directory for the first domain. You'll also want to go into PostfixAdmin and create a 'test' account for yourdomain.com so you've got something to test with.

# mkdir -p /data/postfix
# chmod -R 770 /data/postfix
# chown -R postfix:postfix /data/postfix

Finally, restart Dovecot and Postfix:

# /etc/init.d/postfix restart
# /etc/init.d/dovecot restart

And you're ready to test it all out. You should be able to add new domains, mailboxes and aliases using PostfixAdmin and have it all work properly, including SMTP authentication.

Testing SMTP AUTH by telnet

Now we need to generate base64-encoded strings to use with the PLAIN and LOGIN methods.

# printf 'user@domain.com' | base64
dXNlckBkb21haW4uY29t
# printf 'password' | base64
cGFzc3dvcmQ=

Those two are for the LOGIN method. The next one is for the PLAIN method. If you're impatient to just see if something works, this will gripe you less since it's only a single copy and paste. =)

# printf '\0user@domain.com\0password' | base64
AHVzZXJAZG9tYWluLmNvbQBwYXNzd29yZA==

OK, let's telnet in:

# telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.server.local ESMTP Postfix (Ubuntu)

Great, we got a banner. OK, now let's tell it we want to use extended SMTP with the "ehlo" command:

ehlo test
250-mail.server.local
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH DIGEST-MD5 PLAIN LOGIN
250-AUTH=DIGEST-MD5 PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

Alright. Good. Notice that we support three AUTH methods: DIGEST-MD5, PLAIN, and LOGIN. Let's try PLAIN first, using the string we generated for it above:

AUTH PLAIN AHVzZXJAZG9tYWluLmNvbQBwYXNzd29yZA==
235 2.0.0 Authentication successful
quit
221 2.0.0 Bye

Excellent! If we want to try the LOGIN method, telnet back in and ehlo just as we did before, then:

AUTH LOGIN
334 VXNlcm5hbWU6
dXNlckBkb21haW4uY29t
334 UGFzc3dvcmQ6
cGFzc3dvcmQ=
235 2.0.0 Authentication successful
quit
221 2.0.0 Bye

Again, excellent. (If you were curious, the 334 and 235 SMTP messages are also Base64 encoded, and decode to "Username:" and "Password:" when run through mimencode -u.)


Installing Content Filtering with Postprox

Postprox is a minimalist (approximately 700 lines of pure C) SMTP proxy designed for use with Postfix to make content filtering easier. In this case, we're going to use Postprox to scan incoming messages with clamdscan and spamc and add scanning notices to the message headers.

First, change the "smtp" line at the top of /etc/postfix/master.cf:

smtp      inet  n       -       -       -       -       smtpd -o smtpd_proxy_filter=127.0.0.1:10025

Now, uncomment some lines to enable the "submission" port (587), require authentication on that port, but NOT enable the filtering proxy on that port (to make sure that authenticated users' mail is not filtered):

submission inet n       -       -       -       -       smtpd
#  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING

Now, add the following lines to the bottom of /etc/postfix/master.cf:

# SMTP Proxy.
#
127.0.0.1:10025 inet n n n - 20 spawn
  user=filter argv=/usr/local/sbin/postprox -v -r -c /usr/local/bin/filter.sh 127.0.0.1:10026

# After-filter SMTP server. Receive mail from the content filter
# on localhost port 10026.
#
127.0.0.1:10026 inet n  -       n       -        -      smtpd
    -o smtpd_authorized_xforward_hosts=127.0.0.0/8
    -o smtpd_client_restrictions=
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=
    -o smtpd_junk_command_limit=100000
    -o smtpd_soft_error_limit=10000
    -o smtpd_error_sleep_time=0
    -o smtpd_proxy_filter=
    -o mynetworks=127.0.0.0/8
    -o receive_override_options=no_unknown_recipient_checks

Now add a neutered user to run the script with:

# useradd filter -s /sbin/nologin

Now install postprox. (If you haven't built anything from source before on this machine, don't forget to apt-get install build-essential first.) Download the source from http://www.ivarch.com/programs/postprox.shtml, untar it, cd into it and do a basic ./configure && make && make install. Everything should go swimmingly. Doublecheck that postprox was installed into /usr/local/sbin - if it went somewhere else, either move it there or edit the references to it in Postfix's master.cf, your choice.

Finally, you need to install spamassassin and clamav, and create the filter script that we referenced in the postprox invocation in master.cf.

# apt-get install clamav clamav-daemon spamassassin spamc

To get spamd running, you'll need to edit /etc/default/spamassassin and set ENABLED=1. Once you've done that, make sure everything is running:

# /etc/init.d/spamassassin start
# /etc/init.d/clamav-freshclam start
# /etc/init.d/clamav-daemon start


/usr/local/bin/filter.sh

And finally, create your /usr/local/bin/filter.sh script to tie it all together. One is provided at Postfix, relay MX - grab a copy from that article, place it in /usr/local/bin/filter.sh, and proceed. Note that since our master.cf postprox invocation specified the -r flag, we will reject messages temporarily (451) if either spamd or clamd die!

Remember you need to make your filter.sh executable by your filter user:

# chown root:filter /usr/local/bin/filter.sh && chmod 550 /usr/local/bin/filter.sh

Whew. Now that you've got all that done, issue a postfix reload, break out your handy copy of the EICAR virus and the nearest chunk of spam, and test everything to make sure it works. Be sure to try killing off clamd and/or spamd so that you know exactly what happens when they aren't running, also. (Your server will issue a 451 message to whoever is trying to send mail, asking them to requeue and try again later. Remember, though, THE END USER DOESN'T SEE THESE! so you will probably want to automate in some way to notify you when this happens as well.)

Personal tools