Running a CentOS server with Lighttpd, PHP, MySQL, Exim with virtual users, Dovecot, and Squirrelmail

This tutorial was created based on the following source, with some modifications for GLiCX system. However, we do not guarantee that it will work 100% due to the variation of OS specification in our system. A simple tweak might be needed if it does not work out of box.

Source:
http://www.eazynet.de/running_a_centos_server_with_lighttpd_php_mySQL_ex...

This is a tutorial how to setup a server for mail and web.

It is based on the following components:

OS: Linux CentOS 5.2

HTTP Server: Lighttpd 1.4.19, PHP 5.1.6

Database: MySQL 5.045

Mailserver: Exim 4.63 with Vexim 2.2.1, Spamassassin 3.2.4, Clamav 0.94

IMAP/Pop3 Server: 1.07

This tutorial has been written during setup of a new virtual server. In the beginning some basic tasks and some security stuff will be configured before installing and configuring the main applications on the server.

After initial setup of a minimal server login as root with the provided password and change it immediately:

passwd

Next step is to check the current date and timezone of the server:

date

date --utc

If your timezone and/or date is not what it should be you need to change it:

rm /etc/localtime

ln -s /usr/share/zoneinfo/Asia/Kuala_Lumpur /etc/localtime

date

date -s 101421422008 (sets time+date to 21:42:00 Oct 14 2008)

Let's start now to install the latest fixes:

yum update

If your favourite editor is missing you need to install it:

yum install vim-minimal

For security reason we don't want to work as root directly but create a normal user who is using sudo for running system commands with root privileges.

yum install sudo

adduser -m dracula

passwd dracula

Now check login with user dracula. In case everything is working as expected we need to enable user dracula to run sudo. visudo is the only command that should be used to edit /etc/sudoers:

visudo

This will open /etc/sudoers in safe mode which checks for correct syntax when leaving the editor.

Add this statement at the end of the file:

dracula ALL=(ALL) ALL

If you want to increase the timeout for retyping the passwords when using sudo command you need to add this statement to the Default section:

Defaults timestamp_timeout = 15 (the default is 5 minutes, this will increase the timeout to 15 minutes)

Try to run a sudo command as user dracula:

sudo date

When prompted for a password you need to enter draculas password.

Now let's continue to harden ssh against unwelcomed guests.

cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

vi /etc/ssh/sshd_config

PermitRootLogin no

/etc/init.d/sshd restart

(before restarting sshd make sure you have an open session or you are still able to open a console terminal)

If you now try to connect as root via SSH your login will be refused. To make login more secure login with authorized key is recommended. Login as user dracula and create the directory .ssh and the file .ssh/authorized_keys:

mkdir .ssh

vi .ssh/authorized_keys

The private and public key can be generated with PuTTYgen if you are running a windows PC. Copy the public key in the .ssh/authorized_keys file.

Access to the file and the directory needs to be restricted to the owning user.

chmod 600 .ssh/authorized_keys

chmod 700 .ssh

Check to login with the private key to the server as user dracula. Do not continue with changing /etc/ssh/sshd_config as this will disable SSH for you. The following lines need to be changed/uncommented:

PubkeyAuthentication yes

AuthorizedKeysFile .ssh/authorized_keys

PasswordAuthentication no

UsePAM no

The following statement needs to be added to /etc/ssh/sshd_config:

AllowUsers dracula

After you have made these changes just restart sshd again

/etc/init.d/sshd restart

Keep you current session open and try to login again as dracula using the private key - unless you lose the private key nobody else can login via ssh to the server.

Next step is to setup priorities for yum repoistories and an additional repository from rpmforge.

yum install yum-priorities

In the file /etc/yum.repos.d/CentOS-Base.repo the following needs to added to the sections [base], [addons], [updates], [extras]:

priority=1

Now the rpmforge repository will be added to the system and the GPG keys will be imported:

wget http://apt.sw.be/redhat/el5/en/x86_64/dag/RPMS/rpmforge-release-0.3.6-1....

rpm --import http://dag.wieers.com/rpm/packages/RPM-GPG-KEY.dag.txt

rpm -K rpmforge-release-0.3.6-1.el5.rf.*.rpm

rpm -i rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm

