I built a personal Web server*, and I did it awesomely

Friday, September 15, 2017

I built a personal Web server*, and I did it awesomely

*JK I built 5.

A month or so ago, I was sitting on the floor of my apartment, feeling a sense of ennui. I needed a new hobby. Lying on trigger point therapy balls while reading sci fi, while satisfying, wasn't enough anymore. I was itching to make something.

It just so happens that I'd had a fun idea for a Web application I'd like to build, about which I will say no more because it's not done and you can't have my idea. Around the same time, I got caught up by friends' wedding excitement and offered to build and host some wedding websites.

It doesn't sound like you'd need your own Web server for that, you're thinking. No, it doesn't. But I wanted one.

It's borderline irresponsible to host your own Web server, what with cloud this and cloud that, but I'm feeling irresponsible. And I'm feeling like I want to play with new things.

Thus was born this adventure. Come along with me. Build a Web server awesomely.

I'm going to lay out the ultimate state, just to get you real excited. If it doesn't make sense yet, don't panic; we'll go through each step below.

We're going to make it so that you can have a single Raspberry Pi hosting multiple Web servers, each serving traffic to a different domain name (or subdomain). We'll do this by having all of these domains point to our router's (dynamic, external) IP address, which is configured to forward requests to port 80 to the (static, internal) IP address of our Raspberry Pi. On the Pi, we're running a a reverse proxy server that forwards these requests, based on the domain name in the request, to individual Web servers on other ports, each one serving a single domain. Except I lied there. We'll actually have the domains point to a DDNS hostname, which itself points to our router's IP; we do this because our ISP doesn't guarantee us a static IP address and it could change at any moment.

To make it concrete: You go to www.whatareheirloomtomatoes.com. Because my router has a dynamic IP address, I can't just have www.whatareheirloomtomatoes.com redirect to my router's IP (or I can, but when my router gets assigned a new IP out of nowhere, I'll be sad); instead, I have a CNAME record that aliases my domain to my DDNS hostname, which I've registered for with a DDNS service (e.g. no-ip.com or dynu.com). This DDNS service gets notified when my IP changes (by a small piece of software they provide to poll for changes), so it knows what my current IP is, and forwards your request for www.whatareheirloomtomatoes.com to that IP on port 80. My router sends that request to my Pi on port 80, where nginx is listening; nginx looks up www.whatareheirloomtomatoes.com in a configuration file I've set up and sees that it should forward that request to the port I've specified, say 8080. On 8080, I have a nodejs server running that serves up the content for www.whatareheirloomtomatoes.com. Ta-da!

If you only want to do a subset of these things – like only set up a single Web server, no reverse proxying, no DDNS madness – I've modularized the topics and you can call it quits when it suits you.

By the end of this, here are all of the technologies we will have played with:
  • Development environment:
    • Atom: IDE (optional; use whatever IDE you want)
    • PuTTY: SSH client (optional; only if sshing from Windows to your pi)
    • Bitvise: SFTP client (optional; again only if sshing from Windows to your pi)
  • Web server:
    • Nginx: Reverse proxying
    • Nodejs: Web servers (optional; if you want to serve a static site, you can use nginx alone. Or use Apache, if you want to party like it's 1999. I don't care.)
      • Forever: Keep those Web servers running
      • Nodemon: Reload your server on change
    • ddclient: Update your DDNS service when your ip changes (optional, if your router can connect directly to your DDNS service)
  • Configuration you never cared to know about:
    • Port forwarding on your router
    • Domain DNS settings (for those who have a custom domain)

Ready to start? Follow the guides below on your path to awesomeness.

  1. Part I: Setting up your enviroment: The Pi, the router, and your development machine
  2. Part II: Host a single server (custom domain edition)
  3. Part III: Set up DDNS to deal with your dynamic IP – for free!
  4. Part IV: Why host one server when you could have n servers? [coming soon]