Skip to content

OpenTunnel remote URL never attaches on macOS v2.0.30 despite completed tunnel profile #55864

Closed as not planned

Description

@yutakakohno

Description

Summary

OpenCode V2 remote access previously worked from iPhone Safari through OpenTunnel, then suddenly stopped. The local server works, but no remote HTTPS URL appears despite the default OpenTunnel profile containing the completed-profile file set. The problem persists after upgrading from 2.0.28 to 2.0.30 via Homebrew (anomalyco/tap/opencode-v2).

Observed behavior

  • opencode service get remote returns true.
  • opencode service status lists only a loopback HTTP URL (address omitted).
  • opencode api get /api/info has no HTTPS URL in urls.
  • The local UI and existing-session API work normally; the opencode-go configuration is also reported working.
  • opencode pair --remote ends with Timed out waiting for the remote tunnel.

The default OpenTunnel profile contains these filenames (no contents included):

certificate.pem
chain.pem
private-key.pem
token
tunnel.json

There is no pending.json. File presence alone does not establish that the certificate or remote tunnel is currently valid.

Recovery attempts

None resolved the problem:

  • Restarted the background service.
  • Toggled remote access from false to true.
  • Backed up and moved the default OpenTunnel profile aside, then regenerated it.
  • Updated the CLI from 2.0.28 to 2.0.30 through Homebrew.

Historical diagnostics and limits

Past logs from 2026-10-14 at approximately 09:01 UTC contain these error fragments:

remote access tunnel unavailable; retrying
OpenTunnelClientError: Failed to read certificate
getaddrinfo ENOTFOUND opentunnel.xyz

These establish a DNS lookup failure at that earlier time, not an ongoing DNS failure now. A later GET to the public OpenTunnel API tunnel endpoint returned HTTP 404; that is limited evidence of HTTP reachability for that request, not proof that certificate retrieval, tunnel attachment, or remote access is healthy. The current root cause is unconfirmed.

Expected behavior

With remote access enabled and a valid completed tunnel profile, the service should establish remote access, expose its HTTPS URL in /api/info, and allow the remote client to connect.

Related reports and distinction

Questions for maintainers

  1. How can an attachment failure with this completed-profile file set be diagnosed, and which safely redacted logs would distinguish DNS, certificate, and tunnel-attachment failures?
  2. Is there a supported recovery procedure that preserves the OpenCode database and existing sessions?
  3. Could diagnostics report the failing stage and a safe recovery hint when remote access is enabled but no HTTPS URL becomes available?

Connection URLs, private hostnames, session identifiers, credentials, personal names, and local user paths are intentionally omitted.

Plugins

No response

OpenCode version

2.0.30 (also affected on 2.0.28)

Steps to reproduce

The original trigger is unknown; these are observations from the affected state, not a clean-install reproduction.

  1. On the affected Mac, confirm remote access is enabled with opencode service get remote.
  2. Run opencode service status and opencode api get /api/info: only a loopback HTTP URL is available, with no remote HTTPS URL.
  3. Run opencode pair --remote: it times out waiting for the remote tunnel.
  4. The default OpenTunnel profile has the five completed-profile files listed above and no pending.json.

Screenshot and/or share link

No response

Operating System

macOS, MacBook Air (exact OS version not recorded)

Terminal

No response

