Where to start

For our scenario we have purchased 2 vps and a balancer from OVH, the vps deployed are Ubuntu 18.04. In this post we will not talk about the balancer itself, as each service provider uses different dashboards and technologies so we focus on the vps that will be behind.

The first thing we do is to change the root password of each VPS so that they are identical and we don't go crazy.

We authorize root to login by ssh:

nano /etc/ssh/sshd_config

we look for root and where it says PermitRootLogin we change it to yes, also for the following configurations that we will do we make sure in this file to configure the following.

RSAAuthentication yes

PubkeyAuthentication yes

StrictModes yes

Restart the service

service sshd restart

Edit the /etc/hosts file of all servers to point to all servers other than the same one with a short name, e.g. vps1,vps2,vps3,...., leaving

ip.ip.ip.ip vps1

ip.ip.ip.ip vps2

ip.ip.ip.ip vps3

We generate an ssh key in all vps with:


We copy this key to all the hosts that we have added in the hosts file:

ssh-copy-id [email protected]

ssh-copy-id [email protected]

ssh-copy-id [email protected]

ssh-copy-id ….

As we have set the StrictModes to yes we need to set the permissions of the path $HOME/.ssh/authorized_keys. This file must have permissions 600 and the .ssh directory must have permissions 700, this is a way of securitizing to make sure that the public keys are not compromised, you can also leave it set to no and you would not have to perform this step but it would be less secure, now we are fine tuning points.

chmod 600 ~/.ssh/authorized_keys

chmod 700 ~/.ssh/

Once we have done all the authentication issue and as in any other deployment we first update all the vps, everything that are common tasks we could use some tool, I for example in Linux I use Asbru since it allows us to create a cluster of servers and all the commands we execute in a console will be reflected in the others, as a good time optimizer the less I write the better hehe.

apt update -y

apt upgrade -y

We start to install:

apt install apache2 libapache2-mod-fastcgi -y

Depending on your distribution you may have to download it, for example for Ubuntu 18.04, remembering as always in our posts that whatever is going to be garbage we do it in /tmp and if it does not exist the previous command will not install apache2 and we will have to install it again.

cd /tmp && wget http://mirrors.kernel.org/ubuntu/pool/multiverse/liba/libapache-mod-fastcgi/libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb

apt install apache2 && dpkg -i libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb; sudo apt install -f

It may be that the version of php you want to use is not in the repositories of the distribution to use either, if so for example for Debian and Ubuntu

apt install software-properties-common -y

add-apt-repository ppa:ondrej/php

apt update

As a note in Centos/RHEL install the fedoraproject repo and remi

Now everyone install the php-fpm version corresponding to your project and its necessary modules, in our case for a wordpress we use the version 7.2 and the following modules, in case you want for example the php7.3 version replace 7.2 by 7.3 in all the following line.

apt-get install php7.2 php7.2-fpm php7.2-mysql php7.2-mbstring php7.2-curl php7.2-dom php7.2-gd php7.2-xml php7.2-xmlrpc php7.2-zip php7.2-soap php7.2-intl php7.2-common php7.2-bcmath php7.2-imagick -y

We enable Apache and SSH in the firewall and activate it:

ufw allow in "Apache Full"

ufw allow in "Apache"

ufw allow in "OpenSSH"

ufw enable

We activate the installed and some more apache modules:

a2enmod proxy_fcgi setenvif actions alias rewrite

a2enconf php7.2-fpm

a2enmod http2 headers cache cache_disk expires proxy_https2 ssl

systemctl restart apache2

systemctl start apache-htcacheclean

We change the mpm prefork to event for better performance and reload Apache:

a2dismod mpm_prefork

a2enmod mpm_event

systemctl reload apache2

We check that the MPM is not in prefork, if it says Server MPM: and empty it is ok.

apache2 -V

Edit the apache address file:

nano /etc/apache2/mods-enabled/dir.conf

in it we write the following:

DirectoryIndex index.php index.cgi index.pl index.html index.xhtml index.htm

We create the following file:

nano /etc/apache2/sites-available/web.conf

with the following content, we must replace the serverN by the number that touches, in addition to the documentroot where will be located the files of the web and the logs to identify this web in case of having more sites on the same server, in our case we will use /var/www/html, as we will use lsyncd and its home will be /var/www, not activate any site in root for security, as the directory .ssh of www-data will be in /var/www

ServerName servidorN.dominioweb.com

DocumentRoot /var/www/html/

<Directory "/var/www/html">

Options Indexes FollowSymLinks MultiViews

AllowOverride All

Require all granted

ErrorLog ${APACHE_LOG_DIR}/dominioweb_error.log

CustomLog ${APACHE_LOG_DIR}/dominioweb_access.log combined

RewriteEngine on

RewriteCond %{SERVER_NAME} =servidorN.dominioweb.com

RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

We create the following file for ssl:

nano /etc/apache2/sites-available/webssl.conf

with the following content

ServerAdmin [email protected]

DocumentRoot /var/www/html

ErrorLog ${APACHE_LOG_DIR}/dominioweb_error.log

CustomLog ${APACHE_LOG_DIR}/dominioweb-access.log combined

SSLEngine on

SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem

SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

<FilesMatch "\.(cgi|shtml|phtml|php)$">

