A flexible tunnel management tool that supports SSH, kubectl, and tunneled kubectl port forwarding. Tunnelo allows you to manage multiple tunnels across different hosts and contexts through a simple YAML configuration.
- Support for SSH, kubectl, and tunneled kubectl port forwarding
- Multiple hosts per configuration
- Multiple resources and ports per host
- Automatic tunnel restart on failure
uv tool install . After installation, the tunnelo command will be available directly in your terminal.
Tunnelo uses YAML configuration files to define tunnels. You can specify multiple configuration files when running the tool.
hosts:
- mode: ssh
hostname: example.com
mounts:
- "8080:80"
- "8443:443"
ssh_args: ["-i", "~/.ssh/id_rsa"]hosts:
- mode: kubectl
context: my-cluster
namespace: default
resources:
- resource: service/my-service
ports:
- "8080:80"
- "8443:443"
- resource: deployment/my-deployment
ports:
- "9090:80"For scenarios where you need to connect through an intermediate host to run kubectl port-forward on a remote node:
hosts:
- mode: tunneled_kubectl
teleport:
tsh_host: my-cluster-host
tsh_ssh_jump_args: ["-J", "jump.example.com"] # optional
remote_kube_client: dlmaster
namespace: default # optional
context: my-cluster # optional
sudo: false # optional, can be true or username string
kubectl_args: ["--kubeconfig", "/path/to/config"] # optional
ssh_args: ["-i", "~/.ssh/id_rsa"] # optional
resources:
- resource: service/my-service
ports:
- "8080:80"
- "8443:443"
- resource: deployment/my-deployment
ports:
- "9090:80"This mode creates a two-step tunnel:
- SSH to the cluster host and run kubectl port-forward with a dynamic port
- Create an SSH tunnel from your local machine to the dynamically assigned port
Tunnelo supports Jinja2 templating for dynamic configuration generation. This is useful for creating reusable configurations with variable values.
Template files should use the .yaml.j2 extension and can contain Jinja2 template syntax:
hosts:
- mode: ssh
hostname: {{ hostname }}
mounts:
{% for port in ports %}
- "{{ port }}:80"
{% endfor %}
ssh_args: {{ ssh_args | default([]) }}You can pass variables to templates in several ways:
Via CLI flags:
tunnelo -t config.yaml.j2 -v hostname=example.com -v port=8080Via variable file:
# vars.yaml
hostname: example.com
ports: [8080, 8443]
ssh_args: ["-i", "~/.ssh/id_rsa"]tunnelo -t config.yaml.j2 -vf vars.yamlVia JSON file:
{
"hostname": "example.com",
"ports": [8080, 8443],
"ssh_args": ["-i", "~/.ssh/id_rsa"]
}tunnelo -t config.yaml.j2 -vf vars.jsonAfter installation, the tunnelo command is available directly in your terminal.
Run tunnels from one or more configuration files:
tunnelo -c config1.yaml -c config2.yamlUse Jinja2 templates for dynamic configurations:
# With template variables
tunnelo -t config.yaml.j2 -v hostname=example.com -v port=8080
# With variable file
tunnelo -t config.yaml.j2 -vf vars.yaml
# With JSON variable file
tunnelo -t config.yaml.j2 -vf vars.jsonYou can combine regular config files and templates:
tunnelo -c config1.yaml -t template.yaml.j2 -v var=value -c config2.yamlTo work on the code, can just use the poetry-managed virtual environment
poetry install