Activity

  1. opencode-agent commented on Oct 15, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report! We need the error the service is hitting right now to narrow this down. The log you quoted is from the day before, and the pair --remote timeout only means the service never published a tunnel URL. It doesn't say why.

    The background service attaches the tunnel and only then adds the HTTPS URL to /api/info. If setup fails it either keeps retrying, logging remote access tunnel unavailable; retrying, or gives up after an attach or certificate-issuance failure, logging remote access tunnel stopped; ... once. The cause attached to that line tells us which stage is failing.

    Could you please:

    1. Run opencode service restart, wait about a minute, then find the log directory with opencode debug paths log.
    2. Share the lines from the newest log file that contain remote access tunnel, including the error/cause that follows each one. Feel free to redact hostnames, tunnel IDs and tokens, but please keep the error names and messages (e.g. OpenTunnelClientError: ..., OpenTunnelAttachError, getaddrinfo ..., HTTP status codes).
    3. Share the output of curl -sS -o /dev/null -w '%{http_code}\n' https://opentunnel.xyz/api/tunnel from the same Mac, and tell us whether a DNS filter (Pi-hole, NextDNS, etc.), VPN or proxy is active on that network.

    You can reply here, or edit the issue. If you edit it, please also leave a comment saying you've updated it, so we know you're done.

    Related issues, ordered from most to least likely to be relevant (none looks like an exact match):

  2. yutakakohno commented on Oct 15, 2026

    @yutakakohno
    Author

    Follow-up diagnostics from the affected Mac (2026-10-16, JST):

    • Restarted the service successfully at 2026-10-15 21:53:28 UTC and checked the log after approximately one minute (21:54:29 UTC).
    • opencode service get remote returned true before this restart. The restart returned only a loopback HTTP URL. /api/info checked after the restart still had a loopback URL and no HTTPS URL.
    • The default OpenTunnel profile still contains certificate.pem, chain.pem, private-key.pem, token, and tunnel.json; pending.json is absent. File contents were not collected for publication.
    • There is only one file in the reported log directory, opencode.log. It is receiving new records: 101 timestamped lines, including 86 with role=server, were written from the diagnostic restart through the inspection. The latest timestamp at inspection was 21:53:49 UTC. However, none of those new records contains remote access tunnel, OpenTunnelClientError, or OpenTunnelAttachError. Searching the log directory previously also found only the three historical tunnel warnings from 2026-10-14 09:01–09:02 UTC; I am not presenting those as current failures.
    • The requested GET to the public OpenTunnel API tunnel endpoint returned 404, with curl exit status 0, during this diagnostic restart. This only establishes reachability for that request.
    • macOS scutil --nc list reported no connected system VPN configuration, and scutil --proxy reported no proxy enable flags. These checks do not rule out third-party network extensions, application-specific proxies, or network/router-level filtering. Whether a DNS filter such as Pi-hole or NextDNS is active remains unconfirmed.

    Since the current service writes server logs but no tunnel-stage diagnostic appears after restart, what is the next supported way to capture the attach/setup failure? Is there a specific service logging level or another log destination to check? Please suggest a procedure that preserves the database and existing sessions.

    Private connection URLs, hostnames, IDs, credentials, and local user paths have been omitted.

  3. opencode-agent commented on Oct 15, 2026

    @opencode-agent
    Contributor

    Thanks for collecting all of that. A log with no tunnel lines after a restart is actually what 2.0.30 produces in this case, so it does narrow things down.

    Why nothing is logged: the service only logs about the tunnel in two cases: when setup fails before the tunnel starts (remote access tunnel unavailable; retrying), or when it hits a fatal error (remote access tunnel stopped). After that, the OpenTunnel SDK opens a WebSocket "bridge" to opentunnel.xyz. If that connection is rejected or dropped, the SDK retries with backoff, without logging and without a timeout, and OpenCode doesn't log the SDK's events. In 2.0.30 no log level or other log file shows this stage. I checked this with a profile for a tunnel the server doesn't know: the SDK retried forever with bridge closed: 1002 Expected 101 status code, and none of it would appear in opencode.log.

    Read-only check: this script uses the same SDK version as 2.0.30 (@opentunnel/client 0.4.0) and your default OpenTunnel profile. It briefly attaches a random throwaway route to your tunnel, pointing at an unused local port (127.0.0.1:9), and prints each connection attempt and why it failed. It never creates or deletes a tunnel and doesn't touch OpenCode's database, sessions or service config. It runs separately from the background service, so you don't need to stop the service.

    mkdir -p /tmp/ot-check && cd /tmp/ot-check
    echo '{"type":"module"}' > package.json
    npm i @opentunnel/client@0.4.0 effect
    # save the script below as tunnel-check.mjs, then:
    bun tunnel-check.mjs   # Bun gives the most detailed close reason; Node 22+ also works
    // Read-only check of the default OpenTunnel profile: attaches a throwaway route for 60s and prints each event.
    import { create } from "@opentunnel/client"
    import { Tunnel } from "@opentunnel/client/effect"
    
    const identity = await create().tunnel.get()
    if (!identity) {
      console.log("no default OpenTunnel profile found (not creating one)")
      process.exit(1)
    }
    console.log("profile found; certificate expires", new Date(identity.certificateExpiry).toISOString())
    const tunnel = new Tunnel({
      api: "https://opentunnel.xyz",
      identity,
      routes: { ["diag" + Math.random().toString(16).slice(2, 8)]: "127.0.0.1:9" },
      onEvent: (event) => console.log(new Date().toISOString(), JSON.stringify({ ...event, session: undefined })),
    })
    let done = false
    const timer = setTimeout(async () => {
      done = true
      console.log("not attached after 60s; last error:", tunnel.getStatus().lastError)
      await tunnel.close()
      process.exit(2)
    }, 60_000)
    tunnel.ready.then(
      async () => {
        if (done) return
        clearTimeout(timer)
        console.log("attached OK")
        await tunnel.close()
        process.exit(0)
      },
      (error) => {
        console.log("fatal:", error?.message ?? error)
        process.exit(3)
      },
    )

    The script doesn't print tokens, hostnames or tunnel IDs. Please paste its output here. Any of these results would point to a different cause:

    • bridge closed: 1002 Expected 101 status code repeating: the server is refusing the WebSocket for this tunnel, for example because it no longer knows the tunnel.
    • bridge attach timed out or bridge closed: 1006: the WebSocket to opentunnel.xyz is being blocked or dropped on the network side (filtering, a security product, a router).
    • attach failed: <code>: the server refused the attachment, and the code says why.
    • fatal: ...: an invalid token or a certificate that isn't ready.
    • attached OK: the profile and network are fine, and the problem is in how the service starts the tunnel.

    If you set XDG_DATA_HOME in your shell, please also say whether it is set the same way in the shell where you ran opencode service restart. The service inherits that environment, and the SDK reads the profile from $XDG_DATA_HOME/opentunnel/default, or ~/.local/share/opentunnel/default when it isn't set.

    About recovery that keeps your data: the OpenCode database and sessions are stored separately from the OpenTunnel profile and from the service config's remote setting. Moving the profile aside, and opencode service set remote false / true, don't touch your sessions; the only change is that turning remote off and on gives you a new remote address. Once the output above shows the failing stage, we can say which reset applies. Better logging for this stage is a reasonable request (related: #54624 / #55502), but we can't promise when it will happen.

  4. yutakakohno commented on Oct 15, 2026

    @yutakakohno
    Author

    Follow-up diagnostic (2026-10-16 JST):

    I ran a read-only profile check with the same SDK version used by OpenCode 2.0.30 (@opentunnel/client 0.4.0) on Node 22. The default profile loaded successfully; its certificate expiry is 2027-01-13 UTC. The diagnostic process and launchd both had XDG_DATA_HOME unset, so it used the default ~/.local/share/opentunnel/default profile.

    For 60 seconds, the SDK made six bridge connection attempts. Each disconnected and retried; no initial attach succeeded. The final status was bridge attach timed out. I reported only event types and attempt counts, and withheld connection details. The temporary route targeted 127.0.0.1:9; I checked that this local port was unused, and the script closed the route when the timeout was reached. No tunnel was created or removed, and no OpenCode database, sessions, or service settings were changed.

    This points to the bridge WebSocket connection failing to attach or being dropped, consistent with the network-side case described above. It does not by itself distinguish filtering or routing from a server-side rejection that manifests as a timeout. The public API GET still returns 404 over HTTP; the result does not test the WebSocket bridge. macOS reports no connected system VPN configuration or enabled system proxy; DNS or router filtering remains unknown.

  5. opencode-agent commented on Oct 15, 2026

    @opencode-agent
    Contributor

    Thanks for running the check, it narrowed things down a lot.

    I tried to reproduce this on 2.0.30 (Linux, clean home directory, no XDG_* variables) with opencode pair --remote --yes. Every stage worked: a new tunnel was created, its certificate was issued, the background service attached the bridge, and /api/info listed the remote HTTPS URL next to the loopback one. That was around 23:03 UTC on 2026-10-15. So OpenTunnel's API, certificate issuance and bridge attach were all working from here at that time.

    On your Mac, the profile loads and the certificate is valid, but every bridge attempt ends in bridge attach timed out. The bridge is a WebSocket to opentunnel.xyz. Either the connection never opens, or it opens and no reply comes back within 10 seconds. Since the same steps work from here, the likeliest causes are on the path between your Mac and opentunnel.xyz: DNS or router filtering, a third-party network extension or security tool (some block or interfere with WebSocket upgrades), or a regional problem on the service side like the one in #54596. An HTTP GET returning 404 doesn't rule these out, because it doesn't test the WebSocket upgrade.

    Things that would help narrow it down:

    • Run the same check from another network, e.g. an iPhone hotspot. If it shows attached OK there, the cause is your usual network.
    • Temporarily turn off any third-party network extensions or security tools (macOS System Settings → General → Login Items & Extensions → Network Extensions) and run the check again.
    • If it fails everywhere, post the time (UTC) of a failing run so the maintainers can check it against the service.

    Once the check attaches, opencode service restart should bring back the HTTPS URL. Your sessions and database aren't affected by this.

    One gap on our side: in 2.0.30 the service doesn't log why the bridge keeps failing. While it retries, the log stays silent and opencode pair --remote only reports a timeout. That's why your log showed nothing useful. I've noted this for the maintainers; related: #54624 / #55502.

  6. thdxr commented on Oct 15, 2026

    @thdxr
    Member

    Thanks for the careful diagnostics. Your result (every bridge attempt ending in bridge attach timed out) turned out to be a real OpenTunnel outage, not your network.

    From about 20:30 to 23:20 UTC on Oct 15, the OpenTunnel servers in Tokyo and Paris ran out of database connections during a reconnect storm. Clients in Japan connect through Tokyo. A bridge attach there needed several database round trips and was taking longer than the client's 10-second attach timeout, so the client gave up and retried, over and over. Your check at about 22:11 UTC was right in that window, and so was the bot's "works from here" test, which ran through a different region.

    That's fixed now (anomalyco/opentunnel@5fe2d73, deployed at about 23:20 UTC). Database errors are near zero, attaches complete normally again, and connected tunnels have recovered. We're also cutting the database round trips per attach so a far region can't storm like this again.

    Your profile and certificate (expiring 2027-01-13) are fine, so nothing needs resetting: opencode service restart should bring back the HTTPS URL, or the service will reattach on its own. If it still doesn't attach, please reopen with the UTC time of a failing run.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  7. opencode-agent commented on Oct 18, 2026

    @opencode-agent
    Contributor

    Closing this for now since we haven't heard back. On 2.0.30, opencode pair --remote worked from our side: the tunnel attached and /api/info listed the remote HTTPS URL. Your check showed every bridge attempt to opentunnel.xyz ending in bridge attach timed out. That points to something between your Mac and opentunnel.xyz (DNS or router filtering, a network extension or security tool, or a regional problem on the service side like #54596), which we couldn't reproduce or check from here.

    If it still happens, please reply with the result of the same check from another network (e.g. an iPhone hotspot), or with the UTC time of a failing run, and we can reopen this. Thanks for the careful, privacy-conscious diagnostics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions