Skip to main content
Version: Next

Wstunnel Configuration

InterLink's wstunnel feature enables secure port exposure for pods with containers that have exposed ports. This feature automatically creates websocket tunnel infrastructure outside the virtual node, allowing external access to pod services without requiring VPN connectivity.

Overview

The wstunnel integration provides:

  • Automatic Infrastructure Creation: Deployment, Service, and Ingress resources
  • Secure Tunneling: WebSocket-based tunneling with random password protection
  • Port Forwarding: Automatic forwarding of all exposed container ports
  • External Access: Ingress-based external access with customizable DNS
  • Resource Management: Automatic cleanup when pods are deleted
info

Wstunnel is disabled by default and must be explicitly enabled in the configuration.


Configuration

Virtual Kubelet Configuration

Add the wstunnel configuration to your Virtual Kubelet config file:

# VirtualKubeletConfig.yaml
InterlinkURL: "http://interlink-api:3000"
InterlinkPort: "3000"
VerboseLogging: true
ErrorsOnlyLogging: false

# Network configuration
Network:
EnableTunnel: true # Enable wstunnel feature
WildcardDNS: "tunnel.example.com" # DNS domain for ingress
WstunnelTemplatePath: "/etc/templates/custom.yaml" # Optional: custom template path
WstunnelCommand: "custom-wstunnel-command" # Optional: custom wstunnel client command

# Other configuration...
Resources:
CPU: "10"
Memory: "20Gi"
Pods: "100"

Configuration Options

OptionTypeRequiredDefaultDescription
EnableTunnelboolNofalseEnable/disable wstunnel feature
WildcardDNSstringYes*""DNS domain for ingress hostnames
WstunnelTemplatePathstringNo""Path to custom wstunnel template
WstunnelCommandstringNoDefaultWstunnelCommandCustom wstunnel client command template

*Required when EnableTunnel is true


How It Works

Automatic Trigger

Wstunnel infrastructure is automatically created when:

  1. Network.EnableTunnel is set to true
  2. Pod has containers with exposed ports
  3. Pod does NOT have interlink.eu/pod-vpn annotation

Resource Creation

For each qualifying pod, interLink creates:

  1. Deployment: Runs wstunnel server with WireGuard
  2. Service: Exposes websocket and forwarded ports
  3. Ingress: Provides external access via DNS

Naming Convention

Resources are named using the pattern: {pod-name}-wstunnel

Example: Pod my-web-app → Resources my-web-app-wstunnel


Template System

Default Template

InterLink includes an embedded default template that creates:

# Deployment with wstunnel server
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/component: {{.Name}}
template:
metadata:
labels:
app.kubernetes.io/component: {{.Name}}
spec:
containers:
- name: wireguard
image: ghcr.io/dciangot/dciangot/wg:v0.2
command: ["bash", "-c"]
args:
- ./wstunnel server --log-lvl DEBUG --dns-resolver-prefer-ipv4 --restrict-http-upgrade-path-prefix {{.RandomPassword}} ws://0.0.0.0:8080
ports:
- containerPort: 8080
name: webhook
protocol: TCP
- containerPort: 51820
name: vpn
protocol: UDP
{{- range .ExposedPorts}}
- containerPort: {{.Port}}
name: {{.Name}}
protocol: {{.Protocol}}
{{- end}}
resources:
requests:
cpu: 100m
memory: 90Mi
nodeSelector:
kubernetes.io/os: linux

---
# Service for port exposure
apiVersion: v1
kind: Service
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
spec:
type: ClusterIP
selector:
app.kubernetes.io/component: {{.Name}}
ports:
- port: 8080
targetPort: 8080
name: ws
{{- range .ExposedPorts}}
- port: {{.Port}}
targetPort: {{.TargetPort}}
name: {{.Name}}
protocol: {{.Protocol}}
{{- end}}

