VPSLink – Ubuntu 9.4 Mail Server from Scratch

Like in so many of my other posts I have to state that I am not an expert on this subject. Then why am I posting about it at all you might be asking! Its simple, the experts usually give us just enough info to hang ourselves. Yeah thats right, they make it look simple enough that we consider trying it and then leave out just enough “obvious” info to get us into trouble. To be fair I don’t think they do it on purpose they just forget that the obvious is all but obvious to the poor newbie.

Well after that little poke I have to add that there are some prerequisites to being able to use this little recipe of mine. You need to be able to read…hehehe …sorry bad joke. You need to be able to use vi or nano at least.

This post is a simple recipe for getting the job done, it is most likely not the best way of doing it but it works. The problem with this type of recipe approach is that the “why for’s” and the “where for’s” are minimal or non existent. Any comments and/or corrections are more than welcome.

What this exercise leaves us with in the end of the day is a mail server that can handle multiple domains and email addresses. The domain and user data is stored in an postgresql database while the actual mails end up in special directory.

We will not only be able to administer the mail server from a web interface but the email account holders will be able to access their mail via a web interface. To do this we use Ubuntu 9.4, postfix, postfix-admin, dovecot, roundcube, postgresql and nginx.

Just a note, when I supply a command for the command line I will prefix it with ~#.

First things first:

  1. Install the Ubuntu 9.04 in your VPSLink instance.
  2. If your not from the states the set up your locale
  3. ~#locale-gen en_ZA.UTF-8
    ~#dpkg-reconfigure locales
  4. Its a good idea to set up a sudo user.
  5. ~#adduser --home /home/phil phil
    ~#addgroup --system admin
    ~#echo "%admin ALL=(ALL) ALL" >> /etc/sudoers && adduser phil admin
  6. Log out as root and login with your new user