In the file /etc/yum.repos.d/rpmforge.repo the following statement needs to be added to the [rpmforge] section:

priority=10

This will make sure that no rpm from rpmforge will override any of the CentOS rpm.

Now we can install some additional tools that are not available in the official CentOS repository.

As there are still many script kiddies and bots out there trying to login via ssh you will still see many login tries in /var/log/secure. To avoid this there fail2ban needs to be installed and configured:

yum install fail2ban

vi /etc/fail2ban/jail.conf

[ssh-iptables]

enabled = true

logpath = /var/log/secure

maxretry = 1

/etc/init.d/fail2ban start

chkconfig --level 2345 fail2ban on

Now every IP from where an invalid login is tried will be banned for 10 minutes. In most cases this avoids furthers tries later on.

If you are the only user and no password login is allowed this shouldn't do any harm. In case you still login with using password, you should increase maxretry.

After focussing on security and some basic stuff let's now continue with installing and setup of lighttpd with fastcgi and php.

yum install php php-mbstring php-mcrypt php-pear-DB lighttpd lighttpd-fastcgi

Check vi /etc/php.d/lighttpd.ini for the following statement and change/add it in case it is missing/unset:

cgi.fix_pathinfo = 1

Otherwise fastcgi will not work.

In the file /etc/php.ini check if expose_php is disabled to prevent that PHP will provide to much information to the ouside world:

expose_php = Off

Some basic stuff needs to be changed in /etc/lighttpd/lighttpd.conf. Uncomment the modules that you like to have enabled:

server.modules = (

    "mod_rewrite",

    "mod_redirect",

    "mod_alias",

    "mod_auth",

    "mod_fastcgi",

    "mod_simple_vhost",

If you prefer that lighttpd doesn't report its version number the server.tag should be set to just lighttpd:

server.tag = "lighttpd"

To enable fastcgi remove the comment # from these lines:

fastcgi.server = ( ".php" =>

    ( "localhost" =>

    (

    "socket" => "/var/run/lighttpd/php-fastcgi.socket",

    "bin-path" => "/usr/bin/php-cgi"

    )

    )

)

The next statement will return a 403 to every request that does not match any of the hosted domains domain1 and domain2 (instead of 404):

$HTTP["host"] !~ "(^|\.)domain1$|(^|\.)domain2$" {

    url.access-deny = ( "" )

}

After making the configuration changes the directory for the fastcgi socket needs to be created

mkdir /var/run/lighttpd

chown lighttpd:lighttpd /var/run/lighttpd

and permission for some directories need to be corrected as these belong to apache by default. These files can be found with the find command:

find / -user apache

find / -group apache

Change owner and/or user apache to lighttpd:

chown root:lighttpd /var/lib/php/session

Add MySQL extension to PHP using this command:

yum install php-mysql

Now you can test if the webserver is already working and responding. Create a file in /srv/www/lighttpd/ (which is the default document root directory unless you have changed this) named index.php with the following content

<?php phpinfo(); ?>

and start lighttpd daemon:

/etc/init.d/lighttpd start

Now point your browser to the IP of the server:

http://serverip/phpinfo.php

This will show you the lighttpd page with configured modeuls. Just remove the file afterwards as nodody from outside needs to how the webserver is configured:

rm /srv/www/lighttpd/index.php

As the web server is now properly configured to provide content let's go on with configuring self signed SSL certificates to use https (recommended for phpmyadmin and webmail later on). The certificates will be stored in /etc/lighttpd/ssl/ in a subdirectory with the serverip or domain name (depending on what the certificate will be used for)

mkdir /etc/lighttpd/ssl/serverip -p

cd /etc/lighttpd/ssl/serverip

openssl req -new -x509 -keyout server.pem -out server.pem -days 3650 -nodes

chown lighttpd:lighttpd /etc/lighttpd/ssl -R

chmod 0600 /etc/lighttpd/ssl/serverip

This certificate will be valid 3650 days (10 years) so you do not need to renew it regularly. We need configure SSL url now in /etc/lighttpd/lighttpd.conf. Add the following lines at the end of the file:

$SERVER["socket"] == "serverip:443" {

    server.document-root = "/srv/www/serverip"

    ssl.engine = "enable"

    ssl.pemfile = "/etc/lighttpd/ssl/serverip/server.pem"

}

Make sure /srv/www/serverip exists

mkdir /srv/www/serverip

Run a syntax check on the lighttpd configuration file to check everything is ok

lighttpd -t -f /etc/lighttpd/lighttpd.conf

and restart lighttpd if everything is ok

/etc/init.d/lighttpd restart

You can check with netstat if lighttpd is bound to SSL port:

netstat -tulpn | grep :443

With this running fine next step is to install the MySQL database and phpmyadmin for easier database administration:

yum install mysql mysql-server phpmyadmin

We start MySQL right away

/etc/init.d/mysqld start

and enter a password for the MySQL root user (do not mix it with the system root!)

mysqladmin -u root password password

Now create link for phpmyadmin in the SSL root directory

ln -s /usr/share/phpmyadmin /srv/www/serverip/phpmyadmin

Check the ownership of /usr/share/phpmyadmin/config.inc.php and correct it if group is set to apache

ls -l /usr/share/phpmyadmin/config.inc.php

chown root:lighttpd /usr/share/phpmyadmin/config.inc.php

and edit the file. You need to add a passphrase in the following statement:

$cfg['blowfish_secret']= 'secret'

Now it should be possible to access the database with a webbrowser through phpmyadmin:

https://serverip/phpmyadmin

The next step after setup of MySQL is the mail server including antivirus and antispam applications:

yum install exim mailman clamd clamav spamassassin php-pear

We won't use the standard exim configuration but vexim which provides virtual users stored in a MySQL database and also a easy to use web interface for configuring domains and users.

First we create the vexim user:

useradd vexim -u 90 -d /usr/local/mail -s /sbin/nologin -m

Download and extract vexim package:

cd /usr/share

wget http://silverwraith.com/vexim/vexim2.2.1.tar.gz

tar zxvf vexim2.2.1.tar.gz

chown -R root:root vexim2/

Now the standard exim.con file will be replaced by the one provided with vexim. As some configuration from standard exim.conf will be used later it make sure to have a copy of it.

mv /etc/exim/exim.conf /etc/exim/exim.conf.bak

cp /usr/share/vexim2/docs/configure /etc/exim/exim.conf

cp /usr/share/vexim2/docs/vexim-* /etc/exim/

/etc/exim/exim.conf needs some customization for our needs.

Users and groups must be set to exim:

MAILMAN_USER=exim

MAILMAN_GROUP=exim

exim_user = exim

exim_group = exim

Same user needs to be used in the system_alias section

user = exim

group = exim

IP used for the external interface:

MY_IP = serverip

Furtheron check for the following statements and adjust them (the password is the one used for MySQL database by vexim user):

domainlist local_domains = @ : ${lookup mysql{VIRTUAL_DOMAINS}} : ${lookup mysql{ALIAS_DOMAINS}}

primary_hostname = mail.domain.tld

hostlist relay_from_hosts = localhost

trusted_users = vexim:lighttpd

hide mysql_servers = localhost::(/var/lib/mysql/mysql.sock)/vexim/vexim/password

log_selector = +subject +tls_cipher +tls_peerdn

av_scanner = clamd:/tmp/clamd.socket

.include /etc/exim/vexim-acl-check-spf.conf

.include /etc/exim/vexim-acl-check-helo.conf

.include /etc/exim/vexim-acl-check-rcpt.conf

.include /etc/exim/vexim-acl-check-content.conf

.include /etc/exim/vexim-group-router.conf

This block is taken from the original exim.conf. Just copy it after the spamd stanza.

# If Exim is compiled with support for TLS, you may want to enable the

# following options so that Exim allows clients to make encrypted

# connections. In the authenticators section below, there are template

# configurations for plaintext username/password authentication. This kind

# of authentication is only safe when used within a TLS connection, so the

# authenticators will only work if the following TLS settings are turned on

# as well.

# Allow any client to use TLS.

tls_advertise_hosts = *

# Specify the location of the Exim server's TLS certificate and private key.

# The private key must not be encrypted (password protected). You can put

# the certificate and private key in the same file, in which case you only

# need the first setting, or in separate files, in which case you need both

# options.

tls_certificate = /etc/pki/tls/certs/exim.pem

tls_privatekey = /etc/pki/tls/private/exim.pem

# In order to support roaming users who wish to send email from anywhere,

# you may want to make Exim listen on other ports as well as port 25, in

# case these users need to send email from a network that blocks port 25.

# The standard port for this purpose is port 587, the "message submission"

# port. See RFC 4409 for details. Microsoft MUAs cannot be configured to

# talk the message submission protocol correctly, so if you need to support

# them you should also allow TLS-on-connect on the traditional but

# non-standard port 465.

daemon_smtp_ports = 25 : 465 : 587

tls_on_connect_ports = 465

For basic setup this should be ok.

Following statement should be added to /etc/exim/vexim-acl-check-rcpt.conf right after the comments to avoid spam checking for authenticated login:

accept authenticated = *

This one needs to be changed in the same file as list.dsbl.org has been disabled:

dnslists = zen.spamhaus.org

Go on with changing /etc/exim/vexim-acl-check-content.conf near the end:

spam = vexim:true

spam = vexim:true

The next step is editing /usr/share/vexim2/setup/mysql.sql with the uid and gid of the vexim system user and the MySQL password for vexim database user:

uid smallint(5) unsigned NOT NULL default '90',

gid smallint(5) unsigned NOT NULL default '90',

GRANT SELECT,INSERT,DELETE,UPDATE ON `vexim`.* to "vexim"@"localhost" IDENTIFIED BY 'password';

This file is the database description for vexim and needs to be added to MySQL:

mysql -u root -p < /usr/share/vexim2/setup/mysql.sql

You need to supply the vexim database password in /usr/share/vexim2/vexim/config/variables.php

$sqlpass = "password";

For mailman you also need to change this stanza:

$mailmanroot = "http://www.domain.tld/mailman";

For creating domains and managing mail users with vexim web interface we create a link for the SSL web site:

ln -s /usr/share/vexim2/vexim/ /srv/www/serverip/vexim

As we want to have incoming mails checked for virus and malware ClamAV needs to have read access to incoming mails. These will be put in /var/spool/exim/scan for checking. This directory is only accessible by user and group exim:

# ls -ld /var/spool/exim/scan

drwxr-x--- 2 exim exim 4096 Mar 5 18:54 /var/spool/exim/scan

Therefore we need to add the user clamav to the group exim:

usermod -aG exim clamav

In /etc/clamd.conf we need to check for the following stanza:

# Initialize supplementary group access (clamd must be started by root).

# Default: no

AllowSupplementaryGroups yes

The exim setup is finished - just check the config

exim -bV

If config check reports ok, enable all the necessary daemons for running proper mail services

chkconfig --level 2345 spamassassin on

chkconfig --level 2345 clamd on

chkconfig --level 2345 lighttpd on

chkconfig --level 2345 exim on

and start them (lighttpd should still be running):

/etc/init.d/spamassassin start

/etc/init.d/clamd start

/etc/init.d/exim start

Now vexim web interface should be ready - let's try:

https://serverip/vexim

After configuring a domain and a user, system is ready to receive mail from outside (assuming that your domain MX has been properly configured to use the server als mail server). To receive mail with a email client on any workstation a pop3 and/or imap server needs to be running. Dovecot is fulfilling this function:

yum install dovecot

To setup dovecot to work with the current setup /etc/dovecot.conf needs to be edited. Define the protocols that will be used (prefenrence is SSL secured, but if you like also plain login add imap +pop3):

protocols = imaps pop3s

Any IP4 interface should be used to listen on:

listen = *

The path for SSL certificates and mail directory need to be checked and maybe changed:

ssl_cert_file = /etc/pki/dovecot/certs/dovecot.pem

ssl_key_file = /etc/pki/dovecot/private/dovecot.pem

mail_location = /usr/local/mail/%d/%u

The following settings must fit the ones we have used for the vexim system user:

mail_privileged_group = vexim

first_valid_uid = 90

last_valid_uid = 90

The "passdb pam" authentification block must be disabled

#passdb pam {

    # ...

#}

and the "passdb sql" section must be enabled including the args with the sql config file.

# SQL database

passdb sql {

    # Path for SQL configuration file, see doc/dovecot-sql-example.conf

    args = /etc/dovecot-sql.conf

}

The same is necessary for the userdb section. "userdb sql" must be enabled

# SQL database

userdb sql {

    # Path for SQL configuration file, see doc/dovecot-sql-example.conf

    args = /etc/dovecot-sql.conf

}

instead of "userdb passwd"

#userdb passwd {

    # ...

#}

Dovecor already provides an example for the dovecot-sql.conf which must be copied to /etc

cp /usr/share/doc/dovecot-1.0.7/examples/dovecot-sql-example.conf /etc/dovecot-sql.conf

Following changes need to be made in this file (password is the database password for vexim database user):

driver = mysql

connect = host=localhost dbname=vexim user=vexim password=password

default_pass_scheme = CRYPT

The password and user query are a little bit tricky:

password_query = SELECT username AS user, crypt AS password FROM users WHERE username = '%u'

user_query = SELECT smtp AS mail, uid, gid FROM users WHERE username = '%u'

Now the setup is nearly done. The only steps left are creating the SSL certificates used by dovecot and for authenticated smtp. Dovecot delivers already a script and a config file for generating the keys

/etc/pki/dovecot/dovecot-openssl.cnf

/usr/share/doc/dovecot-1.0.7/examples/mkcert.sh

First edit /etc/pki/dovecot/dovecot-openssl.cnf with the necessary information. Afterwards renmane/remove the existing ones that have been installed with dovecot before running the script:

mv /etc/pki/dovecot/certs/dovecot.pem /etc/pki/dovecot/certs/dovecot.pem.bak

mv /etc/pki/dovecot/private/dovecot.pem /etc/pki/dovecot/private/dovecot.pem.bak

/usr/share/doc/dovecot-1.0.7/examples/mkcert.sh

Now dovecot service can be enabled and started:

chkconfig --level 2345 dovecot on

/etc/init.d/dovecot start

The exim certificates can be created the same way and the same script can be used with some modifications:

cp /usr/share/doc/dovecot-1.0.7/examples/mkcert.sh /usr/share/doc/exim-4.63/doc/mkcert.sh

cp /etc/pki/dovecot/dovecot-openssl.cnf /etc/pki/tls/exim-openssl.cnf

/etc/pki/tls/exim-openssl.cnf can be used without any changes but the paths in /usr/share/doc/exim-4.63/doc/mkcert.sh needs to be adjusted

SSLDIR=${SSLDIR-/etc/pki/tls}

OPENSSLCONFIG=${OPENSSLCONFIG-/etc/pki/tls/exim-openssl.cnf}

CERTFILE=$CERTDIR/exim.pem

KEYFILE=$KEYDIR/exim.pem

chown exim:exim $CERTFILE $KEYFILE

The next step is now to create the certificate:

/usr/share/doc/exim-4.63/doc/mkcert.sh

The finale step: installation of squirrelmail for webmail access

yum install squirrelmail

Unfortunately some file will have owner or group set to apache so this needs to be changed to apache. Search for these files with

find / -user apache

find / -group apache

and change them

chown root:lighttpd /etc/squirrelmail/*

chown lighttpd:lighttpd /var/lib/squirrelmail/prefs

chown lighttpd:lighttpd /var/cache/mod_proxy /var/lib/dav /var/spool/squirrelmail/attach

For changing squirrelmail setup a perl script is delivered with the package:

/usr/share/squirrelmail/config/conf.pl

As imaps is configured in exim.conf this needs to be changed for suirrelmail. Start the script and change

2. Server Settings

    A. Update IMAP Settings : localhost:993 (uw)

       5. IMAP Port : 993

       7. Secure IMAP (TLS) : true

Now create the link to the SSL web site:

ln -s /usr/share/squirrelmail /srv/www/serverip/squirrelmail

Done!

The server is ready to mail services with virtual users for several domains that can be defined via vexim. In case the server should also provide web services beneath administrating MySQL, vexim and squirrelmail, virtual hosts must be added to /etc/lighttpd/lighttpd.conf.

Feel free to use the given setup. If you run into trouble during configuration, if you have any hints how to improve the setup or if you find any errors please let me know.

Have fun!