{"id":49661262,"url":"https://github.com/timwuhaotian/harbor","last_synced_at":"2026-05-06T12:01:56.859Z","repository":{"id":355165942,"uuid":"1224636769","full_name":"timwuhaotian/harbor","owner":"timwuhaotian","description":"Your computer is your exit node Harbor turns any Mac or Windows PC into a private Surge/Clash proxy node via Cloudflare Tunnel. You need a computer in the target network — Harbor makes it a node in seconds. No VPS. No hand-written config. No dependency installs.","archived":false,"fork":false,"pushed_at":"2026-05-02T06:38:01.000Z","size":519,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-02T08:30:09.265Z","etag":null,"topics":["cloudflare","cloudflared","exitnode","remote","remote-access","sing-box","tunnel","vless","vpn-server","vps"],"latest_commit_sha":null,"homepage":"https://harbor.timwuhaotian.dev/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timwuhaotian.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-29T13:29:14.000Z","updated_at":"2026-05-02T06:41:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/timwuhaotian/harbor","commit_stats":null,"previous_names":["timwuhaotian/harbor"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/timwuhaotian/harbor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timwuhaotian%2Fharbor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timwuhaotian%2Fharbor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timwuhaotian%2Fharbor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timwuhaotian%2Fharbor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timwuhaotian","download_url":"https://codeload.github.com/timwuhaotian/harbor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timwuhaotian%2Fharbor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32692774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["cloudflare","cloudflared","exitnode","remote","remote-access","sing-box","tunnel","vless","vpn-server","vps"],"created_at":"2026-05-06T12:01:55.732Z","updated_at":"2026-05-06T12:01:56.853Z","avatar_url":"https://github.com/timwuhaotian.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Harbor\n\nA personal macOS/Windows desktop app that turns your machine into a VLESS WebSocket exit node through Cloudflare Tunnel.\n\n```\nV2Box on phone\n  └─ VLESS + WebSocket + TLS\n     └─ Cloudflare hostname\n        └─ Cloudflare Tunnel\n           └─ Harbor on Mac/Windows\n              └─ local sing-box VLESS inbound\n                 └─ direct outbound from the machine\n```\n\nCloudflare handles public TLS. Harbor runs plain WebSocket on `127.0.0.1`, and `cloudflared` carries that local service through an authenticated tunnel.\n\n## Features\n\n- **Zero-config tunnel** — bundled `cloudflared` and `sing-box` binaries, no manual installation required\n- **QR code \u0026 VLESS link** — scan or copy to connect from any compatible client\n- **System tray** — start/stop Harbor from the menu bar; close-to-tray behavior keeps it running\n- **Auto-launch** — optional login item for persistent operation\n- **EN/中文** — bilingual UI with in-app language switcher (also updates tray menu)\n- **Automatic updates** — built-in update checker with changelog display and direct GitHub Releases download\n- **macOS + Windows** — signed macOS builds (DMG) and Windows installers (NSIS/MSI) via CI/CD\n- **Real-time logs** — live stdout/stderr from sing-box and cloudflared, shown inline\n- **Port conflict detection** — identifies which process is blocking the local port\n- **Dependency check** — verifies bundled binaries at startup with version display and warnings\n- **Custom binary paths** — override bundled sing-box/cloudflared with system-installed versions\n- **About modal** — built-in disclaimer and version info\n\n## Requirements\n\n- **macOS 11.0+** (Big Sur or later) or **Windows 10+**\n- A Cloudflare account with a domain managed by Cloudflare DNS\n\n\u003e Harbor bundles `sing-box` and `cloudflared` binaries. No `brew install` needed.\n\n## Quick Start\n\n1. **Set up a Cloudflare Tunnel** (see [Cloudflare Tunnel Setup](#cloudflare-tunnel-setup) below)\n2. **Download Harbor** from [Releases](https://github.com/timwuhaotian/harbor/releases) or [build from source](#development)\n3. **Open Harbor** and paste your tunnel token + hostname\n4. Click **Start Harbor**\n5. **Scan the QR code** or copy the VLESS link into your client (V2Box, Surge, Shadowrocket, etc.)\n\n## Cloudflare Tunnel Setup\n\nThis guide walks you through creating a Cloudflare Zero Trust Tunnel to expose Harbor's local VLESS WebSocket endpoint to the internet.\n\n### Step 1: Create a Tunnel\n\n1. Log in to the [Cloudflare Dashboard](https://dash.cloudflare.com/)\n2. Navigate to **Zero Trust** → **Networks** → **Tunnels**\n3. Click **Create a tunnel**\n4. Select **Cloudflared** as the connector type\n5. Give it a name (e.g., `harbor-mac`) and click **Save**\n\n### Step 2: Copy the Tunnel Token\n\nCloudflare will show an install command:\n\n```bash\ncloudflared tunnel --no-autoupdate run --token \u003cvery-long-token\u003e\n```\n\nCopy only the `\u003cvery-long-token\u003e` value. You'll paste it into Harbor's **Cloudflare tunnel token** field.\n\n\u003e Harbor passes the token via the `TUNNEL_TOKEN` environment variable, never in process arguments.\n\n### Step 3: Configure the Public Hostname\n\nInside your tunnel settings, go to **Public Hostnames** and click **Add a public hostname**:\n\n| Field       | Value                          |\n|-------------|--------------------------------|\n| Subdomain   | `harbor` (or your choice)      |\n| Domain      | `yourdomain.com`               |\n| Path        | *(leave blank)*                |\n| Type        | **HTTP**                       |\n| URL         | `127.0.0.1:18080`              |\n\nAfter saving, Cloudflare should display the public hostname as `harbor.yourdomain.com`. Use this exact value in Harbor's **Cloudflare hostname** field.\n\n### Step 4: Configure Harbor\n\nOpen Harbor and fill in:\n\n| Field                   | Value                                    | Required |\n|-------------------------|------------------------------------------|----------|\n| Cloudflare hostname     | `harbor.yourdomain.com`                  | Yes      |\n| Cloudflare tunnel token | *(the token from Step 2)*                | Yes      |\n| VLESS UUID              | *(auto-generated, or use your own)*      | Yes      |\n| WebSocket path          | `/harbor` (default)                      | Yes      |\n| Local port              | `18080` (default)                        | Yes      |\n| sing-box Path           | `sing-box` (or full path to override)    | No       |\n| cloudflared Path        | `cloudflared` (or full path to override) | No       |\n\n### Step 5: Start and Connect\n\n1. Click **Start Harbor**\n2. Verify both `sing-box` and `cloudflared` show as **Running**\n3. Copy the generated VLESS link or scan the QR code\n4. Import it into your client:\n\n```\nvless://\u003cuuid\u003e@harbor.yourdomain.com:443?encryption=none\u0026security=tls\u0026type=ws\u0026host=harbor.yourdomain.com\u0026sni=harbor.yourdomain.com\u0026path=%2Fharbor#Harbor-Mac\n```\n\n## Compatible Clients\n\n| Client       | Platform      | Notes                                      |\n|--------------|---------------|--------------------------------------------|\n| **V2Box**    | iOS / iPadOS  | Free on App Store, supports VLESS + WS + TLS |\n| **Surge**    | iOS / macOS   | Paid, advanced routing features            |\n| **Shadowrocket** | iOS       | Paid, popular choice                       |\n| **Clash Meta / Mihomo** | Multi | Supports VLESS WebSocket                 |\n| **sing-box** | Multi         | CLI / GUI clients available                |\n\n## Troubleshooting\n\n### V2Box cannot connect\n\n1. Confirm Harbor shows both `sing-box` and `cloudflared` as **Running**\n2. In Cloudflare Dashboard, verify the tunnel connector shows **Healthy**\n3. Confirm the public hostname service target is `http://127.0.0.1:18080`\n4. Confirm your client's WebSocket path is `/harbor`\n5. Confirm your client uses WebSocket transport and TLS enabled\n6. Check Harbor's runtime logs for `sing-box` config or port errors\n\n### `sing-box` or `cloudflared` not found\n\nHarbor bundles these binaries. If you see a dependency warning:\n- The binaries may be missing from an incomplete install — reinstall from [Releases](https://github.com/timwuhaotian/harbor/releases)\n- Or provide the full path in the settings (e.g., `/opt/homebrew/bin/sing-box`)\n\n### Mac goes to sleep\n\nHarbor requires your Mac to stay awake while remote devices use it. Consider:\n- System Settings → Energy Saver → prevent display sleep when plugged in\n- Use `caffeinate` or a utility like Amphetamine\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────┐\n│                  V2Box (iPhone)                  │\n│    vless://uuid@harbor.yourdomain.com:443        │\n└──────────────────────┬──────────────────────────┘\n                       │ VLESS + WS + TLS\n                       ▼\n┌─────────────────────────────────────────────────┐\n│               Cloudflare Edge                    │\n│  TLS termination → WebSocket → Tunnel connector  │\n└──────────────────────┬──────────────────────────┘\n                       │ HTTP (plain)\n                       ▼\n┌─────────────────────────────────────────────────┐\n│                 Harbor (Mac)                     │\n│  ┌──────────────┐     ┌───────────────────────┐  │\n│  │  sing-box     │────▶│  cloudflared          │  │\n│  │  VLESS WS :18080│     │  tunnel --token TOKEN  │  │\n│  └──────┬───────┘     └───────────┬───────────┘  │\n│         │                         │              │\n│         ▼                         ▼              │\n│  ┌──────────────┐     ┌───────────────────────┐  │\n│  │  direct out   │     │  Cloudflare edge      │  │\n│  └──────────────┘     └───────────────────────┘  │\n└─────────────────────────────────────────────────┘\n```\n\nKey design decisions:\n\n- **No local TLS certificates needed** — Cloudflare terminates TLS on the public hostname\n- **Token passed via environment variable** — never exposed in `ps` or process arguments\n- **sing-box config generated at runtime** — written to `~/Library/Application Support/com.harbor.exitnode/sing-box.json`\n- **Settings persisted locally** — stored in `localStorage`; user-entered values override bundled defaults\n- **Bundled binaries** — `cloudflared` and `sing-box` included, no manual installation required\n- **Close-to-tray** — closing the window hides to system tray; the app stays running\n\n## Development\n\n### Prerequisites\n\n- Rust (stable toolchain)\n- Node.js 18+\n- npm\n\n### Build and Run\n\n```bash\ngit clone https://github.com/timwuhaotian/harbor.git\ncd harbor\nnpm install\nnpm run dev\n```\n\n`npm run dev` launches the Tauri desktop app with hot-reload. Tauri starts the Vite dev server automatically.\n\n### Scripts\n\n| Command | Description |\n|---------|-------------|\n| `npm run dev` | Launch Tauri app with hot-reload |\n| `npm run build` | TypeScript compile + Vite build |\n| `npm run test` | Run frontend tests (Vitest) |\n| `npm run bump` | Bump version and validate changelog entry |\n| `npm run build:mac` | Build unsigned macOS app |\n| `npm run build:mac:signed` | Build signed + notarized macOS app |\n| `npm run verify:mac-signature` | Verify macOS code signature |\n\n### Signed macOS Build\n\n```bash\nnpm run build:mac:signed\nnpm run verify:mac-signature\n```\n\nOutputs:\n\n```\nsrc-tauri/target/release/bundle/macos/Harbor.app\nsrc-tauri/target/release/bundle/dmg/Harbor_\u003cversion\u003e_aarch64.dmg\n```\n\nSee [docs/code-signing.md](docs/code-signing.md) for signing and notarization details.\n\n### Tests\n\n```bash\nnpm test\ncargo test --lib --manifest-path src-tauri/Cargo.toml\n```\n\n### Project Structure\n\n```\nharbor/\n├── src/                          # Frontend (TypeScript)\n│   ├── main.ts                   # App entry, UI rendering, event binding\n│   ├── ui.ts                     # Shared types and utilities\n│   ├── ui.test.ts                # Frontend unit tests\n│   ├── i18n.ts                   # English/Chinese localization\n│   ├── update-checker.ts         # Automatic update check \u0026 download\n│   ├── env.d.ts                  # Type declarations (e.g. __APP_VERSION__)\n│   └── styles.css                # UI styles\n├── src-tauri/                    # Tauri backend (Rust)\n│   ├── src/\n│   │   ├── lib.rs                # Tauri app setup, command registration\n│   │   ├── config.rs             # Settings, VLESS link \u0026 sing-box config builders\n│   │   ├── runtime.rs            # Process management (sing-box, cloudflared)\n│   │   └── main.rs               # Binary entry point\n│   ├── capabilities/\n│   │   └── default.json          # Tauri capability definitions\n│   ├── resources/\n│   │   ├── harbor-defaults.defaults.json # Hardcoded release defaults\n│   │   └── harbor-defaults.bundle.json   # Generated bundled defaults (gitignored)\n│   └── tauri.conf.json           # Tauri configuration\n├── scripts/                      # Build, signing, and CI scripts\n│   ├── build-signed-mac.mjs      # macOS signed build + notarization\n│   ├── bump-version.mjs          # Version bump with changelog validation\n│   ├── fetch-runtimes.mjs        # Download sing-box + cloudflared binaries\n│   ├── prepare-bundled-defaults.mjs  # Copy local defaults to bundle path\n│   ├── release-assets.mjs        # Collect release artifacts from Tauri output\n│   ├── signing-env.mjs           # Parse .env + keychain for signing identity\n│   ├── validate-changelog.mjs    # Ensure changelog has current version entry\n│   └── verify-mac-signature.mjs  # Verify macOS code signature\n├── .github/workflows/\n│   └── release.yml               # CI/CD: test, build macOS + Windows, publish\n└── docs/\n    ├── cloudflare-setup.md       # Detailed Cloudflare Tunnel guide\n    └── code-signing.md           # macOS code signing \u0026 notarization\n```\n\n## Security Notes\n\n- The tunnel token is passed to `cloudflared` via `TUNNEL_TOKEN` environment variable, never in command-line arguments\n- sing-box listens on `127.0.0.1` only — no direct network exposure\n- The VLESS UUID is auto-generated on first launch\n- User-entered tunnel token is saved locally so it can override bundled defaults on next launch\n- Signal handlers (SIGTERM/SIGINT/SIGHUP) clean up child processes on Unix\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimwuhaotian%2Fharbor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimwuhaotian%2Fharbor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimwuhaotian%2Fharbor/lists"}