ISPConfig Perfect Multiserver setup on Ubuntu 20.04 and Debian 10

This tutorial will take you through installing your own ISPConfig 3 multiserver setup with dedicated servers for the panel, web, DNS, mail, and webmail. Both the DNS and mail server will have a mirror server for redundancy. You can easily add more servers of a certain type afterwards.

ISPConfig's official auto-installer will be used to set up the servers. Debian 10 will be used as operating system. The guide has been tested with Ubuntu 20.04.2 as well.

You can read more about the auto-installer here.

1. Preliminary Note

These will be the hosts we're installing:

host       FQDN                   IP
panel     panel.example.com    10.0.64.12
web01     web01.example.com    10.0.64.13
mx1        mx1.example.com        10.0.64.14
mx2        mx2.example.com        10.0.64.15
ns1        ns1.example.com        10.0.64.16
ns2        ns2.example.com        10.0.64.17
webmail    webmail.example.com    10.0.64.18

We will be using example hostnames, IP addresses, and IP ranges. Make sure to change them accordingly in your commands/configuration.

All servers are on the same private network but have their own public IP. If your servers don't have a shared local network, use their public IPv4 addresses.

Before starting the installation of a server, set up an A and eventual AAAA record that points to the public IP address of your server. For example, if the hostname is panel.example.com and the public IP is 11.22.33.44, you should set up an A record for panel.example.com pointing to 11.22.33.44. Every server should have its own public IP and hostname.

2. Installing the master server

Log in as root or run

su -

to become the 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.1 Configure the hostname and hosts

The hostname of your server should be a subdomain like "panel.example.com". Do not use a domain name without a 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". For our hostname panel.example.com, the file shall look like this (some lines may be different, it can differ per hosting provider):

nano /etc/hosts
127.0.0.1 localhost.localdomain   localhost
# This line should be changed on every node to the correct servername:
127.0.1.1 panel.example.com panel
# These lines are the same on every node: 10.0.64.12 panel.example.com panel
10.0.64.13 web01.example.com web01
10.0.64.14 mx1.example.com mx1
10.0.64.15 mx2.example.com mx2
10.0.64.16 ns1.example.com ns1
10.0.64.17 ns2.example.com ns2
10.0.64.18 webmail.example.com webmail # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters

As you can see, we added the hostnames of our other servers aswell, so they can communicate over the internal network later.

Then edit the /etc/hostname file:

nano /etc/hostname

It shall contain only the subdomain part, in our case:

panel

Finally, reboot the server to apply the change:

systemctl reboot

Log in again and check if the hostname is correct now with these commands:

hostname
hostname -f

The output shall be like this:

[email protected]:~$ hostname
panel
[email protected]:~$ hostname -f
panel.example.com

Now we can run the autoinstaller to install all necessary packages and ISPConfig:

wget -O - https://get.ispconfig.org | sh -s -- --no-mail --no-dns --use-php=system

After some time, you will see:

WARNING! This script will reconfigure your complete server!
It should be run on a freshly installed server and all current configuration that you have done will most likely be lost!
Type 'yes' if you really want to continue:

Answer "yes" and hit enter. The installer will now start.

When the installer is finished it will show you the ISPConfig admin and MySQL root password like this:

[INFO] Your ISPConfig admin password is: 5GvfSSSYsdfdYC
[INFO] Your MySQL root password is: kkAkft82d!kafMwqxdtYs

Make sure you write this information down, along with server they are for, as you will need them later.

2.2 Setting up the remote MySQL users for our slave servers

We will log in to MySQL to allow the other servers to connect to the ISPConfig database on this node during installation, by adding MySQL root user records in the master database for every slave server hostname and IP address.

On the terminal, run

mysql -u root -p

Enter your MySQL password and then run the following commands:

CREATE USER 'root'@'10.0.64.13' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'10.0.64.13' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'10.0.64.14' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'10.0.64.14' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'10.0.64.15' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'10.0.64.15' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'10.0.64.16' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'10.0.64.16' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'10.0.64.17' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'10.0.64.17' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'10.0.64.18' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'10.0.64.18' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'web01.example.com' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'web01.example.com' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'mx1.example.com' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'mx1.example.com' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'mx2.example.com' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'mx2.example.com' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'ns1.example.com' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'ns1.example.com' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'ns2.example.com' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'ns2.example.com' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
CREATE USER 'root'@'webmail.example.com' IDENTIFIED BY 'myrootpassword';
GRANT ALL PRIVILEGES ON * . * TO 'root'@'webmail.example.com' IDENTIFIED BY 'myrootpassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;

In the above SQL commands, replace the IP adresses (10.0.64.12 - 10.0.64.18) with the IP addresses of your servers, web01.example.com, mx1.example.com, mx2.example.com, ns1.example.com, ns2.example.com, and webmail.example.com with the hostnames of your servers and myrootpassword with the desired root password (it is good practice to use a different password for each host. Write them down, as you will need them later when installing or updating your slave servers).

When this is done, you can exit MySQL with:

EXIT;

You can now log in to ISPConfig on https://panel.example.com:8080 with the username admin and the password the installer showed you.

2.3 Setting up the firewall

The last thing to do is to set up our firewall.

Log in to the ISPConfig UI, and go to System -> Firewall. Then click "Add new firewall record".

For the panel server, we have to open the following ports:

TCP:

22,80,443,8080,8081

No UDP ports have to be opened through the UI.

We are also going to open port 3306, which is used for MySQL, but only from our local network for security reasons. To do so, run the following command from the CLI, after the change from the ISPConfig panel is propagated (when the red dot is gone):

ufw allow from 10.0.64.0/24 to any port 3306 proto tcp

Your panel is now set up and ready for use.

In the next step, we will install the webserver.

Share this page:

Suggested articles

21 Comment(s)

Add comment

Comments

By: Mario

Excelent document ... Thanks ...

By: skyraisen

Installed with Ubuntu Desktop ~ Desktop & ISP Panel ~ awesome.

By: Tom

If i use the web01 server as panel, do i still need to create a root user per server with granted access to *? Because now my slave servers also have access to all the databases for my websites.

By: Thom Pol

Yes.

By: wwweiss

Absolute great tutorial. It saved me a lot of time!

I think there is a typo in 8.3. Should be ....we will disable the default.... instead of "enable".

Also the DocumentRoot did not work for me the specified folder ist not available. I set it like this:

DocumentRoot "/var/lib/roundcube"

By: Thom Pol

Thanks, resolved the typo.

 

The DocumentRoot can be different, on newer versions it's /var/lib/roundcube/public_html

By: nikos

My system removes additional settings on /etc/rspamd/local.d/options.inc

By: Thom Pol

I have resolved that now, it now uses a conf-custom file.

By: Alexis Sanchez

para cada host eu vou ter que instalar separadamente em uma instalação debian !ou em uma única instalação eu posso ter todos esses hosts ...

By: Vincent

Hey guys! Great Job btw, this guide makes installing ispconfig a breeze. The only problem I have is here, I used --use-nginx, and the guide specifies to change the document root for roundcube in apache settings. I tried changing it manually in /etc/nginx/sites-enabled/100-webmail.whatever.com.vhost without success, here is the error open_basedir restriction in effect. File(/var/lib/roundcube/public_html/index.php) is not within the allowed path(s) with a little more afterwards. So where can I find the permissions/restrictions that ISPConfig applies to clients/websites?Thanks again for everything you guys are doing!

By: Antonio

Is this currently working for vps? Thanks in advance !

By: till

Yes, this works fine on VPS. Just ensure you use full virtualization like KVM, as some things like Linux filesystem quota which is used on the webserver node, and also things like file system attributes will not fully work in container systems like LXC.

By: Markus

Why has every server his own sql server?It should be better, to use a sql Cluster for the database and get it away from the isp servers

By: till

Using a cluster MySQL server is not faster. You forgot the network latency in your calculations. Try it out on real setups and you will see that a local instance that is able to communicate over sockets is faster, plus having local MySQL instances is beneficial for redundancy as well. Using a clustered database makes sense when you have a single application that exceeds the processing or space capacities of the local database, and you can use such setups with ISPConfig as well. But as mentioned earlier, using a local database makes more sense for most setups.

By: Alex

Thanks for the great tutorial. Everything works fine, but when I try to login to roundcube it gives me the error: "Connection to IMAP Server failed" I'd appreciate any ideas how to solve this.

By: till

Please post your support questions here in the forum: https://forum.howtoforge.com/forums/installation-configuration.27/

By: Lupi

Perfect document. Thank you!!!

By: Someone

On page one we were instructed to: "We are also going to open port 3306, which is used for MySQL, but only from our local network for security reasons. To do so, run the following command from the CLI, after the change from the ISPConfig panel is propagated (when the red dot is gone):

ufw allow from 10.0.64.0/24 to any port 3306 proto tcp

"

But on this page we are attempting to use the fqdn of panel.example.com for sql to connect to on port 3306, which wont work, it either needs the local ip address of the server or that server needs its port 3306 open on the public ip, which is indicated is a security risk.  

Just wondering what the proper way forward is here?  Is there a firewall rule I can enter that will only allow connections to the other members in the pool or do I change the "MySQL master server hostname" to be the local ip of that server?

By: mcisar

I had started to use this tutorial to roll out some new servers for my environment.  Was in a bit of a crunch to get a webserver up and so did a quick rollout of just the panel server and web01 (for now).  I did not have an external IP address configured for the webserver (don't normally assign an external IP to the base machine as IPV4 is costly and wasteful when the IP will never be used) so the install failed on the letsencrypt bits and just failed over to a self-signed certificate. 

Is there a way to redo that part of the process after the fact to get the letsencrypt working?  

Which other servers in a multiserver config are going to need to have their own external IP's for this?  Can those external IP's be IPV6 instead of IPV4? 

 

By: MuttleyDoSomething

Brilliant tut for the most part, couldn't have got anywhere without it so thanks for that.

Getting a problem with every command that involves a DNS name (though I have set them up as you laid out) CREATE USER 'root'@'web01.mydomain.world' IDENTIFIED BY 'mypassword';GRANT ALL PRIVILEGES ON * . * TO 'root'@'web01.mydomain.world' IDENTIFIED BY 'mypassword' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;

ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'web01.<myactualdomain.com>'

Will take a look at this later, for now I hope IP's will do - they worked fine.

Thanks for this software, I really appreciate the tie and effort you put into this :D

By: Simon N

Dudes, the software you're writing is freekin' revolutionary. There's a project I'm working on right now that this would make a great part of.

 

Thanks for all your efforts!