# How to Configure a Custom DERP Map URL in Tailcat

> Learn how to configure a custom DERP map URL in Tailcat using the DERPMapURL option or the -derpmap-url CLI flag. Override the default endpoint easily.

- Repository: [Tailscale/tailcat](https://github.com/tailscale/tailcat)
- Tags: how-to-guide
- Published: 2026-08-30

---

**Yes, Tailcat supports custom DERP map URLs via the `DERPMapURL` option in the Go library or the `-derpmap-url` CLI flag, allowing you to override the default `https://tailcat.dev/derpmap.json` endpoint.**

Tailcat is an open-source networking library developed by Tailscale that enables secure NAT traversal using DERP (Designated Encrypted Relay for Packets) relays. While Tailcat ships with a default DERP map hosted at `tailcat.dev`, production deployments often require self-hosted or geographically optimized relay infrastructure, making the ability to specify a **Tailcat custom DERP map URL** essential for advanced network configurations.

## Default DERP Map Behavior

By default, Tailcat automatically fetches its relay configuration from a centralized endpoint. In [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), the constant `DefaultDERPMapURL` is defined as `https://tailcat.dev/derpmap.json` (lines 90-93), which `ConnInfo.Expand` uses when no override is provided.

When `FetchDERPMap` is invoked without custom options, it retrieves the JSON map from this default URL, parses the available DERP regions, and caches the result for subsequent operations. This default behavior requires no configuration but assumes outbound HTTPS access to Tailscale's infrastructure.

## Setting a Custom DERP Map URL Programmatically

To override the default endpoint in Go applications, pass `tailcat.DERPMapURL()` as an option to either `ConnInfo.Expand` or `FetchDERPMap`. The implementation in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) (lines 790-795) inspects this option before falling back to `DefaultDERPMapURL`.

```go
import (
    "context"
    "log"

    "github.com/tailscale/tailcat"
)

func main() {
    ctx := context.Background()
    pk := tailcat.NewPrivateKey()

    // Override the default DERP map source
    err := pk.Public.Expand(
        ctx,
        tailcat.ExpandForServer,
        tailcat.DERPMapURL("https://my.example.com/derpmap.json"),
    )
    if err != nil {
        log.Fatalf("failed to expand ConnInfo: %v", err)
    }
    // Server now uses DERP regions from your custom map
}

```

The `FetchDERPMap` function respects the same option pattern, allowing low-level control over relay discovery when building custom Tailcat integrations.

## Using a Custom DERP Map URL via CLI

The `tailcat` binary exposes the `-derpmap-url` flag, defined in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go) (lines 58-59), which forwards the value to the library's `DERPMapURL` option.

```bash

# Start a server with custom DERP infrastructure

tailcat server -key mykey -derpmap-url https://corp.example.com/derpmap.json

# Connect a client using the same map

tailcat client -key mykey -derpmap-url https://corp.example.com/derpmap.json <server-blob>

```

Both server and client processes must reference the same DERP map to ensure consistent relay selection and key discovery.

## Web Assembly and Browser Usage

The Tailcat web client supports custom DERP maps through the same configuration mechanism. In [`cmd/tailcat-web/tailcat-web.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat-web/tailcat-web.go), the `-derpmap-url` flag is processed identically to the CLI version.

For browser-based applications using the WASM build, the JavaScript API exposes the `DERPMapURL` option:

```javascript
import * as tailcat from "https://cdn.jsdelivr.net/npm/@tailscale/tailcat";

const ci = new tailcat.ConnInfo();
await ci.expand(
    tailcat.ExpandForServer, 
    tailcat.DERPMapURL("https://my.example.com/derpmap.json")
);

```

The WASM implementation in [`web/main_js.go`](https://github.com/tailscale/tailcat/blob/main/web/main_js.go) bridges these options to the underlying Go runtime, ensuring feature parity between native and browser environments.

## Caching and Map Persistence

When using a custom DERP map URL, Tailcat maintains the same caching semantics as the default configuration. The library stores fetched maps in-memory or delegates to a user-provided `DERPMapCache` implementation, preventing redundant HTTP requests during connection retries.

This caching layer applies regardless of whether the source is `https://tailcat.dev/derpmap.json` or a private endpoint. Applications requiring offline capability can pre-populate the cache before calling `ConnInfo.Expand`, ensuring DERP functionality remains available without network access to the map URL.

## Summary

- **Default endpoint**: Tailcat uses `https://tailcat.dev/derpmap.json` defined in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) when no custom URL is specified.
- **Programmatic override**: Pass `tailcat.DERPMapURL("https://...")` to `ConnInfo.Expand` or `FetchDERPMap` (lines 790-795).
- **CLI flag**: Use `-derpmap-url` in both [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go) and [`cmd/tailcat-web/tailcat-web.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat-web/tailcat-web.go).
- **Cross-platform**: Works identically in native Go code, CLI binaries, and WASM browser environments.
- **Caching**: Custom maps are cached using the same mechanisms as defaults, with optional `DERPMapCache` injection.

## Frequently Asked Questions

### How do I specify a custom DERP map URL in Tailcat?

You can specify a custom URL either programmatically by passing `tailcat.DERPMapURL("https://your-url")` to `ConnInfo.Expand`, or via the command line using the `-derpmap-url https://your-url` flag. Both methods override the default `https://tailcat.dev/derpmap.json` endpoint defined in the source code.

### What is the format of the DERP map JSON file?

The DERP map must be a valid JSON object defining DERP regions, each containing a unique region ID, hostnames, and public keys for relay nodes. The schema matches the `tailcfg.DERPMap` structure used throughout the Tailscale ecosystem, ensuring compatibility with existing tooling.

### Does Tailcat cache custom DERP maps differently than the default?

No, Tailcat applies identical caching logic to custom and default DERP maps. Both use the in-memory cache or a user-provided `DERPMapCache` implementation. The cache key includes the URL, allowing simultaneous use of multiple distinct maps without collision.

### Is the custom DERP map URL supported in the WebAssembly build?

Yes, the WASM client fully supports custom DERP map URLs through the JavaScript `DERPMapURL` option or the `-derpmap-url` flag when running `tailcat-web`. The implementation in [`web/main_js.go`](https://github.com/tailscale/tailcat/blob/main/web/main_js.go) ensures the custom URL propagates to the underlying Go runtime.