SSLOptions +StdEnvVars

SSLOptions +StdEnvVars

Enable the sites and deactivate the default site

a2ensite web webssl && a2dissite 000-default && systemctl reload apache2

We move on to edit the php config files:

nano /etc/apache2/mods-enabled/mpm_event.conf

We configure it like this for a server with a 1 core and 2 gb of ram, there are many tutorials on the web so we will not go into detail but you have to adjust it to get the best performance:

ServerLimit 16

StartServers 4

MinSpareThreads 25

MaxSpareThreads 75

ThreadLimit 64

ThreadsPerChild 25

MaxRequestWorkers 150

MaxConnectionsPerChild 0

We changed the php7.2-fpm configuration to extend some limits and not to have problems in the wordpress installation:

nano /etc/php/7.2/fpm/php.ini

We look for the following lines and leave them with these values or to the consumer's taste:

upload_max_filesize = 64M

post_max_size = 70M

max_execution_time = 300

Restart Apache and PHP

service apache2 restart

service php7.2-fpm restart

We upload the wordpress file by scp to one of the servers in /var/www/ in our case

scp wordpress.zip [email protected]:/var/www/

or we use wget from /var/www/ to download the latest version

wget https://es.wordpress.org/latest-es_ES.zip

Install unzip if not already installed

apt install unzip -y

We unzip it being in the server path /var/www:

unzip latest-es_ES.zip

and move it to html which is where our sites point to

rm -rf html

mv wordpress html

We install wordpress and change the ownership and permissions of all files inside the folder using wordpress best practices being in the /var/www/html folder:

cd /var/www/html

chown www-data:www-data -R /var/www/html

find . -type d -exec chmod 755 {} \;

find . -type f -exec chmod 644 {} \;

chmod 600 wp-config.php

We create the index2.html file in each server, it will serve as a probe to know that the server is up:

nano index2.html

Its content will be the following (change N for the server number):

Test Ok! Servidor N

We change the owner of the file:

chown www-data:www-data index2.html

We install wordpress as usual and after the installation we copy all the content to the other server.

rsync -r /var/www/html* vps2:/var/www/html/.

rsync -r /var/www/html* vps3:/var/www/html/.

rsync -r /var/www/html* ...:/var/www/html/.

Now we will synchronize the vps with lsyncd, for this we first install it:

apt install lsyncd -f

Create the /etc/lsyncd/ folder with the following command:

mkdir /etc/lsyncd

We create the configuration file in that folder:

nano /etc/lsyncd/lsyncd.conf.lua

with the following content to point to the servers that we want to synchronize changing the targetlist in each node according to who it is, leaving it something like this:

settings {

logfile = "/var/log/lsyncd/lsyncd.log",

statusFile = "/var/log/lsyncd/lsyncd.status",


www_target_list = {




--Watch out if we add more servers, the last one is the only one without comma at the end.


for _, server in ipairs(www_target_list) do

sync {


source = "/var/www/html",

target = server,

delete = "running",

delay = 1,

exclude = { "wp-config.php", "index2.html" },

rsync = {

rsh = "ssh -l www-data -i /var/www/.ssh/id_rsa",




We must also create the folder /var/log/lsyncd with the following command we create the folder and the files:

mkdir /var/log/lsyncd

touch /var/log/lsyncd/lsyncd.{log,status}

Then we define a password for www-data like this:

passwd www-data

We install rssh:

apt-get install rssh

Edit the configuration file:

nano /etc/rssh.conf

To remove comments from the following lines:



Edit the /etc/passwd file

nano /etc/passwd

and replace the www-data line with this one:


Edit the ssh file to allow login to www-data:

nano /etc/ssh/sshd_config

And we go to the bottom and add this line:

AllowUsers www-data root

If you have more users accessing via ssh add them with spaces after root

Now that we have the user www-data logable we do the following where serverN is the name of the server we want to access with www-data:

su www-data


ssh-copy-id vps2

ssh-copy-id vps3

ssh-copy-id vpsx

We do this on each server to be able to synchronize files between them and run exit in the console to return to root, edit /etc/passwd and now we restrict it by replacing the line where www-data is with this other one


We activate lsync:

service lsyncd start

We check for errors with:

service lsyncd status

And we create a test file inside the folder to see what is created on the other server:

touch prueba.html

Once we are on the sidewalk, we install the mailsutils:

apt install -y mailutils

Select "Internet Site".

we type: dominioweb.com

Edit the file /etc/postfix/main.cf

nano /etc/postfix/main.cf

We go to the bottom and where it says inet_interfaces = all we replace it with:

inet_interfaces = loopback-only

Restart postfix:

systemctl restart postfix

And finally the certificates, if you do not want to complicate your life in this scenario use the free service of cloudflare as it is a joy which provides us with their certificates and on the server with the self-signed more than enough choosing the flexible option of the ssl part in cloudflare, saving us work and trouble because they have changed for example the version of the API if we use Lets encrypt.

Miguel A. Romero in collaboration with TL.

WP Rocket - WordPress Caching Plugin
Ledger Nano X - The secure hardware wallet

WP Rocket - WordPress Caching Plugin
Ledger Nano X - The secure hardware wallet
No hay comentarios

Comenta la entrada