Define your services, routing, auth, and environment presets in one file. Check it into git. Run stunl up.
stunl.yaml is a project-level configuration file that declares your tunnel topology — which services to expose, how to route traffic, and who can access them.
Instead of passing flags every time, you define it once and every teammate gets the same setup. Think of it as your compose file for tunnels.
$ stunl -id myapp \
-ports 'web:3000,api:8080,db:5432:tcp' \
-routing-strategy path \
-password secret \
-oauth github \
-oauth-github-org mycompany
$ stunl up
Loading stunl.yaml...
Starting 3 services...
web → localhost:3000 (http)
api → localhost:8080 (http)
db → localhost:5432 (tcp)
stunl auto-detects your running services and generates a config file.
$ stunl up --init
Detecting running services...
Created stunl.yaml
Detected 3 services:
web → port 3000 (http)
api → port 8080 (http)
postgres → port 5432 (tcp)
Tweak names, add auth, define environments.
$ stunl up
Now everyone on your team runs stunl up and gets the exact same tunnel topology.
Here's a complete stunl.yaml showing all available options.
# Schema version (required, must be 1)
version: 1
# Tunnel subdomain (optional, auto-generated if omitted)
subdomain: my-project
# Custom domain (optional, requires Pro+ tier)
# domain: localshare.io
# Routing strategy for multi-service configs
# Options: path, subdomain
routing: path
# Services to expose (at least one required)
services:
frontend:
port: 3000
api:
port: 8080
protocol: http # default if omitted
postgres:
port: 5432
protocol: tcp
# Access control (optional)
auth:
password: "secret123"
version | Integer. Must be 1. Required. |
subdomain | Tunnel subdomain (e.g., myapp → myapp.stunl.io). Optional. |
domain | Domain to use (default: stunl.io). Pro+ tier. Optional. |
routing | Routing strategy: path or subdomain. Optional. |
auth.password | Password to protect tunnels. Pro+ tier. Optional. |
services.<name>.port | Local port number. Required per service. |
services.<name>.protocol | http (default), tcp, or udp. Optional. |
Service names must contain only letters, digits, hyphens, and underscores.
For OAuth protection, use the -oauth CLI flags alongside stunl up.
Each service maps a name to a local port. At least one service is required.
| Field | Required | Default | Description |
|---|---|---|---|
port |
Yes | — | Local port number (1–65535) |
protocol |
No | http |
http, tcp, udp, or websocket |
Single-service shortcut
When you define only one service, stunl skips multi-port overhead and creates a simple tunnel — exactly like running stunl -port 3000.
services:
web:
port: 3000 # protocol defaults to http
realtime:
port: 8081
protocol: websocket # dedicated WebSocket service
services:
postgres:
port: 5432
protocol: tcp
public_port: 15432 # reserved port for consistent access
redis:
port: 6379
protocol: tcp
# Then connect from anywhere:
# psql -h my-project.stunl.io -p 15432 -U postgres
services:
minecraft:
port: 25565
protocol: udp
public_port: 10042 # friends always connect to this port
Restrict who can access your tunnel. Password auth and OAuth are mutually exclusive.
auth:
password: "my-secret-password"
auth:
oauth:
provider: github # github, google, or microsoft
github_orgs: [my-org] # restrict to org members
github_teams: [my-org/eng] # or specific teams
auth:
oauth:
provider: google
allowed_domains: [mycompany.com]
Controls how traffic is distributed across your HTTP/WebSocket services.
| Strategy | Description |
|---|---|
path |
Route by URL path prefix (default). /api → API service, / → frontend. |
subdomain |
Route by subdomain. api.myapp.stunl.io → API service. |
header |
Route by custom HTTP header value. |
mixed |
Combination of path, subdomain, and header routing. |
round_robin |
Distribute requests evenly across services. |
least_connections |
Route to the service with fewest active connections. |
$ stunl up # use ./stunl.yaml, start all services
$ stunl up -f dev.yaml # use a specific config file
$ stunl up -key st_pro_abc123 # override API key
$ stunl up --init # create example stunl.yaml
stunl up reads stunl.yaml from the current directory by default. Use -f to specify a different path.
Config hierarchy
stunl.yaml defines tunnel topology (services, routing, auth) and goes into git.
Your personal settings (API key, server address, TLS) live in ~/.stunl/config.yaml and stay local.
When you run stunl up, both are merged — connection settings from your personal config, tunnel topology from the project config.
version: "1"
name: acme-app
routing: path
services:
web:
port: 3000
api:
port: 8080
path: /api
db:
port: 5432
protocol: tcp
auth:
password: "dev-secret"
version: "1"
name: ml-dashboard
services:
dashboard:
port: 8501 # Streamlit default port
api:
port: 8000 # FastAPI default port
path: /api
environments:
share:
description: "Dashboard only for stakeholders"
services: [dashboard]
auth:
oauth:
provider: google
allowed_domains: [mycompany.com]
version: "1"
name: my-api
services:
api:
port: 8080
# Even for single services, stunl.yaml is useful:
# - Consistent tunnel name across the team
# - Auth settings checked into version control
# - No need to remember CLI flags
stunl validates your config on load and gives clear errors for any problems.
version must be "1"
http, tcp, udp, or websocket
public_port only on TCP/UDP services (range 10001–19999)
/
github, google, or microsoft
: @ or ,