There is a new version of this tutorial available for Ubuntu 17.04 (Zesty Zapus).

The Perfect Server - Ubuntu 16.04 (Xenial Xerus) with Apache, PHP, MySQL, PureFTPD, BIND, Postfix, Dovecot and ISPConfig 3.1 - Page 2

8. Install Apache, PHP, phpMyAdmin, FCGI, SuExec, Pear, and mcrypt

Apache2, PHP 7, phpMyAdmin, FCGI, suExec, Pear, and mcrypt can be installed as follows:

apt-get install apache2 apache2-doc apache2-utils libapache2-mod-php php7.0 php7.0-common php7.0-gd php7.0-mysql php7.0-imap phpmyadmin php7.0-cli php7.0-cgi libapache2-mod-fcgid apache2-suexec-pristine php-pear php-auth php7.0-mcrypt mcrypt  imagemagick libruby libapache2-mod-python php7.0-curl php7.0-intl php7.0-pspell php7.0-recode php7.0-sqlite3 php7.0-tidy php7.0-xmlrpc php7.0-xsl memcached php-memcache php-imagick php-gettext php7.0-zip php7.0-mbstring

You will see the following question:

Web server to reconfigure automatically: <-- apache2
Configure database for phpmyadmin with dbconfig-common? <-- Yes
MySQL application password for phpmyadmin: <-- Press enter

Then run the following command to enable the Apache modules suexec, rewrite, ssl, actions, and include (plus dav, dav_fs, and auth_digest if you want to use WebDAV):

a2enmod suexec rewrite ssl actions include cgi

a2enmod dav_fs dav auth_digest headers

To ensure that the server can not be attacked trough the HTTPOXY vulnerability, I will disable the HTTP_PROXY header in apache globally.

sudo nano /etc/apache2/conf-available/httpoxy.conf

Paste this content to the file:

<IfModule mod_headers.c>
    RequestHeader unset Proxy early

Enable the config file by running:

a2enconf httpoxy

Restart Apache afterward:

service apache2 restart

If you want to host Ruby files with the extension .rb on your web sites created through ISPConfig, you must comment out the line application/x-ruby rb in /etc/mime.types:

nano /etc/mime.types

#application/x-ruby                             rb

(This is needed only for .rb files; Ruby files with the extension .rbx work out of the box.)

Restart Apache afterwards:

service apache2 restart


8.1 PHP Opcode cache

APCu is a free PHP opcode cacher for caching and optimizing PHP intermediate code. It is strongly recommended to have one of these installed to speed up your PHP page.

APCu can be installed as follows:

apt-get install php7.0-opcache php-apcu

Now restart Apache:

service apache2 restart



To use PHP-FPM with Apache, we need the mod_fastcgi Apache module (please don't mix this up with mod_fcgid - they are very similar, but you cannot use PHP-FPM with mod_fcgid). We can install PHP-FPM and mod_fastcgi as follows:

apt-get install libapache2-mod-fastcgi php7.0-fpm

Make sure you enable the module and restart Apache:

a2enmod actions fastcgi alias
service apache2 restart


8.3 Additional PHP Versions

It is possible to have multiple PHP versions on one server (selectable through ISPConfig) which can be run through FastCGI and PHP-FPM. To learn how to build additional PHP versions (PHP-FPM and FastCGI) and how to configure ISPConfig, please check this tutorial: How To Use Multiple PHP Versions (PHP-FPM & FastCGI) With ISPConfig 3 (Ubuntu 12.10) (works for Ubuntu 16.04 as well).

10.1 Install HHVM (HipHop Virtual Machine)

In this step we will install HHVM with apt. HHVM is a fast PHP engine developed by Facebook.

apt-get -y install software-properties-common
apt-key adv --recv-keys --keyserver hkp:// 0x5a16e7281be7a449
add-apt-repository "deb xenial main"
apt-get update
apt-get -y install hhvm

9. Install Let's Encrypt

ISPConfig 3.1  has builtin support for the free SSL Certificate Authority Let's encrypt. The Let's Encrypt function allows you to create free SSL Certificates for your website in ISPConfig.

Now we will add support for Let's encrypt.

apt-get -y install letsencrypt

10. Install Mailman

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

apt-get install mailman

Select at least one language, e.g.:

Languages to support: <-- en (English)
Missing site list <-- Ok

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

newlist mailman

root@server1:~# newlist mailman
Enter the email of the person running the list:
 <-- admin email address, e.g.
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:              "|/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"

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


Open /etc/aliases afterwards...

nano /etc/aliases

... and add the following lines:

## 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"



afterwards and restart Postfix:

service postfix restart

Finally we must enable the Mailman Apache configuration:

ln -s /etc/mailman/apache.conf /etc/apache2/conf-available/mailman.conf

This defines the alias /cgi-bin/mailman/ for all Apache vhosts, 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 you can find the mailing list archives.

Restart Apache afterwards:

service apache2 restart

Then start the Mailman daemon:

service mailman start


11. Install PureFTPd and Quota

PureFTPd and quota can be installed with the following command:

apt-get install pure-ftpd-common pure-ftpd-mysql quota quotatool

Edit the file /etc/default/pure-ftpd-common...

nano /etc/default/pure-ftpd-common

... and make sure that the start mode is set to standalone and set VIRTUALCHROOT=true:


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.

If you want to allow FTP and TLS sessions, run

echo 1 > /etc/pure-ftpd/conf/TLS

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) [AU]: <-- Enter your Country Name (e.g., "DE").
State or Province Name (full name) [Some-State]:
<-- Enter your State or Province Name.
Locality Name (eg, city) []:
<-- Enter your City.
Organization Name (eg, company) [Internet Widgits Pty 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) []:
<-- 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

