If you are a serious web developer, you might have already figured out that performing experiments and untested upgrades on production servers is a disaster waiting to happen, bringing down the live site with them. Staging live servers (in the form of dev.example.com) usually don't cut it either, especially if you have a lot of file transferring or editing to do. However, local development is still a kludge, as you have to develop in a sub-directory, something like http://localhost/mysite. This has all sorts of implications, the most evident of which being that it breaks cross-content links if you try to pack it and deploy it back to the live site.
Ideally, you would need to develop in subdomains, something like http://mysite.localhost, which would mean that you have the flexibility of local development with the peace of mind of not having to develop in a sub-directory. But, face it. Setting up subdomains is an involving process, requiring hacking around your Apache configuration files. This is suboptimal if you want to do it regularly. Unless you come up with a way to turn http://mysite.localhost to automatically understand where it should find its files.
This article will explain you how to combine WampServer and BIND to create this kind of Holy Grail local web development server on Windows. You will configure a single DNS entry and a single virtual host in order to create a server which can handle infinite subdomains! The only pre-requisite is having a fixed IP address for your server. Well, even 127.0.0.1 will do if you can't do anything better than that!
Ideally, you would need to develop in subdomains, something like http://mysite.localhost, which would mean that you have the flexibility of local development with the peace of mind of not having to develop in a sub-directory. But, face it. Setting up subdomains is an involving process, requiring hacking around your Apache configuration files. This is suboptimal if you want to do it regularly. Unless you come up with a way to turn http://mysite.localhost to automatically understand where it should find its files.
This article will explain you how to combine WampServer and BIND to create this kind of Holy Grail local web development server on Windows. You will configure a single DNS entry and a single virtual host in order to create a server which can handle infinite subdomains! The only pre-requisite is having a fixed IP address for your server. Well, even 127.0.0.1 will do if you can't do anything better than that!
Setting up BIND
BIND is the reference implementation of a DNS server. We need DNS in order to resolve our subdomains into IP addresses for our system to work. As a bonus, we also get active DNS caching which will speed up our web browsing. Talking about killing two birds with one stone!
You can download BIND for Windows as a ZIP archive from ISC. The Windows download appears on the right column, in the "immediate download" box. Unzip this archive on a local folder and double click on BINDInstall.exe. In the installation window, change only the following options:
- Target directory: c:named
- Service account name: named
- Service account password: enter a password you will remember
- Confirm service account password: same as above
- Automatic startup: check
- Keep config files after uninstall: check
Click on Install. After a while it says that "BIND installation completed successfully". Click on OK, then Exit to close the installer.
Right now you have a non working BIND server. The next steps will make sure that we get to a point where we can get this to work for us.
Important note: This tutorial assumes that your server's IP address is 192.168.1.6 and your development domain is local.web. If your setup differs, you'll have to adjust the configuration files accordingly.
Let's begin the customization.
First, create a directory C:\named\zones
Next, create a file C:\named\etc\named.conf
(using a plain text editor, such as Notepad++) with the following contents:
options { directory "c:namedzones"; allow-transfer { none; }; recursion yes; }; zone "local.web" IN { type master; file "db.local.web.txt"; allow-transfer { none; }; }; zone "1.168.192.IN-ADDR.ARPA" IN { type master; notify no; file "1.168.192.in-addr.arpa.txt"; allow-transfer { none; }; }; zone "." IN { type hint; file "db.root.hint.txt"; }; key "rndc-key" { algorithm hmac-md5; secret "your secret key"; }; controls { inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; }; };
A few notes on this file are in order:
- If you want to use a development domain other than local.web, please replace local.web (highlighted in green) with your own domain name, e.g. foobar.local. DO NOT USE A REAL, EXISTING DOMAIN because you will not be able to access it anymore!
- This article also uses reverse DNS; for reverse DNS to work, we have to know the static IP address of your web server and create a reverse zone for this IP cluster. If your IP is 192.168.1.1, the reverse zone will be 1.168.192, that is remove the last octet (number) from the IP address, and reverse the sequence of what's left. If you don't have a static IP on your server and it is the same machine you use for browsing as well, you can use the localhost address (127.0.0.1). So, just replace everything highlighted in cyan with 0.0.127.
- The secret key, highlighted in yellow will be replaced in the next step.
Open up a command line window (e.g. Start - Run - type "cmd" without the quotes, click OK) and type the following commands:
c: cd c:\named\bin rndc-confgen -a rndc-confgen > ..\etc\rndc.conf
Open the file c:\namedetcrndc.conf and find the line starting with a hash (#) and saying something like
secret "something";
Copy this "something" (looks like gibberish) and us it to replace the "your secret key" part I have highlighted in yellow in the named.conf file. Save and close both files.
As in the previous pages, I use the highlighting to denote which parts you have to adjust according to your configuration. Green stands for domain name, cyan for IP addresses.
The next thing we have to do is to configure our DNS zone file. Create a new text file in c:\named\zones\db.local.web.txt
using your plain text editor. Remember, if you do not use local.web as your domain, you'll have to replace this part! Paste the following contents:
$TTL 6h @ IN SOA ns1.local.web. hostmaster.local.web. ( 2009122002 10800 3600 604800 86400 ) NS ns1.local.web. 1 PTR ns1.local.web
Something very important. See the part I have highlighted in magenta? This is the last octet of the IP address of your server. If your server's IP is 192.168.1.1, the last octet is the number after the last full stop, that is 1. Smae goes if the IP is 127.0.0.1, the last octet is 1. If you IP is 192.168.1.8, the last octet is 8 and you'll have to place 8 in the magenta highlighted part, OK?
The part I have highlighted in gray is called the serial number and has the format YYYYMMDDSS where YYYY is a 4-digit year, MM is a 2-digit month, DD is a 2-digit day of the month and SS is a two digit serial. You want this to be as unique as possible, so use today's date and aserial of 02.
Finally, we'll create the global DNS servers hint file, using a text editor, in c:\namedzonesdb.root.hint.txt and pasting the following contents:
; ; There might be opening comments here if you already have this file. ; If not don't worry. ; ; About any leading spaces in front of the lines here: remove them! ; Lines should start in a ;, . or character, not blanks. ; . 6D IN NS A.ROOT-SERVERS.NET. . 6D IN NS B.ROOT-SERVERS.NET. . 6D IN NS C.ROOT-SERVERS.NET. . 6D IN NS D.ROOT-SERVERS.NET. . 6D IN NS E.ROOT-SERVERS.NET. . 6D IN NS F.ROOT-SERVERS.NET. . 6D IN NS G.ROOT-SERVERS.NET. . 6D IN NS H.ROOT-SERVERS.NET. . 6D IN NS I.ROOT-SERVERS.NET. . 6D IN NS J.ROOT-SERVERS.NET. . 6D IN NS K.ROOT-SERVERS.NET. . 6D IN NS L.ROOT-SERVERS.NET. . 6D IN NS M.ROOT-SERVERS.NET. A.ROOT-SERVERS.NET. 6D IN A 198.41.0.4 B.ROOT-SERVERS.NET. 6D IN A 128.9.0.107 C.ROOT-SERVERS.NET. 6D IN A 192.33.4.12 D.ROOT-SERVERS.NET. 6D IN A 128.8.10.90 E.ROOT-SERVERS.NET. 6D IN A 192.203.230.10 F.ROOT-SERVERS.NET. 6D IN A 192.5.5.241 G.ROOT-SERVERS.NET. 6D IN A 192.112.36.4 H.ROOT-SERVERS.NET. 6D IN A 128.63.2.53 I.ROOT-SERVERS.NET. 6D IN A 192.36.148.17 J.ROOT-SERVERS.NET. 6D IN A 198.41.0.10 K.ROOT-SERVERS.NET. 6D IN A 193.0.14.129 L.ROOT-SERVERS.NET. 6D IN A 198.32.64.12 M.ROOT-SERVERS.NET. 6D IN A 202.12.27.33
That's it! Save everything and start BIND. You can do so by clicking Start - Run - type "services.msc" without the quotes - hit OK. In the Windows Services administration panel locate the "ISC BIND" service and start it.
If you have troubles setting up BIND, the following resources will help you (they did help me at least!):
Now that our DNS server is up and running, we'll have to deal with the web server part. Begin by installing WampServer, the easiest package for Apache, PHP and MySQL on Windows. I will assume that you have already done so and you have installed it in c:\wamp
. Launch WampServer and left-click on it, then select "Put Online". This step is mandatory! If you fail to do so, you will get "403 Forbidden" when you try accessing your subdomains.
There is something noticeable about WampServer. Since it supports the co-existence and on-the-fly selection of multiple versions of Apache, PHP and MySQL, each of these servers' version - including its configuration - is housed in a directory of its own. I will assume that your active Apache version is 2.2.11. You can find your active Apache version by left-clicking on WampServer's tray icon and choosing the Apache, Version submenu. The version with a tick mark on the left is the active version. Do note that if you upgrade WampServer you will have to redo the following steps!
Left-click on WampServer's tray icon and choose the Apache, httpd.conf menu item. A Notepad window pops up. Find the line:
# Include conf/extra/httpd-vhosts.conf
and remove the hash in front of it so that it now reads:
Include conf/extra/httpd-vhosts.conf
Edit the file c:\wamp\bin\apache\Apache\2.2.11\conf\extra\httpd-vhosts.conf
(replace 2.2.11 with your active Apache version). Replace its contents with:
<VirtualHost *:80> ServerAdminThis email address is being protected from spambots. You need JavaScript enabled to view it. DocumentRoot "C:/wamp/www" ServerName local.web ServerAlias *.local.web RewriteEngine on RewriteCond %{HTTP_HOST} !^www.* [NC] RewriteCond %{HTTP_HOST} ^([^.]+).local.web RewriteCond c:/wamp/www/%1 -d RewriteRule ^(.*) /%1/$1 [L] </VirtualHost>
The C:/wamp/www part is the absolute path to your web server's root, that is where the files to be served are located in. Edit it if you installed WampServer in a directory different than c:\Wamp. Do note that we are using forward slashes to separate path elements, not backslashes. This is the UNIX way to do it, as Apache began its life as a UNIX server. Also note that the part highlighted in green is the local development domain. If you used something different when setting up BIND (the DNS server) you have to change it here as well.
Save the file and left-click on WampServer's tray icon, choose Apache, Service, Restart service. Congratulations, you're ready!
Let's test that it's working. Create a directory c:\wamp\www\foobar and create the following index.html file inside it:
<html> <head> <title>Foobar!</title> </head> <body> <h1>It works!</h1> <p>This is foobar.local.web</p> </body> </html>
Now access it by pointing your browser to http://foobar.local.web. Success! It should say that it works and that it's foobar.local.web.
Want some more? Create a directory c:\wamp\www\meh and the following inde.html file inside it:
<html> <head> <title>Meh</title> </head> <body> <h1>It works!</h1> <p>This is meh.local.web</p> </body> </html>
Now access it by pointing your browser to http://meh.local.web. Success! It should say that it works and that it's meh.local.web.
You get the idea, right?
You might create directories named joomla, wordpress and drupal, installing the relevant CMS into each one. You can easily access them with joomla.local.web, wordpress.local.web and drupal.local.web respectively. You can do the same with your clients' sites, transferring them with JoomlaPack for example, creating subdirectories inside c:wampwww in the form of client1, client2 and accessing them as client1.local.web, client2.local.web, etc.