> ## Documentation Index
> Fetch the complete documentation index at: https://docs.harbormcp.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Publishing to the Internet

> Expose your local Harbor gateway to the internet with a secure QUIC tunnel.

Harbor's **publish** feature creates an outbound QUIC tunnel from your machine to a relay server, giving your local MCP tools a public HTTPS URL. No port forwarding, no static IP required.

## Quick start

### Desktop app

1. Start the gateway on the **Lighthouse** page
2. Click **Publish** — a public URL and bearer token appear immediately
3. Share the URL and token with any MCP client

### CLI

```sh theme={null}
harbor publish
```

Output:

```
⚓ Harbor Relay
  URL:   https://abc123.relay.harbormcp.ai
  Token: hbr_...
  Press Ctrl+C to stop
```

## Connecting from another machine

Use the public URL and bearer token in any MCP client:

**Claude Code**

```sh theme={null}
claude mcp add harbor --transport http https://abc123.relay.harbormcp.ai/mcp \
  --header "Authorization: Bearer hbr_..."
```

**Cursor** (`~/.cursor/mcp.json`)

```json theme={null}
{
  "mcpServers": {
    "harbor": {
      "url": "https://abc123.relay.harbormcp.ai/mcp",
      "headers": { "Authorization": "Bearer hbr_..." }
    }
  }
}
```

**VS Code** (`.vscode/mcp.json`)

```json theme={null}
{
  "servers": {
    "harbor": {
      "type": "http",
      "url": "https://abc123.relay.harbormcp.ai/mcp",
      "headers": { "Authorization": "Bearer hbr_..." }
    }
  }
}
```

**Another Harbor instance** — Servers → Add Server → Remote, paste the URL and `Authorization` header.

## Cloudflare Tunnel transport

As an alternative to the QUIC relay, Harbor can use [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) via the `cloudflared` CLI.

```sh theme={null}
harbor publish --transport cloudflare
```

This requires `cloudflared` to be installed:

```sh theme={null}
# macOS
brew install cloudflared

# Linux
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 \
  -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflared
```

Harbor spawns `cloudflared tunnel --url http://127.0.0.1:3100` and extracts the assigned `*.trycloudflare.com` URL. No Cloudflare account required for temporary tunnels.

**When to use Cloudflare vs QUIC relay:**

|                  | QUIC relay                          | Cloudflare             |
| ---------------- | ----------------------------------- | ---------------------- |
| Account required | No                                  | No (temporary URLs)    |
| Custom subdomain | Yes                                 | No (trycloudflare.com) |
| Self-hostable    | Yes                                 | No                     |
| Dependency       | None                                | `cloudflared` binary   |
| Who sees traffic | You (self-hosted) or relay operator | Cloudflare             |

***

## Custom subdomain

Use the **Advanced** section in the desktop UI, or the CLI flag:

```sh theme={null}
harbor publish --subdomain myname
# → https://myname.relay.harbormcp.ai
```

If the subdomain is already taken, a random one is assigned.

## Security model

| Layer            | Protection                                                                                          |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| **TLS**          | All traffic to the relay is HTTPS (Caddy + Let's Encrypt)                                           |
| **QUIC tunnel**  | Noise NKpsk2 protocol — authenticated, forward-secret encryption between your machine and the relay |
| **PSK**          | A pre-shared key compiled into Harbor means only official Harbor binaries can establish tunnels     |
| **Bearer token** | Auto-generated per session — callers without the token receive `401`                                |

**What the relay can see:** The relay sees the plaintext of requests before encrypting them for the tunnel. This is equivalent to ngrok or Cloudflare Tunnel. If you need full privacy, run your own relay (see below).

## Self-hosting the relay

Any Harbor user can run their own relay server. The relay is the same `harbor` binary — no separate software needed.

### Prerequisites

* A VPS with a public IP (any cloud provider)
* A domain you control (e.g. `relay.example.com`)
* Docker and Docker Compose

### 1. DNS records

Add two A records pointing to your VPS IP:

```
A    relay.example.com      →  <VPS IP>
A    *.relay.example.com    →  <VPS IP>
```

The wildcard is required for subdomain routing.

### 2. Firewall ports

```sh theme={null}
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 7800/udp
```

### 3. Clone and configure

```sh theme={null}
git clone https://github.com/JoshuaShunk/Harbor.git /opt/harbor/repo
mkdir -p /opt/harbor
```

Create `/opt/harbor/Caddyfile`:

```
relay.example.com, *.relay.example.com {
    reverse_proxy localhost:8443
}
```

<Note>
  For wildcard TLS you need a DNS API provider (e.g. Cloudflare). Standard HTTP challenge only covers the apex domain. See the [Caddy docs](https://caddyserver.com/docs/automatic-https) for DNS challenge setup.
</Note>

Create `/opt/harbor/docker-compose.yml`:

```yaml theme={null}
services:
  caddy:
    image: caddy:latest
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy-data:/data
    restart: unless-stopped

  relay:
    build:
      context: ./repo
      dockerfile: deploy/relay/Dockerfile
    ports:
      - "7800:7800/udp"
      - "8443:8443/tcp"
    volumes:
      - relay-data:/data/harbor-relay
    command:
      - "--quic-port"
      - "7800"
      - "--https-port"
      - "8443"
      - "--domain"
      - "relay.example.com"
      - "--keypair-file"
      - "/data/harbor-relay/keypair"
    restart: unless-stopped

volumes:
  caddy-data:
  relay-data:
```

### 4. Build and start

```sh theme={null}
cd /opt/harbor
docker compose build relay
docker compose up -d
```

### 5. Get your relay's public key

```sh theme={null}
docker compose exec relay harbor relay --print-key --keypair-file /data/harbor-relay/keypair
```

Save this key — your clients need it to connect.

### 6. Publish pointing at your relay

```sh theme={null}
harbor publish --relay relay.example.com:7800 --relay-key <key from step 5>
```

Or in the Harbor desktop UI, open **Advanced** and enter your relay address and key.

### Updating

```sh theme={null}
cd /opt/harbor/repo && git pull origin main
cd /opt/harbor && docker compose build relay && docker compose up -d
```

### Keypair persistence

The relay keypair is stored in the `relay-data` Docker volume at `/data/harbor-relay/keypair`. It persists across container restarts. If you delete the volume, a new keypair is generated and existing clients will need the new public key.

## Why self-host?

Running your own relay means:

* **You** are the only operator — no third party can see your traffic
* The relay code is open source — you can audit exactly what it does
* Your subdomain is on your own domain

The managed relay at `relay.harbormcp.ai` is convenient for personal use. Self-hosting is recommended if you're handling sensitive data or deploying for a team.