Installing the mail stuff:

  1. Your gonna be editing lots of config files so unless you are a masochist and want to use vi rather install nano.
  2. ~#sudo apt-get install nano
  3. We will be using postgresql with postfix so you have to install it.
  4. ~#sudo apt-get install postgresql-8.3 -y
  5. Make sure you can log in with the users that will be created next.
  6. ~#sudo nano /etc/postgresql/8.3/main/pg_hba.conf
    local   all         all                               md5
    ~#sudo /etc/init.d/postgresql-8.3 restart
  7. Create a postfix user and db. Later on when you run the setup.php it will populate the db with the correct schema.
  8. ~#sudo -u postgres createuser -D -A -P postfix
    ~#sudo -u postgres createdb -O postfix postfix
  9. Install dovecot and postfix
  10. ~#sudo apt-get install dovecot-postfix

    Select “Internet Site” when prompted by the install to pick a configuration. Next you will be prompted for your domain name. This is a bit confusing if you are planning to run multiple domains of this instance. You can leave it as your machine name as per default or fill in a domain name as asked. Don’t ask me what the difference is because I could not see any difference and I tried it both ways.

  11. Install the stuff to make postfix and postgresql play nice.
  12. ~#sudo apt-get install postfix-pgsql
  13. We are going to be running postfix admin and roundcube interfaces on nginx and php so we need to install those.
  14. ~#sudo apt-get install nginx
    ~#sudo apt-get install php5-cgi
    ~#sudo apt-get install php5-imap
    ~#sudo apt-get install php5-pgsql
  15. To get fascgi to start on boot the following script from http://tomasz.sterna.tv/2009/04/php-fastcgi-with-nginx-on-ubuntu/ must be created and its permissions set.
  16. ~#sudo nano /etc/init.d/php-fastcgi
    PHP_CGI_NAME=`basename $PHP_CGI`
    start() {
          echo -n "Starting PHP FastCGI: "
          start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
          echo "$PHP_CGI_NAME."
    stop() {
          echo -n "Stopping PHP FastCGI: "
          killall -q -w -u $USER $PHP_CGI
          echo "$PHP_CGI_NAME."
    case "$1" in
          echo "Usage: php-fastcgi {start|stop|restart}"
          exit 1
    exit $RETVAL
    ~#sudo chmod +x /etc/init.d/php-fastcgi
    ~#sudo /etc/init.d/php-fastcgi start
    ~#sudo update-rc.d php-fastcgi defaults
  17. Get postfix-admin.
  18. ~#sudo wget http://sourceforge.net/projects/postfixadmin/files/postfixadmin/postfixadmin_2.3.tar.gz
    ~#sudo tar -zxvf postfixadmin_2.3.tar.gz
    ~#sudo mv postfixadmin-2.3 /var/www/nginx-default/postfixadmin
  19. Update the postfixadmin configuration file with your settings.
  20. ~#sudo nano /var/www/nginx-default/postfixadmin/config.inc.php 

    Change the following settings to:

    $CONF['configured'] = true;
    $CONF['postfix_admin_url'] = $_SERVER['HTTP_HOST'].'/postfixadmin';
    $CONF['database_type'] = 'pgsql';
    $CONF['database_password'] = 'that_password_u_used';

    Update the following variables to what makes sense for your installation

  21. Update nginx to know about postfix-admin by adding the following entry and restarting nginx.
  22. ~#sudo nano /etc/nginx/sites-available/default
    server {
    	listen  80;
            server_name  mydomainthingy.com;
            location / {
                root   /var/www/nginx-default/postfixadmin;
                index  index.php index.html index.htm;
          # pass the PHP scripts to FastCGI server listening on
            location ~ \.php$ {
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  /var/www/nginx-default/postfixadmin/$fastcgi_script_name;
                include        fastcgi_params;
            location ~ /\.ht {
                deny  all;
    ~#sudo /etc/init.d/nginx restart
  23. Switch off magic quotes by editing the php.ini file and then restart php.
  24. ~#sudo nano /etc/php5/cgi/php.ini
    magic_quotes_gpc = Off
    ~#sudo /etc/init.d/php-fastcgi restart
  25. Create a password for the using the setup.php page and save it in the config file.
  26. Browse to http://yourserverip/setup.php and at the bottom of the page enter a “Setup password”. Update config.inc.php with the supplied hash.

    ~#sudo nano /var/www/nginx-default/postfixadmin/config.inc.php
    $CONF['setup_password'] = 'hash_goes_here';
  27. On the http://yourserverip/setup.php page you can now create a admin user using the setup password from then previous step.
  28. We need to create 4 files for postfix containing SQL queries that will give postfix the information it needs.
  29. ~#sudo nano /etc/postfix/my_alias_maps.cf
    user = postfix
    password = yourdbpasswd
    hosts = localhost
    dbname = postfix
    query = SELECT goto FROM alias WHERE address = '%s' AND active = true
    ~#sudo nano /etc/postfix/my_domains_maps.cf
    user = postfix
    password = yourdbpasswd
    hosts = localhost
    dbname = postfix
    query = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = false AND active = true
    ~#sudo nano /etc/postfix/my_mailbox_limits.cf
    user = postfix
    password = yourdbpasswd
    hosts = localhost
    dbname = postfix
    query = SELECT quota FROM mailbox WHERE username = '%s' AND active = true
    ~#sudo nano /etc/postfix/my_mailbox_maps.cf
    user = postfix
    password = yourdbpasswd
    hosts = localhost
    dbname = postfix
    query = SELECT domain || '/' || maildir FROM mailbox WHERE username = '%s' AND active = true
  30. Now we have to update postfix’s main.cf to add the paths to the new files as well as some other updates.
  31. sudo nano /etc/postfix/main.cf

    Add the following to the end of the file.

    virtual_minimum_uid = 150
    virtual_uid_maps = static:150
    virtual_gid_maps = static:8
    virtual_mailbox_base = /var/vmail
    virtual_transport = dovecot
    dovecot_destination_recipient_limit = 1
    virtual_alias_maps = proxy:pgsql:/etc/postfix/my_alias_maps.cf
    virtual_mailbox_limit = proxy:pgsql:/etc/postfix/my_mailbox_limits.cf
    virtual_mailbox_domains = proxy:pgsql:/etc/postfix/my_domains_maps.cf
    virtual_mailbox_maps = proxy:pgsql:/etc/postfix/my_mailbox_maps.cf

    Comment out:

    #home_mailbox = Maildir/
    #mailbox_command = /usr/lib/dovecot/deliver -c /etc/dovecot/dovecot-postfix.conf -n -m "${EXTENSION}"

    Remove mydomainthingy.com from mydestination. (It can’t be in mydestination and virtual_mailbox_domains)

  32. Add the following to the end of the master.cf file under interfaces
  33. ~#sudo nano /etc/postfix/master.cf
    dovecot unix - n n - - pipe flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/deliver -c /etc/dovecot/dovecot-postfix.conf -f ${sender} -d $(recipient)
  34. Create a group called mail, user called vmail and the vmail directory that will hold the mail.
  35. ~#sudo useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin vmail
    ~#sudo mkdir /var/vmail
    ~#sudo chmod 770 /var/vmail
    ~#sudo chown vmail:mail /var/vmail/
  36. Some changes to the dovecot configuration to accept the mail and deliver it using the data in postgresql database.
  37. Set the following as indicated. Where the option is commented out with a # remeber to uncomment it.

    ~#sudo nano /etc/dovecot/dovecot-sql.conf
    driver = pgsql
    connect = host=localhost dbname=postfix user=postfix password=postfix
    default_pass_scheme = MD5-CRYPT
    user_query = SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, 150 AS uid, 8 AS gid, 'dirsize:storage=' ||  quota AS quota FROM mailbox WHERE username = '%u' AND active = true
    password_query = SELECT username as user, password, '/var/vmail/%d/%n' as userdb_home, 'maildir:/var/vmail/%d/%n' as userdb_mail, 150 as userdb_uid, 8 as userdb_gid FROM mailbox WHERE username = '%u' AND active = true
    ~#sudo nano /etc/dovecot/dovecot-postfix.conf
    mail_location = maildir:/var/vmail/%d/%n
    first_valid_uid = 150
    last_valid_uid = 150
    passdb sql {
    args = /etc/dovecot/dovecot-sql.conf
    userdb sql {
    args = /etc/dovecot/dovecot-sql.conf
    master {
    path = /var/run/dovecot/auth-master
    mode = 0660
    user = vmail
    group = mail
  38. Restart both services so changes take effect.
  39. ~#sudo /etc/init.d/postfix restart
    ~#sudo /etc/init.d/dovecot restart
  40. Don’t forget to supply the ssl certificate. If you don’t have any you can create one with openssl.
  41. ~#openssl genrsa -out server.key 1024
    ~#openssl req -new -x509 -key server.key -out server.pem -days 1826
    ~#sudo mv server.key /etc/ssl/private/ssl-mail.key
    ~#sudo mv server.pem /etc/ssl/certs/ssl-mail.pem

Roundcube web client install

  1. Get rouncube.
  2. ~#sudo wget http://downloads.sourceforge.net/project/roundcubemail/roundcubemail/0.3.1/~#roundcubemail-0.3.1.tar.gz
    ~#sudo tar -xvzf roundcubemail-0.3.1.tar.gz --directory=/var/www/nginx-default/
    ~#sudo mv /var/www/nginx-default/roundcubemail-0.3.1 /var/www/nginx-default/roundcubemail
    ~#cd /var/www/nginx-default/roundcubemail/
    ~#sudo chown -R www-data:www-data temp logs
    ~#cd ~
  3. Create rounbcube db and user.
  4. ~#sudo -u postgres createuser -D -A -P roundcube
    ~#sudo -u postgres createdb -O roundcube -E UNICODE roundcube
    ~#sudo -u postgres psql roundcube
    roundcube-# \i /var/www/nginx-default/roundcubemail/SQL/postgres.initial.sql
    roundcube-# grant select on session to public;
    roundcube-# \quit
  5. Configure roundcube.
    ~#sudo mv /var/www/nginx-default/roundcubemail/config/db.inc.php.dist  /var/www/nginx-default/roundcubemail/config/db.inc.php
    ~#sudo mv /var/www/nginx-default/roundcubemail/config/main.inc.php.dist  /var/www/nginx-default/roundcubemail/config/main.inc.php
    ~#sudo nano /var/www/nginx-default/roundcubemail/config/db.inc.php
    $rcmail_config['db_dsnw'] = 'pgsql://roundcube:pass@localhost/roundcube';
    ~#sudo nano  /var/www/nginx-default/roundcubemail/config/main.inc.php
  7. Let nginx know about roundcube.
  8. ~#sudo nano /etc/nginx/sites-enabled/default
        server {
    	    listen          80;
    	    server_name     mail.mydomainthingy.com;
    	    location / {
    		    index index.php index.html;
    		    root  /var/www/nginx-default/roundcubemail;
    	    location ~ \.php$ {
    		    fastcgi_index   index.php;
    		    fastcgi_param     SCRIPT_FILENAME     /var/www/nginx-default/roundcubemail$fastcgi_script_name;
    		    include      fastcgi_params;

Tags: , , , , , , , ,

2 Responses to “VPSLink – Ubuntu 9.4 Mail Server from Scratch”

  1. Kelvin Nicholson Says:

    You have an error that could throw some off, and I have a suggestion:

    1) This SQL query in my_mailbox_maps.cf:

    query = SELECT domain || ‘/’ || maildir) FROM mailbox WHERE username = ‘%s’ AND active = true

    2) The pgsql line in db.inc.php (but I think you fixed it since yesterday?)

    3) In main.inc.php you can edit the following line to get ride of the ‘server’ box upon login:

    $rcmail_config[‘default_host’] = ‘tls://’;

    Thanks for the write-up!

  2. zaries Says:

    Hi Kelvin

    Don’t you need the server box for multiple domains?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: