Build an email server – Roundcube and cyrus
|Send emails over a convenient webmail system without having Google’s prying eyes snooping on your communications.
Why do this?
- Access your email from anywhere.
- Keep giant corporations out of your inbox.
- Take back control of a vital service
On page 68 of Fosspicks this issue, Ben looks at Roundcube , the web-based email system that we’ve been using at Linux Voice Mansions for the last year-and-a-bit. Roundcube is a browser-based IMAP email client, and we’re going to show you how to sample its excellence. We’ll assume you already have a web server; we’re using Apache and we’ll configure a virtual domain to host webmail. First install Roundcube; it’s a PHP application, so those dependencies will also be installed. It also needs a database – we’ll use SQLite here and have included those dependencies too:
$ pacman -S apache roundcubemail sqlite php-sqlite
You can use a different database if you want; Roundcube supports MySQL/MariaDB, PostgreSQL or even MS-SQL. Choose whatever suits your requirements.
The Roundcube configuration file is in /etc/webapps/roundcubemail/config. You need to make a copy of config.inc.php.sample as config.inc.php and edit it according to your needs. Make the following changes at least:
$config[‘smtp_server’] = ‘localhost’;
$config[‘smtp_port’] = 587;
$config[‘db_dsnw’] = ‘sqlite:////var/cache/roundcubemail/sqlite.db?mode=0646’;
$config[‘enable_installer’] = true;
This configures Roundcube to use our mailserver’s submission port so that outbound mail passes through our outbound content filter. The database setup is next; we’re using SQLite so just need to point to a location that is writable by Roundcube – the database will be created automatically. The last thing we do is enable the installer; we’ll use it shortly to verify our configuration and test the installation. But first we need to configure the web server.
The Roundcube package includes an Apache configuration file that you can integrate into your Apache configuration. Copy it into place and link it into Apache’s main configuration:
$ cp /etc/webapps/roundcubemail/apache.conf /etc/httpd/conf/extra/httpd-roundcube.conf
$ echo “Include conf/extra/httpd-roundcube.conf” >> /etc/httpd/conf/httpd.conf
$ mkdir /srv/http
Restart your webserver to make the changes take effect and then point a browser at http://mailserver/roundcube/installer. The first page checks the environment to make sure everything necessary is in place. Pay particular attention to make sure your desired database driver is available. The second page enables you to edit the configuration, but you have to download and save it over the existing one; you might find it easier to just use a text editor. The final screen verifies required write access to parts of the filesystem and allows you to test the IMAP and
SMTP connections.
The last thing the installer does is remind you to disable it – you just need to remove the enable setting that we added to the configuration. Now you can point your browser at your webmail server and try it out. Log in as the test user that we created before (we used a username of “testuser” and password “testpass”).
Sieveshell for command-line users
The sieveshell tool is part of the mail server but, by copying a few files, you can provide it to command-line savvy end-users so they can manage their Sieve rules from the command line. Copy the following files from the mail server onto any other machine where you would like sieveshell to be available:
/usr/bin/sieveshell
/usr/lib/perl5/site_perl/Cyrus/SIEVE/managesieve.pm
/usr/lib/perl5/site_perl/auto/Cyrus/SIEVE/managesieve/managesieve.so
/usr/share/man/man1/sieveshell.1.gz
/usr/share/man/man3/Cyrus::SIEVE::managesieve.3pm.gz
This does, of course, require Perl and binary compatibility and it isn’t something that the Cyrus project officially supports. But it may work out for your command-line users.
Sieve it
We want to give our IMAP users some control over the delivery of their mail to enable them to forward it to someone else, file it into sub-folders or even reject it. The Sieve language enables end users to provide rules for the server to apply when delivering their mail. Rules are written using a simple language, are stored on the server and accessed via a daemon called timsieved that is part of the Cyrus IMAP server. You can use telnet to verify that you connect to it:
$ telnet mailserver sieve
You wouldn’t normally do that though, because the Cyrus server comes with sieveshell, an FTP-like command-line tool for uploading, downloading, activating, de-activating and listing Sieve scripts. To use it as the current user:
$ sieveshell mailserver
If your Linux user is different to your mail user then you’ll need to use the –user argument to supply it. sieveshell will request your IMAP password and display a prompt once it authenticates you. Enter help to see the available commands; there’s also a man page with similar information.
Sieve scripts follow a basic syntax that enables a user to forward, discard or sort messages into sub-folders within their mailbox. The message header information is used to decide which action to take. The language is backed by an internet standard (RFC 5228) and you can find information online to get you up to speed. http://bit.ly/sieve-tutorial is a good one to start with. Here is an example:
require [“fileinto”];
if address :is “From” “bob@example.com”
{
fileinto “Bob’s Ramblings”;
stop;
}
Write that into a file, say testuser.sieve and use sieveshell to upload and then activate it:
$ ./sieveshell --user testuser mailserver
Please enter your password:
> put testuser.sieve
> activate testuser.sieve
> list
testuser.sieve <- active script
> quit
The daemon performs syntax checking and won’t allow an erroneous file to be uploaded. Once it’s in place, any mail from Bob will be filed into the sub-folder (if it exists or, otherwise, into the Inbox). Note that each user can keep many scripts on the server but only one of them can be active.
For Sieve to be of any use to our users, they need to be able to manage their own rules. You could give them their own copy of sieveshell but most users would prefer to manage their rules from within their own email client.
There is a Sieve add-on for Mozilla Thunderbird, but the current release (0.2.2) doesn’t work with Thunderbird version 20 and above. You’ll need to either wait for version 0.2.3 of the plugin or install a nightly build from GitHub (see https://github.com/thsmi/sieve/tree/master/nightly). Once you have a working version, it’s easy to write Sieve scripts from within Thunderbird. You work directly on scripts stored on the server and you get immediate feedback when your scripts contain errors.
Roundcube comes with Sieve support included, but it’s in a plugin and you have to enable it. First, set up its configuration by making a copy of the supplied example
$ cp /usr/share/webapps/roundcubemail/plugins/managesieve/config.inc.php{.dist,}
and then enable it by adding managesieve to the active plugins array defined in the main configuration file, /usr/share/webapps/roundcubemail/config/config.inc.php. Once it’s enabled users will see a ‘Filters’ area on the Roundcube settings page that presents a user-friendly rule editor that doesn’t require knowledge of the Sieve language.
A server certificate
Enter the commands below. When asked for a password, use “testpass” or anything else that you wish. Of all the other questions, the important one requests a Common Name. Enter the server’s fully-qualified domain, mail.mydomain.com.
$openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -out server.pem
$openssl req -new -x509 -key server.pem -subj “/CN=$(hostname -f)” >> server.pem
$chmod 600 server.pem
This creates a private key and a self-signed certificate, both in the same server.pem file. You can specify this same file for both your private key and certificate. Although self-signed certificates work, they will annoy your users!
Batten down the hatches…
To allow our users to access their mail remotely, we want to expose our server’s IMAP and ESMTP interfaces to the internet. However, before doing this we need to implement TLS (Transport Layer Security) and mandate its use. And that requires a server certificate. We’ll assume you have one, but our boxout shows how you can quickly make one that is good enough for testing.
To configure the IMAP server to use TLS, you need your private key, certificate and, if your certificate is signed by a certificate authority, its CA certificate. Store them somewhere that is accessible to both Postfix and Cyrus. You could place them in /etc/mail. Edit /etc/cyrus/imapd.conf to tell Cyrus where to find the key and certificates. Add these definitions (if you have a self-signed certificate then you can omit the last one):
tls_key_file: /path/to/private-key
tls_cert_file: /path/to/server-certificate
tls_ca_file: /path/to/ca-certificate
You also need to configure Cyrus to listen for secure IMAP connections. You can use sed to uncomment the imaps entry (or just edit the file):
$ sed -e ‘/^#s*imapss/s/^#//’ /etc/cyrus/cyrus.conf
You can also restrict insecure IMAP connections to the local machine (Roundcube will still connect this way):
$ sed -i -e ‘s/listen=”imap”/listen=”localhost:imap”/’ /etc/cyrus/cyrus.conf
Finally, restart Cyrus to effect the changes:
$ systemctl restart cyrus-master
Configuring Postfix is similar. You need to add some configuration options to /etc/postfix/main.cf:
smtpd_tls_key_file = /path/to/private-key
smtpd_tls_cert_file = /path/to/server-certificate
smtpd_tls_CAfile = /path/to/ca-certificate
smtpd_tls_security_level = may
smtp_tls_security_level = may
There are two groups of settings that apply to the smtp client-side (for outgoing mail) and the smtpd server-side (for inbound mail). We specify the same key and server certificate that we used for Cyrus.
The may security level is what enables TLS and is one of several possible levels. It announces STARTTLS support to remote SMTP clients but doesn’t require encryption to be used because the SMTP over TLS specification requires that publicly accessible servers (those referenced by public MX DNS records) do not enforce TLS.
However, you can enforce TLS on the submission interface so that email clients must encrypt, by overriding the security level for the submission service defined in /etc/postfix/master.cf:
-o smtpd_tls_security_level=encrypt
Another security measure that you can take is to require your clients to authenticate with the server before they can send email through it. You can achieve this by configuring the submission service to use the same SASL authentication service as the IMAP service. A few changes to its configuration in
/etc/postfix/master.cf makes this happen:
-o smtpd_sasl_auth_enable=yes
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
The recipient restrictions control who can use the service to send mail. You must also add permit_sasl_authenticated into the existing smtpd_client_restrictions before the reject restriction. The client restrictions control who can connect to the service.
These changes allow clients outside of mynetworks to connect to and send email if they can authenticate, but we need to define what mynetworks is. This is a list of trusted SMTP clients – those allowed to relay (send) email. Postfix determines this automatically using the machine’s network interfaces, trusting anything on the same network. We don’t want that; we want all clients to authenticate. To achieve this we can explicitly specify in main.cf to only trust the local host.
mynetworks_style = host
Trusting the local host will allow our webmail system to send mail without going through the authentication mechanism.
There is one other thing to do, and that’s to configure the SASL library that Postfix uses. The library looks in the /usr/lib/sasl2 directory for application-specific configuration files that are named after the application. In Postfix’s case, each service has its own file – the SMTP server’s is called smtpd.conf (this is a default value that can be overriden with a Postfix configuration option, but we’ll just go with the default). Because we just want Postfix to authenticate in exactly the same way as the IMAP server, we can extract the required settings with a little bit of sed:
$ sed -n -e ‘s/^sasl_(.*)/1/p’ /etc/cyrus/imapd.conf > /usr/lib/sasl2/smtpd.conf
With the changes made, you can restart the services:
$ systemctl restart saslauthd postfix
From now on, when users send mail, they will need to connect using TLS and supply their username and password. It’s important to understand what TLS gives us. It’s Transport Layer Security; that means it protects the connection between the mail client and the mail server that is made for each message that a user sends. The server will also attempt to use TLS when relaying those messages to their destinations, but not all mail systems support it, in which case the transmission falls back into the clear.
Regardless of whether TLS was used, messages aren’t encrypted once delivered. There is nothing stopping them from being read, forwarded or altered by anyone able to access them legitimately or otherwise. We can further protect messages with content signing and encryption. When a sender signs a message, its recipients can verify that it is authentic and has not been altered. When a sender encrypts one, it is only readable by its intended recipients.
Both signing and encryption use asymmetric cryptography using public and private key-pairs and there are two implementations in common use for email: S/MIME uses X.509 certificates in a similar way to SSL websites, whereas OpenPGP implements a different key system based on webs of trust where entities known to each other sign each other’s keys. While corporate entities might prefer the S/MIME approach, the fact that it requires trusting a potentially unknown certificate authority to sign keys (in contrast to OpenPGP’s approach being decentralised) and that PGP has been around longer makes PGP the more popular choice for email.
PGP also sees other uses in the open-source world where, for example, it’s used to sign software releases. The open-source implementation is called GNU Privacy Guard, or just GnuPG. You can check if you have it installed with gpg –version and, if necessary, install it on Arch with pacman -S gnupg.
Encryption is typically a user-focussed activity: When Alice sends a secret message to Bob, she uses his public key to encrypt it and he must use his private key to decrypt it. If Alice wants to sign the message, she uses her private key and Bob can use her public key if he wants to validate its authenticity. Neither Alice nor Bob trust their mail systems’ administrators, so they keep their private keys securely on their own computers and use them with their email client.
Enigmail is an add-on for Mozilla Thunderbird that provides OpenPGP tools that use GnuPG underneath. You install it using Thunderbird’s Add-Ons facility and follow the setup wizard that it launches. You can either use an existing key or create a new one. Once it’s installed, you’ll have a new Enigmail menu option. You can try sending signed and encrypted email using Adele, the Friendly OpenPGP Email Robot: just send a message to adele-en@gnupp.de and you should receive a response showing that your test could be decrypted and/or signed. You need to attach your public key, but don’t encrypt the attachment otherwise the robot won’t work.
You can also look at supporting encryption with Roundcube, but there isn’t a complete out-of-the-box solution like Enigmail for it. You could investigate rc_openpgpjs or the Web Encryption Extension (http://senderek.ie/wee). Google is your friend here.
You can, however, use GnuPG on the server side if you want to. To demonstrate this, we’ll configure our Procmail outbound filter to sign and/or encrypt outbound messages. To achieve this, we’ll give the server its own private key for signing and use recipients’ public keys for encryption. You can generate a key on the server; it needs to be owned by the user that runs the outbound filter (in our example this is the cyrus user). Press Enter when prompted for a passphrase to create a key without one; this is more appropriate for server use.
$ gpg --gen-key
You should give the key a Real Name that is the same as the system user (‘cyrus’) so that the key can be found. Otherwise you’ll need to specify it in the following commands by appending the –local-user argument that specifies the key’s ID.
The actual encryption and signing is done by the /etc/procmail/outbound.rc filter. Add a recipe for signed encryption and, in case that fails (as will happen if the recipient’s public key is not in the key ring), another to sign it instead:
# Encrypt for recipient and sign with server’s key
:0 fbw
| cat | gpg --encrypt --armor --recipient $RECIPIENT --sign
# If unable to encrypt, just sign with server’s key
:0 fbwe
| cat | gpg --clearsign
You also need to add RECIPIENT=${recipient} to the procmail-outbound definition in /etc/postfix/master.cf and load any public keys for any recipients that you want to encrypt for.
This is a very basic server-side example to demonstrate how you could implement an outbound signing policy, but think of it as a starting for your own rules that suit your own requirements.
Where next…
There’s plenty more that you can do to continue growing your mail system. Here are some suggestions:
- Implement a SASL back-end to authenticate from LDAP, perhaps your Active Directory server implemented with Samba.
- Implement a second server to use as a backup and use Cyrus-IMAP’s replication capabilities to keep them in sync.
Apache quick start
If you haven’t got Apache and just want to get it up and running to follow along with our Roundcube setup, here’s what you need to do. Start out by installing Apache and SQLite, plus the necessary PHP modules. Then install the module into Apache’s configuration:
$ pacman -S apache sqlite php-apache php-sqlite
$ sed -i -e ‘s:^LoadModule mpm_event_module modules/mod_mpm_event.so$:LoadModule mpm_prefork_module modules/mod_mpm_prefork.so:’
-e ‘/LoadModule dir_module/a LoadModule php5_module modules/libphp5.so’ /etc/httpd/conf/httpd.conf
PHP also has a configuration file; you need to set a time zone and also load the SQLite driver:
$sed -i -e “s:;(date.timezone =)$:1 Europe/London:”
-e “s:;(extension=pdo_sqlite.so):1:” /etc/php/php.ini
$ echo “<?php phpinfo(); ?>” > /srv/http/phptest.php
We also wrote a little test page so that we can check everything is OK, but you must start Apache first, which you do with systemd:
$ systemctl enable apache
$ systemctl start apache
and then point a browser at it. You should see something like the picture.
Further information is available on the Arch Linux wiki; see https://wiki.archlinux.org/index.php/LAMP#PHP.