During the Covid shutdown many people tackled their newly housebound boredom with "projects". Mine was to resurrect my old blog occamsmachete.com and tie the site to some other projects I work on at ActionML. To do this I wanted to run it all from my closet server over residential broadband. Why not get a cloud server? I do have cloud servers for work but wanted to make this work because it is somewhat difficult—call it lockdown inspired perverseness.
This is my project story. It's a semi-technical how to. I assume at least passing familiarity with networking concepts like DHCP, basic Linux admin, and ssh.
occamsmachete.com, the blog
I want to create a web site for my blog at https://occamsmachete.com. There are two ways to do this, use a cloud host like AWS or host from a computer at home. I chose the later because it's free (once you pay for internet and the cost of the computer to run your stuff) and because it is harder to do. It is hard because broadband is not configured to support fixed IP addresses as cloud providers are. I want any reader of my blog to be able to connect to whatever address is currently in use and lots of extra things need to be in place for this to work.
For me this means a server will listen to port 443 on the IP address of occamsmachete.com and the actual address of this domain will change at arbitrary times due to machinations of my ISP (Comcast), which uses DHCP.
For just this blog part of my project I'll need a long checklist of things:
- Namecheap.com domain name host, mine is a service that supports "dynamic" DNS, or DDNS. This allows you to work around the residential ISP (Comcast in my case) who will have you on DHCP, which reassigns your Cable router a new IP address at random times. This changing of IPs will leave your domain resolving to a non-existent IP if you don't update the DNS mapping every time the IP changes.
ddclientA DDNS updater running inside my LAN. This is a bit of software that updates the DNS->IP mapping when Xfinity changes my connection address through DHCP.
- Port forwarding. With residential internet you can connect to any service on the internet but they cannot connect to your devices (with rare exceptions). It may look like they connect to you but some software on your phone or laptop is really polling those services—meaning you are initiating a connection to them every so often to check for new things. To run a web server you will have to enable connections from anyone on the internet at any time. This means they need your domain name to resolve to the correct address (see above) and there must be a port available to connect to. Port forwarding handles this last bit.
- An always on computer for the target system. Mine is a Dell "pizza box" server with 6 Xeon CPUs and 64G of memory. My project involves running some heavy weight Machine Learning but for just the blog, an old retired laptop would suffice. I run Ubuntu 20.04 Linux on the Dell so will call it the "Linux box".
- A static IP address on the LAN or some way to create a destination for the forwarded port(s). In my case I have an Xfinity high speed modem/router connected to my LAN/WiFi router. This means that to accept a connection from the internet, I need to go through both routers, in other words I must have a way for the forwarded ports from the modem go to my router and there be forwarded again to my Linux box. With my Netgear Orbi router that means creating an IP "reservation" and setting my Linux box to have a static address equal to the reserved address on the Orbi. Since most home routers use DHCP, a reserved address will mean the router will not reassign reserved IP addresses so my Linux box can always be fond at the same address over time. This allows me to point the forwarded ports to a static address. Some routers allow you to forward ports to a device by name rather than address, regardless of DHCP, and this simplifies things so that no static LAN address is needed. Alas, this is not my setup.
- Some always on service running on the target system (my linux box) to accept connections on the forwarded port. For me this will be a web server listening on ports 80 (http) and 443 (https). The server will host my blog software.
The first step to getting your home server working is to make some of your cable router's ports tunnel through to your server. This is called Port Forwarding. In my case I had to forward them from my Xfinity cable router AND my Orbi LAN router to finally get to my server.
If anyone tried to connect to the port on your cable modem these connection requests will be forwarded to your LAN and then from there to your server. So connections to 22 (ssh), 80 (http), or 443 (https) will eventually connect to your target server.
- Connect to your DNS host and set your domain's address (A record) to your home IP address. To find your current address search in Google for "what is my ip" et voila. Add this to your host A records in your DNS host for the domain name you want to use (occamsmachete.com for me).
- Froward ports from you cable router/modem to a connected device. For some this might mean forwarding to a specific IP address but for Xfinity you must pick a device and I have only my home router connected. To do this use the web page for your home or get the Xfinity mobile app for managing home networks.
To change forwarding I logged in to https://internet.xfinity.com/connect and chose "see network", which shows my gateway router/modem
from here go to Advanced Settings -> Port Forwarding and choose the Add Port Forward button. This brings up a modal to set a forward. Pick a target device (I only have my Orbi connected so that is all I can choose). Then add a forward for port 22 for ssh. You might as well also add 80 (http) and 443 (https) while you are here
- Next go to your home router's admin screen to do the same forward to your target server (Linux box for me). This will depend on the flavor of home router and is usually in some Advanced settings and called, you guessed it, Port Forwarding. Some routers will allow you to forward to a device so you don't need to worry about LAN DHCP addresses changing but I chose to use a Reserved Address and set my target server to have a fixed address. Either method should work fine. Make sure to save the settings.
I set the same 22, 80, and 443 to be forwarded to my sever. I already know the server responds to 22 because I've logged into it via my LAN. Most Linux distros allow outside connections to a server only on 22 so you can login. But 80 and 443 are often blocked for external (non localhost) connections. No matter, we are only going to use 22 to test.
- Login to your system using ssh:
Maclaurin:~ pat$ ssh firstname.lastname@example.org The authenticity of host '18.104.22.168 (22.214.171.124)' can't be established. ECDSA key fingerprint is SHA256:G+z9FI7YueiEh7l878686kpnnAi0m/jVxLXFmA0blxk. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '126.96.36.199' (ECDSA) to the list of known hosts. Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-42-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Sun 16 Aug 2020 05:22:38 PM UTC System load: 0.0 Temperature: 45.0 C Usage of /: 2.1% of 547.99GB Processes: 342 Memory usage: 1% Users logged in: 1 Swap usage: 0% IPv4 address for eno3: 192.168.1.128 0 updates can be installed immediately. 0 of these updates are security updates. Last login: Sun Aug 16 17:07:25 2020 from 192.168.1.2 pat@angel:~$
Woohoo, made it! But you notice that the first time I tried I used the IP address of the cable router because it takes a few minutes for the DNS address change from step #1 to propagate out to the rest of the world's DNS servers. The next time I connected successfully with
a fix for DHCP
Now we need to account for the fact that cable routers are assigned IP addresses with DHCP and this means they may change at any time. To work around this we need to have a process running all the time on the target server, which checks for IP address changes and adjusts your DNS host mapping immediately. This will require a tool that can modify your mapping without your human intervention. The tool of choice for standard DynDNS or DDNS, is
ddclient, which works with the more standard DNS hosting services. Unfortunately for me, I would have to find one that works with enom's non-standard DDNS interface so I moved my DNS hosting service to Namecheap.com because is has standard DDNS APIs.
Dima's blog has a great tutorial for setting up
ddclient, especially since it covers the Namecheap config part.
I've been learning some node.js so I need to setup Ghost as a blog platform and get auto-updated free SSL certs working with certbot. But that is another story...