Skip to content

jacaudi/towonel-operator

Repository files navigation

towonel-operator

A Kubernetes operator that automates Towonel self-hosted tunnels — provisioning tunnels, deploying agents, and connecting them, declaratively.

Warning

Agentically generated. This codebase was produced through agentic, spec-driven development: each feature began as a written design and implementation spec, then a coding agent executed the plan under human review. Tests, code review, and CI gates apply as they would for any project, but the authorship pattern is not a single human contributor — keep that in mind when evaluating fit for your environment.

What it does

Towonel exposes services behind NAT/CGNAT without inbound ports. This operator drives that from Kubernetes via two resources:

  • TowonelTunnel — the control plane. Reconciles a Towonel invite (token, authorized hostnames, TCP/UDP port reservations) against the Towonel API and owns the token Secret.
  • TowonelAgent — a placement-specific workload that references a tunnel and renders the agent Deployment plus its hostname → origin routing. Multiple agents can share one tunnel for failover.

You can author those resources directly, or annotate a Service, Gateway, or HTTPRoute and let the operator materialize them (the dogfooding path). Set towonel.io/auto-routes: "true" on a Gateway to tunnel its same-namespace HTTPRoutes without annotating each one — see Gateway auto-routes. A Gateway can extend auto-routes to other namespaces with an opt-in towonel.io/auto-routes-namespaces allowlist (off by default) — note the security implications of public cross-namespace exposure. See docs/architecture.md for the why behind the two-resource split.

Quickstart

Prerequisites: a Towonel account + a personal API key, and a Kubernetes cluster. (Full prerequisites and chart values: docs/installation.md.)

1. Install the operator (Helm, OCI chart on GHCR):

kubectl create namespace towonel-system
kubectl create secret generic towonel-api -n towonel-system --from-literal=token='twk_xxx'

helm install towonel-operator \
  oci://ghcr.io/jacaudi/charts/towonel-operator --version <version> \
  --namespace towonel-system \
  --set credentials.existingSecret=towonel-api

Replace <version> with the chart version you want — use the latest release (currently v1.0.1).

2. Create a tunnel (the control plane — provisions the Towonel invite + token):

apiVersion: towonel.io/v1alpha1
kind: TowonelTunnel
metadata:
  name: app
  namespace: towonel-system
spec:
  region: EU
  apiKeySecretRef:
    name: towonel-api
    key: token
  deletionPolicy: Retain

3. Expose a service — either annotate it:

apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: monitoring
  annotations:
    towonel.io/tunnel: enable
    towonel.io/tunnel-ref: towonel-system/app
    towonel.io/hostname: grafana.example.com
spec:
  selector:
    app.kubernetes.io/name: grafana
  ports:
    - name: http
      port: 3000
      targetPort: 3000

…or author a TowonelAgent directly for full control (HTTPS + raw TCP/UDP, failover, direct-path connectivity) — see docs/examples/.

4. Point DNS. The operator does not manage DNS yet — read the tunnel's status (authorizedHostnames, portAllocations[].edge.addresses) and create the records in your DNS provider. See docs/dns.md.

kubectl get towoneltunnel app -n towonel-system -o yaml   # inspect status

Agent metrics (Prometheus)

Operator-managed Towonel agent pods serve Prometheus metrics at /metrics on port 9090. Scraping is opt-in and off by default. Enable a single cluster-wide PodMonitor (selects all agent pods in every namespace) via the chart:

observability:
  metrics:
    agentPodMonitor:
      enabled: true
      # Most Prometheus installs only discover PodMonitors carrying a specific label:
      additionalLabels:
        release: kube-prometheus-stack
  • Requires the Prometheus Operator PodMonitor CRD (monitoring.coreos.com/v1). With the toggle on, helm install/upgrade fails on clusters without it.
  • additionalLabels is usually required. kube-prometheus-stack only selects PodMonitors carrying its release label; without it the PodMonitor is silently ignored — enabled but never scraped.
  • Namespace-scoped Prometheus. The PodMonitor selects pods in all namespaces (namespaceSelector.any: true), but a Prometheus restricted by podMonitorNamespaceSelector must be allowed to read it and the agent namespaces.
  • Existing agents. The metrics port reaches already-running agents only on their next config change; to cover them immediately, run kubectl rollout restart deploy -l app.kubernetes.io/name=towonel-agent.

Documentation

Full docs live in docs/:

Acknowledgements

  • Bernd Schorgers (bjw-s) — this operator's Helm chart is built on the bjw-s app-template common library, which does the heavy lifting of rendering the controller Deployment, RBAC, service account, and service. Thank you for an excellent, reusable chart!
  • Erwan Leboucher (eleboucher) — the creator of Towonel itself (codeberg · github). This operator only automates the client side; Towonel — the hub, edges, and agent — is his work. Thank you for creating a self-hosted Cloudflare Tunnel replacement!

License

MIT

About

Kubernetes operator that declaratively provisions Towonel self-hosted tunnels and agents to expose services behind NAT/CGNAT without inbound ports.

Topics

Resources

License

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages