Documentation / Kubernetes Integration

Kubernetes Integration

Automatically expose Kubernetes services to the internet with a simple annotation

Overview

The stunl Kubernetes Controller watches for Services with the stunl.com/expose annotation and automatically creates tunnel client deployments to expose them to the internet.

How It Works

1. Annotate Service
stunl.com/expose: "true"
2. Controller Creates Tunnel
Deployment: stunl-myapp
3. Service Exposed
https://myapp.stunl.io

Benefits

  • No LoadBalancer or Ingress required
  • Works in any cluster (local, cloud, air-gapped)
  • Automatic TLS certificates
  • GitOps compatible (annotation-based)

Installation

1

Create namespace and RBAC

$ kubectl create namespace stunl-system
$ kubectl apply -f https://stunl.com/k8s/rbac.yaml
2

Create API key secret

$ kubectl create secret generic stunl-api-key \
    --namespace stunl-system \
    --from-literal=api-key=st_pro_your_key_here
3

Deploy the controller

$ kubectl apply -f https://stunl.com/k8s/controller.yaml

# Verify controller is running
$ kubectl get pods -n stunl-system
NAME                               READY   STATUS    RESTARTS   AGE
stunl-controller-7d8f9b6c4-x2k9p   1/1     Running   0          30s

Usage

Add the stunl.com/expose: "true" annotation to any Service to expose it.

service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-web-app
  annotations:
    stunl.com/expose: "true"
    stunl.com/subdomain: "myapp"          # Optional: custom subdomain
    stunl.com/protocol: "http"            # Optional: http (default), tcp, udp
spec:
  selector:
    app: my-web-app
  ports:
    - port: 80
      targetPort: 8080
Apply and check
$ kubectl apply -f service.yaml

# The controller automatically adds the tunnel URL annotation
$ kubectl get svc my-web-app -o jsonpath='{.metadata.annotations.stunl\.com/url}'
https://myapp.stunl.io

Annotations Reference

Annotation Description Default
stunl.com/expose Enable tunnel for this Service "false"
stunl.com/subdomain Custom subdomain {name}-{namespace}
stunl.com/protocol Protocol: http, tcp, udp "http"
stunl.com/domain Pro domain (e.g., localshare.io) stunl.io
stunl.com/use-root Use root domain (no subdomain) "false"

Output Annotation

The controller automatically adds stunl.com/url to the Service with the public tunnel URL once the tunnel is established.

Examples

HTTP Service (Web App)

apiVersion: v1
kind: Service
metadata:
  name: frontend
  annotations:
    stunl.com/expose: "true"
    stunl.com/subdomain: "demo"
spec:
  ports:
    - port: 80
# Result: https://demo.stunl.io

TCP Service (Database)

apiVersion: v1
kind: Service
metadata:
  name: postgres
  annotations:
    stunl.com/expose: "true"
    stunl.com/protocol: "tcp"
    stunl.com/subdomain: "mydb"
spec:
  ports:
    - port: 5432
# Result: mydb.stunl.io:15432

Pro Domain

apiVersion: v1
kind: Service
metadata:
  name: api
  annotations:
    stunl.com/expose: "true"
    stunl.com/domain: "localshare.io"
    stunl.com/subdomain: "api"
spec:
  ports:
    - port: 8080
# Result: https://api.localshare.io

Controller Configuration

The controller can be configured via command-line arguments in the deployment:

Flag Description Default
--tunnel-server stunl server address portal.stunl.com
--client-image Tunnel client container image (required — must specify a pinned version tag, e.g., stunl/client:v5.35.0)
--metrics-bind-address Metrics endpoint address :8080
--health-probe-bind-address Health check endpoint :8081
--leader-elect Enable leader election for HA false

Security Considerations

RBAC Permissions

The controller requires RBAC permissions to get/list/watch/update/patch Services (for annotations and finalizers), create/update/delete Deployments, record Events, and manage Leases for leader election.

API Key Secret

Store your API key in a Kubernetes Secret. The tunnel client pods must be configured to reference this secret via environment variable or volume mount.

Network Policies

The controller deployment includes NetworkPolicy to restrict egress to the Kubernetes API server and DNS only. Tunnel client pods connect to the stunl server directly.

Pod Security

Controller runs as non-root with read-only root filesystem and all capabilities dropped.

Troubleshooting

Tunnel not created

Check controller logs:

kubectl logs -n stunl-system deployment/stunl-controller

Tunnel pod crashing

Check the tunnel deployment logs:

kubectl logs deployment/stunl-{service-name} -n {namespace}

Check events

The controller records validation failures as Events:

kubectl get events --field-selector reason=ValidationFailed

Next Steps