---
title: "Exposed Services"
description: "Publish a loopback dev server, API, or dashboard through Cloud Link on its own port and origin, private by default and live-editable."
canonical: "https://opencodecloud.link/docs/exposed-services/"
lastUpdated: "2026-10-19"
---
Your project rarely lives alone. Cloud Link can publish a loopback service — a
dev server, API, dashboard, or preview build — through the same tunnel as
OpenCode. Services are disabled and private until you explicitly enable them.

## Before you expose a service

- The service must listen on loopback (`127.0.0.1` or `::1`) on an unprivileged
  port from 1024 to 65535.
- The target cannot use port 80 or 443, a Cloud Link service port, the
  connector's proxy port, or OpenCode's managed port range.
- Hostnames, RFC1918 addresses, link-local addresses, and cloud metadata
  addresses are rejected.
- The service should be one you trust. A public service is reachable by anyone
  with its URL.

## How addresses work

OpenCode stays on the main tunnel URL. Each service is served on one of
Cloudflare's supported HTTPS ports:

`8443`, `2053`, `2083`, `2087`, `2096`

No extra DNS record, certificate, or tunnel ingress is needed. Every port
reaches the same tunnel hostname, and the connector routes by port.

### Root service

Leave **Path** empty to let the service own the port root:

```text
https://m-7f3a91c2.opencodecloud.link:8443/
```

Use a root service for applications that emit absolute URLs such as
`/assets/app.js`. A root service owns its port.

### Path service

Set a path prefix to share a port with other path services:

```text
https://m-7f3a91c2.opencodecloud.link:8443/my-app/
```

Path matching uses the raw encoded path. Relative and percent-encoded
separators are rejected before routing. By default the matched prefix is
stripped before forwarding; **Keep path prefix** forwards the full path instead.
The connector also sets `X-Forwarded-Prefix` and re-prefixes path-absolute
redirects.

## Add a service

1. Open **Settings → Services**.
2. Choose **Add service**.
3. Fill in the fields.
4. Save. Changes apply live; you do not need to restart the tunnel.
5. Use **Probe** to confirm the local target is reachable.
6. Use **Copy URL** or **Open** after connecting.

### Field reference

| Field | Meaning |
| --- | --- |
| **Name** | Display name in the list and sidebar |
| **ID** | Identifier used in the service URL |
| **Port** | Public HTTPS port from the supported list |
| **Path** | Optional prefix. Empty means the service owns the port root. |
| **Target** | Loopback address, for example `127.0.0.1:3000` |
| **Enabled** | Serve the service through the tunnel |
| **Public** | Allow anonymous access. Off means Cloud Link credentials are required. |
| **Keep path prefix** | Forward the matched path unchanged instead of stripping it |

New services start with **Enabled** off and **Public** off.

## Private and public access

- **Private** services require the same Cloud Link device or browser
  credential used for OpenCode.
- **Public** services are reachable by anyone who has the URL.

Mark a service public only when its content is safe to share. Public and private
services can share a port, which means they also share a browser origin. A
public page on that origin may be able to request private paths using the
owner's cached credentials. Use separate ports when that matters.

## Separate origin from OpenCode

Services never share the OpenCode origin. OpenCode's `/`, `/api`, `/global`,
and `/auth` paths cannot be shadowed by a service. This keeps OpenCode browser
credentials and storage away from service content.

## Manage from the mobile app

A paired device can add, edit, enable, disable, or remove services from
**Settings → Cloud Link → Exposed services**. The connector validates the
request and returns canonical values.

Remote service management is available only through the device-authenticated
`/_cloudlink` API on the OpenCode origin. The browser credential cannot use it,
and it is never served on a service port.

## Manage from the CLI

The connector must be stopped because it holds the installation lock.

```sh
opencode-cloudlink services list

opencode-cloudlink services add web \
  --target 127.0.0.1:3000 \
  --port 8443 \
  --enable

opencode-cloudlink services add api \
  --target 127.0.0.1:8080 \
  --path /api \
  --enable

opencode-cloudlink services disable web
opencode-cloudlink services enable web
opencode-cloudlink services remove api
```

See [CLI reference](/docs/cli/) for all service options.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| Service will not save | Target must be loopback; ID, port, and path must be valid and unique |
| Service shows unreachable | The local app is stopped, bound elsewhere, or using the wrong port |
| URL returns authentication | The service is private; use Cloud Link credentials |
| Public service returns authentication | Confirm **Public** is enabled and saved |
| Assets or redirects break | Try a root service, or enable **Keep path prefix** |
| Port is rejected | Choose 8443, 2053, 2083, 2087, or 2096 |
| Path is rejected | Do not use the reserved `/_cloudlink` prefix |
| Changes do not apply | Recheck the saved service and probe again |

See [Security and privacy](/docs/security/) for the exposure model.