Friday, September 29, 2006

Virtual Domains with Vpopmail on a qmail server.

In previous post I explained how to install a qmail server on a Red Hat ES machine and how to manage the server connections via tcpserver. Now I will add support to virtual domains using vpopmail.

This guide is based on this one with some modifications to fit my needs. The usual disclaimer is that everything written here that is good is from that guide while the bad tidbits are mine.

Preparing Red Hat ES for vpopmail

To ease the work I chose to use the rpm packages that come with Red Hat by default. First we install the MySQL client and server packages that are included on the Red Hat installation CD's.

# rpm -ivh mysql-4.1.7-4.RHEL4.1 mysqlclient10-3.23.58-4.RHEL4.1 mysql-server-4.1.7-4.RHEL4.1

We also install the devel package needed to compile Vpopmail with MySQL support:
# rpm -ivh mysql-devel-4.1.7-4.RHEL4.1

The default installation of MySQL server has a black password for the root account. This of course is a security risk and we must assign a password to the root account as soon as possible.

First start the MySQL server

# /etc/init.d/mysql start

Now we setup a root password

# mysqladmin -u root password 'mysql-root-pwd'


Before we continue to install Vpopmail we need to install the zlib-devel package but I could not find it in any of the Red Hat CD's. To install it I downloaded a zlib-devel rpm from here and installed it. You can use wget to download the file.

# rpm -ivh zlib-devel-1.2.1.2-1.i386.rpm


Installing Vpopmail

We need some preparations before we can compile and install Vpopmail on the machine. First we create a vchkpw group and vpopmail user with home directory set to /home/vpopmail.

# groupadd -g 89 vchkpw
# useradd -g vchkpw -u 89 -d /home/vpopmail vpopmail

Now we create a vpopmail database on the MySQL server and assign a user and password in the database to access it.

# mysql -u root --password="mysql-root-pwd"

# mysql> CREATE DATABASE vpopmail;
# mysql> GRANT select,insert,update,delete,create,drop ON vpopmail.* TO vpopmailuser@localhost IDENTIFIED BY 'vpoppasswd';
# mysql> quit

In the above command we created a database called vpopmail that will store all the vpopmail domains/users/log/config etc. Then we create a user "vpopmailuser" with password "vpoppasswd" with all priviledges on the vpopmail database. Please feel free to change the user and password to your favorite ones.

Next we create a configuration file that vpopmail processes will use to connect to the MySQL server:

# mkdir ~vpopmail/etc
# chown vpopmail.vchkpw ~vpopmail/etc
# echo "localhost|0|vpopmailuser|vpoppasswd|vpopmail" > ~vpopmail/etc/vpopmail.mysql
# chown vpopmail.vchkpw ~vpopmail/etc/vpopmail.mysql
# chmod 640 ~vpopmail/etc/vpopmail.mysql

Don't copy and paste the echo command above. You must change the vpopmailuser and vpoppasswd to reflect the username and password you configured on the database.

Now we are ready to install Vpopmail on the machine. Download the source package and decompress it in anywhere you feel like:

# wget http://kent.dl.sourceforge.net/sourceforge/vpopmail/vpopmail-5.4.13.tar.gz
# tar xvfz vpopmail-5.4.13.tar.gz
# cd vpopmail-5.4.13

Now we configure the source for our needs. Before running the configuration script make sure you know what features you want enabled/disabled. Once we compile changing a feature will require you to reconfigure and recompile the source code. In my case I am interested mostly on roaming and MySQL support:

# ./configure --enable-roaming-users \ # Enable POP-before-SMTP functionality.
--enable-logging=p \ # Log to syslog errors with passwords
--disable-passwd \ # Disable /etc/passwd (or shadow) accounts
--enable-auth-module=mysql \ # Enable MySQL backend support
--enable-auth-logging \ # Record time and ip of last auth attempt
--enable-sql-logging \ # Enable authentication logging to MySQL/Postgres.
--enable-valias \ # Store email aliases in MySQL
--enable-mysql-limits \ # Use MySQL to store limits.
--enable-many-domains # Store all virtual domain users in a single table.

To learn about other options you can always use the command:

# ./configure --help | less

Finally we simply compile by calling the make command:

make
make install-strip

That's it for installing Vpopmail. Now we can create/delete virtual domains and users within those domains using all Vpopmail commands found in the /home/vpopmail/bin directory:

To add a domain :

/home/vpopmail/bin/vadddomain yourdomain.com yourpassword

To add a mailbox:

/home/vpopmail/bin/vadduser someone@yourdomain.com apassword

To remove a mailbox

/home/vpopmail/bin/vdeluser someone@yourdomain.com

To remove a domain :

/home/vpopmail/bin/vdeldomain yourdomain.com

To change a user's password

/home/vpopmail/bin/vpasswd someone@yourdomain.com newpassword

(Or you can do it via qmailadmin)

To lookup info about a user

/home/vpopmail/bin/vuserinfo someone@yourdomain.com



Configureing tcpserver to manage POP3 connections

As with qmail SMTP we would like our clients to connect to the pop server from anywhere in the world. To do so we setup tcpserver in the qmail init script to accept tcp connections to port 110 and excecute the qmail-pop3d command. To do this simply add the next line after the tcpserver invocation for qmail-smtpd inside the start() method

/usr/local/bin/tcpserver -H -R -l test.canmail.jp -v 0 pop3 var/qmail/bin/qmail-popup test.canmail.jp /home/vpopmail/bin/vchkpw /var/qmail/bin/qmail-pop3d Maildir 2>&1 | /var/qmail/bin/splogger pop3d 3 &

Save the qmail init script and restart the service:

#/etc/init.d/qmail restart


Testing SMTP and POP3 via Telnet

Since SMTP and POP are text based protocols we can easily test them via telnet.

First let's create a test domain and a user:

First create the virtual domain. This command will also create a postmaster account and ask you for a password.

# /home/vpopmail/bin/vadddomain testdomain.jp

Next create a test account in the newly create domain

# /home/vpopmail/bin/vadduser testuser@testdomain.jp

Let's try first sending emails to the testuser using our newly installed qmail SMTP. In the next examples the blue lines are our commands and the red ones are the server responses.

From any machine different from the server using a telnet client:
# telnet server_ip_address 25
Trying 218.45.218.139...
Connected to 218.45.218.139.
Escape character is '^]'.
220 example.jp ESMTP
helo example.jp
250 example.jp
mail from: anyaccount@anydomain.jp
250 ok
rcpt to: testuser@testdomain.jp
250 ok
data
354 go ahead
hello world
.
250 ok 1159529928 qp 17735
quit
221 example.jp
Connection closed by foreign host.

With the above commands we send an email to the testuser at the testdomain in the server. You can see the message was delivered as the server responded with a 250 ok message.

Now let's do the same but send a message to a remote account. For example a gmail account.

From any machine different from the server using a telnet client:
# telnet server_ip_address 25
Trying 218.45.218.139...
Connected to 218.45.218.139.
Escape character is '^]'.
220 example.jp ESMTP
helo example.jp
250 example.jp
mail from: testuser@testdomain.jp
250 ok
rcpt to: anyaccount@gmail.com
553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)
quit
Connection closed by foreign host.

The server did not allow us to send the message because the gmail.com domain is not configured on the list of rcpthosts of qmail. This is very good since we don't want anyone using our server so relay email (specially spam). In the previous example the message was delivered because the testdomain.jp was added to the rcpthosts list of qmail by the vadddomain command.

But then how can the legitimate users that exist in our server send emails to other domains that are not in the rcpthosts list?? Is not like our users are going to send email only between them is it??. Well that is why I configured Vpopmail with roaming support. With roaming support after a user connects to the POP server, Vpopmail records the IP address of the machine the user connected from and modifies the tcp.smtp file to allow the recorded IP address to relay emails to any other domain.

This is called POP-before-SMTP since to be able to send emails with the server the user first needs to connect at least once with the POP server. Let's try by connecting to the POP server via telnet:

telnet 218.45.218.139 110
Trying 218.45.218.139...
Connected to 218.45.218.139.
Escape character is '^]'.
+OK <17844.1159530536@example.jp>
user testuser@testdomain.jp
+OK
pass testuserpass
+OK
list
+OK
1 269
.
quit
+OK
Connection closed by foreign host.

The list command ask the server to list the testuser emails and as we can see the listing shows one new email in the inbox. This is the email we sent on the first test. After this the IP address of the machine we are running the telnet client must be recorded on the tcp.smtp database and if we retry the second example the email will be accepted for delivery this time. Go ahead.. you can try.

Warning: Check your IPTables

When I did remote tests the first time I could not connect remotely to the port 110 on the server. After some time I realized that Red Hat ES by default has some very strict iptable rules (Firewall) set that would not allow remote POP connections.

The easiest way to allow remote SMTP (port 25) and POP3 (port 110) connections is to modify the iptables configuration file in the /etc/sysconfig directory.

# nano /etc/sysconfig/iptables

# Firewall configuration written by system-config-securitylevel
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -p 50 -j ACCEPT
-A RH-Firewall-1-INPUT -p 51 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 110 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT

Make sure the lines in red are in the file and then restart the iptables service:

# /etc/init.d/iptables restart


Final Notes

If you want a first class email server then DO NOT USE this guide. This configuration is the old school of email server configurations for a medium size application with not so much users. Current email servers use SMTP-Auth instead of POP-before-SMTP and some sort of encryption like TLS for SMTP and SSL for POP.

For a real email server that comply with current standards you should look at Cyrus-SASL for SMTP and POP encryption, SMTP-Auth for qmail and Cyrus-IMAP.

Why I still use this old school configuration?? Ask my boss... This email server is to replace a legacy server that has been working for years. Maybe changing the way it works can be annoying to the current users so I was asked to replicate exactly the old server.

No comments:

Post a Comment