Building a Server from Scratch, Part 4: Pages Full of Data


Yes, we are finally coming to the juicy parts. We are now ready to create our Web server, and complement it with a database (DB) server so that we can install our favourite CMS on it. So let’s jump right in.

  • Role: Web server
  • Priority: Required
  • Dependencies: Basic server, virtualisation
  • Features: Two (or three) VMs, one for the Web and one for the database
  • Extensible: Yes
  • Ease of setting up: Very easy but needs a lot of patience
  • Software set: Pound reverse proxy, MySQL/PgSQL database server, LightTPD HTTP server, interpreters for Perl, PHP and Python2
  • Set-up time: Two hours

Time for some theory

Ideally we ought to take the system offline, but this is not possible since we need to fetch software from the Internet.

By now, you will have realised that with the networking set-up that we are currently using, we’ll never get VMs to talk to each other. We need to change things around a bit. One solution would be to use a second network interface on all our VMs configured for internal networking. However, this is a little dirty, because there are no DNS or DHCP servers running on this interface.

The second option would be to use a Virtual Hub, or a TAP/TUN interface to bring all the VMs together, then bridge the TAP interface to eth1 (our internal interface). So all the machines in the office can access the servers. Note that we will not bridge it to eth0. What? Then no one can access our Web server! Relax. We will set up a reverse proxy on the server to forward all Web requests to the Web server. Our database server need not be accessible to the outside world.

Our main server will use port forwarding (between the PC and the VM, so I can give you clear instructions this time, don’t worry). Any other service, such as MediaStreaming, Jabber, etc, can use port forwarding, when necessary. Note, that we will not have a separate VM for FTP but will run FTP on our main server.

Part 1: Web server

Let’s set up our Web server first. I assume that you have read through the VirtualBox manual and have mastered at least one interface. First of all, create a 500 GB (that should be enough to start with) VDI and attach it up to the Web Server VM. Start it up, create a single ReiserFS partition, and mount it under /Web. (Do not use the mount command manually, edit /etc/fstab by hand and then execute mount -a.) Or you can use the appropriate system configuration tool.

Now, launch the Add/Remove Programs tool from the Applications menu in GNOME, and install LightTPD, php5-cgi, Perl, PHP5-MySQL and Python.

You can’t, right? That’s because LightTPD is nowhere in the CentOS repos. You need to add the Dag Wieers repos first. You can install the Dag Wieers repos by adding RPMForge. The instructions, though simple, involve innumerable steps and can be found at the following URL:

Now install everything. After you’re done, you’ll need to edit the /etc/lighttpd.conf file. Set the document root to /Web/Internet (I hope you had chown‘ed and chmod‘ed it properly) and check if the handler extensions for php, pl, cgi and py are registered properly. Also check if the Python, Perl and PHP interpreters are properly referenced to use CGI (rather than FastCGI). There should be something like the following snippet in your config file:

