Category Archives: networking

VirtualBox, Ubuntu and LAMP Stack

Came accross VirtualBox, a free & excellent virtual machine software. I decided to take it for a spin creating a Ubuntu virtual machine LAMP stack on it..

Here We Go

  1. Download and install VirtualBox
  2. Download latest Ubuntu iso installation file
  3. From VirtualBox create a new Virtual Machine. Select type: Linux and version: Ubuntu. On the next step you will be prompted with dvd drive containing the installaion disk, but instead just select the iso downloaded on step 2
  4. Go through the Ubuntu installation steps
  5. It’s also very helpful to install ssh server so you can ssh into your VM later on: sudo apt-get install openssh-server

Voila! You have ubuntu running on your Windows PC

Host and Guest

In virtualization realm, host indicates your physical PC (Windows 7 in my case), and guest is the virtual machine (Ubuntu). Most of virtual machine software documentation uses host and guest terminology heavily so make sure you’re familiar with it

Networking

This is where things get tricky. Virtual machine comes with virtual network adapters, and you have to do few configuration to setup connectivity between your virtual and physical adapters.

By default VirtualBox allows the guest machine to connect to the internet through NAT, so you can download data, browse internet etc. However if you want to run servers from the guest, it won’t be discoverable by the host or other PC in the host’s network immediately.

One approach to make them discoverable is by setting up port forwarding. You get here by going to networking section on the machine’s setting on Virtual Box

portforwarding

Note that setting port forwarding requires the port is actually free on your host machine. Hence I find it very useful to add an IP to your host’s network interface specifically for the VM so you don’t have port conflicts. In this example I added the IP on my interface:

addip

The “AMP”

So there’s the “L – Linux” done. Now for the Apache, Mysql and Php, it can simply be done by using Ubuntu’s apt-get package manager:

  1. Open a terminal / SSH session to your Ubuntu machine
  2. Elevate into root using sudo su root
  3. apt-get install apache2
  4. apt-get install php5
  5. apt-get install mysql-server mysql-client

Few helpful notes:

  • Default doc root is /var/www
  • To start / stop apache: sudo service apache2 stopsudo service apache2 start
  • To start / stop mysql: sudo service mysql stop / sudo service mysql start

Benchmarking Web Page Load Time Using Apache AB Tool

Any apache httpd installation comes with ab tool on the bin folder. This handy tool can be used to perform benchmark testing:

ab -n 10 -c 2 http://www.mycoolwebsite.com/
  • -n 10: Make a total of 10 request to http://www.mycoolwebsite.com/
  • -c 2: Allow maximum simultaneously 2 concurrent request (2 threads)

The output you get is quite self-describing:

This is ApacheBench, Version 2.3 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.vantagefx.com (be patient).....done


Server Software:        Apache
Server Hostname:        www.mycoolwebsite.com
Server Port:            80

Document Path:          /
Document Length:        29320 bytes

