There is a new version of this tutorial available for CentOS 7.6.

The Perfect Server – CentOS 7 (Apache2, Dovecot, ISPConfig 3) - Page 2

10 Install Dovecot

Dovecot can be installed as follows:

yum -y install dovecot dovecot-mysql dovecot-pigeonhole

Create a empty dovecot-sql.conf file and symlink:

touch /etc/dovecot/dovecot-sql.conf
ln -s /etc/dovecot/dovecot-sql.conf /etc/dovecot-sql.conf

Now create the system startup links and start Dovecot:

systemctl enable dovecot
systemctl start dovecot


11 Install Postfix

Postfix can be installed as follows:

yum -y install postfix

Then turn off Sendmail and start Postfix and Mariadb (MySQL):

systemctl enable mariadb.service
systemctl start mariadb.service
systemctl stop sendmail.service
systemctl disable sendmail.service
systemctl enable postfix.service
systemctl restart postfix.service

We disable sendmail to ensure that it does not get started in case it is installed on your server. So the error message "Failed to issue method call: Unit sendmail.service not loaded." can be ignored.


12 Install Getmail

Getmail can be installed as follows:

yum -y install getmail


13 Set MySQL Passwords And Configure phpMyAdmin

Set passwords for the MySQL root account:

[[email protected] tmp]# mysql_secure_installation

In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n]
 <-- ENTER
New password: <-- yourrootsqlpassword
Re-enter new password: <-- yourrootsqlpassword
Password updated successfully!
Reloading privilege tables..
 ... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n]
 <-- ENTER
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n]
 <-- ENTER
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n]
 <-- ENTER
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n]
 <-- ENTER
 ... Success!

Cleaning up...

All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

[[email protected] tmp]#

Now we configure phpMyAdmin. We change the Apache configuration so that phpMyAdmin allows connections not just from localhost (by commenting out the two "Require ip" lines and adding the new line "Require all granted" in the <Directory /usr/share/phpMyAdmin/> stanza):

nano /etc/httpd/conf.d/phpMyAdmin.conf
# phpMyAdmin - Web based MySQL browser written in php
# Allows only localhost by default
# But allowing phpMyAdmin to anyone other than localhost should be considered
# dangerous unless properly secured by SSL

Alias /phpMyAdmin /usr/share/phpMyAdmin
Alias /phpmyadmin /usr/share/phpMyAdmin

<Directory /usr/share/phpMyAdmin/>
   <IfModule mod_authz_core.c>
     # Apache 2.4
     #  Require ip
     #  Require ip ::1
Require all granted </RequireAny> </IfModule> <IfModule !mod_authz_core.c> # Apache 2.2 Order Deny,Allow Deny from All Allow from Allow from ::1 </IfModule> </Directory>

Next we change the authentication in phpMyAdmin from cookie to http:

nano /etc/phpMyAdmin/
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'http';

Then we create the system startup links for Apache and start it:

systemctl enable  httpd.service
systemctl restart  httpd.service

Now you can direct your browser to or and log in with the user name root and your new root MySQL password.


14 Install Amavisd-new, SpamAssassin And ClamAV

To install amavisd-new, spamassassin and clamav, run the following command:

yum -y install amavisd-new spamassassin clamav clamd clamav-update unzip bzip2 unrar perl-DBD-mysql

Edit the freshclam configuration file /etc/freshclam.conf

nano /etc/freshclam.conf

and comment out the line "Example"

# Example

Then we start freshclam, amavisd, and clamd.amavisd:

systemctl enable amavisd.service


15 Installing Apache2 With mod_php, mod_fcgi/PHP5, PHP-FPM And suPHP

ISPConfig 3 allows you to use mod_php, mod_fcgi/PHP5, cgi/PHP5, and suPHP on a per website basis.

We can install Apache2 with mod_php5, mod_fcgid, and PHP5 as follows:

yum -y install php php-devel php-gd php-imap php-ldap php-mysql php-odbc php-pear php-xml php-xmlrpc php-pecl-apc php-mbstring php-mcrypt php-mssql php-snmp php-soap php-tidy curl curl-devel perl-libwww-perl ImageMagick libxml2 libxml2-devel mod_fcgid php-cli httpd-devel php-fpm

Next we open /etc/php.ini...

