Service eligibility and regional restrictions
PuppyIP serves only compliant overseas businesses and their authorized personnel. Proxy services are not available in mainland China. The service may only be used for lawful business activities outside mainland China. Use of this service within mainland China is prohibited.
Hosting a proxy IP or server overseas does not change these restrictions. The service must not be provided to end users in mainland China through relaying, forwarding, sharing or resale. Before use, read the Terms of Service.
Key Takeaways
- The current CLI lists prebuilt binaries for Linux and macOS on x64 and arm64. The TypeScript SDK supports Bun, Node and Deno; older Bun-only descriptions no longer cover the current documentation.
- Routes forward a subdomain to a host:port target. The CLI generates a random route name by default or lets you choose a name such as api. Neither a random name nor TLS replaces application authentication.
- PROXY protocol v1/v2 prefixes a connection with visitor address information. Enable it only when the target explicitly supports it; it is not an HTTP or SOCKS proxy mode.
- The project website shows an OpenCode SDK example. That demonstrates a way to connect a local service, rather than proving that OpenCode has released a built-in integration. Keep the earlier integration plan separate from confirmed availability.
Encrypted transport does not make the URL private
OpenTunnel is a blind TLS tunnel: the public relay forwards encrypted connections, while the local client holds the certificate private key and terminates TLS on your machine. The project says the relay cannot see HTTP plaintext and does not hold that private key. This describes the transport and key boundary, not whether a visitor is authorized.
The tunnel hostname is published in certificate transparency logs. Random route names do not appear in the wildcard certificate record, but common names may still be guessed. Anyone who receives or discovers a full URL can reach its service. A sensitive application must enforce its own login, request verification or other applicable access controls.
The target app may see a connection from a loopback address. It must not treat that as a trusted local operation, or grant access based only on Host or visitor-supplied headers. The tunnel brings an external visitor to a local port; the application still needs to check identity and permissions.
Choose a CLI or SDK, then check platform support
For managing ports on existing local services, choose an installation channel from the official CLI documentation. The current prebuilt binaries cover Linux and macOS on x64 and arm64. These documents do not list Windows prebuilt support. Finding the npm package does not establish that its native binary runs on every operating system.
The opentunnel npm package launches the native Rust CLI. To connect from within your own process, see @opentunnel/client: its current documentation lists Bun, Node and Deno and identifies effect as a peer dependency. Check your runtime version and project dependencies when choosing the SDK.
Create a route to port 3000 and check what it exposes
First confirm that you are authorized to expose the app, that it listens on the intended port and that application authentication is configured before sharing. For a hypothetical development preview shared with an authorized colleague, the target might be 127.0.0.1:3000. This illustrates the workflow; it is not a tunnel we created.
The documented minimal CLI command is opentunnel route add 3000. On first use it creates the tunnel, starts the background service and prints the URL. For a readable route name, use opentunnel route add 3000 --name api. Check the output before sharing the URL with the intended visitors.
Use opentunnel route list to check the route name and target, then opentunnel status to inspect the connection and logs. Once connected, an authorized visitor should still check that the application presents and enforces the intended login or permissions. A connected background service does not prove that application authentication is working.
A route target is host:port without a scheme. Its name is one subdomain label, or @ for the tunnel hostname itself. The current SDK does not route HTTP paths such as /api and /admin to separate targets. Path routing must be handled by the application or an appropriate existing routing layer.
Enable PROXY protocol only for a compatible target
PROXY protocol prefixes each connection with visitor address information. The CLI options are --proxy-protocol v1 and --proxy-protocol v2; the SDK uses proxyProtocol. The target must be configured to understand that header and, as the documentation requires, listen on loopback. Otherwise, the extra bytes can break the target protocol.
For example, the documented command opentunnel route add 3000 --proxy-protocol v2 enables a PROXY protocol v2 header for that target. It does not turn the application into a SOCKS5 or HTTP proxy. Use this example only with a compatible service; an ordinary development web server should not receive it merely to display a visitor IP.
In CLI configuration, a route with options is a table containing target and proxy_protocol. CLI versions older than 0.5.0 cannot read that form. Adding the same target or route name again updates its settings: an add command without --proxy-protocol switches the option off. Check the client version and existing target configuration before changing it.
Understand which process owns each route
The CLI keeps a background connection after route add or up. It can register a login service where systemd or launchd is available; in environments such as containers, it may be an ordinary background process instead. SDK connect runs inside your process and reconnects with backoff after non-fatal disconnections; close stops that connection. Reconnection is not an application availability or service-level guarantee.
The CLI and SDK can share the tunnel identity for a profile, but each declares the routes it handles. The SDK uses routes passed to connect or setRoutes and does not write them into the CLI route configuration. Editing that CLI file and changing SDK settings in your app are separate actions.
Separate the OpenCode example from a released integration
The creator mentioned a forthcoming OpenCode integration in the original October 7 post. The current project website also shows an SDK example mapping an opencode route to a local service. That example demonstrates a connection pattern. It does not establish that OpenCode has released a built-in entry point or made it available to every account; the retained evidence does not confirm a formal integration release.
Use the README, CLI, SDK and protocol documentation read for this guide as the current operating reference, rather than early descriptions of the relay architecture or a single supported runtime. These sources do not fully establish pricing, traffic allowances, regional eligibility or an SLA. Check current service terms when choosing a sharing setup; this guide makes no promise of free, unlimited or continuously available service.
Sources
- OpenTunnel current project README
- OpenTunnel CLI: routes, background service and configuration
- OpenTunnel TypeScript SDK: runtimes and connection management
- OpenTunnel protocol: routes and bridge ownership
- OpenTunnel website source: public access boundaries and OpenCode example
- Dax Raad: October 7 OpenTunnel announcement and OpenCode integration plan
Frequently Asked Questions
Does stopping the connection permanently delete the tunnel URL?
Stopping and deleting are separate actions. CLI down stops the service and removes its startup registration; SDK close stops the current connection. Deleting a tunnel is a separate operation that loses its hostname. Check the app and any URL you shared separately; temporary disconnection is not permanent revocation.
Why do two processes claiming the same route get route_conflict?
A route belongs to one bridge connection at a time. Another bridge claiming an occupied route is rejected and retries with backoff, taking over only after the original bridge goes away. Check whether the CLI and SDK both claim the name, then assign routes according to their intended use.
Should I use SDK memory storage for a long-lived tunnel?
The documentation says a memory store loses its token when the process exits, while created tunnels do not automatically expire. Losing the token removes your ability to delete that tunnel. Persist identities appropriately for long-lived use, or follow the SDK cleanup guidance while you still hold the temporary identity. Do not commit tokens or private-key.pem.