Concurrency Level:      2
Time taken for tests:   4.524 seconds
Complete requests:      10
Failed requests:        0
Write errors:           0
Total transferred:      297360 bytes
HTML transferred:       293200 bytes
Requests per second:    2.21 [#/sec] (mean)
Time per request:       904.890 [ms] (mean)
Time per request:       452.445 [ms] (mean, across all concurrent requests)
Transfer rate:          64.18 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.3      0       4
Processing:   806  887  90.4    852    1063
Waiting:      804  885  90.4    850    1061
Total:        806  887  91.3    852    1067

Percentage of the requests served within a certain time (ms)
  50%    852
  66%    888
  75%    918
  80%   1027
  90%   1067
  95%   1067
  98%   1067
  99%   1067
 100%   1067 (longest request)

Note that however I believe this tool will only request specified html page, not external resources associated with the page (no external images, javascript, css, etc.).

If you want to test https (SSL) page, make sure you have a version of Apache httpd with ssl support, and use abs instead.

Configuring Firewall Packet Filtering Using iptables

This article was tested using iptables v1.3.5 running on CentOS.

Displaying Currently Active Rule

iptables -L -v -n

-v flag turns on verbose mode, and -n causes hostname to be resolved into IP when displaying.

Adding A New Rule

iptables -A INPUT -j ACCEPT -s  -m comment --comment 'Reverse proxy'

Above rule will be added to the end of INPUT chain, and when rule matches (packing coming from ip ), it will be accepted

Rejecting Packets Created From Inbound Conenctions

In the following example all packets from inbound connection are rejected, but not outbound. The only inbound packets allowed are from 72.8.190.105 and 199.241.192.0/22

Chain INPUT (policy ACCEPT 704K packets, 218M bytes)
 pkts bytes target     prot opt in     out     source               destination
  36M 4776M ACCEPT     all  --  *      *       72.8.190.105         0.0.0.0/0       /* Allow incoming from Reverse Proxy*/
4439K  577M ACCEPT     all  --  *      *       199.241.192.0/22     0.0.0.0/0       /* Allow incoming from Reverse Proxy */
  10M 2897M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0       state RELATED,ESTABLISHED /* Accept incoming packets from already established conn */
14586  878K REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0       /* Reject everything else */ reject-with icmp-port-unreachable

This is achieved by checking state. If incoming packet is associated with TCP connection with RELATED / ESTABLISHED then it will be allowed.

Such rule can be added using

iptables -A INPUT -j REJECT -m state --state ESTABLISHED,RELATED -m comment --comment 'Reject everything else'

Saving Rules

Use /sbin/service iptables save to persist changes for the next time the server is rebooted.

Looking up Command for Currently Configure Rules

When you saved your iptables settings, the command used to reconstruct the rules can be looked up on /etc/sysconfig/iptables file

Testing SMTP Server Using Telnet

SMTP server can be tested simply by using telnet client. On Windows 7 above telnet client has to be installed first via control panel (Windows Add/Remove Features)

Following is a sample SMTP commands to send for a standard mail server listening on IP port 25, without authentication

C:telnet  25
HELO mycompany.com
MAIL FROM:
RCPT TO:
DATA
To: Gerry Tan <>
From: My Company Support <>
Subject: Testing mail server via SMTP
Please ignore this email as this is just testing mail server via SMTP

.
quit

The two newlines and dot at the end is important.

SMTP Server With Authentication

To use SMTP username / password authentication, you first need to encrypt it to Base64. It can be done with command line perl:

 perl -MMIME::Base64 -e 'print encode_base64("gerrytan");'
 perl -MMIME::Base64 -e 'print encode_base64("Mypass123");'

Becareful if you username / password contains symbols meaningful to perl! An @ character can be interpreted as perl array. You have to escape it using (I spent an hour figuring out why authentication failed due to this).

And issue AUTH LOGIN command after HELO / EHLO. The server will prompt for username and password in Base 64

220 mail.tpg.com.au ESMTP (mail16) Sendmail ready.
EHLO mail.tpg.com.au
250-mail16.tpgi.com.au Hello  [], pleased to
meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE 28521268
250-DSN
250-AUTH LOGIN PLAIN
250-STARTTLS
250-DELIVERBY
250 HELP
AUTH LOGIN
334 VXNlcm5hbWU6
**********
334 UGFzc3dvcmQ6
**********
235 2.0.0 OK Authenticated
MAIL FROM:
250 2.1.0 ... Sender ok
RCPT TO:
RC250 2.1.5 ... Recipient ok

Thanks to http://exchange.mvps.org/smtp_frames.htm.

DNS SPF Record to Reduce Rejection Rate of Your E-Mail

E-mail (and internet) was invented long time ago with the assumption only very few people will do evil, but it’s not the case nowadays. It is possible to send e-mail to anyone posing as anyone else (ie: if you own the domain apple.com, you can send email as banana.com).

SPF stands for Sender Policy Framework. Long story short, it is set on the DNS zone record to configure What host is allowed to send email as your domain

Testing If Your Domain Is Setup Properly

The openspf website has list of tools you can use to check if your domain already has SPF setup properly. For example:

  1. Go to http://www.openspf.org/Why
  2. Enter the email address you’re sending as on MAIL FROM field and your smtp server under Sender's IP address (eg: smtp.apple.com)
  3. The tool was originally designed to debug rejection.. so although it passes it will say “your mail server rejected a message because”. If you read further, if your SPF record was correct it should say The domain mycompany.com has authorized to send mail on its behalf, so the message should have been accepted. It is impossible for us to say why it was rejected., whereas if it’s incorrect it will say The domain mycompany.com has not published an SPF policy. It is possible that the receiving mail server refuses all mail from domains that do not have an SPF policy.

Configuring SPF Record on Your DNS Zone

This can be done on your domain hosting. Add following DNS record to you domain name (eg: mycompany.com)

v=spf1 a mx ?all

This syntax basically says:

  1. Authorize the IP specified by A record as outbound mailer
  2. Authorize the IP specified by MX record as outbound mailer
  3. Mark everything else as Neutral

More Examples

Further Reading

  • SPF Syntax:
  • Excellent article by Jeff Attwood on his Coding Horror blog about sending email through code: http://www.codinghorror.com/blog/2010/04/so-youd-like-to-send-some-email-through-code.html
  • http://aplawrence.com/Blog/B961.html

Tomcat & Apache Reverse Proxy

I have to admit Apache HTTPD has one of the most confusing documentation among other tools out there. Here are my Apache & Tomcat requirements:

  • A domain name mycoolwebsite.com pointing to my hosting server
  • Tomcat running on http://localhost:8080 on my hosting (default)
  • Apache HTTP server running on http://localhost:80 on hosting (default)
  • Request to http://mycoolwebsite.com should be reverse proxied into Tomcat without the end-user noticing the port difference

After 2 hours of reading documentation, trial and error, I managed to get this setup working using following Apache Reverse Proxy and VirtualHost configuration:


   ServerName mycoolwebsite.com
   ProxyPass        / http://localhost:8080/
   ProxyPassReverse / http://localhost:8080/
   ProxyPassReverseCookieDomain localhost mycoolwebsite.com
   ProxyPreserveHost On

Configuration Explained

  1. ProxyPass directive will cause request to http://mycoolwebsite.com/foo/bar (and any other paths) be internally forwarded to http://localhost:8080/foo/bar. Internally here means the user will never know — it will look as if the response came from http://mycoolwebsite.com. Behind the screen (on the server) Apache forwards the request and obtain the response to/from Tomcat. The trailing slash (/) at the end of http://localhost:8080/ is important because without it request to http://mycoolwebsite.com/style.css will be internally translated to http://localhoststyle.css (which is wrong).
  2. ProxyPassReverse directive is useful when Tomcat sends HTTP 3xx redirect response. If Tomcat redirects http://localhost:8080/logout into http://localhost:8080/login, your end user will see http://localhost:8080/login unless you place this directive.
  3. ProxyPassReverseCookieDomain directive will cause the cookie domain be re-written into the intended domain. Without this end-user would see localhost as their cookie domain (which is again wrong).
  4. ProxyPreserveHost directive will cause the domain header be forwarded into Tomcat. Without this Tomcat will see the incoming request coming from localhost. This is handy when you’re planning to serve multiple host name under Tomcat.

You can try this on be adding the above configuration into your httpd.conf file (typically located on /etc/httpd/conf/httpd.conf). Once you’ve edited the config, restart apache using sudo apachectl -k restart command.

How to Add Additional IP to Your Network Interface on Windows

This guide applies to Windows 7 and 8 but should be similar for older version of Windows. See here for similar guide on Mac OS X.

  1. Go to Control Panel > Network and Internet > Network and Sharing Center > Change Adapter Settings (on the left menu)
  2. Right click on the adapter you’d like to add IP to and select Properties (typically this is your primary network connection — eg: your LAN or wireless card)
  3. On the This connection uses following items selection, find Internet Protocol Version 4 (TCP/IPv4), select it and hit Properties
  4. Ensure your IP settings is manual (Use the following IP address and Use the following DNS server address radio buttons are selected). If it’s still automatic, change it and fill in your IP details. If you’re not sure what to fill, open command prompt and run the ipconfig /all command, this should show you your current network adapter config
  5. Once set to manual, click Advanced on the bottom right, and on the IP addresses area click Add. It will ask you for IP address and subnet mask. Again consult ipconfig /all command if you need to know. Typically you need to find an IP address which hasn’t been used on your network.

Reverse Proxy and Load Balancing using Apache mod_proxy

Reverse Proxy is a type of proxy server that retrieves the resource on behalf of the client such that the response appears to come from the reverse proxy server itself. One useful application of reverse proxy is when you want to expose a server on your internal network to the internet.

Load Balancing is a technique of distributing requests into several backend servers, hence providing redundancy and scalability. Many Java EE app servers came built-in with clustering feature allowing session to be replicated across all nodes in the cluster.

Apache has few modules that can be used to setup the two above. Following is a guide on how to set it up.

  1. Ensure you have an apache-httpd installed. This guide is written against httpd 2.4. If you’re on OSX most likely you’ve already got httpd installed.
  2. Figure out where is your httpd.conf file located. Typically it’s at $HTTPD_ROOT/conf/httpd.conf.
  3. Enable following modules. Module can be enabled by uncommenting (removing the ‘#’ character at the beginning) the LoadModule directive on your httpd.conf:
    [sourcecode]
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
    LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
    LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
    [/sourcecode]
  4. (Optional) depending on your operating system setup, you might need to change the user & group httpd will use to start the process. On my OSX I have to change it into my own user / group (or root). Use the User and Group directive for this
    [sourcecode]
    User gerrytan
    Group staff
    [/sourcecode]
  5. Add the following proxy / load balancer configuration
    [sourcecode]

    BalancerMember http://192.168.1.101:8080 route=node1
    BalancerMember http://192.168.1.102:8080 route=node2
    ProxySet stickysession=BALANCEID

    ProxyPassMatch ^(/.*)$ balancer://mycluster$1
    ProxyPassReverse / http://192.168.1.101:8080/
    ProxyPassReverse / http://192.168.1.102:8080/
    ProxyPassReverseCookieDomain 192.168.1.101 localhost
    ProxyPassReverseCookieDomain 192.168.1.102 localhost
    [/sourcecode]

    The  directive specifies we are defining a load balancer with a name balancer://mycluster with two backend servers (each specified by the BalancerMember directive). In my case my backend servers are 192.168.1.101:8080 and 192.168.1.102:8080. You can add additional IPs to your network interface to simulate multiple backend servers running in different hosts. Note the existence of the route attribute which will be explained shortly.

    The ProxySet directive is used to set the stickysession attribute specifying a cookie name that will cause request to be forwarded to the same member. In this case I used BALANCEID, and in my webapp I wrote a code that will set the cookie value to balancer.node1 or balancer.node2 respectively. When apache detects the existence of this cookie, it will only redirect request to BalancerMemeber which route attribute matches the string after the dot (in this case either node1 or node2). Thanks to this blog article for explaining the step: http://www.markround.com/archives/33-Apache-mod_proxy-balancing-with-PHP-sticky-sessions.html.

    The ProxyPassMatch directive is used to capture and proxy the requests that came into the apache httpd server (the proxy server). It takes a regular expression to match the request path. For example, assuming I installed my httpd on localhost:80, and I made a request to http://localhost/foo, then this directive will (internally) forward the request to http://192.168.1.101:8080/foo.

    The ProxyPassReverse directive is used to rewrite http redirect (302) sent by the backend server, so the client does not bypass the reverse proxy.

    ProxyPassReverseCookieDomain is similar to ProxyPassReverse but applied to cookies.

Few words of warning

There are plenty methods of configuring reverse proxy, this guide uses http reverse proxy which might not deliver the best performance. You might also want to consider AJP reverse proxy for better performance.

How to Add Additional IP to a Network Interface on Mac OS X

See here for similar guide on Windows.

After half an hour surfing various pages, I’ve finally figured out how to assign additional IP to a network interface on Mac OS X (thanks to this apple discussion thread: ).

Adding another IP to your network interface is a handy way of running multiple instance of a process listening on the same port (eg: Tomcat container). This is very useful to perform High-Availability (HA) setup locally on laptop.

This guide is written against OS X Mountain Lion (10.8), but hopefully not that much different for older / newer OS X version.

  1. Open Network Preferences (System Preferences > Network). On the left list box each connection made through available network interfaces are listed. On below screenshot I have two connections configured for my wireless and bluetooth network interface respectively.
  2. On OS X you need to “duplicate a connection” to add an IP to an existing network interface. Typically you would add additional IP to your primary network interface (eg: your wireless or LAN card) so it’s reachable from other host in your network. In my macbook air, since it doesn’t have a LAN port, I used the wifi network interface. Select your primary network connection (“Wi-Fi” in my case), click on the gear icon at the bottom and select Duplicate Service… You might need to click the padlock icon first to perform administrative task.
  3. Enter a name for the new connection, eg: Tomcat NIC 2 and hit Duplicate. The new connection will be created. Although it’s a different connection, it still uses the same network interface (in my case the wifi network interface). Initially the connection might not have an automatically assigned IP.
  4. If the connection does not have an automatically assigned IP, assign it manually. From Network Preferences, select the new connection, and click Advanced… button. Go to the TCP/IP tab, select Configure IPv4 Manually, provide an IPv4 address and subnet mask. Ensure the IP isn’t already used in your network (you can check it using ping).

You can verify the virtual interface has been created by using ifconfig command. Notice in my case I have got more than 1 IP assigned to my wifi interface (en0)

[sourcecode]

$ ifconfig
lo0: flags=8049 mtu 16384
options=3
inet6 fe80::1%lo0 prefixlen 64 scopeid 0×1
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
gif0: flags=8010 mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8863 mtu 1500
ether 70:56:81:c0:c1:4f
inet6 fe80::7256:81ff:fec0:c14f%en0 prefixlen 64 scopeid 0×4
inet 192.168.1.101 netmask 0xffffff00 broadcast 192.168.1.255
inet 192.168.1.2 netmask 0xffffff00 broadcast 192.168.1.255
inet 192.168.1.102 netmask 0xffffff00 broadcast 192.168.1.255
media: autoselect
status: active
p2p0: flags=8843 mtu 2304
ether 02:56:81:c0:c1:4f
media: autoselect
status: inactive
[/sourcecode]