Let's Go Virtual!


Home Page | Comments | Articles | Faq | Documents | Search | Archive | Tales from the Machine Room | Contribute | Login/Register

This week I had to completely reinstall and reconfigure our mail server, that is used by a number of customers with different domains. The latest incarnation of the server used LDAP to manage virtual domains, but we're having so many trouble with such setup that I decided agains it.

After a long time spent reading documentation (some hopelessy wrong or outdated), I decided to write my own, so next time at least I know who to curse.

The configuration we are using is the following:

  1. Postfix as MTA
  2. Dovecot as IMAP/POP server
  3. MySQL for backend
  4. Procmail as "delivery agent"
  5. PostfixAdmin as GUI to maintain domains and virtual users
  6. Horde as WebMail
  7. Vsftpd (this is used by Horde to create autoreply and the like)

Why all this? Well, as said, the server is used by a bunch of customers, so we want virtual domains and virtual users. I've thought about making some scripts to dump the data from a database and create the various Postfix config file automatically, but in the end I didn't liked the idea. We need a database backend for the webmail too, so why not to use one database instead of two?

And we need a web interface to maintain all the domains.

Procmail as 'delivery agent' allow me to create filters, autoreply in an easy way (no Sieve thanks).

As Webmail, Horde so far is the one that I like better. And his interface for creating filters is easy to hack if needs arise.

Of all this, the big problem is Postfix, since the standard version distributed with CentOS/RH does not support MySQL. So I had to use a third-party RPM (postfix-2.3.3-2.el5.centos.mysql_pgsql.i386.rpm).

For the rest, the software came with the OS or was downloaded from the original web sites.

My idea is to keep things clean and simple, in specific, I don't want all the maildirs for all the users dumped into one single directory. I want each "domain" to have his own separated directory in which to put all the users. So is easy to have an overview of which domain is using how much space and whose users is who.

Something like:

virtual (home dir) | +- domain.com | + user | + otheruser | +- someotherdomain.com | + user | + otheruser | ...

So I began by creating one user to handle all the virtual stuff, with his own home dir.

useradd -m -d /var/virtual virtual

I've given this user a real Shell, since I want to use this user from horde to create the .procmail scripts.

This also require a little trick in Procmail. We'll see it later.

Postfix configuration is basically done by adding the various "virtual_" directives mapping them to a mysql: map in the main.cf file. And then creating the maps of course...

virtual_minimum_uid = 1026 virtual_gid_maps = static:1026 virtual_uid_maps = static:1026 virtual_mailbox_base = /var/virtual virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf virtual_mailbox_limit = 51200000 virtual_transport = procmail

See the first 3 directives? In my case '1026' is the user (and group) id of the user 'virtual'. In your case put here the userid/groupid of the user you created.

Now add (or check) the 'restrictions' for the recipients:

smtpd_recipient_restrictions= reject_non_fqdn_recipient, reject_unknown_recipient_domain, permit_mynetworks, reject_unauth_destination

Now is a matter of telling Postfix to use procmail to deliver the mail, this is done in the master.cf file:

procmail unix - n n - - pipe -o flags=RO user=virtual argv=/usr/bin/procmail -t -m USER=${user} \ EXTENSION=${extension} NEXTHOP=${nexthop} /etc/procmailrc

(second and last lines must be one)

This calls procmail giving him some parameters like the username and the domain name (nexthop). We'll use those from procmail to deliver the mail in the right place.

Now we need to read the data from the database, this is done by creating the various "maps" we defined above in the main.cf file. The names of those "maps" is what I've decided, you can change it, as long as you also change the entry in the main.cf file.

# mysql_virtual_alias_maps # read the aliases from mysql user = postfix password = postfix hosts = 127.0.0.1 dbname = postfix query = select goto from alias where address='%s'

# mysql_virtual_mailbox_maps.cf # return the maildir (mailbox) for a user user = postfix password = postfix hosts = 127.0.0.1 dbname = postfix query = select maildir from mailbox where username='%s'

# mysql_virtual_domains_maps.cf # return the virtual domain user = postfix password = postfix hosts = 127.0.0.1 dbname = postfix query = select domain from domain where domain='%s' and active=1

In all the scripts the user, password and dbname have to match your user, password and domain name of course. Those are just examples.

Same goes if you decide to put the db on a different machine, adjust the 'hosts' parameter accordly.

Dovecot is plain simple, what we need to do is to define the "mail_location" specifying the domain and the user's name. Also, we need to specify the "first_valid_uid" and the like to allow our "virtual" user to write the data in the directories. Then we need to use the SQL backend for authentication and write a simple config file for it.

mail_location = maildir:/var/virtual/%d/%n first_valid_uid = 1026 last_valid_uid = 1026 first_valid_gid = 1026 last_valid_gid = 1026 auth default { mechanisms = plain login # SQL database # http://wiki.dovecot.org/AuthDatabase/SQL passdb sql { args = /etc/dovecot-sql.conf } userdb static { args = uid=1026 gid=1026 home=/var/virtual/ allow_all_users=y } }

Once again, 1026 is my uid/gid, you'll have to use the right one. And the 'dovecot-sql.conf' file is what I called it, you can call it as you like, as long as you're consistent with the name.

# dovecot-sql.conf # sql config file for dovecot driver = mysql connect = host=127.0.0.1 dbname=postfix user=postfix password=postfix default_pass_scheme = PLAIN password_query = SELECT username as user,password FROM mailbox where username='%u';

Procmail must deliver in the right directory. There are two way to do it, one is to call dovecot "deliver", the second one is to deliver directly.

Theoretically, the first way is a little faster for dovecot so it doesn't have to re-index all the messages to read them, but I didn't saw any appreciable difference.

For Procmail, the trick is to recall a "standard" procmail script to do the delivery and to call an (eventual) personal procmail script. This is done by postfix, in the master.cf file we have:

procmail unix - n n - - pipe -o flags=RO user=virtual argv=/usr/bin/procmail -t -m USER=${user} \ EXTENSION=${extension} NEXTHOP=${nexthop} /etc/procmailrc

Then in /etc/procmailrc we have:

DEFAULT=/var/virtual/$NEXTHOP/$USER/ INCLUDERC=/var/virtual/$NEXTHOP/$USER/.procmailrc #LOGFILE=/tmp/proclog #VERBOSE=yes

And that's it. Note the last '/' in the 'default' delivery location. That last '/' tells procmail to deliver in Maildir format. Otherwise it will use mailbox.

There isn't much to say about this. The only thing is, since I wanted each user inside the domain's directory, I had to configure it this way to generate the correct 'mailbox' locaiton in the database.

In the configuration file there are plenty of instructions.

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

For Horde there isn't much to say either. BUT if you want to use Ingo procmail's system to create the procmail, you'll have to alter a bit the code to create the procmail scripts in the right directory (at least if you want my directory structure).

In /whereisyourhorde/ingo/config/backend.php remove everything and leave only the "procmail" backend:

/* Procmail */ $backends['procmail'] = array( 'driver' => 'vfs', 'preferred' => 'localhost', 'hordeauth' => false, 'params' => array( 'hostspec' => 'localhost', 'filename' => '.procmailrc', 'username' => 'virtual', 'password' => 'secret', 'vfs_path' => '/var/virtual/%d/%u', 'vfstype' => 'ftp', 'port' => 21, ), 'script' => 'procmail', 'scriptparams' => array( 'path_style' => 'maildir', 'variables' => array( ) ), 'shares' => false );

Note the 'vfs_path' => '/var/virtual/%d/%u', in the standard Ingo configuration, the "%d" prameter does not exists. Here it is the domain (of course). To 'create' the %d parameter we need to alter /whereishorde/ingo/lib/Driver/vfs.php and to be precise, the "_connect" function. Like this:

function _connect() { /* Do variable substitution. */ if (!empty($this->_params['vfs_path'])) { $user = Ingo::getUser(); # change to handle virtual domains -dovecot style # D.B. - March 2009 $pos=strpos($user,'@'); if( $pos !== false ) { $domain=substr($user,$pos+1); } if ($_SESSION['ingo']['backend']['hordeauth'] !== 'full') { $pos = strpos($user, '@'); if ($pos !== false) { $user = substr($user, 0, $pos); } } $this->_params['vfs_path'] = str_replace( array('%u', '%U', '%d'), array($user, $this->_params['username'],$domain), $this->_params['vfs_path']); } if (!empty($this->_vfs)) { return true; } require_once 'VFS.php'; $this->_vfs = &VFS::singleton($this->_params['vfstype'], $this->_params); if (is_a($this->_vfs, 'PEAR_Error')) { $error = $this->_vfs; $this->_vfs = null; return $error; } else { return true; } } }

The changed/added parts are in bold. Not much.

Vsftpd wouldn't be strictly necessary, but it is if you want procmail scripts created by horde.

If you're really paranoid and you don't want to leave FTP open, you can restrict it to listen on 127.0.0.1 or close it down with the firewall from outside.

Create the databases for Horde and PostfixAdmin, be sure you give the right permissions to the right users with the right passwords.

If everything is right, you should be able to start all the processes and send/receive mails without too much trouble. You have to create a domain and a user of course first.

I'd really like to be able to handle the domains/users directly from horde interface and not from PostfixAdmin. Let's be frank, PostfixAdmin looks like shit if compared to Horde...


Comments are added when and more important if I have the time to review them and after removing Spam, Crap, Phishing and the like. So don't hold your breath. And if your comment doesn't appear, is probably becuase it wasn't worth it.

7 messages this document does not accept new posts
Luca Bertoncellosubject By Luca Bertoncello - posted 22/03/2009 18:19
> A me piacerebbe tanto se l'interfaccia di gestione dei domini/utenti potesse essere integrata in Horde, in modo da avere una sola applicazione di cui preoccuparsi invece che due... hummm...

Questo lo puoi fare scrivendoti un Plugin per Horde (che pero' non e' immediato e, nel tuo caso, richiederebbe praticamente la riscrittura di PostfixAdmin).
PERO'! Posso suggerirti un piccolo barbatrucco: Horde ti permette di creare un Link a pagine esterne (lo feci dal Provider dove lavoravo proprio per avere, da Horde, un pulsante per accedere alle configurazioni).
Purtroppo non ricordo esattamente la sintassi, ma la lessi e presi paro-paro dalle FAQ di Horde.
Un po' di CSS tagliati su misura per Horde e PostfixAdmin e l'utente non si accorge di niente!

Ciao

--
Luca Bertoncello


Davide Bianchi-AT- Luca Bertoncello By Davide Bianchi - posted 22/03/2009 19:17

> > A me piacerebbe tanto se l'interfaccia di gestione dei domini/utenti potesse essere integrata in Horde, in modo da avere una sola applicazione di cui preoccuparsi invece che due... hummm...
>
> Questo lo puoi fare scrivendoti un Plugin per Horde (che pero' non e' immediato e, nel tuo caso, richiederebbe praticamente la riscrittura di PostfixAdmin).

Era il senso del mio 'hummm'...

--
Davide Bianchi


lucac81webmail By lucac81 - posted 23/03/2009 09:12

Bella guida D. io ho una configurazione simile ed effettivamente di howto ce ne sono tantissimi, ma spesso incompleti o non piu validi.
Per la questione webmail e gestione utenti io sto usando con successo Roundcube[1], è ancora in beta, ma è abbastanza stabile, ed esiste una semplice patch, rcpfa[2] per integrare la gestione utente di postfixadmin, quindi vacation/forward/autoreply

[1] http://www.roundcube.net/
[2] http://nejc.skoberne.net/projects/rcpfa/

--
lucac81


Daniele-AT- lucac81 By Daniele - posted 23/03/2009 10:53

> Per la questione webmail e gestione utenti io sto usando con successo >Roundcube[1], è ancora in beta, ma è abbastanza stabile, ed esiste una semplice >-Patch, rcpfa[2] per integrare la gestione utente di postfixadmin, quindi >vacation/forward/autoreply

Peccato che roundcube sta collezionando più exploit di phpbb in un tempo relativamente molto più breve, basta vedere i log di un qualsiasi webserver (anche se non lo usa), per trovarsi 2^n (con n tendente a $cifrone) tentativi su roundcube...

--
Daniele


GianlucaProcmail By Gianluca - posted 17/12/2009 12:46

Grazie per questa tua guida.
Di recente mi sono accorto che invando una email a piu' destinatari appartenenti al dominio virtuale quest'email giungeva unicamente all'ultimo indirizzo email della lista dei destinatati (sia che essi fosseto 'to' o 'cc').
Indagando ho scoperto che il problema era legato a procmail e l'ho risolto aggiungento dalla configurazione di Postfix a riga/opzione:

procmail_destination_recipient_limit = 1

Ciao.
Gianluca

--
Gianluca


Roby By Roby - posted 23/11/2010 18:18

Ciao, ho provato a seguire questa guida e tutto sembra funzionare tranne per un dettaglio.

 

Il sistema non genera le dir fisiche nelle quali infilare le mail ed ovviamente non accetta i login.

 

Cavolo può essergli preso?

--
Roby


Davide Bianchi@ Roby By Davide Bianchi - posted 23/11/2010 19:22

Il sistema non genera le dir fisiche nelle quali infilare le mail ed ovviamente non accetta i login.

Verifica i log, quasi sicuramente e' un problema di permessi.

--
Davide Bianchi


7 messages this document does not accept new posts

Previous Next

Davide Bianchi, works as Unix/Linux administrator for an hosting provider in The Netherlands.

Do you want to contribute? read how.  
 


This site is made by me with blood, sweat and gunpowder, if you want to republish or redistribute any part of it, please drop me (or the author of the article if is not me) a mail.


This site was composed with VIM, now is composed with VIM and the (in)famous CMS FdT.

This site isn't optimized for vision with any specific browser, nor it requires special fonts or resolution.
You're free to see it as you wish.

Web Interoperability Pleadge Support This Project
Powered By Gojira