Serving private resources to public internet with tunneling
I have several applications running on home network that need to be accessible from public internet. What's a simple and secure way to achieve this?
Port forwarding
Port forwarding is one way to expose applications on your local network to public internet. You define how the inbound traffic is forwarded internally per source IP range, network protocol, and port. The router acts like a reverse proxy and you maintain the routing table. Although this does the job, there are a few things I dislike about port forwarding.
- ISP Restrictions: Some ISPs block port forwarding. Use portcheckers to verify if your port is open.
- Dynamic IP: Home internet plans usually come with dynamic IPs. If your services are behind a DNS, you need to keep it updated. Some routers support dynamic DNS update but a more practical approach is to write a script that periodically checks for IP changes and updates the DNS record if needed, assuming your DNS provider has such API (most do). The workaround is still not ideal, there is a delay between pings and basically there is another cron job you have to babysit.
- Exposure of IP/DNS: Your public IP and DNS info are exposed. Not comfortable with this at all. The internet is a wild wild west full of unwanted traffic from web crawlers, port scanners, vulnerability scanners...
- Complex Troubleshooting: Port forwarding is not always sufficient, firewall rules on the router, the kernel, or Docker containers can block inbound traffic and complicate troubleshooting.
- Multiple Devices: When your applications run on several devices and routers, you often need multi hops of port forwarding (i.e., multiple "reverse proxies"). Managing those rules across different devices can be a hassle, especially when things have been running smoothly for awhile then suddenly one device's IP changes for example. You’ve already lost track of your network topology and need to troubleshoot again.
- Router Bugs: Sometimes port forwarding simply stops working due to router bugs. Randomly enabling or disabling a certain router feature can invalidate your port forwarding rules.
Port fowarding is unreliable and requires constant maintenance effort. It's even more frustrating that some factors are beyond your control, and this is the final straw that made me seek an alternative.
Tunneling
One example of such service is Cloudflare Tunnel. Essentially, you install a Cloudflare Tunnel daemon (as a docker container or a binary) on one of your devices, VMs or such. As long as this daemon can reach public internet (Cloudflare) and your resources on internal network, it will create an encrypted tunnel between your origin web server and Cloudflare. All the issues with inbound traffic are gone, the set up is dead simple and should take a few mins. Once the daemon is installed, specify the internal endpoint for the service you want to expose, and assign a public hostname. That's it, you're good to go.
Their free tier is good enough for my use case atm, hopefully it remains free or cheap. And here are a bunch of alternatives just in case.