Documentation / Project Config

Project Config (stunl.yaml)

Define your services, routing, auth, and environment presets in one file. Check it into git. Run stunl up.

Overview

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.

Before: CLI flags every time
$ stunl -id myapp \
  -ports 'web:3000,api:8080,db:5432:tcp' \
  -routing-strategy path \
  -password secret \
  -oauth github \
  -oauth-github-org mycompany
After: one command
$ stunl up

Loading stunl.yaml...
Starting 3 services...
  web     → localhost:3000 (http)
  api     → localhost:8080 (http)
  db      → localhost:5432 (tcp)

Quick Start

1

Generate a config

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)
2

Edit the config (optional)

Tweak names, add auth, define environments.

3

Start your tunnels

$ stunl up
4

Commit to git

Now everyone on your team runs stunl up and gets the exact same tunnel topology.

Full Schema

Here's a complete stunl.yaml showing all available options.

stunl.yaml
# 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"

Schema Reference

versionInteger. Must be 1. Required.
subdomainTunnel subdomain (e.g., myappmyapp.stunl.io). Optional.
domainDomain to use (default: stunl.io). Pro+ tier. Optional.
routingRouting strategy: path or subdomain. Optional.
auth.passwordPassword to protect tunnels. Pro+ tier. Optional.
services.<name>.portLocal port number. Required per service.
services.<name>.protocolhttp (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.

Services

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.

Protocols

HTTP (default) + WebSocket
services:
  web:
    port: 3000                # protocol defaults to http
  realtime:
    port: 8081
    protocol: websocket      # dedicated WebSocket service
TCP (databases, SSH, game servers)
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
UDP (game servers)
services:
  minecraft:
    port: 25565
    protocol: udp
    public_port: 10042       # friends always connect to this port

Authentication

Restrict who can access your tunnel. Password auth and OAuth are mutually exclusive.

Password protection
auth:
  password: "my-secret-password"
OAuth with GitHub
auth:
  oauth:
    provider: github           # github, google, or microsoft
    github_orgs: [my-org]     # restrict to org members
    github_teams: [my-org/eng] # or specific teams
OAuth with Google (domain restriction)
auth:
  oauth:
    provider: google
    allowed_domains: [mycompany.com]

Routing Strategies

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.

CLI Reference

stunl up
$ 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

Config Files

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.

Real-World Examples

Next.js + Go API + PostgreSQL
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"
Streamlit + FastAPI
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]
Single service (simple mode)
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

Validation Rules

stunl validates your config on load and gives clear errors for any problems.

  • version must be "1"
  • At least one service must be defined
  • Ports must be 1–65535, no duplicates across services
  • Protocols must be http, tcp, udp, or websocket
  • public_port only on TCP/UDP services (range 10001–19999)
  • Path prefixes must start with /
  • Password and OAuth are mutually exclusive
  • OAuth provider must be github, google, or microsoft
  • Environment service references must exist in the top-level services
  • Service names cannot contain : @ or ,

Next Steps