{"id":1137,"date":"2012-08-27T15:38:24","date_gmt":"2012-08-27T07:38:24","guid":{"rendered":"http:\/\/rmohan.com\/?p=1137"},"modified":"2012-08-27T15:38:24","modified_gmt":"2012-08-27T07:38:24","slug":"multi-site-dynamic-apache-configurations","status":"publish","type":"post","link":"https:\/\/mohan.sg\/?p=1137","title":{"rendered":"Multi-Site Dynamic Apache Configurations"},"content":{"rendered":"<p>In a continuing effort to make my hosting cloud more dynamic, I have had to become relatively creative with my Apache configurations so that my farm can remain relatively flexible with little or no reconfiguration on newly introduced servers. This presents a big problem when working with a multi-site Apache configuration, and an even bigger problem when SSL certificates are involved. As many of you probably already know, you need to have one network interface (virtual or physical) dedicated to a particular domain SSL certificate. It\u2019s easy enough to grab a wildcard SSL certificate from GoDaddy and bind a single network interface to all subdomains, but when you have a farm configuration where you\u2019re hosting multiple domains from the same web servers, then you\u2019ll need to have a dedicated NIC for each wildcard domain SSL certificate. That\u2019s ok, we can handle this by creating virtual NICs (eth0:1) and giving them their own IP address, and Apache is none the wiser. But, this is where our Apache configuration starts to become a problem. With Apache, we know that we can listen by IP address, but not by interface, so in order for us to keep a common configuration between all of the servers in our farm, we\u2019ll need to figure out a way for it to be able to dynamically handle binding when the IP address is not statically defined.<\/p>\n<p>If you\u2019re not fully understanding the issue right now, that\u2019s ok. Let me outline the environment consideration a little bit better with a pseudo-diagram:<\/p>\n<pre>                Load Balancer -\r\n                VIP1 = 10.1.1.2 (www.example1.com)\r\n                                              - www01.example1.com\r\n                                              - www02.example1.com\r\n                                              - www03.example1.com\r\n                VIP2 = 10.1.1.3 (www.example2.com)\r\n                                              - www01.example2.com\r\n                                              - www02.example2.com\r\n                                              - www03.example2.com\r\n\r\n                SERVER1:\r\n                www01.example1.com:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0www01.example2.com:\r\n                \\\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0 \u00a0     \/\r\n                eth0 = 10.1.1.10\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 eth0:1 = 10.1.1.11\r\n\r\n                SERVER2:\r\n                www02.example1.com:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0www02.example2.com:\r\n                \\                                                   \/\r\n                eth0 = 10.1.1.20\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 eth0:1 = 10.1.1.21\r\n\r\n                SERVER3:\r\n                www03.example1.com:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0www03.example2.com:\r\n                \\                                                   \/\r\n                eth0 = 10.1.1.30  \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 eth0:1 = 10.1.1.31\r\n<\/pre>\n<p>This is a relatively common and efficient setup, and in fact may be extrapolated by many more sites and domains hosted from the same server farms. Our Apache configuration is relatively simple to setup by telling the VirtualHost sections what IP to listen on, as such (www01 example):<\/p>\n<pre>Listen 10.1.1.10:80\r\n&lt;VirtualHost 10.1.1.10:80&gt;\r\n        DocumentRoot \/var\/www\/example1_root\r\n        CustomLog logs\/www.example1.com-access_log combined\r\n        ErrorLog logs\/www.example1.com-error_log\r\n&lt;\/VirtualHost&gt;\r\n\r\nListen 10.1.1.11:80\r\n&lt;VirtualHost 10.1.1.11:80&gt;\r\n        DocumentRoot \/var\/www\/example2_root\r\n        CustomLog logs\/www.example2.com-access_log combined\r\n        ErrorLog logs\/www.example2.com-error_log\r\n&lt;\/VirtualHost&gt;\r\n<\/pre>\n<p>The problem with this setup is that as we deploy a new box into the farm, we\u2019ll need to reconfigure Apache to listen on the new IP addresses that it gets for it\u2019s eth0 and eth0:1 \u2026 That\u2019s ok, and really can be done with relative ease, but what if we want to have it so that we can deploy a new box (say, from VMware template?) with a preloaded configuration, and have it just work (mmm, Linked Clones anyone? <img decoding=\"async\" src=\"http:\/\/www.rhcedan.com\/wp-includes\/images\/smilies\/icon_smile.gif\" alt=\":)\" \/> )? For this case, we\u2019ll need to completely redesign the way that our Apache configuration is structured so that we don\u2019t need to do any configuration after a box is deployed, and so that we can have a common configuration between www01,www02,www03, etc\u2026 This is nice for management too because we\u2019ll always know that each farm server has the same configuration, and we\u2019ll never have to worry about typos or anything like that. Sounds nice, so I\u2019ll stop the suspense.<\/p>\n<p>Now, Apache gives us the nice and native ability to import environment variables into our configuration, which means that we can figure out everything that we need for our configuration prior to it being loaded, and pass those values on. This means, through our advanced (eh?) bash scripting skills, that we can figure out what the IP addresses of our interfaces are, populate an environment variable, and pass that knowledge on to Apache. We\u2019ll start with \/etc\/sysconfig\/httpd. From the httpd startup script, \/etc\/sysconfig\/httpd gets inherited prior to loading the Apache configuration, so we can declare in here any variables that we will need and they will be retained within Apache\u2019s execution scope.<\/p>\n<p>The bare metal\u2026<\/p>\n<p>\/etc\/sysconfig\/httpd:<\/p>\n<pre># Configuration file for the httpd service.\r\n\r\n#\r\n# The default processing model (MPM) is the process-based\r\n# 'prefork' model.  A thread-based model, 'worker', is also\r\n# available, but does not work with some modules (such as PHP).\r\n# The service must be stopped before changing this variable.\r\n#\r\n#HTTPD=\/usr\/sbin\/httpd.worker\r\n\r\n#\r\n# To pass additional options (for instance, -D definitions) to the\r\n# httpd binary at startup, set OPTIONS here.\r\n#\r\n#OPTIONS=\r\n\r\n#\r\n# By default, the httpd process is started in the C locale; to\r\n# change the locale in which the server runs, the HTTPD_LANG\r\n# variable can be set.\r\n#\r\n#HTTPD_LANG=C\r\n\r\nIPADDR_ETH0=$(ifconfig eth0 | grep inet | grep -v inet6 | awk '{print $2}' | sed -e s\/addr:\/\/g)\r\nIPADDR_ETH01=$(ifconfig eth0:1 | grep inet | grep -v inet6 | awk '{print $2}' | sed -e s\/addr:\/\/g)\r\n\r\nexport IPADDR_ETH0 IPADDR_ETH01\r\n<\/pre>\n<p>\/etc\/httpd\/conf.d\/vhosts.conf:<\/p>\n<pre> # Pass in our environment variables where we've defined the IP addresses\r\n # for each of our NICs\r\n PassEnv IPADDR_ETH0\r\n PassEnv IPADDR_ETH01\r\n\r\n # Listen on 80 and 443 on our www0x.example1.com NIC\r\n NameVirtualHost ${IPADDR_ETH0}:80\r\n NameVirtualHost ${IPADDR_ETH0}:443\r\n\r\n # Listen on 80 and 443 on our www0x.example2.com NIC\r\n NameVirtualHost ${IPADDR_ETH01}:80\r\n NameVirtualHost ${IPADDR_ETH01}:443\r\n\r\n # Redirect all of our hosts to HTTPs -- Regular HTTP is soooo lame <\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/www.rhcedan.com\/wp-includes\/images\/smilies\/icon_smile.gif\" alt=\":)\" \/><\/p>\n<pre> &lt;VirtualHost ${IPADDR_ETH0}:80&gt;\r\n     RewriteEngine on\r\n     RewriteRule ^\/(.*)$ https:\/\/%{HTTP_HOST}\/$1 [L,R]\r\n &lt;\/VirtualHost&gt;\r\n\r\n &lt;VirtualHost ${IPADDR_ETH01}:80&gt;\r\n     RewriteEngine on\r\n     RewriteRule ^\/(.*)$ https:\/\/%{HTTP_HOST}\/$1 [L,R]\r\n &lt;\/VirtualHost&gt;\r\n\r\n # www.example1.com SSL example\r\n &lt;VirtualHost ${IPADDR_ETH0}:443&gt;\r\n     DocumentRoot \/var\/www\/example1\r\n     CustomLog logs\/${HTTP_HOST}-access_log combined\r\n     ErrorLog logs\/${HTTP_HOST}-error_log\r\n     TransferLog logs\/${HTTP_HOST}-access_log\r\n     SSLEngine on\r\n     SSLCertificateFile \/etc\/httpd\/conf.d\/certs\/_.example1.com.crt\r\n     SSLCertificateKeyFile \/etc\/httpd\/conf.d\/certs\/example1.com.key\r\n     SSLCertificateChainFile \/etc\/httpd\/conf.d\/certs\/gd_bundle.crt\r\n &lt;\/VirtualHost&gt;\r\n\r\n # www.example2.com SSL example\r\n &lt;VirtualHost ${IPADDR_ETH01}:443&gt;\r\n     DocumentRoot \/var\/www\/example2\r\n     CustomLog logs\/${HTTP_HOST}-access_log combined\r\n     ErrorLog logs\/${HTTP_HOST}-error_log\r\n     TransferLog logs\/${HTTP_HOST}-access_log\r\n     SSLEngine on\r\n     SSLCertificateFile \/etc\/httpd\/conf.d\/certs\/_.example2.com.crt\r\n     SSLCertificateKeyFile \/etc\/httpd\/conf.d\/certs\/example2.com.key\r\n     SSLCertificateChainFile \/etc\/httpd\/conf.d\/certs\/gd_bundle.crt\r\n &lt;\/VirtualHost&gt;\r\n<\/pre>\n<p>And in doing it this way, we can dynamically create Apache configurations for each new box that we put into the farm. Using this method, we\u2019ll be able to expand or reduce the size of the farm with little impact or effort.<\/p>\n<p>As always, feel free to contact me with any questions, comments, or corrections<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a continuing effort to make my hosting cloud more dynamic, I have had to become relatively creative with my Apache configurations so that my farm can remain relatively flexible with little or no reconfiguration on newly introduced servers. This presents a big problem when working with a multi-site Apache configuration, and an even bigger [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"_links":{"self":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/1137"}],"collection":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1137"}],"version-history":[{"count":2,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/1137\/revisions"}],"predecessor-version":[{"id":1139,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/1137\/revisions\/1139"}],"wp:attachment":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1137"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1137"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1137"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}