The Perfect Server - Debian 10 (Nginx, BIND, Dovecot, ISPConfig 3.2)
This tutorial shows how to prepare a Debian 10 server (with Nginx, BIND, Dovecot) for the installation of ISPConfig 3.2, and how to install ISPConfig 3.2. ISPConfig 3 is a web hosting control panel that allows you to configure the following services through a web browser: Apache or nginx web server, Postfix mail server, Courier or Dovecot IMAP/POP3 server, MySQL, BIND or MyDNS nameserver, PureFTPd, SpamAssassin, ClamAV, and many more. This setup covers Nginx web server, BIND as DNS Server, and Dovecot as IMAP / POP3 server.
1 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. Before proceeding further you need to have a minimal installation of Debian 10. This might be a Debian minimal image from your hosting provider or you use the Minimal Debian Server tutorial to setup the base system.
All commands below are run as root user. Either log in as root user directly or log in as your normal user and then use the command
su -
to become root user on your server before you proceed. IMPORTANT: You must use 'su -' and not just 'su', otherwise your PATH variable is set wrong by Debian.
2 Install the SSH Server
If you did not install the OpenSSH server during the system installation, you can do it now:
apt-get -y install ssh openssh-server
From now on you can use an SSH client such as PuTTY and connect from your workstation to your Debian 10 server and follow the remaining steps from this tutorial.
3 Install a shell text editor (Optional)
I'll use the nano text editor in this tutorial. Some users prefer the classic vi editor, therefore I will install both editors here. The default vi program has some strange behavior on Debian and Ubuntu; to fix this, we install vim-nox:
apt-get -y install nano vim-nox
(You don't have to do this if you use a different text editor such as joe.)
4 Configure the Hostname
The hostname of your server should be a subdomain like "server1.example.com". Do not use a domain name without subdomain part like "example.com" as hostname as this will cause problems later with your mail setup. First, you should check the hostname in /etc/hosts and change it when necessary. The line should be: "IP Address - space - full hostname incl. domain - space - subdomain part". Edit /etc/hosts. Make it look like this:
nano /etc/hosts
127.0.0.1 localhost.localdomain localhost 192.168.0.100 server1.example.com server1 # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
Then edit the /etc/hostname file:
nano /etc/hostname
It shall contain only the subdomain part, in our case:
server1
Finally, reboot the server to apply the change:
reboot
Log in again and check if the hostname is correct now with these commands:
hostname
hostname -f
The output shall be like this:
root@server1:/tmp# hostname
server1
root@server1:/tmp# hostname -f
server1.example.com
5 Update Your Debian Installation
First make sure that your /etc/apt/sources.list contains the buster/updates repository (this makes sure you always get the newest updates for the ClamAV virus scanner - this project publishes releases very often, and sometimes old versions stop working), and that the contrib and non-free repositories are enabled.
nano /etc/apt/sources.list
deb http://deb.debian.org/debian/ buster main contrib non-free
deb-src http://deb.debian.org/debian/ buster main contrib non-free
deb http://security.debian.org/debian-security buster/updates main contrib non-free
deb-src http://security.debian.org/debian-security buster/updates main contrib non-free
Run
apt-get update
to update the apt package database and
apt-get upgrade
to install the latest updates (if there are any).
6 Change the Default Shell
/bin/sh is a symlink to /bin/dash, however we need /bin/bash, not /bin/dash. Therefore we do this:
dpkg-reconfigure dash
Use dash as the default system shell (/bin/sh)? <-- No
If you don't do this, the ISPConfig installation will fail.
7 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
apt-get install ntp
and your system time will always be in sync.
8 Install Postfix, Dovecot, MySQL, rkhunter, and binutils
We can install Postfix, Dovecot, MySQL, rkhunter, and Binutils with a single command:
apt-get install postfix postfix-mysql postfix-doc mariadb-client mariadb-server openssl getmail4 rkhunter binutils dovecot-imapd dovecot-pop3d dovecot-mysql dovecot-sieve dovecot-lmtpd sudo curl
You will be asked the following questions:
General type of mail configuration: <-- Internet Site
System mail name: <-- server1.example.com
To secure the MariaDB / MySQL installation and to disable the test database, run this command:
mysql_secure_installation
We don't have to change the MariaDB root password as we just set a new one during installation. Answer the questions as follows:
Change the root password? [Y/n] <-- y
New password: <-- Enter a new database root password
Re-enter new password: <-- Repeat the database root password
Remove anonymous users? [Y/n] <-- y
Disallow root login remotely? [Y/n] <-- y
Remove test database and access to it? [Y/n] <-- y
Reload privilege tables now? [Y/n] <-- y
Next, open the TLS/SSL and submission ports in Postfix:
nano /etc/postfix/master.cf
Uncomment the submission and smtps sections as follows and add lines where necessary so that this section of the master.cf file looks exactly like the one below. IMPORTANT: Remove the # in front of the lines that start with smtps and submission too and not just from the -o lines after these lines!
[...]
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
[...]
Restart Postfix afterwards:
service postfix restart
We want MariaDB to listen on all interfaces, not just localhost, therefore we edit /etc/mysql/mariadb.conf.d/50-server.cnf and comment out the line bind-address = 127.0.0.1:
nano /etc/mysql/mariadb.conf.d/50-server.cnf
[...]
# Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. #bind-address = 127.0.0.1
[...]
Save the file. Then set the password authentication method in MariaDB to native so we can use PHPMyAdmin later to connect as root user:
echo "update mysql.user set plugin = 'mysql_native_password' where user='root';" | mysql -u root
Edit the file /etc/mysql/debian.cnf and set the MYSQL / MariaDB root password there twice in the rows that start with the word password.
nano /etc/mysql/debian.cnf
The MySQL root password that needs to be added is shown in red. In this example, the password is "howtoforge".
# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host = localhost
user = root
password = howtoforge
socket = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host = localhost
user = root
password = howtoforge
socket = /var/run/mysqld/mysqld.sock
basedir = /usr
To prevent the error 'Error in accept: Too many open files' we will set higher open file limits for MariaDB now.
Open the file /etc/security/limits.conf with an editor:
nano /etc/security/limits.conf
and add these lines at the end of the file.
mysql soft nofile 65535
mysql hard nofile 65535
Next, create a new directory /etc/systemd/system/mysql.service.d/ with the mkdir command.
mkdir -p /etc/systemd/system/mysql.service.d/
and add a new file inside:
nano /etc/systemd/system/mysql.service.d/limits.conf
paste the following lines into that file:
[Service]
LimitNOFILE=infinity
Save the file and close the nano editor.
Then we reload systemd and restart MariaDB:
systemctl daemon-reload
systemctl restart mariadb
Ignore the warning: "Warning: The unit file, source configuration file or drop-ins of mariadb.service changed on disk. Run 'systemctl daemon-reload' to reload units.".
Install the dbconfig-common system:
apt-get install dbconfig-common dbconfig-mysql
There is currently a problem with the Debian dbconfig-common system which prevents the installation of RoundCube later, fix it by running this command:
sed -i -r 's/_dbc_nodb="yes" dbc_mysql_exec/_dbc_nodb="yes"; dbc_mysql_exec/g' /usr/share/dbconfig-common/internal/mysql
Now check that networking is enabled. Run
netstat -tap | grep mysql
The output should look like this:
root@server1:~# netstat -tap | grep mysql
tcp6 0 0 [::]:mysql [::]:* LISTEN 4027/mysqld
root@server1:~#
9 Install Amavisd-new, SpamAssassin, and ClamAV
To install amavisd-new, SpamAssassin, and ClamAV, we run:
apt-get install amavisd-new spamassassin clamav clamav-daemon unzip bzip2 arj nomarch lzop cabextract p7zip p7zip-full unrar lrzip apt-listchanges libnet-ldap-perl libauthen-sasl-perl clamav-docs daemon libio-string-perl libio-socket-ssl-perl libnet-ident-perl zip libnet-dns-perl libdbd-mysql-perl postgrey
The ISPConfig 3 setup uses amavisd which loads the SpamAssassin filter library internally, so we can stop SpamAssassin to free up some RAM:
systemctl stop spamassassin
systemctl disable spamassassin
10 Install Nginx, PHP (PHP-FPM), and Fcgiwrap
Nginx is available as a package for Debian which we can install as follows:
apt-get install nginx
If Apache2 is already installed on the system, stop it now...
systemctl stop apache2
The message "Failed to stop apache2.service: Unit apache2.service not loaded." is fine and does not indicate an error.
... and remove Apache's system startup links:
systemctl disable apache2
Start nginx afterwards:
systemctl start nginx
(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 PHP 7.3 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) which we install as follows:
apt-get install php7.3-fpm
PHP-FPM is a daemon process that runs a FastCGI server on the socket /var/run/php/php7.3-fpm.sock.
To get MySQL support in PHP, we can install the php7.3-mysql package. It's a good idea to install some other PHP modules as well as you might need them for your applications. You can search for available PHP modules like this:
apt-cache search php7
Pick the ones you need and install them like this:
apt-get install php7.3 php7.3-common php7.3-gd php7.3-mysql php7.3-imap php7.3-cli php7.3-cgi php-pear mcrypt imagemagick libruby php7.3-curl php7.3-intl php7.3-pspell php7.3-recode php7.3-sqlite3 php7.3-tidy php7.3-xmlrpc php7.3-xsl memcached php-memcache php-imagick php-gettext php7.3-zip php7.3-mbstring memcached php7.3-soap php7.3-fpm php7.3-opcache php-apcu
Next open /etc/php/7.3/fpm/php.ini...
nano /etc/php/7.3/fpm/php.ini
... and set cgi.fix_pathinfo=0 and your timezone:
[...] cgi.fix_pathinfo=0 [...] date.timezone="Europe/Berlin" [...]
(You can find all available timezones in the /usr/share/zoneinfo directories and its subdirectories.)
Now reload PHP-FPM:
systemctl restart php7.3-fpm
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.
Install the fcgiwrap package:
apt-get install fcgiwrap
After the installation, the fcgiwrap daemon should already be started; its socket is /var/run/fcgiwrap.socket. If it is not running, you can use the fservice fcgiwrap script to start it.
That's it! Now when you create a nginx vhost, ISPConfig will take care of the correct vhost configuration.
10.1 Install phpMyAdmin
Since Debian 10, PHPMyAdmin is not available as .deb package anymore. Therefore we will install it from source.
Create folders for PHPMyadmin:
mkdir /usr/share/phpmyadmin
mkdir /etc/phpmyadmin
mkdir -p /var/lib/phpmyadmin/tmp
chown -R www-data:www-data /var/lib/phpmyadmin
touch /etc/phpmyadmin/htpasswd.setup
Go to the /tmp directory and download the PHPMyAdmin sources:
cd /tmp
wget https://files.phpmyadmin.net/phpMyAdmin/4.9.0.1/phpMyAdmin-4.9.0.1-all-languages.tar.gz
Unpack the downloaded archive file and move the files to the /usr/share/phpmyadmin folder and clean up the /tmp directory.
tar xfz phpMyAdmin-4.9.0.1-all-languages.tar.gz
mv phpMyAdmin-4.9.0.1-all-languages/* /usr/share/phpmyadmin/
rm phpMyAdmin-4.9.0.1-all-languages.tar.gz
rm -rf phpMyAdmin-4.9.0.1-all-languages
Create a new config file for PHPMyaAdmin based on the provided sample file:
cp /usr/share/phpmyadmin/config.sample.inc.php /usr/share/phpmyadmin/config.inc.php
Open the config file with nano editor:
nano /usr/share/phpmyadmin/config.inc.php
Set a secure password (blowfish secret) which must be 32 chars long:
$cfg['blowfish_secret'] = 'bD3e6wva9fnd93jVsb7SDgeiBCd452Dh'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
Don't use my example blowfish secret, set your own one!
Then add a line to set the directory which PHPMyAdmin shall use to store temporary files:
$cfg['TempDir'] = '/var/lib/phpmyadmin/tmp';
In the next step, we will configure the phpMyadmin configuration store (database).
Log into MariaDB as root user:
mysql -u root -p
In the MariaDB shell, create a new database for PHPMyAdmin:
MariaDB [(none)]> CREATE DATABASE phpmyadmin;
Then create a new user:
MariaDB [(none)]> CREATE USER 'pma'@'localhost' IDENTIFIED BY 'mypassword';
Replace the word mypassword with a secure password of your choice in the commands above and below, use the same password both times. Then grant the user access to this database and reload database permissions.
MariaDB [(none)]> GRANT ALL PRIVILEGES ON phpmyadmin.* TO 'pma'@'localhost' IDENTIFIED BY 'mypassword' WITH GRANT OPTION;
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> EXIT
Finally, load the SQL tables in