docs: add Coder Desktop stale-tunnel recovery and improve macOS log capture (#26735)

## What

Adds a **Recovering from a stale tunnel** section to the Coder Desktop
user guide, with separate macOS and Windows procedures, and tightens the
existing macOS log-collection instructions.

## Why

Users in the field have hit a state where Coder Desktop's menu bar /
tray shows **Coder Connect** as enabled but the embedded tunnel is no
longer working:

* `workspace.coder` fails to resolve (`No such host`), or
* DNS returns stale `fd60:627a:a42b::/48` addresses that no longer
route, causing `coder ssh`, file sync, and the directory picker to hang.

Related issues:

* coder/coder#26669 — `ExistsViaCoderConnect` false positives when Coder
Desktop has stale DNS
* coder/coder-desktop-windows#171 — Tray reports Coder Connect as
healthy while tunnel/DNS is broken

Until the underlying state-management gap is fixed in the apps, the docs
should give users (and support) a safe, repeatable way to recover
without rebooting.

## Changes

`docs/user-guides/desktop/index.md`:

1. **New "Recovering from a stale tunnel" section** under
Troubleshooting:
* **macOS:** stop the VPN configuration with `scutil --nc stop`, quit
the app via `osascript`, restart the helper daemon in place with
`launchctl kickstart -k system/com.coder.Coder-Desktop.Helper`, flush
DNS caches, then relaunch.
* Includes a warning to **not** use `launchctl bootout`, which removes
the daemon from launchd's system domain entirely and is not
re-bootstrapped on app relaunch.
* Includes a verification step using the built-in sentinel hostname
`is.coder--connect--enabled--right--now.coder` (defined in
`tailnet/conn.go` as `IsCoderConnectEnabledFmtString`) so users don't
need a workspace name to confirm the tunnel is healthy.
* Uses `dig @fd60:627a:a42b::53` (explicit server) and `dscacheutil -q
host -a name` because plain `dig` does not respect the macOS system
resolver.
* **Windows:** stop the app and `Coder Desktop` service, flush DNS,
restart, then verify the NRPT rule and Wintun adapter. Notes that
`ipconfig /flushdns` does not reset the embedded resolver and that
filtering agents (e.g., Zscaler) may still shadow `.coder` lookups.
2. **macOS log-collection improvements:**
* Switch the predicate from `subsystem == "com.coder.Coder-Desktop"` to
`subsystem BEGINSWITH "com.coder.Coder-Desktop"` so the export captures
the app, helper daemon, and network extension (which all log under
prefixed subsystems).
* Add a `log stream` example for live tailing while reproducing an
issue.

## Verification

* `npx markdownlint-cli2 docs/user-guides/desktop/index.md` — 0 errors.
* macOS recovery steps were validated end-to-end on a real install (the
`kickstart -k` form, in particular, was confirmed to restart the helper
without breaking the install, unlike `bootout`).

---

Created on behalf of @mdanter

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
Co-authored-by: Atif Ali <atif@coder.com>
Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
Co-authored-by: Matyas Danter <mdanter@gmail.com>
This commit is contained in:
blinkagent[bot]
2026-08-14 12:31:04 -04:00
committed by GitHub
co-authored by blink-so[bot] Atif Ali Nick Vigilante Matyas Danter
parent 57dc47dc42
commit 043bebb7bc
+130 -3
View File
@@ -169,7 +169,121 @@ You can also configure a `Updater:ForcedChannel` string value to lock users to a
- Check system permissions for network extensions
- Ensure only one copy of Coder Desktop is installed
### Collecting Logs
### Recover from a stale tunnel
If the menu bar or tray shows **Coder Connect** as enabled but workspaces are
unreachable (SSH hangs, `workspace.coder` fails to resolve, or file sync cannot
list the workspace directory), the embedded tunnel may be in a stale state.
Restart the helper components first.
If that doesn't resolve the issue, reboot your computer.
<div class="tabs">
#### macOS
Run the following commands in a terminal.
These steps leave the app and helper daemon installed.
They only restart the running tunnel and flush DNS caches.
1. Stop the Coder VPN configuration:
```shell
vpn_name=$(scutil --nc list | grep "com.coder.Coder-Desktop" | awk -F'"' '{print $2}' | tail -n1)
if [ -n "$vpn_name" ]; then scutil --nc stop "$vpn_name"; fi
```
2. Quit the Coder Desktop app:
```shell
osascript -e 'tell application id "com.coder.Coder-Desktop" to quit'
```
3. Restart the helper daemon in place:
```shell
sudo launchctl kickstart -k system/com.coder.Coder-Desktop.Helper
```
> [!WARNING]
> Do not use `launchctl bootout` here. `bootout` removes the daemon from
> launchd's system domain entirely, and relaunching the app does not
> re-bootstrap it. Use `kickstart -k` to restart it in place.
4. Flush DNS caches:
```shell
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
```
5. Confirm the stale tunnel is gone (the command should print nothing):
```shell
scutil --nc list | grep "com.coder.Coder-Desktop"
```
6. Relaunch **Coder Desktop** from your `/Applications` folder and toggle **Coder Connect** back on.
To verify the tunnel is healthy after relaunching, query the built-in sentinel
hostname against Coder Desktop's embedded DNS server:
```shell
dig @fd60:627a:a42b::53 AAAA is.coder--connect--enabled--right--now.coder +short
dscacheutil -q host -a name is.coder--connect--enabled--right--now.coder
```
Both commands should return an `fd60:627a:a42b::/48` address.
If `dig` returns nothing or `dscacheutil` reports no entries, Coder Connect is not publishing DNS.
[Collect logs](#collect-logs) and file an issue.
#### Windows
Run the following in an **elevated PowerShell** session.
The service restart clears the embedded DNS state.
The NRPT and adapter checks confirm the system routing policy is intact.
1. Stop the app and the VPN service:
```ps1
Get-Process -Name "Coder Desktop" -ErrorAction SilentlyContinue | Stop-Process -Force
Stop-Service -Name "Coder Desktop" -Force
```
2. Flush DNS caches:
```ps1
ipconfig /flushdns
Clear-DnsClientCache
```
3. Start the service again and relaunch the app:
```ps1
Start-Service -Name "Coder Desktop"
Start-Process "C:\Program Files\Coder Desktop\CoderDesktop.exe"
```
4. After re-enabling Coder Connect in the tray, verify the NRPT rule and the Wintun adapter exist:
```ps1
Get-DnsClientNrptRule | Where-Object { $_.Namespace -like "*.coder" }
Get-NetAdapter | Where-Object { $_.InterfaceDescription -like "*Wintun*" }
```
If either command returns nothing while Coder Connect shows as enabled,
the tunnel did not finish coming up. Disable and re-enable the toggle, or
repeat the steps above.
> [!NOTE]
> `ipconfig /flushdns` does not reset Coder Desktop's embedded DNS resolver;
> restarting the service is what clears its internal cache. If you are running
> a network filtering agent (for example, Zscaler), it may shadow `.coder`
> lookups even after the tunnel comes back. Check with your IT team if DNS
> still fails after a clean restart.
</div>
### Collect logs
When reporting an issue, attach the relevant log files so we can diagnose it faster.
@@ -182,11 +296,24 @@ Coder Desktop and its network extension write to the Apple [unified logging syst
1. Export the unified logs for the last hour with the `log` command:
```sh
log show --predicate 'subsystem == "com.coder.Coder-Desktop"' \
log show --predicate 'subsystem BEGINSWITH "com.coder.Coder-Desktop"' \
--info --debug --last 1h > ~/Desktop/coder-desktop.log
```
Adjust `--last` (e.g. `30m`, `2h`, `1d`) to cover the time the issue occurred. You can also view the same logs interactively in **Console.app** by filtering on the `com.coder.Coder-Desktop` subsystem.
The `BEGINSWITH` predicate captures the app, the helper daemon, and the
network extension, which all log under subsystems prefixed with
`com.coder.Coder-Desktop`. Adjust `--last` (e.g. `30m`, `2h`, `1d`) to
cover the time the issue occurred.
You can stream the logs live while reproducing an issue:
```shell
log stream --predicate 'subsystem BEGINSWITH "com.coder.Coder-Desktop"' --info --debug
```
You can also view the same logs interactively in **Console.app** by
filtering on `subsystem:com.coder.Coder-Desktop` with Info and Debug
messages enabled.
2. If you're using file sync, also collect the Mutagen daemon log: