How I setup smida.it server

August 2013 - A boring and outdated list of steps I followed in to setup the smida.it server


In this HowTo I would like to collect all the series of operations I did to bring up the Smida.it server.

Here you can go through all the single commands and steps that I followed to have a fully functional server, from the domain and server purchase to the mail server set up.

Table of contents


Next: Users and accounts, Previous: Top, [Index]

1 Introduction

Recently (August 2013, why always on August?), due to a bike accident, I broke my left wrist, so that I had to stay for a long period at home. As a software engineer, my efficiency drops drastically with only one hand, so that, with a cast on my left hand and the keyboard on my right hand, I decided to spend my time for doing some easy work, the kind of work that gets always postponed because there is never time to actually do it.

One of the work I always wanted to do was setting up a personal server with many services I may need for my personal life, store files, communicate with people, share ideas and experience. With this excuse I could also learn how to do better things that I never had (and probably I will never have) the opportunity to learn, like writing web code (HTML, CSS, PHP), administrating a server, managing a database.

The service I decided to use was offered by OVH.DE.

In past I had some bad experiences with virtual servers, due to slowness and bandwidth limitation, so that this time I preferred having a physical one. The hardware I chose is the so called KS 4G:

not a supercomputer, but enough for my needs.

As to start, from my new machine I wanted the following services:

Considering that I am very far from being a system administrator rather than a web developer, I wouldn't exclude that on all the steps I followed I could have made some mistakes, I'm open to receive from the possible reader of this howto advices for improvements.


Next: SSH server, Previous: Introduction, [Index]

2 Users and accounts

After a couple of days I requested the server, I got an e-mail with a public IP (94.23.22.176) and a root password. Time to connect and start.

The first connection goes through ssh:

# ssh root@94.23.22.176

and as a first thing it's always good to change the predefined root password.

The root password should be secure enough to avoid brutal forcing. The following command is a way generate 16 characters random passwords which are a mixture of low and capital letters and numbers:

$ tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs

I can now set the new generated password as a root password:

# passwd

A lower privileged user is a must to have on every Linux based system, so that let's create, for example, the user 'andi' in the group 'andi'.

Create first the group:

# groupadd andi

and then the user that belongs to the newly created group:

# useradd -d /home/andi -g andi -m -k /etc/skel/ -s /bin/bash andi

At the same way as we did with the root user, let's assign a random password to the user 'andi':

# passwd andi

Although 'andi' is a lower privileged user, it's always good to set an equally secure password, because, as we will see, 'andi' will be the first entry point to this server.


Next: DNS record, Previous: Users and accounts, [Index]

3 SSH server

I consider ssh to be a very secure and reliable service, nevertheless, some peculiarities more, wouldn't harm.

Let's edit the ssh configuration file

# vim /etc/ssh/sshd_config

ssh is a protocol that moves on TCP/IP through the port 22. Moving the default port number to a non default one makes port scanning programs to not find immediately the service they are looking for. Let's set for example 76543 to be the default port:

Port 76543

Assuming that password brutal forcing can work, I prefer to deny the possibility to login as root user

PermitRootLogin no

I would also prefer only some specific users to be allowed to login via ssh, in my case only the user 'andi'

AllowUsers andi

Next: DNS records, Previous: SSH server, [Index]

3.1 SSH keys

Password login is always the weakest point for a secure connection. ssh gives the possibility to use keys instead. For doing this you need to generate and upload your key on the server.

In case you don't have one, with the following command you generate an ssh key

$ ssh-keygen

The new key will be stored under /home/<user>/.ssh/id_rsa. To upload the key on the server, copy the the public side of the key in the file .ssh/id_rsa.pub using scp.

$ scp ~/.ssh/id_rsa.pub andi@94.23.22.176:/home/andi

On the server side let's create the directory .ssh first in the home directory, since the server is new and doesn't have anything configured yet.

$ cd
$ mkdir ~/.ssh
	

Applying the new key is a matter of copy paste on a file called authorized_keys under .ssh

$ cat id_rsa.pub > .ssh/authorized_keys

To upload other keys, for example to bee able to access from more than one PC, either I use the same key for all my PCs or I can enqueue on authorized_keys as many keys as my computers. Next time I would use '>>' instead of '>':

$ cat id_rsa-2.pub >> .ssh/authorized_keys

Then I delete the id_rsa.pub file from my home directory on the server:

$ rm id_rsa.pub

If all this sounds complicated or long, ssh provides a shortcut to all these laborious operations, just hit from your PC:

$ ssh-copy-id andi@94.23.22.176

and all what we did before will be automatically done.

At this point I can set ssh daemon to deny all the accesses through username and password and use only authentication via ssh key. On the sshd_config file I set:

PasswordAuthentication no

Let's restart ssh daemon:

# /etc/init.d/ssh restart

From now on, on every connection to the server should not ask anymore for the password, bu ssh should pull me directly on the server, while it will deny all the accesses to every kind of connection attempts on other computers and to all the users other than 'andi'.

If I get the following error while restarting ssh:

[....] Restarting OpenBSD Secure Shell server: sshdCould not load host key: /etc/ssh/ssh_host_ecdsa_key

it's because the latest versions of ssh expect also a key authentication from the sever side, apparently to avoid cases of DNS spoofing.

To mute this error, just create a key on the server side:

ssh-keygen -t ecdsa -b 521 -C "$(whoami)@$(hostname)-$(date -I)" -f /etc/ssh/ssh_host_ecdsa_key

Next: Git server, Previous: SSH server, [Index]

4 DNS record

Smida.it is an old domain I bought time ago from aruba.it which was quite disappointing as a service. I decided to keep it and transfer it to ovh.

OVH.DE gives the possibility to modify the DNS entry related to your domain manually directly from the control manager in your personal page. If you, then, are familiar with BIND9 , the configuration file will look familiar and it will not be hard to configure.

Of course, please keep in mind, that the Bind9 configuration file we are going to personalize, is not on our server but on a different machine that works specifically as a DNS server (in ovh is dns200.anycast.me and ns200.anycast.me).

The file we are going to change on those servers is loaded somewhere by bind9 and in some named.conf files there should be an entry like this:

zone "smida.it" {
	type master;
	file "/etc/bind/db.smida.it";
};
	

where db.smida.it should indeed be our file. I guess that the inverted translation file is automatically generated by some tools.

First of all let's set the association between IP address and smida.it domain:

IN A		94.23.22.176
	

This tells to the DNS server that the IPv4 (A) address 94.23.22.176 has to be associated to the logical domain name of 'smida.it'.


Next: DNS record, Previous: Mail and MX record, [Index]

4.1 Subdomains

Let's list what exactly I want to have from my new server, and whitch subdomains I need:

I want all the addresses I listed to point to my smida.it machine. For doing this BIND9 gives the possibility to create aliases and I'm going to create an alias for each subdomain I want.

The alias section of the bind db file, will look something like:

andi		IN CNAME	smida.it.
blog		IN CNAME	smida.it.
git		IN CNAME	smida.it.
lists		IN CNAME	smida.it.
mail		IN CNAME	smida.it.
webmail		IN CNAME	smida.it.
www		IN CNAME	smida.it.
	

I intentionally omitted the mail services. Let's have a look to them in the following section.


Next: Git server, Previous: Subdomains, [Index]

4.2 Mail and MX record

The MX record is that record that a DNS server looks for when it has to translate the domain for e-mails. If we omit to set this record, our e-mails wouldn't be translated by any DNS and therefore rejected.

Here is how the MX record looks like in BIND9:

IN MX		10 imap.smida.it.
imap		IN A 94.23.22.176
	

The number '10' is a priority number in case we have more than one mail server, it's not my case, so that it doesn't really matter what its value is.

At the end I set the smtp subdomain as an alias of imap.

smtp		IN CNAME	imap.smida.it.
	

Before considering my DNS configuration file ready to go, I also want to set the SPF (Sender Policy Framework) record, so that my email won't be considered as spam by mail servers:

600 	IN TXT		"v=spf1 include:smida.it ~all"
	

And finally my DNS configuration file will look like:

$TTL 86400
@	IN SOA dns200.anycast.me. andi.smida.it. (2013082501 86400 3600 3600000 300)
IN NS		dns200.anycast.me.
IN NS		ns200.anycast.me.
IN MX		10 imap.smida.it.

IN A		94.23.22.176
imap		IN A		94.23.22.176

600 		IN TXT		"v=spf1 include:smida.it ~all"

andi		IN CNAME	smida.it.
blog		IN CNAME	smida.it.
git		IN CNAME	smida.it.
lists		IN CNAME	smida.it.
mail		IN CNAME	smida.it.
smtp		IN CNAME	imap.smida.it.
webmail		IN CNAME	smida.it.
www		IN CNAME	smida.it.
	

For the other parameters, refer to the BIND 9 Administrator Reference Manual


Next: Web server: Apache, Previous: DNS record, [Index]

5 Git server

I am a big fan of git and I cosider it one of the most important features my server should have. Let's start by installing it.

# apt-get install git
	

As first I create a 'git' user and group. The new user has to handle all the git repositories and they have be shared within all the other users.

# groupadd git
# useradd -d /home/git -g git -m -k /etc/skel/ -s /bin/bash git
# passwd git
	

Let's assign a secure password to 'git' as we did for 'andi' and 'root':

$ tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs
	

Since the git user is a kind of "shared user", I pretend other users belonging to the same group to be able to freely access and modify files and directories created by 'git'. For doing this I add in the git's .bashrc the following:

# vim ~git/.bashrc

umask 002
	

So that every file created by 'git' will have permission '664' while directories '775'. In this way all the users in the group 'git' are able to modify git's files.

I add, then, 'andi' to the group 'git'

# usermod -a -G git andi
	

Now it's time to create a directory 'git' in '/' that will conatain all my repositories:

# cd /
# mkdir git
	

This directory has to belong to 'git':

# chown git:git git
	

Now we can start populating our repositories:

# su git
$ git clone --mirror git://git.etezian.org/ktest.git
	

The '--mirror' options generate a new repostory and adds all the git objects in it. Ktest is a software that I started long time ago for Linux Kernel testing but never had time to proceed any further.

It's now time to test our git server. Git is able to work over ssh and indeed this will be the tunnel that git will estabilish to clone the repository. As descriped previously , on the host machine which ssh public key I uploaded on the server and as user 'andi', I run:

$ git clone ssh://andi@smida.it:76543/git/ktest.git
	

In case I want to allow other users to be able to clone and push, I just need to add their ssh keys as described here and enable them in /etc/ssh/sshd_config:

$ cat id_rsa.pub >> ~git/.ssh/authorized_keys
	

Next: Web git, Previous: Git server, [Index]

5.1 Git daemon

Of course, I don't want to add on my ssh list everyone who wants to get my git repositories. For this, git has a server application that enables a git protocol that doesn't need any autentication in reading.

This application is called git-daemon and in order to start it, just hit:

# git daemon --base-path=/git/ --reuseaddr --user=git --group=git /git/
	

I want this sevice to start already at the PC boot, so that I need to enable it on the debian init system.

I will create an script that starts my daemon and put it in the Debian init directoriea. Debian gives ready in /etc/init.d a script skeleton for handling daemons, it needs just to be modified and adapted:

# cd /etc/init.d
# cp skeleton git-daemon
# vim git-daemon
	

This is what I got at the end:

#! /bin/sh

set -e

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="a really simple server for Git repositories"
NAME=git-daemon
PIDFILE=/var/run/git.pid
DAEMON=/usr/bin/git
DAEMON_ARGS="daemon --base-path=/git/ --reuseaddr --pid-file=$PIDFILE --user=git --group=git /git/"
SCRIPTNAME=/etc/init.d/git-daemon

[ -x "$DAEMON" ] || exit 0

. /lib/init/vars.sh

. /lib/lsb/init-functions

do_start()
{
        start-stop-daemon --start -b --quiet --pidfile $PIDFILE --exec $DAEMON --test >gt; /dev/null \
                || return 1
        start-stop-daemon --start -b --quiet --pidfile $PIDFILE --exec $DAEMON -- \
                $DAEMON_ARGS \
                || return 2
}

do_stop()
{
        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
        RETVAL="$?"

        [ "$RETVAL" = 2 ] && return 2

        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON

        [ "$?" = 2 ] && return 2

        rm -f $PIDFILE
        return "$RETVAL"
}

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
  restart)
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
        exit 3
        ;;
esac
	

Let's give to the new file executable permissions:

# chmod a+x git-daemon
	

