The Perfect Server - CentOS 7 x86_64 (nginx, Dovecot, ISPConfig 3)
Version 1.0
Authors: Till Brehm, Srijan Kishore and Falko Timme
Follow howtoforge on Twitter
This tutorial shows how to prepare a CentOS 7 x86_64 server for the installation of ISPConfig 3, and how to install ISPConfig 3 on it. ISPConfig 3 is a webhosting control panel that allows you to configure the following services through a web browser: nginx web server, Postfix mail server, MySQL, BIND nameserver, PureFTPd, SpamAssassin, ClamAV, Mailman, and many more. Since version 3.0.4, ISPConfig comes with full support for the nginx web server in addition to Apache; this tutorial covers the setup of a server that uses nginx, not Apache. The ISPConfig 3 apache perfect server tutorial is available here.
ISPConfig 3 Manual
In order to learn how to use ISPConfig 3, I strongly recommend to download the ISPConfig 3 Manual.
On about 300 pages, it covers the concept behind ISPConfig (admin, resellers, clients), explains how to install and update ISPConfig 3, includes a reference for all forms and form fields in ISPConfig together with examples of valid inputs, and provides tutorials for the most common tasks in ISPConfig 3. It also lines out how to make your server more secure and comes with a troubleshooting section at the end.
1. Requirements
To install such a system you will need the following
- Download the two CentOS 7.0 DVDs from a mirror next to you (the list of mirrors can be found here: http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7.0-1406-x86_64-DVD.iso.
- A fast internet connection
2. Preliminary Note
In this tutorial I use the hostname server1.example.com with the IP address 192.168.0.100 and the gateway 192.168.0.1. These settings might differ for you, so you have to replace them where appropriate. Please install the minimal CentOS 7 installation from this tutorial link before proceeding ahead.
3 Install nano editor and adjust /etc/hosts
yum -y install nano wget
Next we edit /etc/hosts. Make it look like this:
nano /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 192.168.0.100 server1.example.com server1 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
and set the hostname to server1.example.com:
echo 'server1.example.com' > /etc/hostname
4 Configure The Firewall and install some basic network software
(You can skip this chapter if you have already disabled the firewall at the end of the basic system installation.)
I want to install ISPConfig at the end of this tutorial which comes with its own firewall. That's why I disable the default CentOS firewall now. Of course, you are free to leave it on and configure it to your needs (but then you shouldn't use any other firewall later on as it will most probably interfere with the CentOS firewall).
Run
systemctl stop firewalld.service
systemctl disable firewalld.service
rm '/etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service'
rm '/etc/systemd/system/basic.target.wants/firewalld.service'
[root@server1 ~]#
and disable the firewall.
To check that the firewall has really been disabled, you can run
firewall-cmd --state
afterwards. The output should look like this:
[root@server1 ~]# firewall-cmd --state
not running
[root@server1 ~]#
yum -y install net-tools NetworkManager-tui
5 Disable SELinux
SELinux is a security extension of CentOS that should provide extended security. In my opinion you don't need it to configure a secure system, and it usually causes more problems than advantages (think of it after you have done a week of trouble-shooting because some service wasn't working as expected, and then you find out that everything was ok, only SELinux was causing the problem). Therefore I disable it (this is a must if you want to install ISPConfig later on).
Edit /etc/selinux/config and set SELINUX=disabled:
nano /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
# targeted - Targeted processes are protected,
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
Afterwards we must reboot the system:
reboot
6 Enable Additional Repositories And Install Some Software
We will enable EPEL repositories on our CentOS system as lots of the packages that we are going to install in the course of this tutorial are not available in the official CentOS 7.0 repositories:
yum -y install epel-release
yum -y install yum-priorities
Edit /etc/yum.repos.d/epel.repo...
nano /etc/yum.repos.d/epel.repo
... and add the line priority=10 to the [epel] section:
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=1
priority=10
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
[...]
Then we update our existing packages on the system:
yum update
Now we install some software packages that are needed later on:
yum -y groupinstall 'Development Tools'
7 Quota
(If you have chosen a different partitioning scheme than I did, you must adjust this chapter so that quota applies to the partitions where you need it.)
To install quota, we run this command:
yum -y install quota
Now we check if quota is already enabled for the filesystem where the website (/var/www) and maildir data (var/vmail) is stored. In this example setup, I have one big root partition, so I search for ' / ':
mount | grep ' / '
[root@server1 ~]# mount | grep ' / '
/dev/mapper/centos-root on / type xfs (rw,relatime,attr2,inode64,noquota)
[root@server1 ~]#
If you have a separate /var partition, then use:
mount | grep ' /var '
instead. If the line contains the word "noquota", then proceed with the following steps to enable quota.
Enabling quota on the / (root) partition
Normally you would enable quota in the /etc/fstab file, but if the filesystem is the root filesystem "/", then quota has to be enabled by a boot parameter of the Linux Kernel.
Edit the grub configuration file:
nano /etc/default/grub
search fole the line that starts with GRUB_CMDLINE_LINUX and add rootflags=uquota,gquota to the commandline parameters so that the resulting line looks like this:
[...]
GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/swap vconsole.font=latarcyrheb-sun16 rd.lvm.lv=centos/root crashkernel=auto vconsole.keymap=us rhgb quiet rootflags=uquota,gquota"
[...]
and apply the changes by running the following command.
cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg_bak
grub2-mkconfig -o /boot/grub2/grub.cfg
and reboot the server.
reboot
Now check if quota is enabled:
mount | grep ' / '
[root@server1 ~]# mount | grep ' / '
/dev/mapper/centos-root on / type xfs (rw,relatime,attr2,inode64,usrquota,grpquota)
[root@server1 ~]#
When quota is active, we can see "usrquota,grpquota" in the mount option list.
Enabling quota on a separate /var partition
If you have a separate /var partition, then edit /etc/fstab and add ,uquota,gquota to the / partition (/dev/mapper/centos-var):
nano /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun Sep 21 16:33:45 2014
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 1 1
/dev/mapper/centos-var /var xfs defaults,uquota,gquota 1 2
UUID=9ac06939-7e43-4efd-957a-486775edd7b4 /boot xfs defaults 1 3
/dev/mapper/centos-swap swap swap defaults 0 0
Then run
mount -o remount /var
quotacheck -avugm
quotaon -avug
to enable quota.
8 Synchronize The System Clock
It is a good idea to synchronize the system clock with an NTP (network time protocol) server over the Internet. Simply run
yum -y install ntp
and your system time will always be in sync.
9 Install MariaDB
We will install MariaDB-server and client as follows:
yum -y install mariadb mariadb-server
We want the Mariadb service to run on and after boot, and start the service as:
systemctl enable mariadb.service
systemctl start mariadb.service
Set passwords for the MySQL root account:
mysql_secure_installation
[root@server1 ~]# mysql_secure_installation
/usr/bin/mysql_secure_installation: line 379: find_mysql_client: command not found
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
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
Enter current password for root (enter for none): <--ENTER
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: <--yourmariadbpassword
Re-enter new password: <--yourmariadbpassword
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!
[root@server1 ~]#
10 Install Dovecot
Dovecot can be installed as follows:
yum -y install dovecot dovecot-pigeonhole dovecot-mysql
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.service
systemctl start dovecot.service
11 Install Postfix
Postfix can be installed as follows:
yum -y install postfix
Then turn off Sendmail and start Postfix:
systemctl enable mariadb.service
systemctl start mariadb.service
systemctl stop sendmail.service
systemctl disable sendmail.service
systemctl enable postfix.service
systemctl restart postfix.service
12 Install Getmail
Getmail can be installed as follows:
yum -y install getmail
13 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:
sa-update
freshclam
systemctl enable amavisd.service
14 Install Nginx, PHP5 (PHP-FPM), And Fcgiwrap
Nginx is available as a package for CentOS 7.0 (from EPEL) which we can install as follows:
yum -y install nginx
If Apache2 is already installed on the system, stop it now...
systemctl stop httpd.service
... and remove Apache's system startup links:
systemctl disable httpd.service
Then we create the system startup links for nginx and start it:
systemctl enable nginx.service
systemctl start nginx.service
(If both Apache2 and nginx are installed, the ISPConfig 3 installer will ask you which one you want to use - answer nginx in this case. If only one of these both is installed, ISPConfig will do the necessary configuration automatically.)
We can make PHP5 work in nginx through PHP-FPM (PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites). We can install php-fpm together with php-cli and some PHP5 modules like php-mysql which you need if you want to use MySQL from your PHP scripts as follows:
yum -y install php-fpm php-cli php-mysql php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc php-pecl-apc php-magickwand php-mbstring php-mcrypt php-mssql php-snmp php-soap php-tidy
Next we open /etc/php.ini...
nano /etc/php.ini
... and change the error reporting (so that notices aren't shown any longer):
[...]
;error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
error_reporting = E_ALL & ~E_NOTICE
[...]
Also set cgi.fix_pathinfo=0:
nano /etc/php.ini
[...]
; 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 PATH_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
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://www.php.net/manual/en/ini.core.php#ini.cgi.fix-pathinfo
cgi.fix_pathinfo=0
[...]
(Please read http://wiki.nginx.org/Pitfalls to find out why you should do this.)
In addition to that, in order to avoid errors like
[08-Aug-2011 18:07:08] PHP Warning: phpinfo(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'Europe/Berlin' for 'CEST/2.0/DST' instead in /usr/share/nginx/html/info.php on line 2
... in /var/log/php-fpm/www-error.log when you call a PHP script in your browser, you should set date.timezone in /etc/php.ini:
[...]
[Date]
; Defines the default timezone used by the date functions
; http://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone
date.timezone = "Europe/Berlin"
[...]
Next create the system startup links for php-fpm and start it:
systemctl enable php-fpm
systemctl restart php-fpm
PHP-FPM is a daemon process (with the init script /etc/init.d/php-fpm) that runs a FastCGI server on port 9000.
To get CGI support in nginx, we install Fcgiwrap.
Fcgiwrap is a CGI wrapper that should work also for complex CGI scripts and can be used for shared hosting environments because it allows each vhost to use its own cgi-bin directory.
As there's no fcgiwrap package for CentOS 7.0, we must build it ourselves. First we install some prerequisites:
yum -y install fcgi-devel
Now we can build fcgiwrap as follows:
cd /usr/local/src/
git clone git://github.com/gnosek/fcgiwrap.git
cd fcgiwrap
autoreconf -i
./configure
make
make install
This installs fcgiwrap to /usr/local/sbin/fcgiwrap.
Next we install the spawn-fcgi package which allows us to run fcgiwrap as a daemon:
yum -y install spawn-fcgi
Open /etc/sysconfig/spawn-fcgi...
nano /etc/sysconfig/spawn-fcgi
... and modify the file as follows:
# You must set some working options before the "spawn-fcgi" service will work.
# If SOCKET points to a file, then this file is cleaned up by the init script.
#
# See spawn-fcgi(1) for all possible options.
#
# Example :
#SOCKET=/var/run/php-fcgi.sock
#OPTIONS="-u apache -g apache -s $SOCKET -S -M 0600 -C 32 -F 1 -P /var/run/spawn-fcgi.pid -- /usr/bin/php-cgi"
FCGI_SOCKET=/var/run/fcgiwrap.socket
FCGI_PROGRAM=/usr/local/sbin/fcgiwrap
FCGI_USER=apache
FCGI_GROUP=apache
FCGI_EXTRA_OPTIONS="-M 0770"
OPTIONS="-u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -S $FCGI_EXTRA_OPTIONS -F 1 -P /var/run/spawn-fcgi.pid -- $FCGI_PROGRAM"
Now add the user nginx to the group apache:
usermod -a -G apache nginx
Create the system startup links for spawn-fcgi...
chkconfig spawn-fcgi on
... and start it as follows:
systemctl start spawn-fcgi
You should now find the fcgiwrap socket in /var/run/fcgiwrap.socket, owned by the user and group apache (some scripts, e.g. Mailman, expect to be run by the user/group apache, that's why we don't run spawn-fcgi as user/group nginx, but instead add nginx to the apache group).
14.1 Additional PHP Versions
Starting with the ISPConfig 3.0.5, it is possible to have multiple PHP versions on one server (selectable through ISPConfig) which can be run through FastCGI and PHP-FPM. The procedure of building additional PHP versions on CentOS is described in this tutorial: How To Use Multiple PHP Versions (PHP-FPM & FastCGI) With ISPConfig 3 (CentOS 6.3)