Being reachable on a public IP address

Posted on 2021-May-23 in networking

Note: I am not affiliated or employed by any of the providers mentioned below. I am only providing links for convenience, I make no money or karma when you click any of those.

selfhosting

Say you want to host some service at home and make it reachable from the Internet. What are your options?

Most obvious choice: start a server on your home network, forward the adequate ports from your home router, done. While this is by far the easiest solution, it is not ideal for several reasons:

  • If your home router belongs to your ISP, it may not have the option to forward ports to your internal network.
  • Even with your own router, your ISP may simply not allow open the ports you want to the outside world. I have experience with an ISP using ports 80 and 443 for their own router needs, making it impossible to use them for home services.

If the service you want to host at home uses exotic port numbers like a Synology NAS or a NextCloud instance, it should be fine. Just forget about hosting your own web site at home.

Your next hurdle might simply be your public IP address. In many cases, ISPs provide temporary public IP addresses. That should not be a problem with a little help from a dynamic DNS provider. Open an account with a provider like no-ip.com or dyndns and make sure you run their client on a 24x7 server on your home network to update your dynamic DNS entry every time your public IP changes.

That is exactly what I did in the past. I used dyndns for a while, then switched to no-ip when dyndns became a pain to use. In all cases you get a choice of the subdomain and your server ends up being something like myserver.yet-another-dynamic-provider.com. That's fine if all you want is a pointer to your home server but if you are serving web pages or anything relevant to a larger audience than yourself, those names are not really cool.

Another option would be to purchase a domain name from a registrar that offers an API (ideally an SDK) to allow you to script a name/address change from your home server. Domain names can get really cheap those days, especially for top-level domains like .xyz. Don't get attracted by the latest discounts, the important price to watch is the renewal price. I have rented some names for less than $1/year the first year, only to be greeted with a $30+/year renewal price a year later when I had started circulating that domain name to everyone who should care about it. That's not cool.

Once you have your own domain name, the procedure to follow is to run a cron job every minute or so to do:

  • Get the IP address associated to myservice.mydomain
  • Get your current home public IP address
  • If they are different, call the script to update myservice.mydomain with your new public IP address. Don't forget to set a short TTL for that particular name so it hopefully gets updated fast when the address changes.

Updating your IP/name should ideally be delegated to your home router if you could reliably program it to trigger an event every time your public IP changes, together with the new address. Unfortunately most ISP-provided routers are not programmable. Dynamic DNS providers will give you a client to download that does just what is described above, running on a separate machine on your home network.

A reliable way to learn your own public IP address is to ask a service like ipinfo.io.

Something as simple as:

curl ipinfo.io

There are several sites available for that kind of service and most of them have rate-limiting so make sure your client update script is not started too often, depending on terms and conditions from the site you use.

With that in hand you should be able to make your home server visible from the Internet on a reachable name. You may still suffer from ports like HTTP/HTTPS being blocked on your router, forcing you to publish an address for your self-hosted blog that look like myblog.mydomain:9998/

That works but that isn't very nice. It opens a port on your home IP address, which widens your attack surface. If the service you host gets caught into a DDoS storm you won't be able to use your Internet connection until the storm subsides.

After years of using such tricks, I moved on to another solution that involves renting an IP address and a server. Let me elaborate:

Go find a cheap Virtual Private Server (VPS) online. In Europe you can probably rent one from OVH or Hetzner for a handful of euros per month. You don't care about powerful CPUs, lots of RAM, or lots of disk space. All you want is enough power to run a minimal Linux distro, a public IP address, and ideally unlimited traffic on a reasonable bandwidth. The cheapest I could find is 2 euros/month for unlimited traffic with 250Mbit/s bandwidth.

That VPS will be your front-end to the Internet. Register its IP address with your DNS like myblog.mydomain and this shouldn't change until you decide to move to another VPS. No need to run an update script every minute.

Next step is to create a permanent link between your home network and your VPS. Several options there:

  • Run a reverse SSH tunnel if you know how this works, e.g. with autossh.
  • Run your own Virtual Private Network (VPN) between your VPS and your home network.

I won't get into how to use autossh to build a tunnel that automatically restarts when the link gets broken as there are excellent tutorials for that. You absolutely need to plan for that link to get broken every time your home Internet connection gets interrupted, e.g. when someone brutally unplugs your router to plug in the vacuum cleaner, or when your ISP decides to upgrade your modem firmware. Get real: your home connection is not in a data center.

