The Perfect Load-Balanced & High-Availability Web Cluster With 2 Servers Running Xen On Ubuntu 8.04 Hardy Heron - Page 2
7. Apache/PHP5/Ruby (web1, web2)
7.1 Software installation
Now we install Apache:
apt-get install apache2 apache2-doc apache2-mpm-prefork apache2-utils libexpat1 ssl-cert
Next we install PHP5 and Ruby (both as Apache modules):
apt-get install libapache2-mod-php5 libapache2-mod-ruby php5 php5-common php5-curl php5-dev php5-gd php5-idn php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-mhash php5-ming php5-mysql php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl
7.2 Apache configuration
Next we edit /etc/apache2/mods-available/dir.conf :
vi /etc/apache2/mods-available/dir.conf
and change the DirectoryIndex line:
<IfModule mod_dir.c> #DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm DirectoryIndex index.html index.htm index.shtml index.cgi index.php index.php3 index.pl index.xhtml </IfModule>
Now we have to enable some Apache modules (SSL, rewrite, suexec, and include):
a2enmod ssl
a2enmod rewrite
a2enmod suexec
a2enmod include
Reload the Apache configuration:
/etc/init.d/apache2 force-reload
We will add some domains in the vhost configuration file :
mkdir /var/www/example
mkdir /var/www/yoursite
mkdir /var/www/example/web
mkdir /var/www/example/ssl
mkdir /var/www/yoursite/web
mkdir /var/www/yoursite/ssl
echo "Include /etc/apache2/vhosts.conf" >> /etc/apache2/apache2.conf
vi /etc/apache2/vhosts.conf
#NameVirtualHost 192.168.1.106:80 #<VirtualHost 192.168.1.106:80> # ServerName localhost # ServerAdmin root@localhost # DocumentRoot /var/www/sharedip #</VirtualHost> #NameVirtualHost 192.168.1.107:80 #<VirtualHost 192.168.1.107:80> # ServerName localhost # ServerAdmin root@localhost # DocumentRoot /var/www/sharedip #</VirtualHost> ###EXAMPLE.COM### <VirtualHost 192.168.1.106:80> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example/web SetEnvIf Request_URI \.jpg dontlog SetEnvIf Request_URI \.gif dontlog SetEnvIf Request_URI \.css dontlog SetEnvIf Request_URI \.png dontlog SetEnvIf Request_URI \.txt dontlog CustomLog /var/log/apache2/example.com-access.log combined env=!dontlog ErrorLog /var/log/apache2/example.com-error.log Redirect /webmail http://www.example.com:81/squirrelmail Redirect /squirrelmail http://www.example.com:81/squirrelmail ErrorDocument 400 /error/invalidSyntax.html ErrorDocument 401 /error/authorizationRequired.html ErrorDocument 403 /error/forbidden.html ErrorDocument 404 /error/fileNotFound.html ErrorDocument 405 /error/methodNotAllowed.html ErrorDocument 500 /error/internalServerError.html ErrorDocument 503 /error/overloaded.html </VirtualHost> <VirtualHost 192.168.1.106:81> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example/web SetEnvIf Request_URI \.jpg dontlog SetEnvIf Request_URI \.gif dontlog SetEnvIf Request_URI \.css dontlog SetEnvIf Request_URI \.png dontlog SetEnvIf Request_URI \.txt dontlog CustomLog /var/log/apache2/example.com-access.log combined env=!dontlog ErrorLog /var/log/apache2/example.com-error.log ErrorDocument 400 /error/invalidSyntax.html ErrorDocument 401 /error/authorizationRequired.html ErrorDocument 403 /error/forbidden.html ErrorDocument 404 /error/fileNotFound.html ErrorDocument 405 /error/methodNotAllowed.html ErrorDocument 500 /error/internalServerError.html ErrorDocument 503 /error/overloaded.html </VirtualHost> ### Un-comment this part if you will use SSL on this virtual host. ### Dont forget to create or copy certificate files before you restart apache. #<IfModule mod_ssl.c> #<VirtualHost 192.168.1.106:443> # ServerName example.com # ServerAlias www.example.com # DocumentRoot /var/www/example/web # SetEnvIf Request_URI \.jpg dontlog # SetEnvIf Request_URI \.gif dontlog # SetEnvIf Request_URI \.css dontlog # SetEnvIf Request_URI \.png dontlog # SetEnvIf Request_URI \.txt dontlog # CustomLog /var/log/apache2/example.com-access.log combined env=!dontlog # ErrorLog /var/log/apache2/example.com-error.log # SSLEngine on # SSLCertificateFile /var/www/example/ssl/www.example.com.crt # SSLCertificateKeyFile /var/www/example/ssl/www.example.com.key # SSLCertificateChainFile /var/www/example/ssl/www.example.com.key.org # Redirect /webmail http://www.example.com:81/squirrelmail # Redirect /squirrelmail http://www.example.com:81/squirrelmail # ErrorDocument 400 /error/invalidSyntax.html # ErrorDocument 401 /error/authorizationRequired.html # ErrorDocument 403 /error/forbidden.html # ErrorDocument 404 /error/fileNotFound.html # ErrorDocument 405 /error/methodNotAllowed.html # ErrorDocument 500 /error/internalServerError.html # ErrorDocument 503 /error/overloaded.html #</VirtualHost> #</IfModule> <VirtualHost 192.168.1.106:10001> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example/web SetEnvIf Request_URI \.jpg dontlog SetEnvIf Request_URI \.gif dontlog SetEnvIf Request_URI \.css dontlog SetEnvIf Request_URI \.png dontlog SetEnvIf Request_URI \.txt dontlog CustomLog /var/log/apache2/example.com-access.log combined env=!dontlog ErrorLog /var/log/apache2/example.com-error.log Redirect /webmail http://www.example.com:81/squirrelmail Redirect /squirrelmail http://www.example.com:81/squirrelmail ErrorDocument 400 /error/invalidSyntax.html ErrorDocument 401 /error/authorizationRequired.html ErrorDocument 403 /error/forbidden.html ErrorDocument 404 /error/fileNotFound.html ErrorDocument 405 /error/methodNotAllowed.html ErrorDocument 500 /error/internalServerError.html ErrorDocument 503 /error/overloaded.html </VirtualHost> <VirtualHost 192.168.1.106:20001> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example/web SetEnvIf Request_URI \.jpg dontlog SetEnvIf Request_URI \.gif dontlog SetEnvIf Request_URI \.css dontlog SetEnvIf Request_URI \.png dontlog SetEnvIf Request_URI \.txt dontlog CustomLog /var/log/apache2/example.com-access.log combined env=!dontlog ErrorLog /var/log/apache2/example.com-error.log Redirect /webmail http://www.example.com:81/squirrelmail Redirect /squirrelmail http://www.example.com:81/squirrelmail ErrorDocument 400 /error/invalidSyntax.html ErrorDocument 401 /error/authorizationRequired.html ErrorDocument 403 /error/forbidden.html ErrorDocument 404 /error/fileNotFound.html ErrorDocument 405 /error/methodNotAllowed.html ErrorDocument 500 /error/internalServerError.html ErrorDocument 503 /error/overloaded.html </VirtualHost> ###YOURSITE.COM### <VirtualHost 192.168.1.107:80> ServerName yoursite.com ServerAlias www.yoursite.com DocumentRoot /var/www/yoursite/web SetEnvIf Request_URI \.jpg dontlog SetEnvIf Request_URI \.gif dontlog SetEnvIf Request_URI \.css dontlog SetEnvIf Request_URI \.png dontlog SetEnvIf Request_URI \.txt dontlog CustomLog /var/log/apache2/yoursite.com-access.log combined env=!dontlog ErrorLog /var/log/apache2/yoursite.com-error.log Redirect /webmail http://www.yoursite.com:81/squirrelmail Redirect /squirrelmail http://www.yoursite.com:81/squirrelmail ErrorDocument 400 /error/invalidSyntax.html ErrorDocument 401 /error/authorizationRequired.html ErrorDocument 403 /error/forbidden.html ErrorDocument 404 /error/fileNotFound.html ErrorDocument 405 /error/methodNotAllowed.html ErrorDocument 500 /error/internalServerError.html ErrorDocument 503 /error/overloaded.html </VirtualHost> <VirtualHost 192.168.1.107:81> ServerName yoursite.com ServerAlias www.yoursite.com DocumentRoot /var/www/yoursite/web SetEnvIf Request_URI \.jpg dontlog SetEnvIf Request_URI \.gif dontlog SetEnvIf Request_URI \.css dontlog SetEnvIf Request_URI \.png dontlog SetEnvIf Request_URI \.txt dontlog CustomLog /var/log/apache2/yoursite.com-access.log combined env=!dontlog ErrorLog /var/log/apache2/yoursite.com-error.log ErrorDocument 400 /error/invalidSyntax.html ErrorDocument 401 /error/authorizationRequired.html ErrorDocument 403 /error/forbidden.html ErrorDocument 404 /error/fileNotFound.html ErrorDocument 405 /error/methodNotAllowed.html ErrorDocument 500 /error/internalServerError.html ErrorDocument 503 /error/overloaded.html </VirtualHost> ### Un-comment this part if you will use SSL on this virtual host. ### Dont forget to create or copy certificate files before you restart apache. #<IfModule mod_ssl.c> #<VirtualHost 192.168.1.107:443> # ServerName yoursite.com # ServerAlias www.yoursite.com # DocumentRoot /var/www/yoursite/web # SetEnvIf Request_URI \.jpg dontlog # SetEnvIf Request_URI \.gif dontlog # SetEnvIf Request_URI \.css dontlog # SetEnvIf Request_URI \.png dontlog # SetEnvIf Request_URI \.txt dontlog # CustomLog /var/log/apache2/yoursite.com-access.log combined env=!dontlog # ErrorLog /var/log/apache2/yoursite.com-error.log # SSLEngine on # SSLCertificateFile /var/www/yoursite/ssl/www.yoursite.com.crt # SSLCertificateKeyFile /var/www/yoursite/ssl/www.yoursite.com.key # SSLCertificateChainFile /var/www/yoursite/ssl/www.yoursite.com.key.org # Redirect /webmail http://www.yoursite.com:81/squirrelmail # Redirect /squirrelmail http://www.yoursite.com:81/squirrelmail # ErrorDocument 400 /error/invalidSyntax.html # ErrorDocument 401 /error/authorizationRequired.html # ErrorDocument 403 /error/forbidden.html # ErrorDocument 404 /error/fileNotFound.html # ErrorDocument 405 /error/methodNotAllowed.html # ErrorDocument 500 /error/internalServerError.html # ErrorDocument 503 /error/overloaded.html #</VirtualHost> #</IfModule>
The "SetEnvIf Request_URI ... " and "env=!dontlog" options are there to make logs cleaner, they will not log access to images and css files.
I use ISPConfig shareip files and error pages : HERE
Modify them to your needs.
First install wget :
apt-get install wget
cd /var/www
wget http://www.blogama.org/errorpages.tar.gz
tar -zxvf errorpages.tar.gz
rm -rf errorpages.tar.gz
chmod 755 /var/www/error/ -R
cp -av /var/www/error/ /var/www/example/web/
cp -av /var/www/error/ /var/www/yoursite/web/
We will now edit the file /etc/apache2/sites-available/default so that it doesn't log ldirectord (the load balancer) requests :
mv /etc/apache2/sites-available/default /etc/apache2/sites-available/default.bak
vi /etc/apache2/sites-available/default
And paste this :
NameVirtualHost * <VirtualHost *> ServerAdmin webmaster@localhost DocumentRoot /var/www/ <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/> Options FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory> ErrorLog /var/log/apache2/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn #CustomLog /var/log/apache2/access.log combined SetEnvIf Request_URI "^/ldirectord\.php$" dontlog SetEnvIf Request_URI "token" dontlog SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog SetEnvIf Request_URI \.ico dontlog CustomLog /var/log/apache2/access.log combined env=!dontlog ServerSignature On Alias /doc/ "/usr/share/doc/" <Directory "/usr/share/doc/"> Options Indexes MultiViews FollowSymLinks AllowOverride None Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 ::1/128 </Directory> </VirtualHost>
Now we will open some ports in apache that will be used later on :
vi /etc/apache2/ports.conf
Listen 80 Listen 81 Listen 10001 Listen 20001 <IfModule mod_ssl.c> Listen 443 </IfModule>
Port 10001 and 20001 will be used for monitoring. Port 81 will be for webmail.
We must restart apache to apply the modifications we made :
/etc/init.d/apache2 restart
7.3 Preparing the apache nodes for load balancing
Finally we must configure our Apache cluster nodes web1.example.com and web2.example.com to accept requests on the virtual IP addresses 192.168.1.106 and 192.168.1.107.
apt-get install iproute
Add the following to /etc/sysctl.conf:
vi /etc/sysctl.conf
# Enable configuration of arp_ignore option net.ipv4.conf.all.arp_ignore = 1 # When an arp request is received on eth0, only respond if that address is # configured on eth0. In particular, do not respond if the address is # configured on lo net.ipv4.conf.eth0.arp_ignore = 1 # Ditto for eth1, add for all ARPing interfaces #net.ipv4.conf.eth1.arp_ignore = 1 # Enable configuration of arp_announce option net.ipv4.conf.all.arp_announce = 2 # When making an ARP request sent through eth0 Always use an address that # is configured on eth0 as the source address of the ARP request. If this # is not set, and packets are being sent out eth0 for an address that is on # lo, and an arp request is required, then the address on lo will be used. # As the source IP address of arp requests is entered into the ARP cache on # the destination, it has the effect of announcing this address. This is # not desirable in this case as adresses on lo on the real-servers should # be announced only by the linux-director. net.ipv4.conf.eth0.arp_announce = 2 # Ditto for eth1, add for all ARPing interfaces #net.ipv4.conf.eth1.arp_announce = 2
Then run this:
sysctl -p
Add this section for the virtual IP address to /etc/network/interfaces:
vi /etc/network/interfaces
auto lo:0 iface lo:0 inet static address 192.168.1.106 netmask 255.255.255.255 pre-up sysctl -p > /dev/null auto lo:1 iface lo:1 inet static address 192.168.1.107 netmask 255.255.255.255 pre-up sysctl -p > /dev/null
Then run this:
Please note: after the following step you will probably get this error: SIOCSIFFLAGS: Cannot assign requested address
That is a normal bug and you can ignore it.
ifup lo:0
ifup lo:1
If you change the IP at a later stage its recommended to do ifup lo:0 then ifdown lo:0 then again ifup lo:0
Finally we must create the file ldirectord.php. This file is requested by the two load balancer nodes repeatedly so that they can see if the two Apache nodes are still running along with MySQL. I assume that the document root of the main apache web site on web1 and web2 is /var/www, therefore we create the file /var/www/ldirectord.php:
vi /var/www/ldirectord.php
and copy this :
<?php $dbhost = 'localhost'; $dbuser = 'ldirectord'; $dbpass = 'LDIRECTORD_PASSWORD'; $conn = mysql_connect($dbhost, $dbuser, $dbpass) or die ('Error connecting to mysql'); print "Connected to MySQL"; ?>
Later we will set up MySQL with local access to user "ldirectord", right now the file won't work.