Securing Public Facing Services - My Homelab Experience
Nothing is quite as satisfying as self-hosting your own services. I know I do it for things like Bitwarden, Immich, and a ton of other docker containers. However, when it comes to serving these services to your friends and family, things get a little more complicated. You need to expose these services so they can access them, and you'll be tempted to port-forward the service ports or use a reverse proxy like NGINX Proxy Manager (NPM) to expose these services. That's fine- in fact, it's definitely possible to do! But you have to understand the risk involved with exposing these services to the internet. If you're not careful, it's only a matter of time before some vulnerability on your network is exploited. I'm here to tell you the tips of the trade regarding public facing services, and what tools you have to prevent attackers from messing with your stuff.
Getting straight to the point, there are several ways you can access and serve your services remotely:
VPN (Wireguard, etc.)
Reverse Proxy (NGINX Proxy Manager, etc.)
Port-Forward
Cloudflare Tunnel
Tailscale
One of the most recommended and safest ways is to use a VPN, such as Wireguard, to connect to your LAN remotely. Then you'll have access to anything on your LAN without having to expose public facing ports at the router. By doing this, you'll be able to access your stuff through a safe channel, and you'll reduce your attack surface significantly. This is definitely what I would recommend for someone who doesn't want to think too hard about security. You'll still want to make sure your Wireguard server endpoint is kept up-to-date, as that's the only thing that will need to be public-facing in this scenario. The only concern with this approach is the added friction- you'll have to use Wireguard to access any of your services. That's a real pain, especially when you're trying to get other people who aren't YOU to access those services. Yes, you could spin up Wireguard keys for all your "customers" who want to access your services, but you could be granting access to your entire LAN to a bunch of friends and family, not to mention allowing them to route their internet traffic through you while connected. You may want to do some additional configuration if you want to prevent this.
Another option is to simply use a reverse proxy or port-forward the services at your router. If you own a domain, you could host these web services over a reverse proxy such as NGINX Proxy Manager. This is my primary method for exposing services, but it does come with some drawbacks such as understanding the risks involved with your services being open to the public. You'll be probed and prodded by bots, and you're bound to run into someone trying to exploit vulnerabilities. It's happened to me plenty. The key is to be ready for that eventuality, have a plan, and reduce your attack surface as much as possible.
How I do it: I have two approaches. Most of my private services I access over my VPN. I VPN in, access these private services, and I never have to expose them to the web. This reduces my attack surface significantly. Then, I use NPM for the truly "public" services. These are things I want my friends / family to access. However, these services must be frequently updated to ensure they are getting security updates. I also only try and expose services from developers with a reputation. Hosting a vibe-coded slop project that someone just made? That's a bad move. Hosting a popular open-source project that has a million stars on github, and has been around for years and years? Probably safer. It's ideal you're building a sixth sense for this sort of thing.
Even though I don't use them, I think many should look into Tailscale or Cloudflare Tunnels. Many on reddit/r/selfhosted will tell you that Cloudflare Tunnels are a solid option for helping secure public facing services. I don't use it personally simply because it's an external dependency I want to avoid.
Being ready for disaster is key regardless. Truly private data is probably best only accessed via your VPN- if it's public facing, the worst case scenarios are that data can leak and get in the hands of those who should not have it. They may delete or destroy things, and maybe even run malware. My environment leverages docker containers, which are for the most part, isolated sandboxes. If someone exploits a container, I have plans in place for how to react.
Knowing this, I run routine backups of important data, isolate everything with Docker, and employ lots of monitoring tools. I run Beszel, a system monitoring tool, which I set thermal, CPU, MEM, and Storage thresholds for. If any of these thresholds are exceeded, I get notifications. These notifications have allowed me to detect attacks many times. I monitor and graph a lot of stuff as well with Grafana, so I can look at trends over time. You could also employ a SIEM logging server so you can look at historical events. It's a lot to establish, but if you're going to host public-facing services, it's going to pay off.
One thing you could do is leverage AI for diagnostics and monitoring. If the adversary is going to use AI to find exploits, why can't you do it first? AI can advise you on your weaknesses as well. In fact, during one attack I recently experienced, I was able to mitigate an attack by using fail2ban and geoblocking IPs. This is something that I implemented with the help of local LLMs. Geoblocking can prevent a bulk of the bots from probing you. Definitely look into using AI as a cyber security tool, with moderation.
It may feel discouraging to know the work involved with safely exposing services to the web, it's possible to do relatively safely as long as you understand the risks. I've been running my own services for years, and yes, while there have been the occasional hiccups, nothing has been catastrophic. Assume someone is knocking on your front door, trying to get in, and take the necessary precautions. Once you do that, the adversary will have a much harder door to get through.