There are several options for running your own VPN to your VPS:

IPSec

That stuff is reserved for network admins who received a complete training on setting it up and running it correctly. Don't try this at home, life is too short.

OpenVPN

I used that one for years until Wireguard became available on all recent Linux boxes. OpenVPN is a cool project but very heavy in terms of resources and not very performant. Configuring a simple point-to-point OpenVPN server is a major pain in the butt that is likely to take you several hours every time it stops working. You may be lucky enough to have an option to run an OpenVPN client on your home router (e.g. if you built your own with OpenWRT) but don't count on it. A GUI won't make your configuration issues magically go away.

Wireguard

Wireguard is the new VPN kid on the block. This (entirely free) Linux kernel module is now included into most Linux distros and works out of the box with very few configuration steps. You can find Wireguard clients for Linux, Mac, Windows, Android, and iOS. In most cases the client deals directly with the OS kernel, making it very efficient and extremely fast compared to OpenVPN. Subscribing a mobile phone onto a VPN is just a matter of scanning a QR code, it is ridiculously simple. There are excellent tutorials about how to set up your own Wireguard VPN.

Tailscale

Tailscale is a commercial service available for free to home users, within some reasonable limits. Tailscale is based on Wireguard but offers an even simpler configuration: install clients on your machines, log onto Tailscale with your credentials, done. The best part is that you don't even have to deal with setting up a NAT on your private network, enabling packet forwarding or firewall rules of any kind. If all you want is a working setup, take some time to read through their docs. The only downside I found is that updating the client often requires re-authenticating to tailscale, interrupting the service without warning. It is Ok for a smartphone VPN client but not really cool for 24x7 servers running without much supervision.

There are other advantages to running Tailscale vs running Wireguard like out-of-the-box support for mesh configuration. Check both out before you make up your mind on a given VPN solution.

Now let's assume you are running your own VPN between your VPS and your home server. Your next step will be to install a reverse proxy on your VPS to forward all requests made to a given port or host name to a specific address:port combination on your private network. Something like: incoming requests for myblog.mydomain (80 or 443) get forwarded to 10.10.10.2 (same ports), which is the address of your home server on your VPN. Internet users only see the VPS public address, your home server only listens to its VPN address and is not reachable from anywhere except other machines on the same VPN.

The beauty of that approach is that you can host several services from multiple domains on the same public IP address and let the reverse proxy do its job and forward to whatever home server you happen to run. You can even request server certificates from LetsEncrypt and install them all on your reverse proxy, then run a straight non-TLS connection between your VPS and home server. That line is already protected by your VPN.

Several choices are available for reverse proxies. I tend to use nginx which is a real breeze to set up.

If you need to forward other ports or other protocols you can use a bare-bone solution like socat to forward packets from the public IP on your VPS to an internal address on your VPN. Beware that socat will terminate as soon as the connection is broken, so best encapsulate it into a systemd service or simply a while loop in a shell script to automatically restart it when needed.

The final result is quite nice: the only visible IP address is the one you rent with your Virtual Server, on your choice of DNS name and port. If it gets caught into a DDoS storm, your service will become unreachable but your home Internet stays fine. Many VPS providers offer DDoS protection tools which may be efficient enough to stop most such attacks.

Meanwhile, your home address is only connected through a VPN based on UDP packets, which makes it a lot harder to discover by stupid Internet-searching robots. Using a solution like Wireguard is unlikely to eat up lots of CPU/RAM on your home server: in my experience a Raspberry Pi 4 is largely enough to saturate a 250Mbit/s connection. If you are paranoid, you can run Virtual Machines or containers on your RPi4 to encapsulate your services and limit damages in case someone manages to take control of your VPS. Make sure you run automatic updates on that VPS Linux box because you won't log onto it every day.

If your home connection is slower than what your VPS can serve, you also probably want to rate-limit that VPN connection if you don't want to flood your home Internet connection the day your service becomes popular. Some good tutorials should help there.

I have no pointed any particular tutorial in that post as new good ones keep popping up every day and I am too lazy to do a good research that will become obsolete in a year.

Enjoy your public home services!