I also need it to execute the script during boot everytime I have to restart the server:

# cd /etc/rc2.d
# ln -s ../init.d/git-daemon S06git-daemon
# cd /etc/rc3.d
# ln -s ../init.d/git-daemon S06git-daemon
# cd /etc/rc4.d
# ln -s ../init.d/git-daemon S06git-daemon
# cd /etc/rc5.d
# ln -s ../init.d/git-daemon S06git-daemon
	

In order to keep things clean, at the same way I would like to stop the script correctly when shutting down the server:

# cd /etc/rc0.d
# ln -s ../init.d/git-daemon K01git-daemon
# cd /etc/rc6.d
# ln -s ../init.d/git-daemon K01git-daemon
	

How I set the script, git daemon exposes all the repositories under the '/git' directory, but first it checks on each of them for the existence of an empty file called 'git-daemon-export-ok', so that I need to create it on the repositories I want to expose:

# su git
$ cd /git/ktest.git
$ touch git-daemon-export-ok
	

Now I'm ready to start the server:

# /etc/init.d/git-daemon start
	

Let's make a test on a PC and, if everything is done properly, it should work

$ git clone git://git.smida.it/ktest.git
	

Next: Web server: Apache, Previous: Git daemon, [Index]

5.2 Web git

I could now think to install a web front end for for my repositories and in the git book I found some good tips. I decided anyway to not follow any of those advices but to take as example the Linux Kernel way and using cgit . But for doing this I first need to set up a web server which we will se in the next chapter.

Chapter 7 of this howto goes through the cgit configuration.


Next: Web git, Previous: Git server, [Index]

6 Web server: Apache

Apache HTTP server will give me the opportunity to publish my personal web pages (the ones you are reading) and my blog. Let's start by installing it:

# apt-get install apache2
# apt-get install libapache2-mod-php5
	

PHP will be useful for the blog.

I create a new configuration file for smida.it:

# vim /etc/apache2/sites-available/smida.it
	
<VirtualHost *:80>
        ServerAdmin andi@smida.it
        ServerName git.smida.it

        DirectoryIndex cgit.cgi

        Alias /cgit.png /var/www/cgit/cgit.png
        Alias /cgit.css /var/www/cgit/cgit.css
        Alias /cgit/ /var/www/cgit/cgit.cgi/

        DocumentRoot /var/www/cgit/
        <Directory />
                AllowOverride None
                Options FollowSymlinks ExecCGI
                Order allow,deny
                Allow from all

                <Files cgit.cgi>
                        SetHandler cgi-script
                </Files>
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
	

I enable the new site:

# a2ensite smida.it
	

and populate the directory /var/www/smida.it with the xhtml files. Then I can restart apache

# /etc/init.d/apache2 restart
	

That's it!


Next: Smida.it on git, Previous: Web server: Apache, [Index]

6.1 Userdir

Userdir is an Apache mode that allows to access to the files in ~/public_html via web, following the link http://<site_url>/~<user_name>.

I want to have this feature for the user 'andi', so that first I login as 'andi' and I create the directory 'public_html':

$ mkdir ~/public_html
	

As 'root' I enable the new apache mode:

# a2enmod userdir
	

and restart Apache:

# /etc/init.d/apache2 restart
	

Now by writing in my browser

http://www.smida.it/~andi
	

I will see in a file system structure the content of the directory ~/public_html.

On Apache I can set a redirect to the public_html if someone tries to access through http://andi.smida.it.

I creat and edit the Apache file 'andi.smida.it':

# vim /etc/apache2/sites-available/andi.smida.it
	
<VirtualHost *:80>
	ServerAdmin andi@smida.it
	ServerName andi.smida.it

	DocumentRoot /home/andi/public_html
	Redirect / http://www.smida.it/~andi
</VirtualHost>
	

enable it:

# a2ensite andi.smida.it
	

and restart Apache:

# /etc/init.d/apache2 restart
	

Next: Web git: cgit, Previous: Userdir, [Index]

6.2 Smida.it on git

As I said earlier, I am a big fan of git, therefore I would also like to maintain my web pages with git.

Log in first as 'git' user:

# su git
	

and create the repository directory:

$ cd /git
$ mkdir smida.it.git
	

In the end initalize a bare git repository:

$ cd smida.it.git
$ git --bare init
	

On the host side I go on the directory that contains all the web files:

$ cd /.../smida.it
	

and initialize a new git repository:

$ git init
	

I add the remote corresponding to the smida server:

$ git remote add origin ssh://andi@smida.it:76543/git/smida.it.git
$ git fetch origin
	

and I make the first commit:

$ git add .
$ git commit -s
$ git push origin master
	

If you are not familiar with git, I suggest to fix this as soon as possible, starting reading the Git book .

I have now all the contents of my web pages on the git server, I need, now, to update them on /var/www/smida.it. First I clone the repository locally on the server, for example in the /root directory:

$ su
# cd
# git clone /git/smida.it
	

I update, then what is on /var/www/smida.it:

# cd ..
# rsync -av smida.it/ /var/www/smida.it/ --exclude=.git*
	

Everytime that I push something new to smida.it from my personal PC, I have to update the web content more or less as follows:

# cd /root/smida.it
# git pull
# cd ..
# rsync -av smida.it/ /var/www/smida.it/ --exclude=.git*
	

Next: Mail server, Previous: Web server: Apache, [Index]

7 Web git: cgit

For this section of the howto, Max's post on his blog was useful.

There are many web interfaces for git, but the one I like more is cgit . Cgit is developed in C, has the most modern UI and is the one used by the Kernel community . Today (August 2013) the latest version is 0.9.2.

For compiling and installing cgit, we need some preliminary packages:

# apt-get install gcc make libssl-dev curl
	

Purists administrators can say that a server shouldn't have building capabilities because it's just a server and should work only as such; but in principle is my personal server and I'm not a purist :)

I get the latest version:

$ wget http://git.zx2c4.com/cgit/snapshot/cgit-0.9.2.tar.xz
	

I untar it:

$ tar -xf cgit-0.9.2.tar.xz
	

build it:

$ cd cgit-0.9.2
$ make
	

and, as root user, install it:

# make install
	

By default the web part of cgit is installed under /var/www/htdocs/cgit, there's nothing wrong on that, but I want it to be under /var/www/cgit:

# mv /var/www/htdocs/cgit /var/www/
# rmdir /var/www/htdocs/
	

Now let's tell Apache about the new web pages by creating a new apache configuration file:

# vim /etc/apache2/sites-available/git.smida.it
	
<VirtualHost *:80>
	ServerAdmin andi@smida.it
	ServerName git.smida.it

	DirectoryIndex cgit.cgi

	Alias /cgit.png /var/www/cgit/cgit.png
	Alias /cgit.css /var/www/cgit/cgit.css
	Alias /cgit/ /var/www/cgit/cgit.cgi/

	DocumentRoot /var/www/cgit/
	<Directory />
		AllowOverride None
		Options FollowSymlinks ExecCGI
		Order allow,deny
		Allow from all

		<Files cgit.cgi>
			SetHandler cgi-script
		</Files>
	</Directory>

	ErrorLog ${APACHE_LOG_DIR}/error.log

	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn

	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
	

Save, enable and then, as usual, let's restart Apache:

# a2ensite git.smida.it
# /etc/init.d/apache2 restart
	

Now my git web page is ready and reachable by typing on a browser: http://git.smida.it. In a first place you wouldn't see anything, just a blank page with some junk on it because we haven't still personalized cgit.

Cgit has a configuration file that allows to customize the frontend and the behavior, mine looks like this:

# vim /etc/cgitrc
	
# Enable caching of up to
1000 output entriess
cache-size=1000

# Specify some default clone prefixes
clone-prefix=git://git.smida.it

# Specify the css url
css=/cgit.css

# Specify the logo url
logo=/cgit.png

favicon=/cgit.png

# Show extra links for each repository on the index page
enable-index-links=1

# Show number of affected files per commit on the log pages
enable-log-filecount=1

# Show number of added/removed lines per commit on the log pages
enable-log-linecount=1

# Set the title and heading of the repository index page
root-title=Smida.it git repositories
root-desc=All repositories

# Allow download of tar.gz, tar.bz2 and zip-files
snapshots=tar.gz

source-filter=/usr/lib/cgit/filters/syntax-highlighting.sh

remove-suffix=1

##
## List of common mimetypes
##
mimetype.git=image/git
mimetype.html=text/html
mimetype.jpg=image/jpeg
mimetype.jpeg=image/jpeg
mimetype.pdf=application/pdf
mimetype.png=image/png
mimetype.svg=image/svg+xml
	

At the bottom of the gitrc file, we can list our git repositories we want to expose to the world, in my case I want to expose my awful ktest, so that I add:

# List of repositories
repo.url=ktest.git
repo.path=/git/ktest.git
repo.desc=Kernel testing suite
repo.owner=Andi Shyti
	

Next: Mail server, Previous: Web git: cgit, [Index]

7.1 robots.txt

Periodically search engines unleash their bots (or robots) to index all the web pages. What they do is to poll every single web page and go though all the possible links. There's nothing wrong with that because we all want our websites to be reached by search engines. But git pages, usually, don't contain something that people may search and mostly the web pages may get huge and full of links where every link means a git operation (if for example it goes through the git history). Moreover robots work in multithreading, so that they start multi instances of indexing on our web git pages.

It's good, then, to politely ask to robots to avoid indexing our git pages. Indeed bots before starting their job on a specific website they look for a file called robots.txt where the owner of the website expresses his will to index or not portions of his pages. In my case I don't want any of my git web pages to be indexed. So that I create the file robots.txt:

# vim /var/www/cgit/robots.txt
	

The syntax is fairly simple and you can choose whitch parts of your website you don't want to be indexed:

User-agent: *
Disallow: /
	

In my case I disallow robots to scan starting from the root directory, which is git.smida.it.


Next: Web mail, Previous: Web git: cgit, [Index]

8 Mail server

Workaround.org from Cristoph Haas is very useful to me setting up a persona mail server and I followed his instructions almost step by step. For more accurate explanations please refer to it.

Essentially we need for four components for building up a working mail client: DNS, postfix, mysql and dovecot.

The DNS MX record will forward all the mails to my machine. But we did already the DNS registration so that we don't need to care anymore.

Pstfix plays different roles in the mail gaming. First establishes smtp connections with the clients, reads the e-mail to understand the content and evaluate if the mail is spam or a valid mail and then makes a connection with MySQL to see if the mail domain belongs to that server and if the 'To:' address is recognized as well. At the end, delivers the mail to dovecot.

Dovecot takes over the mails from postfix and stores them somewhere in the file system. It's also able to set an imap(s) or pop3(s) connection for clients who want to download the e-mails locally on their machines.


Next: Postfix, Previous: Mail server, [Index]

8.1 MySQL setup

MySQL will be the pool where I will store all the informations regarding the mail server. Indeed I'm going to store in a database mail accounts, domains and aliases.

Let's start by installing MySQL:

# apt-get install mysql-server
	

During the installation it will ask for the MySQL root password (which is not the system root password) and, as we are used, let's insert a random generated password:

$ tr -dc A-Za-z0-9 < /dev/urandom | head -c 32 | xargs
	

MySQL now is installed and ready to use. I create the database "mailserver":

# mysqladmin -p create mailserver
	

Now I can login and start working directly on the database:

# mysql -p -u root mailserver
	

As in all the systems, I create a less privileged user called "mailuser" which will have only selection power on each table of the database:

mysql> grant select on mailserver.*
	-> to 'mailuser'@'127.0.0.1'
	-> identified by 'veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx';
Query OK, 0 rows affected (0.00 sec)
	

With "identified by 'password'" I specify the password of the 'mailuser' user, if you are following these instructions, care to place your own password, of course the one I wrote is not the one I set on my server.

Now I start creating the tables. On the 'virtual_domains' table I will keep informations about the domains supported by my mail server:

mysql> create table `virtual_domains` (
	-> `id` int(11) not null auto_increment,
	-> `name` varchar(50) not null,
	-> primary key (`id`)
	-> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.07 sec)
	

On 'virtual_users' I store the informations about the mail accounts for each domain:

mysql> create table `virtual_users` (
	-> `id` int(11) not null auto_increment,
	-> `domain_id` int(11) not null,
	-> `password` varchar(100) not null,
	-> `email` varchar(100) not null,
	-> primary key (`id`),
	-> unique key `email` (`email`),
	-> foreign key (domain_id) references virtual_domains(id) on delete cascade
	-> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.08 sec)
	

And at the end I want each user to have the possibility to have more than one alias (this step is not necessary):

mysql> create table `virtual_aliases` (
	-> `id` int(11) not null auto_increment,
	-> `domain_id` int(11) not null,
	-> `source` varchar(100) not null,
	-> `destination` varchar(100) not null,
	-> primary key (`id`),
	-> foreign key (domain_id) references virtual_domains(id) on delete cascade
	-> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.08 sec)
	

The database is set now let's start insterting the data we need.

In the virtual domains I insert the domain 'smida.it':

mysql> insert into `mailserver`.`virtual_domains` (
	-> `id`,
	-> `name`
	-> ) values (
	-> '1', 'smida.it'
	-> );
Query OK, 1 row affected (0.02 sec)
	
virtual domains
id name
1 smida.it

The first mail address inserted will be the mine in the table virtual_users:

mysql> insert into `mailserver`.`virtual_users` (
	-> `id`,
	-> `domain_id`,
	-> `password`,
	-> `email`
	-> ) values (
	-> '1', '1',
	-> '{SSHA256}...',
	-> 'andi@smida.it'
	-> );
Query OK, 1 row affected (0.02 sec)
	
virtual users
id domain id password email
1 1 {SSHA256}... andi@smida.it

I decided to ecrypt passwords in SHA256, it's always better to not store plain passwords. At the end I create an alias for my account which will be of the type name.surname@smida.it.

mysql> insert into `mailserver`.`virtual_aliases` (
    -> `id`,
    -> `domain_id`,
    -> `source`,
    -> `destination`
    -> ) values (
    -> '1', '1', 'andi.shyti@smida.it', 'andi@smida.it'
    -> );
Query OK, 1 row affected (0.03 sec)
	
virtual aliases
id domain_id source destination
1 1 andi.shyti@smida.it andi@smida.it

My database now is all set and ready to be connected to postfix.

mysql> quit
Bye
	

Next: Dovecot, Previous: MySQL setup, [Index]

8.2 Postfix

Postfix receives incoming e-mails through smtp and performs a first check on them.

Let's start installing it first:

# apt-get install postfix postfix-mysql
	

During the postfix installation it will ask about the mail server configuration type and I choose Internet site and then it will ask to enter the domain, I type smida.it.

During the mail server setup, through each step we have to add bits and pieces to the postfix configuration, for now we will see just how to make postfix to interact with mysql and the tables we already created .

Let's start making postfix to know which are the domains stored in the database. We do that by creating a file which will keep all the instructions for selecting a specific domain:

# vim /etc/postfix/mysql-virtual-mailbox-domains.cf
	
user = mailuser
password = veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx
hosts = 127.0.0.1
dbname = mailserver
query = select 1 from virtual_domains where name='%s'
	

As you can see in this file we provide instructions on how to connect to the database: username, host, password (of course is the fake password I generated in the previous chapter) and database name. We also provide the query string that postfix has to execute when looking for a domain.

Now we need to tell postfix that everytime it has to look for a specific domain it has to refer to the file just created:

# postconf -e virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
	

We could try a first preliminary test to see if the connection works and the query is performed:

# postmap -q smida.it mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
1
	

If the result is 1 it means that we didn't do any mistake.

At the same way we create a configuration file for the mail accounts:

# vim  /etc/postfix/mysql-virtual-mailbox-maps.cf
	
user = mailuser
password = veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx
hosts = 127.0.0.1
dbname = mailserver
query = select 1 from virtual_users where email='%s'
	

I inform postfix about the file:

# postconf -e virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
	

And I test it:

# postmap -q andi@smida.it mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
1
	

As before, if I get 1, it means that the connection works.

And, finally, I do the exact same operations for the aliases:

# vim /etc/postfix/mysql-virtual-alias-maps.cf
	
user = mailuser
password = veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx
hosts = 127.0.0.1
dbname = mailserver
query = select destination from virtual_aliases where source='%s'
	
# postconf -e virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf
	

A final test:

# postmap -q andi.shyti@smida.it mysql:/etc/postfix/mysql-virtual-alias-maps.cf
andi@smida.it
	

In this last case I expect to get the destination for the specific source.


Next: SSL, Previous: Postfix, [Index]

8.3 Dovecot

Dovecot will take care of handing over from postfix all the received mails and store them somewhere in the file system. Moreover, dovecot is able to set smtp(s) or pop3(s) connections to allow users to download the mails locally on their PC through their favourite mail client.

We need first to create the user that dovecot will use to store the mails. In my case I want the mails to be stored in the path:

/var/vmail/<domain>/<user>/
	

all the mails will be saved in maildir format. Let's create now the user and the group vmail:

# groupadd -g 5000 vmail
# useradd -g vmail -u 5000 -d /var/vmail -m vmail
	

Let's edit and configure dovecot:

# vim /etc/dovecot/dovecot.conf
	

This an example on how dovecot.conf should look like:

auth_mechanisms = plain login
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:/var/vmail/%d/%n/Maildir:LAYOUT=fs
mail_privileged_group = mail
passdb {
  args = /etc/dovecot/dovecot-sql.conf.ext
  driver = sql
}

protocols = imap

service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  unix_listener auth-master {
    mode = 0600
    user = vmail
  }
  user = root
}

service imap-login {
  inet_listener imap {
    port = 0
  }
}

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

userdb {
  driver = passwd
}

userdb {
  args = uid=5000 gid=5000 home=/var/vmail/%d/%n allow_all_users=yes
  driver = static
}

verbose_ssl = yes
protocol pop3 {
  pop3_uidl_format = %08Xu%08Xv
}

protocol lda {
  auth_socket_path = /var/run/dovecot/auth-master
  log_path =
  mail_plugins = sieve
  postmaster_address = andi@smida.it
}
	

This configuration file enables only imaps connections, indeed it uses the public certificate /etc/ssl/certs/dovecot.pem and the private key in /etc/ssl/private/dovecot.pem. For more detailed explanations of the parameters refer to workaround.org. Keep in mind that there are some differences because dovecot I'm using is version 2.1.7 while on workaround.org is used an older version and they are quite different.

Dovecot connects to mysql to fetch the user informations and the passwords since it's going to estabilish smtp connections. The database details are stored in the file /etc/dovecot/dovecot-sql.conf.ext:

# vim /etc/dovecot/dovecot-sql.conf.ext
	
driver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mailuser password=veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx
default_pass_scheme = SSHA256
password_query = select email as user,password from virtual_users where email = '%u'
	

I specify as encryption method SSHA256, the same as the one used during the database insertion. Remember to put your own password, the one written is the fake password I generated before. It's better to make this file unaccessible to other users:

# chown root:root /etc/dovecot/dovecot-sql.conf.ext
# chmod go= /etc/dovecot/dovecot-sql.conf.ext
	

While we need the user vmail to be able to read from the dovecot.conf since postfix delivers through the user vmail:

# chgrp vmail /etc/dovecot/dovecot.conf
# chmod g+r /etc/dovecot/dovecot.conf
	

Now we need to tell postfix to use dovecot as delivery agent in his master configuration file:

# vim /etc/postfix/master.cf
	

We need to add the following two lines, the indentation must be done only with spaces:

dovecot unix - n n - - pipe
flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}
	

At the end we tell postfix to use dovecot for the virtual delivery:

# postconf -e virtual_transport=dovecot
# postconf -e dovecot_destination_recipient_limit=1
	

Now we can reload the postfix configuration:

# postfix reload
	

Next: SMTP restriction, Previous: Dovecot, [Index]

8.4 SSL

The use of the SSL protocol will allow us to have encrypted connection with the smida mail server from both the sides, smtp and imap. SSL is based on a public certificate and a private key which are stored in files, usually under /etc/ssl/certs/ are the public certificates and under /etc/ssl/private/ are the private keys.

I create first the certificates for dovecot therefore for the imap protocol

# openssl req -new -x509 -days 3650 -nodes -out /etc/ssl/certs/dovecot.pem -keyout /etc/ssl/private/dovecot.pem
	

Users belonging to the 'others' type shouldn't be able to read the private key:

# chmod o= /etc/ssl/private/dovecot.pem
	

I restart dovecot in order to load the two keys:

# /etc/init.d/dovecot restart
	

I do the same for postfix and the smtp protocol; first I generate the certificates:

# openssl req -new -x509 -days 3650 -nodes -out /etc/ssl/certs/postfix.pem -keyout /etc/ssl/private/postfix.pem
	

I limit the access to the private key:

# chmod o= /etc/ssl/private/postfix.pem
	

At the end I enable them in postfix:

# postconf -e smtpd_tls_cert_file=/etc/ssl/certs/postfix.pem
# postconf -e smtpd_tls_key_file=/etc/ssl/private/postfix.pem
	

For enabling the authenticated smtp in posftix I need some more configuration:

# postconf -e smtpd_sasl_type=dovecot
# postconf -e smtpd_sasl_path=private/auth
# postconf -e smtpd_sasl_auth_enable=yes
# postconf -e smtpd_recipient_restrictions="permit_mynetworks \
     permit_sasl_authenticated \
     reject_unauth_destination \
     reject_unknown_client_hostname \
     reject_unknown_sender_domain \
     reject_unauth_pipelining"
	

in this case postfix will not reject mails coming from the smida network and that are authenticated through SASL, while will reject all the unauthenticated connections, unkown hostnames, unknown senders and mails sent ahead in the time.

Reload postfix:

# postfix reload
	

Now finally I should be able to send and receive mails using my new smida.it server.


Next: Accman, Previous: SSL, [Index]

8.5 SMTP restriction

One of the most annoying thing to deal with mails is spam, so that having in place a minimum of anti-spam security may benefit our mail system.

Next: HELO restriction, Previous: SMTP restriction, [Index]

8.5.1 Black list

The blacklisting is done based on the IP address of the sender. Fortunately there are some websites that keep track of IPs that use to send spam. To use those services I need to inform postfix where to check for the incoming e-mail, so that I add the following url: bl.spamcop.net zen.spamhaus.org dnsbl-1.uceprotect.net to the smtpd_recipient_restrictions variable in main.cf:

# vim /etc/postfix/main.cf
	
smtpd_recipient_restrictions = permit_mynetworks
   permit_sasl_authenticated
   reject_unknown_client_hostname
   reject_unknown_sender_domain
   reject_unauth_pipelining
   reject_rbl_client bl.spamcop.net 
   reject_rbl_client zen.spamhaus.org 
   reject_rbl_client dnsbl-1.uceprotect.net 
   reject_unauth_destination
	

Reload postfix:

# postfix reload
	

Next: Grey list, Previous: Black list, [Index]

8.5.2 HELO restriction

When a client connects to a mail server, the first command sent is a HELO greeting followed by the hostname. Postfix has a special variable smtpd_helo_restrictions to perform a further restriction. Let's set this variable in main.cf:

# vim /etc/postfix/main.cf
	
smtpd_helo_restrictions = reject_invalid_helo_hostname,
   reject_non_fqdn_helo_hostname,
   reject_unknown_helo_hostname
	

In this case we will reject hosts that are using as HELO hostname invalid or unknown hostnames or not fully qualified domain names.

Then let's reload again postfix:

# postfix reload
	

Next: Accman, Previous: HELO restriction, [Index]

8.5.3 Grey lists

The greylisting mechanism doesn't make any mail filtering, i.e. is not allowed to reject mails rather than delaying the mail reception. Infact it rejects in a first place the mail taking advantage of the fact that mail servers have an outgoing queue and in case of error they retry to send the mail again. The second attempt is not rejected.

First I install tumgreyspf which is the program that performs the greylisting:

# apt-get install tumgreyspf
	

And then I add to the postfix smtpd_recipient_restrictions variable the tumgrey policy:

smtpd_recipient_restrictions = permit_mynetworks
   permit_sasl_authenticated
   reject_unknown_client_hostname
   reject_unknown_sender_domain
   reject_unauth_pipelining
   reject_rbl_client bl.spamcop.net
   reject_rbl_client zen.spamhaus.org
   reject_rbl_client dnsbl-1.uceprotect.net
   check_policy_service unix:private/tumgreyspf 
   reject_unauth_destination
	

And reload postfix:

# postfix reload
	

Next: Web mail, Previous: SMTP restriction, [Index]

8.6 Accman

Accman (ACCountMANager) is a little stupid program that I wrote to help me to insert other users in the virtual_users database. It's very far from being complete, but it's handy and doesn't ask to other possible users to connect to the database.

For building accman I need to install the mysql client libraries:

# apt-get install libmysqlclient-dev
	

Then it's better to create a user which will have only insertion rights on the virtual_users table:

# mysql -p mailserver


mysql> grant insert on mailserver.virtual_users
    -> to 'officer'@'127.0.0.1'
    -> identified by 'veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx';
Query OK, 0 rows affected (0.00 sec)
	

We can get accman directly from git:

$ git clone git://git.etezian.org/accman.it
	

As I said, the program is far from being complete and it needs some customization directly in the code:

I need to set my domain:

$ vim include/accman.h


- #define DOMAIN "etezian.org"
+ #define DOMAIN "smida.it"
	

and my mysql credentials:

$ vim src/db_user.c


-         if (!mysql_real_connect(conn, "localhost", "user", "password",
+         if (!mysql_real_connect(conn, "127.0.0.1", "officer", "veKI8vDcd4ebIhNwz5FrJvKxqW67L0Sx",
	

now I can build it and install it:

$ make
# make install
	

The usage is fairly simple, just hit accman and it starts. Let's assume we want to create the user donald.duck@smida.it:

$ accman
Insert user name (user@smida.it): donald.duck
Password:
Re-type password:
Do you want to insert new user 'donald.duck@smida.it'? [Y/n]

User donald.duck@smida.it inserted correctly
	

when accman asks for the user care to not insert the full e-mail, but just the name without the domain.


Next: Mailing lists, Previous: SMTP restriction, [Index]

9 Web mail

For this part of the tutorial I've been helped by Chris post Roundcube for your Debian Squeeze Mail Server on his blog

Could be useful to also have a webmail application to be able to read the mails when I don't have my mail client under my hands. There are two webmail frontends, SquirrelMail and Roundcube. The first is one of the most used, a bit old fashion, though, while Roundcube has a bit more modern interface and a few features more.

Let's start installing it:

# apt-get install roundcube roundcube-mysql
	

I configure Apache for the new website:

# vim /etc/apache2/sites-available/mail.smida.it
	
<VirtualHost *:80>
        ServerAdmin andi@smida.it
        ServerName mail.smida.it
        ServerAlias mail.* webmail.*

        DocumentRoot /var/lib/roundcube
        Alias /program/js/tiny_mce/ /usr/share/tinymce/www/
        <Directory /var/lib/roundcube/>
                Options +FollowSymLinks
                AllowOverride All
                Order allow,deny
                Allow from all
        </Directory>
        <Directory /var/lib/roundcube/config>
                Options -FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /var/lib/roundcube/temp>
                Options -FollowSymLinks
                AllowOverride None
                Order allow,deny
                Deny from all
        </Directory>
        <Directory /var/lib/roundcube/logs>
                Options -FollowSymLinks
                AllowOverride None
                Order allow,deny
                Deny from all
        </Directory>
        <Directory /usr/share/tinymce/www/>
                Options Indexes MultiViews FollowSymLinks
                AllowOverride None
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>
	

I enable the website:

# a2ensite mail.smida.it
	

And I restart Apache:

# /etc/init.d/apache2 restart
	

To make roundcube working I need also to make some customisations to the roundcube configuration file. It's written in PHP and dynamically loaded to the web pages, so that I don't need to restart any services for reloading my changes:

# vim /etc/roundcube/main.inc.php
	

These are the lines I changed for my webmail pages:

$rcmail_config['default_host'] = 'ssl://localhost';
$rcmail_config['default_port'] = 993;
$rcmail_config['smtp_server'] = 'localhost';
$rcmail_config['smtp_user'] = '%u';
$rcmail_config['smtp_pass'] = '%p';
$rcmail_config['create_default_folders'] = TRUE;
$rcmail_config['product_name'] = 'Smida.it';
	

As suggested in Chris's blog, I also change the label in the mainpage to be "Email" instead of "username", since the user logs in using his e-mail and not username:

# vim /usr/share/roundcube/program/localization/en_US/labels.inc
	
$labels['username'] = 'Email';
	

I can also modify the logo by replacing the existing one in /usr/share/roundcube/skins/default/images/roundcube_logo.png, the image has to be 178x47px.


Next: Mailing lists, Previous: Web mail, [Index]

9.1 Secure HTTP

Would be better to encrypt the HTTP session for my web mail reading. Therefore I would like Apache to establish a secure http connection with the browsers. Apache supports https protocol over the port 443 by using certificates as we did for the mail server. As well we need to create a public and a private key:

# openssl req -new -x509 -days 365 -nodes -out /etc/ssl/certs/apache.pem -keyout /etc/ssl/private/apache.key
	

Now we tell apache to connect through https for the domain mail.smida.it and use the certificates I created:

# vim /etc/apache2/sites-available/mail.smida.it
	

I replace the default 80 port:

<VirtualHost *:443>
   ...
</VirtualHost>
	

and I ask to enable SSL providing the path to the certificates:

<VirtualHost *:443>
        SSLEngine On
        SSLCertificateFile /etc/ssl/certs/apache.pem
        SSLCertificateKeyFile /etc/ssl/private/apache.key

		...

</VirtualHost>
	

The problem now is that apache will not respond anymore to the port 80 for mail.smida.it and it will open one of the domains I registered (blog or www). Moreover everytime I want to connect to my mail web page, I would always need to write manually 'https://' which on the long term could be annoying.

One way how to fix this is to tell apache to redirect all the connections to mail.smida.it through https 443 port. I do this by adding on the top of the file sites-available/mail.smida.it a VirtualHost section which will just respond to the http requests and will direct those to https://mail.smida.it:

<VirtualHost *:80>
        ServerAdmin andi@smida.it
        ServerName mail.smida.it
        ServerAlias mail.* webmail.*

        DocumentRoot /var/lib/roundcube
        Redirect permanent / https://mail.smida.it
</VirtualHost>

<VirtualHost *:443>
   ...
</VirtualHost>
	

I restart Apache and my webmail pages are ready to be used:

# /etc/init.d/apache2 restart
	

Next: Bottom, Previous: Web mail, [Index]

10 Mailing lists

The web page here was my reference for this section.

Perhaps having a mailing list on an own server is a bit of asking to much to a private server, but it could be fun to share it as a social network with friends, family or for private projects. The mailing list engine I chose is Mailman.

I install mailman first:

# apt-get install mailman
	

And I create a configuration file in Apache to respond to the domain lists.smida.it. Mailman provides already an apache configuration, I just need to copy it to the sites-available directory and personalize it:

# cp /etc/mailman/apache.conf /etc/apache2/sites-available/mailman.conf
# vim /etc/apache2/sites-available/mailman.conf
	
<Directory /usr/lib/cgi-bin/mailman/>
    AllowOverride None
    Options ExecCGI
    AddHandler cgi-script .cgi
    Order allow,deny
    Allow from all
</Directory>
<Directory /var/lib/mailman/archives/public/>
    Options FollowSymlinks
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>
<Directory /usr/share/images/mailman/>
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>


<VirtualHost *:80>
    ServerName lists.smida.it
    DocumentRoot /var/www/lists
    ErrorLog /var/log/apache2/lists-error.log
    CustomLog /var/log/apache2/lists-access.log combined
    
    <Directory /var/lib/mailman/archives/>
        Options FollowSymLinks
        AllowOverride None
    </Directory>
    
    Alias /pipermail/ /var/lib/mailman/archives/public/
    Alias /images/mailman/ /usr/share/images/mailman/
    ScriptAlias /admin /usr/lib/cgi-bin/mailman/admin
    ScriptAlias /admindb /usr/lib/cgi-bin/mailman/admindb
    ScriptAlias /confirm /usr/lib/cgi-bin/mailman/confirm
    ScriptAlias /create /usr/lib/cgi-bin/mailman/create
    ScriptAlias /edithtml /usr/lib/cgi-bin/mailman/edithtml
    ScriptAlias /listinfo /usr/lib/cgi-bin/mailman/listinfo
    ScriptAlias /options /usr/lib/cgi-bin/mailman/options
    ScriptAlias /private /usr/lib/cgi-bin/mailman/private
    ScriptAlias /rmlist /usr/lib/cgi-bin/mailman/rmlist
    ScriptAlias /roster /usr/lib/cgi-bin/mailman/roster
    ScriptAlias /subscribe /usr/lib/cgi-bin/mailman/subscribe
    ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/
</VirtualHost>
	

I create a directory 'lists' in /var/www:

# mkdir /var/www/lists
	

And I enable the new site:

# a2ensite mailman.conf
# /etc/init.d/apache2 restart
	

Some configurations are needed for mailman to get to know the new lists.smida.it as a domain:

# vim /etc/mailman/mm_cfg.py
	
DEFAULT_EMAIL_HOST = 'lists.smida.it'
DEFAULT_URL_HOST = 'lists.smida.it'
DEFAULT_URL_PATTERN = 'http://%s/'
MTA='Postfix'
	

In the last line I tell mailman that the mail transfer agent to use is postfix.

Now we need to inform postfix about the new domain:

# postconf -e 'relay_domains = lists.smida.it'
# postconf -e 'mailman_destination_recipient_limit = 1'
	

And we need to make sure that in master.cf there are the following two lines for the mail delivery:

# vim /etc/postfix/master.cf
	
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}
	

I need, then, to insert in the database more details about the new domain:

# mysql -p mailserver
	

I create a new table which will contain informations about the transport domains:

mysql> create table virtual_transport (
    -> `id` int(11) not null auto_increment,
    -> `domain_id` int(11) not null,
    -> `domain` varchar(50) not null,
    -> `transport` varchar(50) not null,
    -> primary key(`id`),
    -> unique key `domain`(`domain`),
    -> foreign key (domain_id) references virtual_domains(id) on delete cascade
    -> ) engine=InnoDB charset=utf8;
Query OK, 0 rows affected (0.07 sec)
	

I insert the informations related to lists.smida.it:

mysql> insert into `virtual_transport` (`domain_id`, `domain`, `transport`)
    -> values (
    -> '1', 'lists.smida.it', 'mailman:');
Query OK, 1 row affected (0.03 sec)
	
virtual transport
id domain_id domain transport
1 1 lists.smida.it mailman:

Once the database is ready, I need to create a file with the database account details and the query string for postfix, as I did for the other tables :

# vim /etc/postfix/mysql-virtual_transports.cf
	
user = mailuser
password = 0XTDoEpvvzIZ8pyG
hosts = 127.0.0.1
dbname = mailserver
query = SELECT transport FROM virtual_transport WHERE domain='%s'
	

Remember that the password is fake and to put your own. I set the file permissions:

# chmod o= /etc/postfix/mysql-virtual_transports.cf
	

And tell postfix to use this file for the transport domain mapping:

# postconf -e 'transport_maps = proxy:mysql:/etc/postfix/mysql-virtual_transports.cf'
	

To make the changes effective I restart postfix:

# /etc/init.d/postfix restart
	

Now I'm ready to use the mailing list, but first I need to create one. I'll start with the list that mailman likes, i.e. "mailman":

# newlist --urlhost=lists.smida.it --emailhost=lists.smida.it mailman
	

The list creation is interactive and it will ask first for the administrator mail, in my case andi@smida.it:

Enter the email of the person running the list: andi@smida.it
	

Then it will ask the password for the administrative interface. As usual you can use this command to generate one:

$ tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs
	

At the end it will provide a list of standard mail accounts used for the list management and it will send an e-mail to notify the creation of the "mailman" mailing list. We need to copy paste that list in the aliases file:

# vim /etc/aliases
	
## mailman mailing list
mailman:              "|/var/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/var/lib/mailman/mail/mailman admin mailman"
mailman-bounces:      "|/var/lib/mailman/mail/mailman bounces mailman"
mailman-confirm:      "|/var/lib/mailman/mail/mailman confirm mailman"
mailman-join:         "|/var/lib/mailman/mail/mailman join mailman"
mailman-leave:        "|/var/lib/mailman/mail/mailman leave mailman"
mailman-owner:        "|/var/lib/mailman/mail/mailman owner mailman"
mailman-request:      "|/var/lib/mailman/mail/mailman request mailman"
mailman-subscribe:    "|/var/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe:  "|/var/lib/mailman/mail/mailman unsubscribe mailman"
	

Everytime I create new aliases I make them effective by running:

# newaliases
	

I restart postix:

# /etc/init.d/postfix restart
	

And I finally give life to mailman:

# /etc/init.d/mailman start
	

Home / Index / Top / Last: Mailing lists

Andi Shyti
email: andi (at) smida (dot) it
IRC: cazzacarna