Then restart PureFTPd:

service pure-ftpd-mysql restart

Edit /etc/fstab. Mine looks like this (I added ,usrjquota=quota.user,,jqfmt=vfsv0 to the partition with the mount point /):

nano /etc/fstab

# /etc/fstab: static file system information.
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
# <file system> <mount point> <type> <options> <dump> <pass>
/dev/mapper/server1--vg-root / ext4 errors=remount-ro,usrjquota=quota.user,,jqfmt=vfsv0 0 1
# /boot was on /dev/sda1 during installation
UUID=39762f15-3a49-4982-add3-139d5040b48a /boot ext2 defaults 0 2
/dev/mapper/server1--vg-swap_1 none swap sw 0 0
/dev/fd0 /media/floppy0 auto rw,user,noauto,exec,utf8 0 0

To enable quota, run these commands:

mount -o remount /

quotacheck -avugm
quotaon -avug

 Which will show the following output:

root@server1:~# quotacheck -avugm
quotacheck: Scanning /dev/mapper/server1--vg-root [/] done
quotacheck: Cannot stat old user quota file //quota.user: No such file or directory. Usage will not be subtracted.
quotacheck: Cannot stat old group quota file // No such file or directory. Usage will not be subtracted.
quotacheck: Cannot stat old user quota file //quota.user: No such file or directory. Usage will not be subtracted.
quotacheck: Cannot stat old group quota file // No such file or directory. Usage will not be subtracted.
quotacheck: Checked 11642 directories and 81307 files
quotacheck: Old file not found.
quotacheck: Old file not found.
root@server1:~# quotaon -avug
/dev/mapper/server1--vg-root [/]: group quotas turned on
/dev/mapper/server1--vg-root [/]: user quotas turned on

12. Install BIND DNS Server

BIND can be installed as follows:

apt-get install bind9 dnsutils haveged

13. Install Vlogger, Webalizer, and AWstats

Vlogger, webalizer, and AWstats can be installed as follows:

apt-get install vlogger webalizer awstats geoip-database libclass-dbi-mysql-perl

Open /etc/cron.d/awstats afterwards...

nano /etc/cron.d/awstats

... and comment out everything in that file:


#*/10 * * * * www-data [ -x /usr/share/awstats/tools/ ] && /usr/share/awstats/tools/

# Generate static reports:
#10 03 * * * www-data [ -x /usr/share/awstats/tools/ ] && /usr/share/awstats/tools/


14. Install Jailkit

Jailkit is needed only if you want to chroot SSH users. It can be installed as follows (important: Jailkit must be installed before ISPConfig - it cannot be installed afterwards!):

apt-get install build-essential autoconf automake1.11 libtool flex bison debhelper binutils

cd /tmp
tar xvfz jailkit-2.19.tar.gz
cd jailkit-2.19
./debian/rules binary

You can now install the Jailkit .deb package as follows:

cd ..
dpkg -i jailkit_2.19-1_*.deb
rm -rf jailkit-2.19*

15. Install fail2ban and UFW

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

apt-get install fail2ban

To make fail2ban monitor PureFTPd and Dovecot, create the file /etc/fail2ban/jail.local:

nano /etc/fail2ban/jail.local

enabled  = true
port     = ftp
filter   = pureftpd
logpath  = /var/log/syslog
maxretry = 3

enabled = true
filter = dovecot-pop3imap
action = iptables-multiport[name=dovecot-pop3imap, port="pop3,pop3s,imap,imaps", protocol=tcp]
logpath = /var/log/mail.log
maxretry = 5

enabled  = true
port     = smtp
filter   = postfix-sasl
logpath  = /var/log/mail.log
maxretry = 3

Then create the following two filter files:

nano /etc/fail2ban/filter.d/pureftpd.conf

failregex = .*pure-ftpd: \(.*@<HOST>\) \[WARNING\] Authentication failed for user.*
ignoreregex =

nano /etc/fail2ban/filter.d/dovecot-pop3imap.conf

