Using Nginx to Proxy Requests to sMash Apps

I now have a few sMash apps sitting on my VPS, running on different ports.  I wanted to be able to access each of them on their own subdomain  – like this :

Application URL Real location
App Builder ab.soal.org
97.107.131.88:8070
WordPress blog blog.soal.org 97.107.131.88:8081
Some Other App app.soal.org 97.107.131.88:8082

(97.107.131.88 is my VPS’s current IP address)

I had no idea how to do this, but it turned out to be fairly simple:

  1. Point your subdomains to your VPS’s IP address
  2. Setup a proxy on VPS on port 80 that routes requests to the appropriate app, based on the requested URI

For step 2, I decided to try Nginx (pronounced “Engine X”)  – a web server that can act as a reverse proxy. Nginx is becoming increasingly popular due to its small footprint and excellent scalability.

Here’s what I did. Remember, I’m a beginner, so don’t hesitate to post a comment if you spot something I’m getting wrong!

1. Point Your Subdomains to Your VPS’s IP address

My domains are managed by Powweb, who provide a Web UI  for configuring domains. Here, you can see how the 3 subdomains mentioned above are configured to point to my VPS:

Pointing my subdomains to my VPS's IP address using a Web-base Zone File editor.
Pointing my subdomains to my VPS’s IP address using a Web-base Zone File editor.

Initially, I naïvely thought I’d be able to achieve my objective by pointing my subdomains to the appropriate IP and port in this tool.  However, it turns out that this level of DNS configuration is agnostic of port numbers – it can only deal with IP addresses. So at this stage, we simply point all subdomains to the VPS IP, ignoring the port. Once this has taken hold (which can take a couple of hours), requests to all those subdomains – on any port – will get forwarded to the VPS as-is.

An interesting consequence of this is that I can access any of my sMash apps on any of the  subdomains, by explicitly specifying the port: App Builder on blog.soal.org:8070, my Other App on ab.soal.org:8082 etc… (and I would normally even be able to access this blog on a e.g. ab.soal.org:8081,  but WordPress does some redirecting which prevents it from fully working).

This isn’t ideal: we don’t really want users to have to specify port numbers on those URIs. We want them to be able to access the apps without specifying a port at all, i.e. by requesting the subdomain corresponding to the app they want on port 80.

So in step 2, we will set up a reverse-proxy on the VPS. It will listen for inbound requests on port 80, then reroute them to the appropriate sMash app based on the URI that was originally requested.

2. Install and Configure Nginx

Nginx’s community is still growing so it doesn’t yet benefit from quite as much documentation as mod_proxy or squid.  That said, it’s still pretty easy to figure out.  To install on Ubuntu, do:

sudo apt-get install nginx

And you can then start/stop/restart it with:

sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx restart

Once up and running, it should be serving on port 80. You should be able to access it and see its minimal welcome page, like this: http://97.107.131.88/

Nginx saying hello, keeping it simple
Nginx says hello, keeps it simple.

Next, edit Nginx’s config file to set up the proxy behaviour:

sudo vim /etc/nginx/nginx.conf

I added 3 server entries under the http context – one fore each of my apps. Here’s my nginx.conf (with the unchanged bits cut out):

   ## ... some stuff left unchanged ...

http {

    ## ... some stuff left unchanged ...

    server {
      listen 80;
      server_name ab.soal.org;
      location / {
        proxy_pass http://localhost:8070;
      }
    }

    server {
      listen 80;
      server_name blog.soal.org;

      proxy_redirect off;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      location / {
        proxy_pass http://localhost:8081;
      }
    }

    server {
      listen 80;
      server_name app.soal.org;
      location / {
        proxy_pass http://localhost:8082;
      }
    }

}

After saving your updated configuration, restart Nginx and it will be effective immediately.

Notice how the WordPress entry has a few extra directives (proxy_set_header etc…). WordPress does some redirecting based on the requested hostname. In our setup, without these settings, the requested host as seen by WordPress would be “localhost”, since the request is coming from a proxy on the same machine. Consequently, WordPress would respond with some HTTP 302 redirects  that would try to send the client to http://localhost! We therefore need to specify headers containing the original requested host name, thereby making the proxy a little more transparent.

Check out the Nginx configuration documentation for details on the directives used above. Also see the configuration section of the Nginx wiki for lots more examples.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: