Symptoms
- Workspace agents report as healthy/connected in the Coder dashboard
coder ssh,coder ping, and web applications (VS Code Web, terminals, etc.) fail with errors like:Internal error dialing workspace agent. Error: agent is unreachable
- Restarting the agent process temporarily resolves the issue
- The failure is intermittent, that is, sometimes connections work, sometimes they don't
Root Cause
This occurs when a DERP map configuration places Tailscale public DERP nodes and private (internal) DERP nodes in the same region.
Within a single DERP region, all nodes must form a full mesh, that is, they forward packets to each other on behalf of clients. When one node is on the public internet (e.g., derp1.tailscale.com) and another is on a private network with no public IP, the public node cannot reach the private node. The mesh is broken, and relay traffic silently fails.
Why the failure is intermittent
A client connecting to a region may land on any node in that region. If the client lands on the public node and the agent lands on the private node (or vice versa), packets never reach each other because the two nodes can't forward between themselves. When both peers happen to land on the same node, connectivity works normally.
Background: How DERP Relay Works
When two peers (e.g., your local machine and a workspace agent) communicate through Coder:
- Direct connection (preferred): Coder attempts a direct peer-to-peer WireGuard tunnel via NAT traversal
- DERP relay (fallback): If direct connectivity fails (restrictive NATs, firewalls, etc.), traffic is relayed through a DERP server. Traffic remains end-to-end encrypted via WireGuard; the DERP server only sees encrypted packets.
Within a region, nodes are treated as interchangeable replicas and must mesh with each other to forward packets between clients connected to different nodes.
Across regions, nodes never communicate with each other. Each peer selects a home region (lowest latency), and when peer A relays to peer B, it connects directly to B's home DERP region. Both peers just need to be able to reach the same node, that is, the DERP servers themselves never talk to each other.
This is why placing the nodes in separate regions fixes the problem: there is no meshing requirement across regions, and each peer's home region is one it can actually reach.
Diagnosis
1. Check the DERP map configuration
Review the Coder server's DERP configuration (set via --derp-config-path or --derp-config-url). A problematic configuration has public and internal nodes sharing a region ID:
{
"Regions": {
"1": {
"RegionID": 1,
"RegionCode": "us-west",
"RegionName": "US West",
"Nodes": [
{
"Name": "public-derp",
"RegionID": 1,
"HostName": "derp1.tailscale.com",
"CanPort80": true
},
{
"Name": "internal-derp",
"RegionID": 1,
"HostName": "internal-derp.example.com",
"DERPPort": 8443
}
]
}
}
}If any region contains a mix of publicly-routable and privately-routable nodes, this is the issue.
2. Check the coordinator debug page
Navigate to https://<your-coder-url>/debug/coordinator. If both peers (client and agent) show as connected but data isn't flowing, the DERP relay path is the likely culprit.
3. Test with coder ping
coder ping -v <workspace>
If it hangs indefinitely while the agent shows healthy in the dashboard, the relay path is broken.
Resolution
Place internal DERP servers and Tailscale public DERP servers in separate regions:
{
"OmitDefaultRegions": true,
"Regions": {
"1": {
"RegionID": 1,
"RegionCode": "public",
"RegionName": "Tailscale Public",
"Nodes": [
{
"Name": "public-derp",
"RegionID": 1,
"HostName": "derp1.tailscale.com",
"CanPort80": true
}
]
},
"900": {
"RegionID": 900,
"RegionCode": "internal",
"RegionName": "Internal DERP",
"Nodes": [
{
"Name": "internal-derp",
"RegionID": 900,
"HostName": "internal-derp.example.com",
"DERPPort": 8443
}
]
}
}
}If all users and workspaces are on a corporate network and do not need Tailscale's public DERP nodes, the simplest configuration is to remove them entirely by setting "OmitDefaultRegions": true and only defining your internal regions.
After updating the configuration, restart the Coder server. Affected workspace agents will need to be restarted or will reconnect automatically.
Common Questions
Do I need Tailscale's public DERP nodes?
Coder includes Tailscale's public DERP map by default so that connectivity works out of the box. If all of your users and workspaces are on the same private network, you can safely remove them. If some users connect from outside the corporate network (e.g., from home without a VPN), keeping the public nodes as a separate fallback region can help.
Does the Coder control plane need to be publicly accessible?
The control plane must be reachable by all clients. This does not necessarily mean public internet, it could be a VPN, private gateways, or zero-trust proxies all work. The requirement is: every client must be able to reach the Coder control plane AND at least one DERP server that the workspace agent can also reach.
What if a client can't reach the internal DERP?
If a client can't reach the workspace agent's home DERP region, Coder will attempt other regions as a fallback. However, for reliable connectivity, ensure all clients can reach at least one DERP region that the workspace agents can also reach.
Key Rule
All nodes within a single DERP region must be able to form a full mesh. Never place publicly-routable and privately-routable DERP nodes in the same region. If you run your own DERP infrastructure, assign it a dedicated region ID and either remove the default Tailscale public regions or leave them as separate regions.