cgi.assign = ( ".php" => "/usr/bin/php-cgi", ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/env/ python" )

You’ll also need to add index.php,, and index.cgi to the list of default index documents, but be wary of the order you put them in.

Please check the paths of all the interpreters. And last, but not the least, change the default port binding (server.port) to 8888.

Now to test your server. Create a page with the following text and save it as /Web/Internet/default.php:

<? phpinfo(); ?>

Start up Lighty:

/etc/init.d/lighttpd start

And point your browser to http://localhost:8888 (or http://web.officenetwork.local:8888 if you are accessing it from outside the VM). If all went well, you should be greeted by a spick and span PHPINFO test page. If it didn’t, check and re-check your config file, and then do it all over again, before trying to re-start Lighty.

There is a second part to this. All that happened earlier was to serve the public. How about our own office? We need an Intranet, with an ECMS, an Intranet mail server (somewhat like Exchange), a document collaboration system (like Google Docs), Wikis and what not. And it wouldn’t be nice if someone from Tunisia, looking for his car insurance, clicked on your link from Google Search and found himself staring at the log-in page of your corporate mail server. He might try some stuff, too. So we need a separate instance of the server (a virtual server), running on our Web server, to hold our Intranet.

To start with, open up your /Web directory and create another directory called Intranet. Then, copy the following snippet to your Lighty config file:

$SERVER["socket"] == ":80" {
     server.document-root        = "/Web/Intranet"

We are done. Just restart LightTPD, copy your phpinfo page over to /Web/Intranet, and access your Intranet server.

If case you are mystified by my choice of ports, let me clear a part of your doubts. We are going to access our Intranet site by just typing in the address of our VM. On the other hand, traffic to the public part of our Web server will be handled by Pound, a reverse proxy, which will filter our inbound traffic and automatically forward it to port 8888.

Our problem is this: We just cannot let our Intranet server be forwarded by our reverse proxy. If we do that, one fine day Google will decide to index our website, and it’ll come up with all sorts of nasty trade secrets. But our Web mail access was supposed to be via our Intranet site. No, no! We cannot do that. What we can do, however, is to leave our Intranet site as it is and create a separate (a third) socket bind for our Mail server. If you want to know the sort of problems Google causes, go to the following site, which I found by searching for it in Google:

Anyway, create this bind:

$SERVER["socket"] == ":9999" {
     server.document-root        = "/Web/Webmail"

Of course, create the directories and test the stuff with our PHPINFO tactic.

That finishes the Web server part. Now for our reverse proxy.
Part 2: Pound for Pound
We need to set up a reverse proxy (RP) to forward all HTTP requests from our server to our Web VM. We use a RP called Pound to do it.

Why do we need a RP? Putting all our VMs directly on the Internet would mean that everyone can access our Web, database and mail servers. That would be suicide. C’mon, once someone guesses the root password for our DB server, we’re finished. We are not going to put anything directly on the Internet. What we’ll do instead is create reverse proxies to filter wanted traffic, and also abstractise all our VMs and show ONE computer to the whole world. Do you really think is just one server?

But before we set up our reverse proxy, we need to alter our networking set-up.

Part 2.5: Virtual distributed Ethernet

Now push your CentOS VM into the background and come to your Ubuntu. Launch a terminal and execute the following:

# apt-get install vde2 bridge-utils
#  echo “tun” >> /etc/modules
# modprobe tun
# tunctl -t tap0
# vde_switch -tap tap0 -daemon
# chmod -R a+rwx /var/run/vde.ctl
# brctl addbr br0
# ifconfig tap0 promisc
# brctl addif br0 tap0
# brctl addif br0 eth1
# ifconfig br0 netmask up

We’re done…almost! All we need to do now is tweak DNSMASQ a bit. Open up the DNSMASQ config file, and make a few changes:

  1. Add one except line:
    except-interface eth1
  2. Add one interface line. This should not be required, but it’s better to be safe:
  3. And a CNAME record (you’ll realise later why this is required)

Re-start DNSMASQ. It’ll now run exactly as we want it to.

Shut down the CentOS VM, and then in the VBox GUI, open Networking Settings. You had attached your machine to eth1; now separate it from eth1 and attach it to tap0. Save your settings, and re-launch the VM. Pretty soon, you’ll see it boot up and get all its networking information from our server over the Virtual Network.

Back to Part 2: The Pound reverse proxy

Anyway, we need to get pounding unless we want to keep our website one great secret. To start with, query the eth0 IP address:

# ifconfig eth0

Now get running. Install Pound:

# apt-get install pound

That should do the trick. Pound is now installed. All we need to do is configure it. Why is configuring something always a pain in the posterior?

Anyway, open up the Pound configuration file (/etc/pound/pound.cfg). To start with, edit what is re-usable:

  1. Change the user and group. For this series, I’m doing everything as the root. You can select anything as per your own security model.
  2. I personally prefer Apache type logs. To get them, change LogLevel to 3.

Now we need to set up the actual reverse proxy part. Delete the ListenHTTP segment at the end of the file, and start from scratch. I’ll give you the entire configuration in the form of a snippet as below, but you need to change the domain names as per your own domain registrations. Specifically, I’m using, and officenetwork.local but you need to change the sample to your own registered domain.

Also, you got the eth0 address earlier using the ifconfig command. It should have been, but it could be anything. Just take note of that too. And make sure that the address is different for eth0 and eth1.

Use the following snippet:

     Port 80
          HeadRequire “Host: .*”
          Address web.officenetwork.local
          Port 8888
          HeadRequire “Host: .*”
          Address web.officenetwork.local
          Port 9999
     Address server.officenetwork.local
     Port 80
     xHTTP 0
          HeadRequire “Host: .*webmail.officenetwork.local”
          Address web.officenetwork.local
          Port 9999

That should do it. Now you’ll have to dive in to your FreeDNS account or tell your domain registrar to add a subdomain pointing to the master site ( Of course, use your own domain names here.

Part 3: The database

What good is a Web server without a database back-end? When you are using a database, you’ll have to differentiate between your needs for the database and choose you software accordingly. By principle, MySQL is the best choice when it comes to serving as a back-end for your CMS, but is the worst choice if you are into transaction processing.

I’d recommend you create two new VMs with squeaky clean CentOS 5.3 on it (do not clone), name them pgsql and mysql, and install PostgreSQL and MySQL into them accordingly. Insert them into the network by plugging them into the TAP interface. I’m not elaborating on this due to space constraints.

Part 4: The true test

Start LightTPD on you Web VM and Pound on the server first.

Sit down at the console of your Web VM, visit and download WordPress. Extract the TGZ file into the root of your Intranet Web root directory (/Web/Intranet).

Now open Firefox and head over to http://localhost. Set up WordPress (it’s pretty simple). When it comes to selecting a database server, use mysql.officenetwork.local or whatever you named your MySQL server. Go on accordingly. If the set-up succeeds, bingo!

Now start testing this set-up. Use a browser on the server, on any client, on other VMs, and finally from outside your office (set up something on the public site first). Some of it might not work, so troubleshoot accordingly. To start with, ask at the forums and Google Groups, post to LUG mailing lists, etc. You should get your answers soon, if not immediately. You can also reach me at bg13_ina at users.sorceforge dot net. Questions and troubleshooting stuff are always welcome.

Next up?

Get three more subdomains, pop, smtp and imap registered for your domain name. We set up e-mail next month.


The VDE part was lifted off (though modified for our setup) from “Setting Up A Virtual Infrastructure” by Ajitabh Pandey, LFY Oct 2008, Pages 38-44.


  1. I’m on ubuntu and trying connect My SQL database with Visual Basic Applications, actually I’m facing an error while I execute the code on ubuntu another side its working fine with Window operating system.
    rs!Cname is run proper in window but not run in ubuntu give error item can not find.
    Now, if i written code like in format rs(0).value
    code run in perfectly in ubuntu…
    please, provide me some example of data connection in ubuntu with mysql and VB.


Please enter your comment!
Please enter your name here