{"id":50197796,"url":"https://github.com/steig/tube","last_synced_at":"2026-05-25T19:00:47.340Z","repository":{"id":360126783,"uuid":"1116022110","full_name":"steig/tube","owner":"steig","description":"Local development proxy for .test domains on macOS — HTTPS out of the box, menu bar app, and web dashboard.","archived":false,"fork":false,"pushed_at":"2026-05-25T04:55:11.000Z","size":770,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T06:43:19.130Z","etag":null,"topics":["developer-tools","dnsmasq","golang","https","local-development","macos","menu-bar-app","mkcert","nginx","reverse-proxy","test-domains"],"latest_commit_sha":null,"homepage":"https://github.com/steig/tube/releases/latest","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/steig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-14T03:09:21.000Z","updated_at":"2026-05-25T04:55:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/steig/tube","commit_stats":null,"previous_names":["steig/tube"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/steig/tube","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steig%2Ftube","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steig%2Ftube/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steig%2Ftube/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steig%2Ftube/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steig","download_url":"https://codeload.github.com/steig/tube/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steig%2Ftube/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33488942,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T14:31:05.219Z","status":"ssl_error","status_checked_at":"2026-05-25T14:31:02.878Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["developer-tools","dnsmasq","golang","https","local-development","macos","menu-bar-app","mkcert","nginx","reverse-proxy","test-domains"],"created_at":"2026-05-25T19:00:27.246Z","updated_at":"2026-05-25T19:00:47.326Z","avatar_url":"https://github.com/steig.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tube\n\n\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"docs/assets/logo.svg\" alt=\"tube logo\" width=\"120\"\u003e\n\n### Local development proxy with `.test` domains\n\n**Stop memorizing port numbers. Start using pretty URLs.**\n\n[![Go Version](https://img.shields.io/badge/Go-1.23+-00ADD8?style=flat\u0026logo=go)](https://go.dev)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Tests](https://img.shields.io/badge/Tests-Passing-brightgreen.svg)]()\n[![macOS](https://img.shields.io/badge/macOS-Supported-black?logo=apple)]()\n\n[Features](#-features) • [Quick Start](#-quick-start) • [Screenshots](#-screenshots) • [Documentation](#-documentation)\n\n---\n\n\u003c/div\u003e\n\n## The Problem\n\nDuring development, you juggle multiple services:\n\n```\nFrontend:  http://localhost:3000\nAPI:       http://localhost:8080\nAdmin:     http://localhost:4200\nDocs:      http://localhost:3001\n```\n\n**tube** fixes this:\n\n```\nFrontend:  https://app.test\nAPI:       https://api.test\nAdmin:     https://admin.test\nDocs:      https://docs.test\n```\n\nBoth HTTP and HTTPS work out of the box with trusted local certificates.\n\n## ✨ Features\n\n| Feature | Description |\n|---------|-------------|\n| 🌐 **Pretty URLs** | Access `myapp.test` instead of `localhost:3000` |\n| 🔒 **HTTPS Support** | Auto-generated trusted certificates with mkcert |\n| 🖥️ **Menu Bar App** | Control everything from your macOS menu bar |\n| 📊 **Web Dashboard** | Beautiful UI at `localhost:3249` |\n| ⚡ **Zero Config DNS** | One command sets up macOS resolver |\n| 🔄 **Live Reload** | Add projects without restarting |\n| 🛠️ **CLI + GUI** | Use whichever you prefer |\n\n## 🚀 Quick Start\n\n### 1. Install\n\nThe fastest path: a POSIX `sh` install script that detects your OS/arch,\nverifies SHA256 against the published `checksums.txt`, and installs\n`tube` to `/usr/local/bin`.\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/steig/tube/main/scripts/install.sh | sh\n```\n\nPin a specific version or install without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/steig/tube/main/scripts/install.sh \\\n  | TUBE_VERSION=v0.1.0 sh\ncurl -fsSL https://raw.githubusercontent.com/steig/tube/main/scripts/install.sh \\\n  | TUBE_PREFIX=\"$HOME/.local\" sh\n```\n\nRuntime deps (nginx, dnsmasq, mkcert) aren't installed by the script — grab\nthem separately: `brew install nginx dnsmasq mkcert`.\n\n\u003e On macOS the install script also drops `tube-gui` (menu bar app)\n\u003e alongside `tube`. Run `tube-gui \u0026` after installing.\n\n\u003cdetails\u003e\n\u003csummary\u003eBuild from source instead\u003c/summary\u003e\n\n```bash\n# Clone and build\ngit clone https://github.com/steig/tube.git\ncd tube\nmake build-all\n\n# Add to PATH\nsudo cp bin/tube bin/tube-gui /usr/local/bin/\n```\n\u003c/details\u003e\n\n### 2. Initialize (one-time)\n\n```bash\ntube init\n```\n\nThis configures tube and sets up HTTPS with trusted local certificates (requires [mkcert](https://github.com/FiloSottile/mkcert)).\n\n### 3. Setup DNS (one-time)\n\n```bash\ntube setup\n```\n\nThis creates `/etc/resolver/test` so `*.test` domains work automatically.\n\n### 4. Add Your Projects\n\n```bash\ntube add myapp 3000\ntube add api 8080\n```\n\n### 5. Start Services\n\n```bash\ntube start\n```\n\n### 6. Open Your App\n\n```bash\nopen https://myapp.test\n```\n\nThat's it! 🎉 Both `http://` and `https://` work.\n\n---\n\n## 📸 Screenshots\n\n### Menu Bar App\n\nRun `tube-gui` to get a persistent menu bar icon:\n\n```\n┌───────────────────────────────┐\n│ tube ●                        │  ← Green = running\n├───────────────────────────────┤\n│ ● Services Running            │\n├───────────────────────────────┤\n│ Projects                     ▸│\n│   ├─ myapp.test       :3000   │\n│   ├─ api.test         :8080   │\n│   └─ dashboard.test   :4200   │\n├───────────────────────────────┤\n│ Start Services                │\n│ Stop Services                 │\n├───────────────────────────────┤\n│ Open Dashboard...             │\n│ Quit tube                     │\n└───────────────────────────────┘\n```\n\n### Web Dashboard\n\nAccess at `http://localhost:3249`:\n\n```\n╭──────────────────────────────────────────────────────────────────╮\n│                                                                  │\n│   tube Dashboard                              ● Running          │\n│                                                                  │\n├──────────────────────────────────────────────────────────────────┤\n│                                                                  │\n│   Services                                                       │\n│   ┌─────────────────────┐  ┌─────────────────────┐              │\n│   │ ● nginx             │  │ ● dnsmasq           │              │\n│   │   running (pid 123) │  │   running (pid 456) │              │\n│   └─────────────────────┘  └─────────────────────┘              │\n│                                                                  │\n│   [Start Services]  [Stop Services]                              │\n│                                                                  │\n├──────────────────────────────────────────────────────────────────┤\n│                                                                  │\n│   Projects                                                       │\n│   ┌────────────────────────────────────────────────────────────┐│\n│   │ ● myapp        http://myapp.test              :3000   [x]  ││\n│   │ ○ api          http://api.test                :8080   [x]  ││\n│   │ ● dashboard    http://dashboard.test          :4200   [x]  ││\n│   └────────────────────────────────────────────────────────────┘│\n│                                                                  │\n│   [________name________] [__port__] [Add Project]                │\n│                                                                  │\n╰──────────────────────────────────────────────────────────────────╯\n```\n\n---\n\n## 📖 CLI Reference\n\n### Project Management\n\n```bash\ntube add \u003cname\u003e \u003cport\u003e    # Add a project (e.g., tube add api 8080)\ntube remove \u003cname\u003e        # Remove a project\ntube list                 # List all projects with status\n```\n\n### Service Control\n\n```bash\ntube start                # Start nginx + dnsmasq\ntube stop                 # Stop all services\ntube restart              # Restart all services\ntube status               # Show service status\n```\n\n### System Setup\n\n```bash\ntube init                 # Initialize tube config + SSL certificates\ntube setup                # Configure macOS DNS (run once)\ntube uninstall            # Remove DNS configuration\ntube dns-status           # Check DNS resolver status\ntube doctor               # Diagnose issues\n```\n\n### SSL Management\n\n```bash\ntube ssl status           # Show SSL configuration\ntube ssl install          # Install mkcert CA to trust store\ntube ssl generate         # Generate/regenerate certificates\ntube ssl enable           # Enable HTTPS\ntube ssl disable          # Disable HTTPS (HTTP only)\n```\n\n### Example Session\n\n```bash\n$ tube add frontend 3000\n✓ Added project 'frontend' on port 3000\n\n$ tube add backend 8080\n✓ Added project 'backend' on port 8080\n\n$ tube list\nNAME                 PORT     URL                                           STATUS\n─────────────────────────────────────────────────────────────────────────────────\nbackend              8080     https://backend.test                          ○\nfrontend             3000     https://frontend.test                         ○\n\n● = running  ○ = stopped\n\n$ tube start\n✓ Started nginx\n✓ Started dnsmasq\nServices are running!\n\n$ tube status\nnginx:   running (pid 12345)\ndnsmasq: running (pid 12346)\n\n$ open https://frontend.test  # 🎉 It works!\n```\n\n---\n\n## ⚙️ Configuration\n\nConfiguration lives in `~/.tube/config.yaml`:\n\n```yaml\n# Domain settings\ndomain: example.com\ntunnel_prefix: dev-\n\n# Local proxy settings\nproxy:\n  local_domain: .test        # TLD for local domains\n  dashboard_port: 3249       # Dashboard port\n\n# Service binaries\nnginx:\n  binary: nginx\n  http_port: 80\n  https_port: 443\n\ndnsmasq:\n  binary: dnsmasq\n  port: 53\n\n# SSL/HTTPS settings\nssl:\n  enabled: true\n  cert_file: ~/.tube/ssl/wildcard.test.pem\n  key_file: ~/.tube/ssl/wildcard.test-key.pem\n\n# Your projects\nprojects:\n  frontend: 3000\n  backend: 8080\n  admin: 4200\n```\n\n### Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `TUBE_CONFIG` | Config file path | `~/.tube/config.yaml` |\n| `TUBE_*` | Any config key, prefixed with `TUBE_` and uppercased | (per-key default) |\n\n---\n\n## 🏗️ Architecture\n\n```\n                        ┌─────────────────┐\n                        │    Browser      │\n                        │ myapp.test:443  │\n                        └────────┬────────┘\n                                 │\n                                 ▼\n┌─────────────────────────────────────────────────────────────┐\n│                    macOS DNS Resolver                        │\n│                                                              │\n│  /etc/resolver/test  ──►  nameserver 127.0.0.1              │\n│                                                              │\n└────────────────────────────────┬────────────────────────────┘\n                                 │\n                                 ▼\n┌─────────────────────────────────────────────────────────────┐\n│                        dnsmasq                               │\n│                                                              │\n│  *.test  ──►  127.0.0.1                                     │\n│                                                              │\n└────────────────────────────────┬────────────────────────────┘\n                                 │\n                                 ▼\n┌─────────────────────────────────────────────────────────────┐\n│                         nginx                                │\n│                                                              │\n│  :80  (HTTP)   ──►  proxy_pass http://127.0.0.1:PORT        │\n│  :443 (HTTPS)  ──►  proxy_pass http://127.0.0.1:PORT        │\n│                     (SSL termination with mkcert certs)      │\n│                                                              │\n└────────────────────────────────┬────────────────────────────┘\n                                 │\n                                 ▼\n┌─────────────────────────────────────────────────────────────┐\n│                    Your Application                          │\n│                                                              │\n│                    localhost:3000                            │\n│                                                              │\n└─────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## 🛠️ Development\n\n### Prerequisites\n\n- Go 1.23+\n- nginx\n- make\n\n### Build\n\n```bash\n# Clone\ngit clone https://github.com/steig/tube.git\ncd tube\n\n# Enter nix shell (optional, but recommended)\nnix develop\n\n# Build CLI only\nmake build\n\n# Build GUI only\nmake build-gui\n\n# Build both\nmake build-all\n```\n\n### Test\n\n```bash\n# Run unit tests\nmake test\n\n# Run tests in Docker (includes nginx/dnsmasq)\nmake test-docker\n\n# Integration tests\nmake test-integration\n\n# Coverage report\nmake coverage\n```\n\n### Project Structure\n\n```\ntube/\n├── cmd/\n│   ├── tube/              # CLI entry point\n│   └── tube-gui/          # GUI entry point\n├── internal/\n│   ├── cli/               # CLI commands (cobra)\n│   ├── config/            # Configuration (viper)\n│   ├── dns/               # macOS resolver management\n│   ├── gui/               # Menu bar + dashboard\n│   ├── proxy/             # nginx/dnsmasq managers\n│   ├── service/           # Process lifecycle\n│   └── ssl/               # Certificate management (mkcert)\n├── templates/\n│   ├── nginx/             # nginx config templates\n│   └── dnsmasq/           # dnsmasq config templates\n├── docs/                  # Documentation\n├── scripts/               # Build/test scripts\n└── Makefile\n```\n\n---\n\n## 📚 Documentation\n\n| Document | Description |\n|----------|-------------|\n| [Installation](docs/installation.md) | Detailed install guide |\n| [CLI Reference](docs/cli-reference.md) | All commands |\n| [Configuration](docs/configuration.md) | Config options |\n| [GUI Guide](docs/gui.md) | Menu bar \u0026 dashboard |\n| [Architecture](docs/architecture.md) | How it works |\n| [Troubleshooting](docs/troubleshooting.md) | Common issues |\n| [Contributing](CONTRIBUTING.md) | How to contribute |\n\n---\n\n## 🗺️ Roadmap\n\n- [x] Core CLI\n- [x] nginx reverse proxy\n- [x] macOS DNS resolver\n- [x] Menu bar app\n- [x] Web dashboard\n- [x] HTTPS with mkcert\n- [ ] Cloudflare Tunnel integration\n- [ ] Linux support\n- [ ] Homebrew formula\n\n---\n\n## 🤝 Contributing\n\nContributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) first.\n\n```bash\n# Fork, clone, branch\ngit checkout -b feature/my-feature\n\n# Make changes, test\nmake test\n\n# Commit and push\ngit commit -m \"Add my feature\"\ngit push origin feature/my-feature\n\n# Open PR\n```\n\n---\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Made for developers who are tired of remembering port numbers** 🚀\n\n[Report Bug](https://github.com/steig/tube/issues) • [Request Feature](https://github.com/steig/tube/issues)\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteig%2Ftube","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteig%2Ftube","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteig%2Ftube/lists"}