http-internal (resource)
A shared cluster resource — not per-app, but referenced by many. It defines the Gateway that every internal-only app attaches its HTTPRoute to. The Gateway is reachable from the home LAN and over the NetBird mesh, but not from the public internet.
Think of it as the "internal counterpart" to the public Gateway that the edge cluster terminates traffic into. An app that should never be reachable by the internet attaches to http-internal and is reachable by mesh members only.
What it composes
The shared resource declares:
Gatewayinternal— Envoy Gateway listener with a private-zone wildcard certificate, addressable only on cluster-internal and mesh IPs.HTTPRouteparent reference — apps reference this gateway by name from their ownHTTPRouteresources.- Backend TLS policy — wherever upstream services speak TLS internally, the listener trusts the homelab's internal CA.
The matching public-zone Gateway is provisioned by Envoy Gateway at the cluster level and isn't part of this resource.
How an app uses it
# k8s/apps/talos/<app>/<app>-httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: <app>
namespace: <app>
spec:
parentRefs:
- name: internal
namespace: gateway-system # the parent Gateway from http-internal
hostnames:
- <app>.int.kueber.eu
rules:
- backendRefs:
- name: <app>
port: 80
The app declares its hostname under *.int.kueber.eu (or whichever internal zone applies) and the Gateway routes it. Public-zone apps attach to the public Gateway instead.
Why internal vs. public Gateway is separated
- Different TLS chain. The internal Gateway terminates with a private-zone certificate that's only trusted by clients on the home LAN / mesh. The public Gateway uses a Let's Encrypt cert that the open internet trusts.
- Different scope of "compromise." A misconfigured
HTTPRouteon the internal Gateway can't accidentally expose an app to the public web. The wrong Gateway is the wrong listener; nothing else changes. - Different policies. The internal Gateway is more permissive (no rate limits, no WAF). The public one is locked down.
Operational notes
- The internal zone (
*.int.kueber.eu) is served by the home DNS — see AdGuard Home for how clients resolve it. - Adding a new internal app: declare an
HTTPRouteagainstparentRefs: [internal], add the hostname to the AdGuard DNS rewrites (or to UniFi's local resolver), and the cluster routes it. - If an internal app needs to also be exposed publicly (rare), add a second
HTTPRouteagainst the public Gateway. Don't try to dual-mode one resource.