---
# Ingress for external access
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/server-snippets: |
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: ws-{{.Name}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: 8080

Template Variables

The template system provides these variables:

VariableTypeDescriptionExample
{{.Name}}stringResource namemy-web-app-wstunnel
{{.Namespace}}stringPod namespacedefault
{{.RandomPassword}}stringSecurity passworda1b2c3d4e5f6...
{{.WildcardDNS}}stringDNS domaintunnel.example.com
{{.ExposedPorts}}[]PortMappingPort mappingsSee below

Port Mapping Structure

type PortMapping struct {
Port int32 // Container port number
TargetPort int32 // Target port (usually same as Port)
Name string // Port name
Protocol string // Protocol (TCP/UDP)
}

Custom Templates

You can provide custom templates by:

  1. Creating a custom template file:

    # /etc/templates/custom-wstunnel.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: {{.Name}}
    namespace: {{.Namespace}}
    spec:
    # Your custom configuration...
  2. Configuring the template path:

    Network:
    EnableTunnel: true
    WildcardDNS: "tunnel.example.com"
    WstunnelTemplatePath: "/etc/templates/custom-wstunnel.yaml"
  3. Mounting the template in the Virtual Kubelet deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: virtual-kubelet
    spec:
    template:
    spec:
    containers:
    - name: virtual-kubelet
    volumeMounts:
    - name: wstunnel-template
    mountPath: /etc/templates/custom-wstunnel.yaml
    subPath: custom-wstunnel.yaml
    volumes:
    - name: wstunnel-template
    configMap:
    name: wstunnel-template

Pod Configuration

Basic Pod with Exposed Ports

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
restartPolicy: Never

Pod with Custom Timeout

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
annotations:
interlink.virtual-kubelet.io/wstunnel-timeout: "5m"
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
restartPolicy: Never

Disabling Wstunnel for Specific Pods

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
annotations:
interlink.eu/pod-vpn: "true" # Use VPN instead of wstunnel
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
restartPolicy: Never

Adding Extra Ports

You can specify additional ports to forward beyond those defined in the pod specification using the interlink.eu/wstunnel-extra-ports annotation:

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
annotations:
interlink.eu/wstunnel-extra-ports: "8080,9090:metrics:UDP,3000:api"
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
restartPolicy: Never

Extra Ports Format:

  • Simple port: 8080 - Forward port 8080 with TCP protocol
  • Named port: 9090:metrics - Forward port 9090 with name "metrics" and TCP protocol
  • Full specification: 3000:api:UDP - Forward port 3000 with name "api" and UDP protocol
  • Multiple ports: 8080,9090:metrics:UDP,3000:api - Comma-separated list

This is useful for:

  • Internal services not exposed in container specs
  • Debug ports (e.g., pprof, metrics endpoints)
  • Dynamic port allocation scenarios
  • Services running on non-standard ports

DNS Configuration

Wildcard DNS Setup

Configure your DNS provider to point wildcard subdomains to your ingress controller:

*.tunnel.example.com → your-ingress-controller-ip

Generated Hostnames

For each pod, the system generates hostnames using the pattern:

ws-{pod-name}-wstunnel.{WildcardDNS}

Examples:

  • Pod web-serverws-web-server-wstunnel.tunnel.example.com
  • Pod api-gatewayws-api-gateway-wstunnel.tunnel.example.com

Client Connection Commands

Automatic Command Generation

When wstunnel is enabled, interLink automatically generates a client command annotation for each pod with exposed ports. This annotation contains the complete command needed to connect to the pod's services from a remote location.

Annotation: interlink.eu/wstunnel-client-commands

Example

For a pod with exposed ports, the annotation will contain:

curl -L https://github.com/erebe/wstunnel/releases/latest/download/wstunnel-linux-x64 -o wstunnel && chmod +x wstunnel

./wstunnel client --http-upgrade-path-prefix a1b2c3d4e5f6 -R tcp://[::]:8080:localhost:8080 -R tcp://[::]:9090:localhost:9090 ws://ws-my-pod-wstunnel.tunnel.example.com:80

Command Structure

  1. Download: Downloads the latest wstunnel client binary
  2. Connect: Establishes the websocket tunnel with:
    • --http-upgrade-path-prefix: Unique random password for authentication
    • -R tcp://[::]:PORT:localhost:PORT: Port forwarding rules (one per exposed port)
    • ws://ENDPOINT:80: Websocket endpoint using generated hostname

Retrieving the Command

# Get the complete client command for a pod
kubectl get pod my-pod -o jsonpath='{.metadata.annotations.interlink\.eu/wstunnel-client-commands}'

# Or view all annotations
kubectl describe pod my-pod

Multiple Ports

When a pod exposes multiple ports, all ports are included in a single command with multiple -R options:

# Pod with ports 8080, 9090, and 3000
./wstunnel client --http-upgrade-path-prefix randompassword \
-R tcp://[::]:8080:localhost:8080 \
-R tcp://[::]:9090:localhost:9090 \
-R tcp://[::]:3000:localhost:3000 \
ws://ws-my-pod-wstunnel.tunnel.example.com:80

Custom Client Command

You can customize the wstunnel client command that gets generated in the pod annotations by setting the WstunnelCommand configuration option.

Default Command Template

The default command template is:

curl -L https://github.com/erebe/wstunnel/releases/download/v10.4.4/wstunnel_10.4.4_linux_amd64.tar.gz -o wstunnel.tar.gz && tar -xzvf wstunnel.tar.gz && chmod +x wstunnel\n\n./wstunnel client --http-upgrade-path-prefix %s %s ws://%s:80

Custom Command Configuration

# VirtualKubeletConfig.yaml
Network:
EnableTunnel: true
WildcardDNS: "tunnel.example.com"
WstunnelCommand: "wget https://example.com/wstunnel -O wstunnel && chmod +x wstunnel && ./wstunnel client --http-upgrade-path-prefix %s %s ws://%s:80"

Command Template Parameters

The command template must include three %s placeholders in this order:

  1. Random Password: Unique authentication token for the tunnel
  2. Port Options: Space-separated -R options for each exposed port
  3. Ingress Endpoint: The websocket endpoint hostname

Example Custom Commands

Using different wstunnel versions:

WstunnelCommand: "curl -L https://github.com/erebe/wstunnel/releases/download/v10.1.0/wstunnel_10.1.0_linux_amd64.tar.gz -o wstunnel.tar.gz && tar -xzvf wstunnel.tar.gz && chmod +x wstunnel && ./wstunnel client --http-upgrade-path-prefix %s %s ws://%s:80"

Using pre-installed wstunnel:

WstunnelCommand: "wstunnel client --http-upgrade-path-prefix %s %s ws://%s:80"

Using different download methods:

WstunnelCommand: "wget https://github.com/erebe/wstunnel/releases/download/v10.4.4/wstunnel_10.4.4_linux_amd64.tar.gz && tar -xzvf wstunnel_10.4.4_linux_amd64.tar.gz && chmod +x wstunnel && ./wstunnel client --http-upgrade-path-prefix %s %s ws://%s:80"

Using custom binary location:

WstunnelCommand: "curl -L https://github.com/erebe/wstunnel/releases/download/v10.4.4/wstunnel_10.4.4_linux_amd64.tar.gz -o wstunnel.tar.gz && tar -xzvf wstunnel.tar.gz && chmod +x wstunnel && /usr/local/bin/wstunnel client --http-upgrade-path-prefix %s %s ws://%s:80"
warning

The custom command template must be properly formatted with exactly three %s placeholders. Incorrect formatting will result in malformed client commands in the pod annotations.


Security Considerations

Authentication

  • Each wstunnel instance uses a unique random password
  • Passwords are generated using cryptographically secure random numbers
  • Access is restricted via the restrict-http-upgrade-path-prefix parameter

Network Security

  • WebSocket connections are established over HTTP/HTTPS
  • Consider using TLS termination at the ingress level
  • Implement network policies to restrict traffic if needed

Resource Security

  • Wstunnel resources are automatically cleaned up when pods are deleted
  • Resources are labeled for easy identification and management
  • Consider implementing RBAC policies for wstunnel resources

Monitoring and Troubleshooting

Checking Wstunnel Status

# List all wstunnel resources
kubectl get deployment,service,ingress -l interlink.virtual-kubelet.io/type=wstunnel

# Check specific pod's wstunnel resources
kubectl get deployment,service,ingress -l app.kubernetes.io/component=my-pod-wstunnel

# Check wstunnel pod logs
kubectl logs -l app.kubernetes.io/component=my-pod-wstunnel

Common Issues

  1. Pod IP not assigned

    # Check pod status
    kubectl get pod my-pod -o yaml | grep -A 10 status

    # Check virtual kubelet logs
    kubectl logs -l nodeName=virtual-kubelet
  2. Wstunnel timeout errors

    # Increase timeout annotation
    kubectl annotate pod my-pod interlink.virtual-kubelet.io/wstunnel-timeout=10m
  3. DNS resolution issues

    # Test DNS resolution
    nslookup ws-my-pod-wstunnel.tunnel.example.com

    # Check ingress configuration
    kubectl get ingress my-pod-wstunnel -o yaml
  4. Template errors

    # Check virtual kubelet logs for template parsing errors
    kubectl logs -l nodeName=virtual-kubelet | grep -i template
  5. Custom command issues

    # Check if custom WstunnelCommand is properly formatted
    kubectl get pod my-pod -o jsonpath='{.metadata.annotations.interlink\.eu/wstunnel-client-commands}'

    # Verify the command has exactly three %s placeholders
    # Check virtual kubelet logs for command formatting errors
    kubectl logs -l nodeName=virtual-kubelet | grep -i wstunnel

Debug Commands

# Get pod with full details
kubectl get pod my-pod -o yaml

# Check wstunnel deployment
kubectl describe deployment my-pod-wstunnel

# Test websocket connection
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: test" -H "Sec-WebSocket-Version: 13" \
http://ws-my-pod-wstunnel.tunnel.example.com/your-random-password

# Check service endpoints
kubectl get endpoints my-pod-wstunnel

Best Practices

Configuration

  • Set appropriate WildcardDNS that you control
  • Use custom templates for specific requirements
  • Configure reasonable timeout values based on your infrastructure
  • When using custom WstunnelCommand, ensure it includes exactly three %s placeholders
  • Test custom commands thoroughly before deploying to production

Security

  • Regularly rotate ingress TLS certificates
  • Implement network policies to restrict access
  • Monitor wstunnel resource usage

Operations

  • Monitor DNS resolution and ingress health
  • Set up alerts for wstunnel pod failures
  • Regular cleanup of orphaned resources

Performance

  • Size wstunnel pods appropriately for your traffic
  • Use appropriate resource limits in custom templates
  • Consider using NodePort or LoadBalancer services for high traffic

Migration Guide

From VPN to Wstunnel

  1. Update Virtual Kubelet configuration:

    Network:
    EnableTunnel: true
    WildcardDNS: "tunnel.example.com"
  2. Remove VPN annotations from pods:

    kubectl annotate pod my-pod interlink.eu/pod-vpn-
  3. Restart pods to trigger wstunnel creation:

    kubectl delete pod my-pod
    kubectl apply -f my-pod.yaml

From Wstunnel to VPN

  1. Add VPN annotation to pods:

    metadata:
    annotations:
    interlink.eu/pod-vpn: "true"
  2. Restart pods to use VPN instead of wstunnel


Advanced Configuration

Custom Ingress Controller

# Custom template with different ingress controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
tls:
- hosts:
- ws-{{.Name}}.{{.WildcardDNS}}
secretName: {{.Name}}-tls
rules:
- host: ws-{{.Name}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: 8080

Resource Limits

# Custom template with resource limits
spec:
template:
spec:
containers:
- name: wireguard
resources:
requests:
cpu: 100m
memory: 90Mi
limits:
cpu: 500m
memory: 256Mi

Multiple Ingress Rules

# Multiple ingress rules for different services
spec:
rules:
- host: ws-{{.Name}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: 8080
{{- range .ExposedPorts}}
- host: {{.Name}}-{{.Port}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: {{.Port}}
{{- end}}