failregex = (?: pop3-login|imap-login): .*(?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed|Aborted login \(\d+ authentication attempts).*rip=(?P<host>\S*),.*
ignoreregex =

Add the missing ignoreregex line in the postfix-sasl file:

echo "ignoreregex =" >> /etc/fail2ban/filter.d/postfix-sasl.conf

Restart fail2ban afterwards:

service fail2ban restart

To install the UFW firewall, run this apt command:

apt-get install ufw

Share this page:

Suggested articles

17 Comment(s)

Add comment


From: Tuumke

Errors were encountered while processing: amavisd-newE: Sub-process /usr/bin/dpkg returned an error code (1)

From: till

The most likely reason is a invalid hostname of your server. amvus will not start if there is no fully qualified domain name set as hostname.

From: bernie

 Hi, memcached seems not to work?

From: ei8ht

Hi Folks, 

Let's encrypt is available in ubunu's repo. Can i use that one instead of building it from source? 

Kind regards


From: Tuumke

root@server:/opt/certbot# quotaon -avugquotaon: using // on /dev/vda1 [/]: No such processquotaon: Quota format not supported in kernel.quotaon: using //quota.user on /dev/vda1 [/]: No such processquotaon: Quota format not supported in kernel.root@server:/opt/certbot#


From: till

The Linux kernel of your server does not support quota. Quota is available in all standard kernels but it might be that your server provider installed a kernel without quota support. Contact your ISP and tell them that you need quota support in the kernel.

From: CorSch

I just followed this tutorial and it looks like neither postfix nor dovecot are using /var/log/mail.log for logging.

They use /var/log/syslog instead. So the fail2ban service will not start, due to a missing logfile. (/var/log/mail.log)

From: CorSch

I've found a solution on chown syslog:adm /var/log sudo chmod 0775 /var/log sudo service rsyslog restart sudo service postfix restart Now is postfix using the mail.log file

From: Pay87

In step 8 we install "libapache2-mod-fcgid" and in step 8.2 you say we should not mix PHP-FPM with mod_fcgid. So is it correct to not install PHP-FPM when mod-fcgid is installed in step 8? By the way which PHP version should get selected in ISPConfig website creation settings...? Mod_php? I am always not sure which one is recommended here. :) Thanks

From: till

Both have to be installed. Never use mod_php, it is insecure and this option exists only for legacy reasons. Use either php-fpm or php-fcgi and enable suexec in the website settings.

From: Pay87

Thanks Till. Now I understood what you mean with don't mix it up. Just because I am curious, why is mod_php insecure? Is it insecure in general or only when you have different vhosts and they could access each other data more likely?

From: till

The problems with mod_php can only occur on servers that run more than one website. With mod_php, all PHP scripts on all websites get executed as apache (www-data) user, so an attacker that would get into website A (e.g. a small block) would be able to gain access to credit card data that might be stored in website B (a shop system of another customer). With php-fcgi or php-fpm and suexec on, the PHP scripts get executes under the user of the website, so site A from our example runs as web1, and web B runs as web2 Linux user so that a hacker that got into A can not open the database credentials file of site B as it is owned by a different Linux user (off course the permissions must be like 0600 on that file).

From: xavidp

I did not get the letsencrypt certificates created by ispconfig (maybe some isse was there since I migrated the ispconfig from a ubuntu 14.04 server to a new one with 16.04?).

I seemed to have avoided the issue by means of running manually the /opt/certbot/certbot-auto and accepting to choose the domains/sites for which I wanted the certificates created.


Extra info: I had some error like:

  File "/root/.local/share/letsencrypt/local/lib/python2.7/site-packages/requests/packages/urllib3/contrib/", line 193, in recv    [self.socket], [], [], self.socket.gettimeout())


And googling a bit for this type of error, I installed a few extra python packages (just in case), and now I seem to be able to avoid the timeout, and everything run smoothly (12 domains in the same go, wohooo!)

The extra packages I installed:


sudo apt-get install python-pip

pip install pyopenssl ndg-httpsclient pyasn1


In case this helps to someone else.


From: manyk

Why can't we install jailkit from packages with apt? Seems it's the same version as the one from this tutorial (2.19)?

From: Gwyneth Llewelyn

I have the same question...

From: Gwyneth Llewelyn

Regarding the fail2ban configuration: There is already a ignoreregex line in postfix-sasl: ignoreregex = authentication failed: Connection lost to authentication server$

Also, why are new filters created for pureftpd and dovecot? After all, the current release of fail2ban already has filters for those two... but they look quite different from the ones in this tutorial (note: they are the same filters than on previous tutorials...)

From: Alexander Savin

8.3 Additional PHP Versions

How To Use Multiple PHP Versions (PHP-FPM & FastCGI) With ISPConfig 3 (Ubuntu 12.10) (works for Ubuntu 16.04 as well).

There is version for Ubuntu 16.04 -