nano /etc/php.ini

... and change the error reporting (so that notices aren't shown any longer), set the timezone and uncomment cgi.fix_pathinfo=1:

;error_reporting = E_ALL & ~E_DEPRECATED
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PAppp.tldTH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
date.timezone = 'Europe/Berlin' [...]

Next we install suPHP (there is a mod_suphp package available in the repositories, but unfortunately it isn't compatible with ISPConfig, therefore we have to build suPHP ourselves):

cd /usr/local/src
tar zxvf suphp-0.7.2.tar.gz

CentOS 7 uses apache-2.4, so we need a patch suphp before we can compile it aganst Apache. The patch gets applied like this:

wget -O suphp.patch
patch -Np1 -d suphp-0.7.2 < suphp.patch
cd suphp-0.7.2
autoreconf -if
[[email protected] suphp-0.7.2]# autoreconf -if
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `config'.
libtoolize: copying file `config/'
libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to and
libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree.
libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated.  For more info, see: installing 'config/config.guess' installing 'config/config.sub' installing 'config/install-sh' installing 'config/missing'
src/ installing 'config/depcomp'
[[email protected] suphp-0.7.2]#

It will apply the patch, now we can compile the new source as follows:

./configure --prefix=/usr/ --sysconfdir=/etc/ --with-apr=/usr/bin/apr-1-config --with-apache-user=apache --with-setid-mode=owner --with-logfile=/var/log/httpd/suphp_log
make install

Then we add the suPHP module to our Apache configuration...

nano /etc/httpd/conf.d/suphp.conf
LoadModule suphp_module modules/

... and create the file /etc/suphp.conf as follows:

nano /etc/suphp.conf
;Path to logfile
;User Apache is running as
;Path all scripts have to be in
;Path to chroot() to before executing script
; Security options
;Check wheter script is within DOCUMENT_ROOT
;Send minor error messages to browser
;PATH environment variable
;Umask to set, specify in octal notation
; Minimum UID
; Minimum GID

;Handler for php-scripts
;Handler for CGI-scripts

Edit the file /etc/httpd/conf.d/php.confto enable php parsing only for phpmyadmin, roundcube and other system packages in /usr/share but not for websites in /var/www as ISPConfig will activate PHP for each website individually.

nano /etc/httpd/conf.d/php.conf

change the lines:

<FilesMatch \.php$>
SetHandler application/x-httpd-php


<Directory /usr/share>
<FilesMatch \.php$>
SetHandler application/x-httpd-php

So that the PHP handler is enclosed by the Directory directive.

Enable httpd and PHP-FPM to get started at boot time and start the PHP-FPM service.

systemctl start php-fpm.service
systemctl enable php-fpm.service
systemctl enable httpd.service

Finally we restart Apache:

systemctl restart httpd.service

15.1 Installation of mod_python

The apache module mod_python is not available as RPM package, therefor we will compile it from source. The first step is to install the python development files and download the current mod_python version as tar.gz file

yum -y install python-devel
cd /usr/local/src/
tar xfz mod_python-3.5.0.tgz
cd mod_python-3.5.0

and then configure and compile the module

make install

and enable the module in apache

echo 'LoadModule python_module modules/' > /etc/httpd/conf.modules.d/10-python.conf
systemctl restart httpd.service


16 Install PureFTPd

PureFTPd can be installed with the following command:

yum -y install pure-ftpd

Then create the system startup links and start PureFTPd:

systemctl enable pure-ftpd.service
systemctl start pure-ftpd.service

Now we configure PureFTPd to allow FTP and TLS sessions. FTP is a very insecure protocol because all passwords and all data are transferred in clear text. By using TLS, the whole communication can be encrypted, thus making FTP much more secure.

OpenSSL is needed by TLS; to install OpenSSL, we simply run:

yum install openssl

Open /etc/pure-ftpd/pure-ftpd.conf...

vi /etc/pure-ftpd/pure-ftpd.conf

If you want to allow FTP and TLS sessions, set TLS to 1:

# This option can accept three values :
# 0 : disable SSL/TLS encryption layer (default).
# 1 : accept both traditional and encrypted sessions.
# 2 : refuse connections that don't use SSL/TLS security mechanisms,
#     including anonymous sessions.
# Do _not_ uncomment this blindly. Be sure that :
# 1) Your server has been compiled with SSL/TLS support (--with-tls),
# 2) A valid certificate is in place,
# 3) Only compatible clients will log in.

TLS                      1

In order to use TLS, we must create an SSL certificate. I create it in /etc/ssl/private/, therefore I create that directory first:

mkdir -p /etc/ssl/private/

Afterwards, we can generate the SSL certificate as follows:

openssl req -x509 -nodes -days 7300 -newkey rsa:2048 -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem

Country Name (2 letter code) [XX]: <-- Enter your Country Name (e.g., "DE").
State or Province Name (full name) []:
<-- Enter your State or Province Name.
Locality Name (eg, city) [Default City]:
<-- Enter your City.
Organization Name (eg, company) [Default Company Ltd]:
<-- Enter your Organization Name (e.g., the name of your company).
Organizational Unit Name (eg, section) []:
<-- Enter your Organizational Unit Name (e.g. "IT Department").
Common Name (eg, your name or your server's hostname) []:
<-- Enter the Fully Qualified Domain Name of the system (e.g. "").
Email Address []:
<-- Enter your Email Address.

Change the permissions of the SSL certificate:

chmod 600 /etc/ssl/private/pure-ftpd.pem

Finally restart PureFTPd:

systemctl restart pure-ftpd.service

That's it. You can now try to connect using your FTP client; however, you should configure your FTP client to use TLS.


17 Install BIND

We can install BIND as follows:

yum -y install bind bind-utils

Make a backup of the existing /etc/named.conf file and create a new one as follows:

cp /etc/named.conf /etc/named.conf_bak
cat /dev/null > /etc/named.conf
nano /etc/named.conf
// named.conf
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
// See /usr/share/doc/bind*/sample/ for example named configuration files.
options {
        listen-on port 53 { any; };
        listen-on-v6 port 53 { any; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        allow-query     { any; };
				allow-recursion {"none";};
        recursion no;
logging {
        channel default_debug {
                file "data/";
                severity dynamic;
zone "." IN {
        type hint;
        file "";
include "/etc/named.conf.local";

Create the file /etc/named.conf.local that is included at the end of /etc/named.conf (/etc/named.conf.local will later on get populated by ISPConfig if you create DNS zones in ISPConfig):

touch /etc/named.conf.local

Then we create the startup links and start BIND:

systemctl enable named.service
systemctl start named.service


18 Install Webalizer, And AWStats

Webalizer and AWStats can be installed as follows:

yum -y install webalizer awstats perl-DateTime-Format-HTTP perl-DateTime-Format-Builder


19 Install Jailkit

Jailkit is used to chroot SSH users and cronjobs. It can be installed as follows (important: Jailkit must be installed before ISPConfig - it cannot be installed afterwards!):

cd /tmp
tar xvfz jailkit-2.17.tar.gz
cd jailkit-2.17
make install
cd ..
rm -rf jailkit-2.17*


20 Install fail2ban

This is optional but recommended, because the ISPConfig monitor tries to show the log:

yum -y install fail2ban

Then create the system startup links for fail2ban and start it:

systemctl enable fail2ban.service
systemctl start fail2ban.service


21 Install rkhunter

rkhunter can be installed as follows:

yum -y install rkhunter


22 Install Mailman

Since version 3.0.4, ISPConfig also allows you to manage (create/modify/delete) Mailman mailing lists. If you want to make use of this feature, install Mailman as follows:

yum -y install mailman

Before we can start Mailman, a first mailing list called mailman must be created:

touch /var/lib/mailman/data/aliases
/usr/lib/mailman/bin/newlist mailman

[[email protected] tmp]# /usr/lib/mailman/bin/newlist mailman
Enter the email of the person running the list:
 <-- admin email address, e.g. [email protected]
Initial mailman password: <-- admin password for the mailman list
To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases' program:

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

Hit enter to notify mailman owner...
 <-- ENTER

[[email protected] tmp]#

Open /etc/aliases afterwards...

vi /etc/aliases

... and add the following lines:

mailman:              "|/usr/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/usr/lib/mailman/mail/mailman admin mailman"
mailman-bounces:      "|/usr/lib/mailman/mail/mailman bounces mailman"
mailman-confirm:      "|/usr/lib/mailman/mail/mailman confirm mailman"
mailman-join:         "|/usr/lib/mailman/mail/mailman join mailman"
mailman-leave:        "|/usr/lib/mailman/mail/mailman leave mailman"
mailman-owner:        "|/usr/lib/mailman/mail/mailman owner mailman"
mailman-request:      "|/usr/lib/mailman/mail/mailman request mailman"
mailman-subscribe:    "|/usr/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe:  "|/usr/lib/mailman/mail/mailman unsubscribe mailman"



afterwards and restart Postfix:

systemctl restart postfix.service

Now open the Mailman Apache configuration file /etc/httpd/conf.d/mailman.conf...

nano /etc/httpd/conf.d/mailman.conf

... and add the line ScriptAlias /cgi-bin/mailman/ /usr/lib/mailman/cgi-bin/. Comment out Alias /pipermail/ /var/lib/mailman/archives/public/ and add the line Alias /pipermail /var/lib/mailman/archives/public/:

#  httpd configuration settings for use with mailman.

ScriptAlias /mailman/ /usr/lib/mailman/cgi-bin/
ScriptAlias /cgi-bin/mailman/ /usr/lib/mailman/cgi-bin/
<Directory /usr/lib/mailman/cgi-bin/>
    AllowOverride None
    Options ExecCGI
    Order allow,deny
    Allow from all

#Alias /pipermail/ /var/lib/mailman/archives/public/
Alias /pipermail /var/lib/mailman/archives/public/
<Directory /var/lib/mailman/archives/public>
    Options Indexes MultiViews FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
    AddDefaultCharset Off

# Uncomment the following line, to redirect queries to /mailman to the
# listinfo page (recommended).

# RedirectMatch ^/mailman[/]*$ /mailman/listinfo

Restart Apache:

systemctl restart httpd.service

Create the system startup links for Mailman and start it:

systemctl enable mailman.service
systemctl start mailman.service

After you have installed ISPConfig 3, you can access Mailman as follows:

You can use the alias /cgi-bin/mailman for all Apache vhosts (please note that suExec and CGI must be disabled for all vhosts from which you want to access Mailman!), which means you can access the Mailman admin interface for a list at http://<vhost>/cgi-bin/mailman/admin/<listname>, and the web page for users of a mailing list can be found at http://<vhost>/cgi-bin/mailman/listinfo/<listname>.

Under http://<vhost>/pipermail/<listname> you can find the mailing list archives.

Share this page:

17 Comment(s)

Add comment

Please register in our forum first to comment.


By: Anonymous

For both pureftp and named the old style commands for enabling and starting are used.

By: Anonymous

Now that you changed the commands to the new style you can delete this comment. it is not longer of any use, but could be confusing.

By: admin

Fixed that in the guide some time ago.

By: Celso Coslop

You recommended using mod_phyton, however this module was replaced by mod_wsgi that we can found in EPEL. Not sure if this is a drop-in replacement, however the documentation say 'embeded' mode is equivalent. Please consider reviewing your install instructions because I do not have enough knowledge to test it, and mod_wsgi seems the path to follow.

By: admin

The guide is correct here by installing mod_python. mod_wsgi is an alternate way to add python suppport but not a drop in replacement for mod_python. So by installing mod_wsgi instead of mod_pythonlike you suggest, you will loose the ability to enable python Support for your website in ISPConfig. When there is mod_wsgi Support in ispconfig in a future Version, then you can Switch to mod_wsgi.

By: Celso Coslop

Thanks for clarify the mod_wsgi issue. I can see more users are requesting support for mod_wsgi because mod_python is no longer being developed. Maybe task 2600 can be included in ispconfig 3.1 release, this is a suggestion because I cannot see this item in the roadmap... Follow the ticket number and description. Thank you.

FS#2600 - Support for mod_wsgi

By: LanDruïd

At part:  14 Install Amavisd-new, SpamAssassin And ClamAV
- two packages are not available -> clamd & unrar


At part: 18 Install Webalizer, And AWStats
- one package is not available -> webalizer

During installtion i've noticed messages that some packages were not available so i tried to install them again with next output:

[[email protected]]# yum -y install clamd unrar webalizer
Loaded plugins: fastestmirror, priorities
Loading mirror speeds from cached hostfile
 * base:
 * epel:
 * extras:
 * updates:
69 packages excluded due to repository priority protections
No package clamd available.
No package unrar available.
No package webalizer available.
[[email protected]]#


At part: 22 Install Mailman

I've edited /etc/httpd/conf.d/mailman.conf as shown, but what about the lines Require all granted?

#  httpd configuration settings for use with mailman.
ScriptAlias /mailman/ /usr/lib/mailman/cgi-bin/
ScriptAlias /cgi-bin/mailman/ /usr/lib/mailman/cgi-bin/
<Directory /usr/lib/mailman/cgi-bin/>
    AllowOverride None
    Options ExecCGI
    Require all granted
    Order allow,deny
    Allow from all
#Alias /pipermail/ /var/lib/mailman/archives/public/
Alias /pipermail /var/lib/mailman/archives/public/
<Directory /var/lib/mailman/archives/public>
    Options Indexes MultiViews FollowSymLinks
    AllowOverride None
    Require all granted
    Order allow,deny
    Allow from all
    AddDefaultCharset Off
# Uncomment the following line, to redirect queries to /mailman to the
# listinfo page (recommended).
# RedirectMatch ^/mailman[/]*$ /mailman/listinfo

By: Anonymous

Exact same problems here. Would love to hear a solution or easy fix for this.

 Many thanks


 I have followed this guide and tried to manage my DNS but it didn't work.
There was a problem with file permission because /var/named/chroot/var/named/named.local was owned by root:root.I suppose in this guide it should be: 

touch /etc/named.conf.local
chown named:named named.local  



By: admin

Wouldn't be interesting to fix the guide ???

I also have another issue with amavisd, 

 [[email protected] named]# systemctl status amavisd.service
amavisd.service - Amavisd-new is an interface between MTA and content checkers.
   Loaded: loaded (/usr/lib/systemd/system/amavisd.service; enabled)
   Active: failed (Result: start-limit) since Sun 2014-11-30 19:20:36 CET; 6min ago
  Process: 7639 ExecStart=/usr/sbin/amavisd -c /etc/amavisd/amavisd.conf (code=exited, status=255)

/usr/sbin/amavisd -c /etc/amavisd/amavisd.conf

 The value of variable $myhostname is "sd-67295", but should have been
  a fully qualified domain name; perhaps uname(3) did not provide such.
  You must explicitly assign a FQDN of this host to variable $myhostname
  in amavisd.conf, or fix what uname(3) provides as a host's network name!

I have modified inside  /etc/amavisd/amavisd.conf the right settings for $myhostname but doesn't help


By: admin

The amavisd issue happens when your Server has a invalid hostname. E.g. a non fqdn hostname.

By: jeffsss

 i am trying to follow the steps for setting up suphp and i cannot be successful


when i do autoreconf -if i get



libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'config'

libtoolize: copying file 'config/'

libtoolize: consider adding 'ac_config_macro_dir([m4[)' to and

libtoolize:rerunning libtoolize, to keep the correct libtool macros in-tree.

libtoolize: consider adding '-I m4' to ACLOCAL_AMFLAGS in warning: am_init_automake: two- and three- arugments forms are deprecated. for more info see



By: James Bush

Hey, great guide!

I am having problems with compiling Suphp. I get all the way to autoreconfig -if and it will not do right it pops up a few errors.

I was wondering if you could give me some advice, or tell me if its ok to take it off...or something I can provide what ever you need to help troubleshoot it.

I have found some more directions for suphp so I am going to try thouse, but I would rather have some advice first. I kinda of feel like I am using a old url.

By: Jonathon Gilbert

CentOS 7 uses apache-2.4, so we need a patch suphp before we can compile it aganst Apache. The patch gets applied like this:

wget -O suphp.patch -Np1 -d suphp-0.7.2 < suphp.patchcd suphp-0.7.2autoreconf -if


I seem to have an issue where the reply i get when i use the command:

patch -Np1 -d suphp-0.7.2 < suphp.patch

it returns:

 sudo patch -Np1 -d suphp-0.7.2 < suphp.patch

patch: **** Only garbage was found in the patch input.

By: keybd_user

The suPHP link no longer exists.

Can anyone supply a working link with a patch ?

By: till

Use the latest version of this tutorial and not this old archived version: