While ngrok already uses ngrok to dogfood ngrok.com , I can’t forget about its close cousin: When your engineers use your product to power their homelabs.
Honestly, I’m not even sure what to call it. Doglabbing? Homefooding ?
Either way, I’ve heard plenty of stories about how ngrokkers use endpoints and Traffic Policy to access their homelabs from everywhere, or securely share services with friends and family, and thought it was about time for a round-robin look at the shapes of their networks, the policies that rule them, and the gateways that wire it all up.
So, let’s hear from each engineer, in their own words, about exactly how they’re using ngrok for their personal homelabs and self-hosted side projects.
While I also use ngrok + Traffic Policy for my home lab, my recent use case was for actually for my website and blog on a VPS, where I wanted to host umami as a privacy-focused alternative to Google Analytics via docker .
To avoid having to run it bare metal or to set up a reverse proxy or similar plumbing (the server already runs nginx and not much else), I used ngrok to expose the service and Traffic Policy to secure it—the admin interface should only be accessible to me, where the client-side script needs to be publicly accessible.
I secure all services with OAuth and IP Intelligence rules to filter on conn.client_ip.is_on_blocklist (and geo location, occasionally).
However, since umami needs to serve its script client-side, I needed to set up some exclusion rules to the OAuth path to ensure /script.js can be served (and that it works!) without OAuth. I’ve had to use this trick for other services that expose external endpoints, but do not completely contain them on one path.
Agent configuration:
What’s happening here? On every HTTP request, this policy:
I wanted to be able to have a central policy for controlling auth, header additions, and not need to think about these on a per endpoint basis.
My solution was to create a CloudEndpoint CRD attached to wildcard domain, use set-vars to chop off the subdomain and forward-internal to an internal endpoint. Now I don’t need to worry where my internal endpoints live, just what they are named. I have ngrok Kubernetes Operator -managed AgentEndpoints , ngrok Docker -started endpoints, and internal CloudEndpoints all with consistent behavior and unified auth.
Gateway config via the ngrok Kubernetes Operator and a CloudEndpoint CRD:
I’m a long-time Kubernetes user, and I wanted to run Kubernetes in my home lab because I like the ecosystem and I like trying new projects. I wanted a way to hit these projects when I’m not at home, and generally expose these services on the internet, with something simple that wouldn’t require a lot of feeding and wouldn’t force me to open up ports or deal with UPnP or anything like that.
I’m used to setting up K8s in a cloud environment, where I have easy access to a cloud load balancer, or even static IPs for on-prem, but when you’re at the mercy of your ISP, this is a lot trickier. See the MetalLB project for proof of how hard this can be based on your network.
ngrok’s Traffic Policy and ability to put OAuth in front of my applications was a big plus. It’s an extra layer of protection to make sure I’m the only one accessing my homelab, and I don’t have to worry about security vulnerabilities in the apps themselves or doxxing my IP because people don’t see where I’m hosting everything.
And it just works wherever—if I unplugged my homelab and went to Cali for an offsite, and had internet access, it would be up and running again.
Ingress resources for Argo CD’s dashboard and gRCP server:
Referenced TrafficPolicy CRDs:
What’s happening in these policies?
The google-oauth policy:
The only-trusted-ips policy:
For the past few years, I’ve slowly been de-Googling my life. One of the last Google services in my life was Google Photos, which remained for one reason: sharing. After going on a trip, I want to give my companions access to all the pictures I took, allowing them to pick their favorites and download them. I also want an easy, convenient place for them to share their pictures with me.
After doing some research, I came across the perfect solution: immich !
Well, almost perfect. The main downside is that it would run on my home server, so I’d have to be careful about how I expose it. I came up with a few requirements:
The first thing I need to do is pick a login method. While it would be super simple to just pick Google OAuth, it kind of defeats the purpose. Instead, I’ll use SimpleLogin. It’s a little more setup, but it’s free and lets me use my Proton address. ngrok has an OIDC Traffic Policy action , meaning I can set up OIDC with a few lines of YAML!
From there, I check that the email of the logged-in user exists in a list of all allowed users, created using the set-vars action. If not, they are rejected, ensuring unauthorized users never contact my home network. From there, ngrok routes traffic to an internal endpoint, depending on the host (service) they are trying to reach. Each service also has its own access list.
The internal endpoints are initiated by agents that sit in my home network. They do nothing more than forward the traffic to the appropriate local IP/port, meaning I only ever have to interact with the local machine to occasionally update the system/ ngrok client.
The coolest thing about this setup is that immich can be configured with OAuth as well! By configuring immich with the same OAuth settings as our OIDC action and turning on Auto Start , they will be transparently logged into immich after authenticating at my ngrok -powered gateway.
Even better, by turning on Auto Register , an account will be automatically created for them upon first login! This means I can manage my users solely through the immich_users variable in my traffic policy. When I want to add a new user, I add their protonmail address to that list, they sign in, and they can immediately start updating and sharing!
The biggest limitation of my current approach is that the immich mobile app does not work with this setup. It wants to connect to the server (unauthenticated) to obtain OIDC information. While I could update my policy to allow those particular routes to be accessed without authentication, I would rather err on the side of security. As someone who does not use a phone much, I can live with the tradeoff.
Gateway config with a Cloud Endpoint:
What’s happening here? On every HTTP request, this policy does a lot:
I used to run a URL shortener in college. That was a mistake, but you know, once you start running something you can’t stop running it, so I’ve been running it forever, ever since then. It would be nice to run it with no servers involved because maintaining servers is fun, but not maintaining them is also fun.
Since I started working at ngrok, I noticed that many work-related URLs are long and hard to read, like https://www.notion.so/ngrok/$PAGE-TITLE-$super-long-uuid-$super-long-hash-uuid . go.ngrok.pizza/page-title is way shorter.
It seemed like a fun challenge to try and make an fully functioning URL shorterner with no external dependencies, and so I ended up with the following policy.
This uses ngrok’s Internal Endpoints as the sorta key/value database, which is written to with the http-request action, and read with the forward-internal action.
I won’t exactly recommend using anything like this, but I do think it’s a neat hack!
Gateway config + shortener logic with a Cloud Endpoint:
What’s happening here? Well, a lot, but in short—on every HTTP request, this policy:
We can’t officially call your setup an attempt at “homefooding” (well, unless you join us , and yes, I’m still workshopping the name), but we’d love to have you building gateways and policies alongside us.