As your website grows, there will be a point when there are more people accessing your web server than possible for a single server to handle. This is when load balancing will become a critical step in your Drupal setup. Load balancing increases reliability of your application in case a web server goes down and spreads the load across multiple web servers. In this tutorial, we are going to use HAProxy as a Layer 4 Load Balancer for our Drupal website. We will have a proxy server, two web servers, and one database server, all running on Ubuntu 14.04 LTS (Trusty Tahr) 32-bit.
The public will be able to access the proxy server; this server will then use an algorithm to redirect the user to a web server which will access the database server if needed and respond with generated web page or content requested.
In a production environment, there would be separate physical servers for each proxy, web, and database. However, for the sake of simplicity and availability, I will be using virtual machines.
Setting Up Vagrant
Vagrant is an easy tool you can use to quickly “create and configure lightweight, reproducible, and portable development environments.” Along with this, you will need to install VirtualBox to emulate these virtual machines.
Go ahead and create a folder for our Vagrant environment. For example, I will create mine at: C:\Users\{user-name}\Documents\Vagrant\drupal. Note: this directory will not contain any Drupal files.
Open up command prompt and run this command to download the Ubuntu 14.04 32-bit box:
1 |
vagrant box add ubuntu/trusty32 |
This will download the pre-configured box for VirtualBox which will reduce the time required to create our later virtual machines.
In this directory, lets initialize Vagrant. To do this, run:
1 |
vagrant init ubuntu/trusty32 --minimal |
This will create a configuration file called “Vagrantfile” in that directory. This file will define basic settings for our virtual machines such as box, hostname, and public/private IP. Throughout this tutorial, we will keep adding configurations for the different servers we are going to set up.
Setting Up Web Server 1
Lets get started with this Load Balancing Setup, but starting with both of our web servers. These web servers will be the actual computers processing the web page, while the proxy server will just forward the requests.
To start, lets edit our Vagrantfile to look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Vagrant.configure(2) do |config| # Sets up all virtual machines using this box. config.vm.box = "ubuntu/trusty32" # Agent forwarding over SSH connections is enabled config.ssh.forward_agent = true config.vm.define "web1" do |web1| # Sets hostname of server. config.vm.hostname = "web1" # Allows access to server from host machine. # 127.0.0.1:8884 (Your computer) ---> 192.168.50.4:80 (Server) config.vm.network :forwarded_port, guest: 80, host: 8884 # Sets IP for private network with other servers. config.vm.network "private_network", ip: "192.168.50.4", # Set name of the internal network. virtualbox__intnet: "intnet" end end |
We will set the option to set up all our virtual machines as Ubuntu 14.04. We will give this specific virtual machine, a host name of web1. Forwarding ports allows a machine only connected to a private network, and not a public network to be accessed by the host computer. So for example, we set up the port 8884 to redirect to port 80 on the guest. As a result, if we visit 127.0.0.1:8884 on our host computer, it will be forwarded to port 80 of that virtual machine. We have set the private IP as 192.168.50.4. This is the type of IP that web1 and all other servers to be set up will use to communicate with each other. We have set the internal network name to “intnet” which we will need to keep constant throughout all servers.
Once you have saved this, go ahead and start up this server using this command:
1 |
vagrant up web1 |
This will import the Ubuntu box, and configure the server according to our settings in Vagrantfile. This will take longer the first time since it has to get everything set up.
Once the virtual machine has booted up you can ssh into it using:
1 |
vagrant ssh web1 |
Installing Dependencies
Then lets update the package list and install the required software:
1 2 |
sudo apt-get update sudo apt-get install nginx php5-fpm php5-mysql php5-gd |
Before we start with downloading and running Drupal, we need to first configure PHP and Nginx.
Configuring PHP
Lets start with editing the configuration of php5-fpm:
1 |
sudo nano /etc/php5/fpm/php.ini |
In this file, find the option cgi.fix_pathinfo. By default, this value is set to 1. However, this is a security risk since you can access a file by typing in something that is close to it. Uncomment and change the value to 0:
1 |
cgi.fix_pathinfo=0 |
Now you can save and exit out of this file since we are done with it.
Next, lets edit pool.d/www.conf:
1 |
sudo nano /etc/php5/fpm/pool.d/www.conf |
Here, if not set to this value already, change the listen value to the php5-fpm unix domain socket:
1 |
listen = /var/run/php5-fpm.sock |
Save and exit. Now lets restart the php5-fpm process for these changes to take effect:
1 |
sudo service php5-fpm restart |
Configuring Nginx
It is time to configure our web server, Nginx. To start, lets make a copy of the default site config in the available sites. Then, lets edit it:
1 2 |
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/drupal sudo nano /etc/nginx/sites-available/drupal |
Now make changes accordingly so your drupal virtual hosts file looks like this in the server block(Note: only replace corresponding lines with lines below, do not simply copy and paste the code):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
server { # Listen for requests in port 80. listen 80; # Comment out IPv6 line. #listen [::]:80 default_server ipv6only=on; # Root of where our Drupal files will be located. root /var/www/drupal; # Order in which to look for index files. index index.php index.html index.htm; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; # Uncomment to enable naxsi on this location # include /etc/nginx/naxsi.rules } # redirect server not found pages to /404.html error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini try_files $uri =404; # With php5-cgi alone: #fastcgi_pass 127.0.0.1:9000; # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } } |
This will listen to all requests coming from port 80. We will also comment out the IPv6 line. Change the root to where you will have your Drupal files. I have set my root to /var/www/drupal. Uncomment the 404 and 50x error lines. Comment out the line under “# With php5-cgi alone” since we have installed php5-fpm. Add the line above “# With php5-cgi alone” in the example to immediately return a 404 if an exact match is not found.
Once you have completed this, lets remove the default virtual host from the enabled sites, and make a symbolic link of drupal to the enabled sites from the available sites:
1 2 |
sudo rm /etc/nginx/sites-enabled/default sudo ln -s /etc/nginx/sites-available/drupal /etc/nginx/sites-enabled/ |
Now that we have configured everything, lets restart the nginx service:
1 |
sudo service nginx restart |
Preparing Drupal
Lets go into our home directory and download the latest version of Drupal. I will be downloading 8.0.0-beta4. You can find the latest Drupal releases here.
1 2 |
cd ~ wget http://ftp.drupal.org/files/projects/drupal-8.0.0-beta4.tar.gz |
Once this is finished downloading, we can extract the contents:
1 |
tar xzvf drupal-8.0.0-beta4.tar.gz |
After the contents are extracted, we can now create the directory we defined as root in nginx. Lets create this folder and copy all the Drupal files to there:
1 2 |
sudo mkdir -p /var/www/drupal sudo cp -r ~/drupal-8.0.0-beta4/* /var/www/drupal |
Setting Permissions
Lets set the owner of all these files to our user account, in this case “vagrant”, and change the group to “www-data”, the web server user:
1 |
sudo chown -R vagrant:www-data /var/www/drupal |
Now lets also add our user to the www-data group, and give that group permission to read and write to all files:
1 2 |
sudo usermod -a -G www-data vagrant sudo chmod -R g+rw /var/www/drupal |
You should now be able to access the Drupal installation page by visiting 127.0.0.1:8884 which we set up in the port forwarding setting in the Vagrantfile. However, don’t install Drupal just yet! We still need to sync up both web servers.
Setting Up Web Server 2
There are two ways you can go about creating web server 2. You can either repeat the process of setting up web server 1 or you can create a clone of web server 1 and have vagrant set up the replica. I will be going with the latter.
First, lets create a replica box. To do this, halt your first webserver:
1 |
vagrant halt web1 |
Then, lets create a package of that virtual machine:
1 |
vagrant package web1 |
This command will package everything in web1 into your Vagrant directory as package.box.
Now, in your Vagrantfile, go ahead and add the configuration for web2:
1 2 3 4 5 6 7 8 9 10 |
config.vm.define "web2" do |web2| # Custom box name config.vm.box = "drupal-nginx-php" # Location of packaged box config.vm.box_url = "file:///C:/Users/{user-name}/Documents/Vagrant/drupal/package.box" config.vm.hostname = "web2" config.vm.network :forwarded_port, guest: 80, host: 8886 config.vm.network "private_network", ip: "192.168.50.5", virtualbox__intnet: "intnet" end |
You can give the box we just packaged a name like “drupal-nginx-php”. Set “config.vm.box_url” as the location of the package.box. We will be giving this machine a hostname of web2, port forwarding HTTP IP of 8886, and a private network IP of 192.168.50.5.
Now, lets start both of our servers again:
1 |
vagrant up web1 web2 |
Synchronizing Drupal Between Web Servers
We need to synchronize the Drupal folder between both servers so if an image or module gets uploaded on one server, it will not be broken if another user connecting to the other servers is looking for that content.
There are many solutions to syncing file on two different servers such as GlusterFS, and NFS. While using GlusterFS, the core directory in Drupal always replied with a Input/output error. As a result, I will be using Unison to sync files across web1 and web2. As an alternative you can also use a script I wrote that utilize inotifywait and scp to sync files.
The benefit of using inotifywait with scp is that it will only sync whenever there is a file modified, created, deleted, or moved. However, this option is unidirectional, so you will need to run it on both servers. On the other hand, Unison is bidirectional and can run on one server only.
Syncing with Unison
Start by installing unison on both machines:
1 |
sudo apt-get install unison |
Once installed, run the command which will create the folder “~/.unison”:
1 |
unison |
Now, on web1, lets make a copy the default profile and edit our drupal profile:
1 2 |
cp ~/.unison/default.prf ~/.unison/drupal.prf nano ~/.unison/drupal.prf |
Make your drupal profile for Unison look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# Folders to sync root = /var/www/drupal root = ssh://[email protected]//var/www/drupal # batch mode: ask no questions at all batch = true # automatically accept default (nonconflicting) actions auto = true # synchronize modification times times = true # synchronize owner owner = true # synchronize group attributes group = true |
Save and exit. You can find more settings in the Unison User Manual.
You only need one server running Unison since it syncs bidirectionally, so you only need to create this profile file on one machine. The root variables in this file will tell unison which folders to sync. Since the second folder to sync is on another server, we give it a absolute folder via ssh.
To sync both files you can run:
1 |
unison drupal |
The first time you run this, you might get a prompt asking you whether you want to add web2’s ECDSA key fingerprint to your known hosts. Type “yes”. It will also for the first time create archives of all the files which will take some time depending on the amount of files you have. For Drupal 8, it should take a minute or less.
However, there is a problem. This will only sync once and exit. We want unison to keep syncing the files. For this, we can use the -repeat
flag.
Still there is an issue if we just run this from our SSH client. First, once we start Unison with repeat, it will start, but we cannot run any other command without stopping Unison. Second, we need to keep our terminal open at all times. If we close our client, a HUP or hangup will be sent to the server, and Unison will be stopped.
The Solution? We can use screen
. We can start unison in screen and detach from it. Even if we exit our client, we can go back into the screen and see output from Unison.
If you do not already have screen installed:
1 |
sudo apt-get install screen |
Next you can start a new screen by typing:
1 |
screen |
It will look like your screen was cleared. Now lets starts unison with repeat mode set to watch, or whenever a file is updated:
1 |
unison drupal -repeat watch |
If repeat by watch does not work, you can set a value for how many seconds it should wait to sync again:
1 |
unison drupal -repeat 1 |
The above will sync the folders every second. You should keep it low when configuring Drupal, however once you have set up Drupal and don’t need constant syncing, you can increase the amount of time between each sync, set a cron job, or manually run the command whenever you update one server.
You can disconnect from the screen by keying Ctrl + A + D. This will keep the process running. If you ever want to reattach to the screen, get the screen id from the list:
1 |
screen -list |
Then, use the beginning characters of the screen to reattach:
1 |
screen -r {id} |
Note: If you only have one screen open, using -r will automatically reattach you to that screen.
Syncing with drupal_sync (inotifywait + scp)
If you want to use my Bash script you will first need to install inotify-tools:
1 |
sudo apt-get install inotify-tools |
Once you have done this, transfer this file over to your home (~) directory through SFTP or another method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#!/bin/bash SYNC_DIR="/var/www/drupal" REMOTE_USER="vagrant" REMOTE_HOST="192.168.50.5" LAST_MODIFY_TIME=0 do_start() { inotifywait -mr $SYNC_DIR --timefmt '%Y%m%d%H%M%S' --format '%T %e %w%f' -e create,modify,attrib,move,delete | while read time event file; do case $event in CREATE|MODIFY|MOVE_TO|CREATE,ISDIR) if [ $event = MODIFY ]; then if [ $LAST_MODIFY_TIME -ne 0 ]; then if [ $(($time - $LAST_MODIFY_TIME)) -lt 5 ]; then continue; fi; fi LAST_MODIFY_TIME=$time; continue fi fi if [ $event = CREATE,ISDIR ]; then exists=$(ssh $REMOTE_USER@$REMOTE_HOST "[ -d $file ] && echo 1 || echo 2") if [ $exists = 1 ]; then continue fi fi scp -rp $file $REMOTE_USER@$REMOTE_HOST:$file ;; ATTRIB|ATTRIB,ISDIR) perm=$(stat -c "%U %G" $file) permr=$(ssh $REMOTE_USER@$REMOTE_HOST "stat -c '%U %G' $file") if [ "$perm" != "$permr" ]; then echo $perm | while read owner group; do ssh $REMOTE_USER@$REMOTE_HOST "chown $owner:$group $file"; done fi ;; MOVE_FROM|DELETE|DELETE,ISDIR) exists=$(ssh $REMOTE_USER@$REMOTE_HOST "test -e $file && echo 1 || echo 0") if [ $exists = 1 ]; then ssh $REMOTE_USER@$REMOTE_HOST "rm -r $file" fi ;; esac done & echo "Drupal Sync Started" } do_stop() { if [ -z "$(pgrep inotifywait)" ]; then echo "Drupal Sync Process Never Started" else pkill inotifywait echo "Drupal Sync Process Killed" fi } show_status() { if [ -z "$(pgrep inotifywait)" ]; then echo "Drupal Sync is Not Running" else echo "Drupal Sync is Running" fi } case "$1" in start) do_start ;; stop) do_stop ;; status) show_status ;; restart|force-reload) do_stop do_start ;; *) echo "Usage: drupal_sync {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac |
Edit the variables at the top of the script to your server settings.
Before we can run this script, we need to add permissions to execute this file:
1 |
chmod +x ~/drupal_sync |
Now transfer it over to your other server with scp:
1 |
scp ~/drupal_sync vagrant@192.168.50.5:~/drupal_sync |
Note: you will also need to edit the variabled at the top of the script on the other server, web2, so that the “$REMOTE_HOST” is set to the private IP of web1.
We can run the file, however every time it will prompt you for the other server’s ssh password. To allow automatic access we need to make a pair of SSH keys:
1 |
ssh-keygen -t rsa |
Do not give a name, or pass-phrase, just press enter.
Once you have generated a pair of RSA keys, we need to add the public key to the authorized keys of the other server:
1 |
cat ~/.ssh/id_rsa.pub | ssh vagrant@192.168.50.5 'cat >> ~/.ssh/authorized_keys' |
Now, after you complete this command by typing in the password of [email protected] again, the next time you ssh you should automatically be connected:
1 |
ssh vagrant@192.168.50.5 |
If you are taken to a new SSH screen, congratulations it has worked, to exit back into your other server:
1 |
exit |
Now repeat this process of generating RSA keys from web2 to web1, so web2 can access web1 without being prompted for a password.
Once both of your servers can SSH to each other automatically, you can start the drupal sync script on both servers:
1 |
~/drupal_sync start |
Setting Up The Database Server
Now that we have successfully set up and synced both of our web servers, web1 and web2, it is time to set up the database server that is going to be accessed by both.
Start by adding the virtual machine settings in Vagrantfile:
1 2 3 4 5 |
config.vm.define "db" do |db| config.vm.hostname = "db" config.vm.network "private_network", ip: "192.168.50.6", virtualbox__intnet: "intnet" end |
We will give this server a host name of db and a private IP of 192.168.50.6.
Lets get the database server up and running:
1 |
vagrant up db |
Installing MySQL
Once the virtual machine has booted, lets ssh into the server, update package list, and install MySQL server:
1 2 3 4 |
vagrant ssh db sudo apt-get update sudo apt-get install mysql-server |
While this is installing, it will ask you to make and confirm your root user password, make this complex!
Once this has finished install, we need to run the actual MySQL installation:
1 |
sudo mysql_install_db |
By default, many things will be included in this install for testing. To be more secure, run this command:
1 |
sudo mysql_secure_installation |
Configuring MySQL
As of right now, MySQL will only accept connections coming from the same computer, so we need to allow for it to accept connections from outside by enabling remote access.
Lets edit the MySQL configuration file:
1 |
sudo nano /etc/mysql/my.cnf |
Under the section [mysqld] change the value of bind-address from localhost to the private IP of the db server.
1 |
bind-address = 192.168.50.6 |
When you are finished, save and close out of the editor. Next, lets restart the MySQL server for the changes to take effect:
1 |
sudo service mysql restart |
Creating MySQL Database & Users
Now that we have MySQL listening to a private IP that our web servers can access, we need to create MySQL users for our web servers.
Log in to MySQL as the root user with the password we set earlier:
1 |
mysql -u root -p |
First, lets create our drupal database:
1 |
CREATE DATABASE drupal CHARACTER SET utf8 COLLATE utf8_general_ci; |
Now lets create users for both web servers:
1 2 |
CREATE USER 'drupal_user'@'192.168.50.4' IDENTIFIED BY 'password'; CREATE USER 'drupal_user'@'192.168.50.5' IDENTIFIED BY 'password'; |
The IP following the name of your user should be the private IP’s of your web servers. I have set the password as “password” for both my users, however you should change it to something much more secure.
The last thing we need to do is grant privileges to these users at their respective IP address. For Drupal, you need to give these privileges to your users:
1 2 |
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON drupal.* TO 'drupal_user'@'192.168.50.4'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON drupal.* TO 'drupal_user'@'102.168.50.5'; |
Once done, flush privileges and exit:
1 2 3 |
FLUSH PRIVILEGES; exit |
Our database server, db, is now configured and ready to be used by web1 and web2.
Setting Up The Proxy / Load Balancing Server
The only server left to set up is the load balancing server which acts as a proxy to both web servers. This may be the last to be set up, but certainly the most critical in this setup.
Lets add the server config to our Vagrantfile:
1 2 3 4 5 6 7 8 |
config.vm.define "balancer" do |balancer| config.vm.hostname = "balancer" config.vm.network :forwarded_port, guest: 80, host: 9090 # We want to be assinged a public IP config.vm.network "public_network" config.vm.network "private_network", ip: "192.168.50.7", virtualbox__intnet: "intnet" end |
This server will have a host name of balancer. We have also declared a private IP of 192.168.50.6 and forward port 80 to port 9090 in our local machine. Once important different between the rest of the other server and this server is the fact we set in the configuration that we want to be connected to the public network. This will automatically assign and public IP to the server. We can then access this server at that IP from our host machine.
Lets start up the balancer server:
1 |
vagrant up balancer |
Since we have set this server to connect to the public network, it might ask you to choose an adapter. Try the first one, if it doesn’t work, halt and up balacer again, then choose the other option/s. For me, my Wi-Fi Adapter worked.
Finding the Public IP
Once the server has booted up, notice the order of your network adapters, it should look something like this:
1 2 3 4 |
==> balancer: Preparing network interfaces based on configuration... balancer: Adapter 1: nat balancer: Adapter 2: bridged balancer: Adapter 3: intnet |
Find where the “bridged” adapter is. Mine is set as bridged for Adapter 2.
Next, lets ssh into the balancer server.
1 |
vagrant ssh balancer |
To get our IP configuration, lets run this command:
1 |
ifconfig |
Since my second adapter was the bridged network, I will look at the second link: eth1 for my IP address. It will be printed after “inet addr”. My public IP for the balancer is 192.168.1.110. This will be the IP we will use to connect to the balancer/proxy in our browser.
Installing HAProxy
Now, lets update package list, and install haproxy:
1 2 |
sudo apt-get update sudo apt-get install haproxy |
Configuring HAProxy
Lets make it so that HAProxy will start on every boot of the server:
1 |
sudo nano /etc/default/haproxy |
In this file, change the value of “ENABLED” to 1.
1 |
ENABLED=1 |
Save this file and exit.
Now, it’s time to set up the main HAProxy configuration:
1 |
sudo nano /etc/haproxy/haproxy.cfg |
We will let the global settings stay the same. Under “defaults”, change the mode and option from “http” to “tcp”:
1 2 3 4 5 |
defaults ... mode tcp option tcplog ... |
Replacing “http” with “tcp” will tell HAProxy that we are going to be using a Layer 4 Load Balancing.
Next, we need to make a frontend, the balancer, with the address to listen, and which backend to point to. The frontend is the server the public can access, and the backend are servers that cannot be directly accessed, like web1 and web2. Add the www frontend:
1 2 3 |
frontend www bind 192.168.1.110:80 default_backend drupal-backend |
You want to bind the public IP with port 80. So, whenever someone requests at port 80 to that public IP, it will use the default backend, “drupal-backend”. Now, lets define “drupal-backend”:
1 2 3 4 5 |
backend drupal-backend balance roundrobin mode tcp server webserver1 192.168.50.4:80 check server webserver2 192.168.50.5:80 check |
Here, we have defined that we want to use the round robin algorithm to chose a server for the request. There are many algorithms you can choose from. Here are a few:
- roundrobin – “Each server is used in turns, according to their weights.”
- leastconn – “The server with the lowest number of connections receives the connection.”
- source – “The source IP address is hashed and divided by the total weight of the running servers to designate which server will receive the request. This ensures that the same client IP address will always reach the same server as long as no server goes down or up.”
- uri – “This algorithm hashes either the left part of the URI (before the question mark) or the whole URI (if the “whole” parameter is present) and divides the hash value by the total weight of the running servers. … This ensures that the same URI will always be directed to the same server as long as no server goes up or down.”
You can find more algorithms in the HAProxy Configuration Manual.
Again, the mode as “tcp” will specify we want Layer 4 and not Layer 7 Load Balancing. We also define our two servers with names “webserver1” and “webserver2”. The check is added at the end to check the health of the server before sending the request there. If one server fails, the other server will be sent all the requests.
We are done configuring HAProxy, so lets save and exit.
HAProxy Logging
If you want to enable logging, you need to edit /etc/rsyslog.conf:
1 |
sudo nano /etc/rsyslog.conf |
Find and uncomment the first two lines, then add the third line:
1 2 3 |
$ModLoad imudp $UDPServerRun 514 $UDPServerAddress 127.0.0.1 |
Logging will now be enabled, and HAProxy logs can be viewed at: /var/log/haproxy.log once started.
When you are done editing this file, save and exit. Now, restart both rsyslog and haproxy services:
1 2 |
sudo service rsyslog restart sudo service haproxy restart |
Installing Drupal
We are finally at the last step of getting Drupal working on a Load Balanced setup. It is time to install Drupal.
You should now be able to see the Drupal installation page when you visit the public IP of your load balancing server from your host machine.
Once you click “Save and continue” on the Profile selection page, settings.php and services.yml should appear in /var/www/drupal/sites/default/.
By default, Drupal will not be able to edit these as necessary because it does not have permission to write to these files as it’s user www-data. Since we set the group permissions to www-data, we need to give the group write permissions on these files:
1 2 |
sudo chmod g+w /var/www/drupal/sites/default/settings.php sudo chmod g+w /var/www/drupal/sites/default/services.yml |
Once done with the process, it is recommended you remove write permissions to keep your site secure:
1 2 |
sudo chmod g-w /var/www/drupal/sites/default/settings.php sudo chmod g-w /var/www/drupal/sites/default/services.yml |
You can now continue with the installation. Once the database options come up, you need to specify the private IP, database, user, and password we made during the MySQL Database server setup.
Again, follow the configuration of Drupal, and you should soon come to your new Drupal install on a Layer 4 Load Balanced Setup using HAProxy.
Conclusion
There you go, we now have a fully functional Layer 4 Load Balacing Setup using 4 servers running Drupal. As your traffic increases, this setup will reduce load on your servers by spreading your users out to different servers. It can also be fail-safe. If one day you wake up to find one of your servers down, throughout the night all your traffic was being sent to the other available server/s, so your users wouldn’t have experienced any downtime with your website.
To test if the load balancing is working and/or with your algorithm of choice, you can view the logs we enabled during the HAProxy server setup at /var/log/haproxy.log.
This blog post was made for Google Code-In 2014. This task has by far been the most challenging, and I have truly expanded my knowledge on Linux servers and Unix commands.
Troubleshooting
If you try running the command vagrant, and you get a response that says the command could not be found, try appending the directory of where vagrant.exe exists to the “PATH” variable in your System/User Environment Variables.
If you are having trouble when running vagrant ssh, this is because there is no ssh command on Windows by default. Luckily, if you have git, you can add the {git-directory}/bin to your System/User Evironment Variables to get access to many commands such as ssh, and ls on Windows. if you do no have git installed, you can use PuTTY to SSH to your server at 127.0.0.1:2200, or the assigned forwarded port for SSH.
If you get 50x errors while visiting your HTTP forwarded ports on web1 or web2, and have this in your nginx logs: “*1 connect() to unix:/var/run/php5-fpm.sock failed (13: Permission denied)”, you need to edit /etc/php5/fpm/pool.d/www.conf and uncomment these lines:
1 2 3 |
listen.owner = www-data listen.group = www-data listen.mode = 0660 |
If you get PHP Fatat errors such as: “Unexpected [, expecting )”, this is because you have installed a version of php5-fpm below PHP 5.4. This error means your PHP version does not support short-hand array notation in PHP. Solution is to find a PPA to update your PHP version to 5.4+ or update to Ubuntu 14.04 which should have PHP 5.4+ with php5-fpm.
I wonder if you have considered write-split problem when load balancing mysql operations. In principle, you can load balance mysql reads but not mysql writes and Drupal needs to be modified to separate database read and write operations to take advantage DB load balancing (especially read).