Stop memorizing port numbers. Start using pretty URLs.
Features • Quick Start • Screenshots • Documentation
During development, you juggle multiple services:
Frontend: http://localhost:3000
API: http://localhost:8080
Admin: http://localhost:4200
Docs: http://localhost:3001
tube fixes this:
Frontend: https://app.test
API: https://api.test
Admin: https://admin.test
Docs: https://docs.test
Both HTTP and HTTPS work out of the box with trusted local certificates.
| Feature | Description |
|---|---|
| 🌐 Pretty URLs | Access myapp.test instead of localhost:3000 |
| 🔒 HTTPS Support | Auto-generated trusted certificates with mkcert |
| 🖥️ Menu Bar App | Control everything from your macOS menu bar |
| 📊 Web Dashboard | Beautiful UI at localhost:3249 |
| ⚡ Zero Config DNS | One command sets up macOS resolver |
| 🔄 Live Reload | Add projects without restarting |
| 🛠️ CLI + GUI | Use whichever you prefer |
The fastest path: a POSIX sh install script that detects your OS/arch,
verifies SHA256 against the published checksums.txt, and installs
tube to /usr/local/bin.
curl -fsSL https://raw.githubusercontent.com/steig/tube/main/scripts/install.sh | shPin a specific version or install without sudo:
curl -fsSL https://raw.githubusercontent.com/steig/tube/main/scripts/install.sh \
| TUBE_VERSION=v0.1.0 sh
curl -fsSL https://raw.githubusercontent.com/steig/tube/main/scripts/install.sh \
| TUBE_PREFIX="$HOME/.local" shRuntime deps (nginx, dnsmasq, mkcert) aren't installed by the script — grab
them separately: brew install nginx dnsmasq mkcert.
On macOS the install script also drops
tube-gui(menu bar app) alongsidetube. Runtube-gui &after installing.
Build from source instead
# Clone and build
git clone https://github.com/steig/tube.git
cd tube
make build-all
# Add to PATH
sudo cp bin/tube bin/tube-gui /usr/local/bin/tube initThis configures tube and sets up HTTPS with trusted local certificates (requires mkcert).
tube setupThis creates /etc/resolver/test so *.test domains work automatically.
tube add myapp 3000
tube add api 8080tube startopen https://myapp.testThat's it! 🎉 Both http:// and https:// work.
Run tube-gui to get a persistent menu bar icon:
┌───────────────────────────────┐
│ tube ● │ ← Green = running
├───────────────────────────────┤
│ ● Services Running │
├───────────────────────────────┤
│ Projects ▸│
│ ├─ myapp.test :3000 │
│ ├─ api.test :8080 │
│ └─ dashboard.test :4200 │
├───────────────────────────────┤
│ Start Services │
│ Stop Services │
├───────────────────────────────┤
│ Open Dashboard... │
│ Quit tube │
└───────────────────────────────┘
Access at http://localhost:3249:
╭──────────────────────────────────────────────────────────────────╮
│ │
│ tube Dashboard ● Running │
│ │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Services │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ ● nginx │ │ ● dnsmasq │ │
│ │ running (pid 123) │ │ running (pid 456) │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ [Start Services] [Stop Services] │
│ │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Projects │
│ ┌────────────────────────────────────────────────────────────┐│
│ │ ● myapp http://myapp.test :3000 [x] ││
│ │ ○ api http://api.test :8080 [x] ││
│ │ ● dashboard http://dashboard.test :4200 [x] ││
│ └────────────────────────────────────────────────────────────┘│
│ │
│ [________name________] [__port__] [Add Project] │
│ │
╰──────────────────────────────────────────────────────────────────╯
tube add <name> <port> # Add a project (e.g., tube add api 8080)
tube remove <name> # Remove a project
tube list # List all projects with statustube start # Start nginx + dnsmasq
tube stop # Stop all services
tube restart # Restart all services
tube status # Show service statustube init # Initialize tube config + SSL certificates
tube setup # Configure macOS DNS (run once)
tube uninstall # Remove DNS configuration
tube dns-status # Check DNS resolver status
tube doctor # Diagnose issuestube ssl status # Show SSL configuration
tube ssl install # Install mkcert CA to trust store
tube ssl generate # Generate/regenerate certificates
tube ssl enable # Enable HTTPS
tube ssl disable # Disable HTTPS (HTTP only)$ tube add frontend 3000
✓ Added project 'frontend' on port 3000
$ tube add backend 8080
✓ Added project 'backend' on port 8080
$ tube list
NAME PORT URL STATUS
─────────────────────────────────────────────────────────────────────────────────
backend 8080 https://backend.test ○
frontend 3000 https://frontend.test ○
● = running ○ = stopped
$ tube start
✓ Started nginx
✓ Started dnsmasq
Services are running!
$ tube status
nginx: running (pid 12345)
dnsmasq: running (pid 12346)
$ open https://frontend.test # 🎉 It works!Configuration lives in ~/.tube/config.yaml:
# Domain settings
domain: example.com
tunnel_prefix: dev-
# Local proxy settings
proxy:
local_domain: .test # TLD for local domains
dashboard_port: 3249 # Dashboard port
# Service binaries
nginx:
binary: nginx
http_port: 80
https_port: 443
dnsmasq:
binary: dnsmasq
port: 53
# SSL/HTTPS settings
ssl:
enabled: true
cert_file: ~/.tube/ssl/wildcard.test.pem
key_file: ~/.tube/ssl/wildcard.test-key.pem
# Your projects
projects:
frontend: 3000
backend: 8080
admin: 4200| Variable | Description | Default |
|---|---|---|
TUBE_CONFIG |
Config file path | ~/.tube/config.yaml |
TUBE_* |
Any config key, prefixed with TUBE_ and uppercased |
(per-key default) |
┌─────────────────┐
│ Browser │
│ myapp.test:443 │
└────────┬────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ macOS DNS Resolver │
│ │
│ /etc/resolver/test ──► nameserver 127.0.0.1 │
│ │
└────────────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ dnsmasq │
│ │
│ *.test ──► 127.0.0.1 │
│ │
└────────────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ nginx │
│ │
│ :80 (HTTP) ──► proxy_pass http://127.0.0.1:PORT │
│ :443 (HTTPS) ──► proxy_pass http://127.0.0.1:PORT │
│ (SSL termination with mkcert certs) │
│ │
└────────────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
│ │
│ localhost:3000 │
│ │
└─────────────────────────────────────────────────────────────┘
- Go 1.23+
- nginx
- make
# Clone
git clone https://github.com/steig/tube.git
cd tube
# Enter nix shell (optional, but recommended)
nix develop
# Build CLI only
make build
# Build GUI only
make build-gui
# Build both
make build-all# Run unit tests
make test
# Run tests in Docker (includes nginx/dnsmasq)
make test-docker
# Integration tests
make test-integration
# Coverage report
make coveragetube/
├── cmd/
│ ├── tube/ # CLI entry point
│ └── tube-gui/ # GUI entry point
├── internal/
│ ├── cli/ # CLI commands (cobra)
│ ├── config/ # Configuration (viper)
│ ├── dns/ # macOS resolver management
│ ├── gui/ # Menu bar + dashboard
│ ├── proxy/ # nginx/dnsmasq managers
│ ├── service/ # Process lifecycle
│ └── ssl/ # Certificate management (mkcert)
├── templates/
│ ├── nginx/ # nginx config templates
│ └── dnsmasq/ # dnsmasq config templates
├── docs/ # Documentation
├── scripts/ # Build/test scripts
└── Makefile
| Document | Description |
|---|---|
| Installation | Detailed install guide |
| CLI Reference | All commands |
| Configuration | Config options |
| GUI Guide | Menu bar & dashboard |
| Architecture | How it works |
| Troubleshooting | Common issues |
| Contributing | How to contribute |
- Core CLI
- nginx reverse proxy
- macOS DNS resolver
- Menu bar app
- Web dashboard
- HTTPS with mkcert
- Cloudflare Tunnel integration
- Linux support
- Homebrew formula
Contributions welcome! Please read CONTRIBUTING.md first.
# Fork, clone, branch
git checkout -b feature/my-feature
# Make changes, test
make test
# Commit and push
git commit -m "Add my feature"
git push origin feature/my-feature
# Open PRMIT License - see LICENSE for details.
Made for developers who are tired of remembering port numbers 🚀