Custom DERP: tls: unsupported certificate

I’m trying to see if I can set up a custom DERP server on a little EC2 instance in a nearby region but something isn’t right. I’m using the guide at https://tailscale.com/kb/1118/custom-derp-servers

Here’s some detail:

Routing:

My EC2 instance has an elastic ip associate to it. I’ve also created an A record in DNS to point to the EIP with FQDM of derp.mydomain.com - this works just fine as I can connect to my instance using the domain.

Software:

  • Linux 5.11.0-1019-aws #20~20.04.1-Ubuntu SMP Tue Sep 21 10:40:39 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
  • go version go1.17.1 linux/amd64
  • derper has no version info available, installed using go install tailscale.com/cmd/derper@main

Networking:

The EC2 is behind a security group with the following ports open:

  • TCP 0.0.0.0:22 for SSH
  • TCP 0.0.0.0:443 for derper
  • UDP 0.0.0.0:3478 for STUN (thanks @bradfitz)

Tailscale ACL:

    ...
    "derpMap": {
        "OmitDefaultRegions": true, //set to test custom DERP server
        "Regions": {
            "900": {
                "RegionID": 900,
                "RegionCode": "cpt-s7s",
                "RegionName": "Capetown",
                "Nodes": [
                    {
                        "Name": "1",
                        "RegionID": 900,
                        "HostName": "derp.mydomain.com"
                    }
                ]
            }
        }
    }

When I authorize a node, I run:

sudo tailscale netcheck

Report:
	* UDP: false
	* IPv4: (no addr found)
	* IPv6: no
	* MappingVariesByDestIP: 
	* HairPinning: 
	* PortMapping: 
	* Nearest DERP: Capetown
	* DERP latency:
		- cpt-s7s: 2.6ms   (Capetown)

Clearly my local machine is not reachable via this DERP server.

Tailscale also isn’t starting up properly since I’m not allowing it access to the default DERP servers:

sudo tailscale status

unexpected state: Starting

The stdout of the running derper is:

derper -hostname derp.mydomain.com -c test
derper: serving on :443 with TLS

TLS handshake error from : <MY IP> remote error: tls: unsupported certificate

Any help would be greatly appreciated.

You also need UDP port 3478 for STUN. That’s what the Tailscale nodes use, among other things, to measure which DERP is the nearest.

Thanks for the quick reply, I’ve added that port - unfortunately I still get the same errors.

What does curl -v https://derp.mydomain.com say?

Output is (replaced domain and IP addresses):

$ curl -v https://derp.mydomain.com

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 1.2.3.4:443...

* Connected to derp.mydomain.com (1.2.3.4) port 443 (#0)

* ALPN, offering h2

* ALPN, offering http/1.1

* successfully set certificate verify locations:

*  CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt

*  CApath: none

} [5 bytes data]

* TLSv1.3 (OUT), TLS handshake, Client hello (1):

} [512 bytes data]

* TLSv1.3 (IN), TLS handshake, Server hello (2):

{ [122 bytes data]

* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):

{ [15 bytes data]

* TLSv1.3 (IN), TLS handshake, Certificate (11):

{ [4183 bytes data]

* TLSv1.3 (IN), TLS handshake, CERT verify (15):

{ [78 bytes data]

* TLSv1.3 (IN), TLS handshake, Finished (20):

{ [36 bytes data]

* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):

} [1 bytes data]

* TLSv1.3 (OUT), TLS handshake, Finished (20):

} [36 bytes data]

* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256

* ALPN, server accepted to use h2

* Server certificate:

*  subject: CN=derp.mydomain.com

*  start date: Sep 27 18:07:56 2021 GMT

*  expire date: Dec 26 18:07:55 2021 GMT

*  subjectAltName: host "derp.mydomain.com" matched cert's "derp.mydomain.com"

*  issuer: C=US; O=Let's Encrypt; CN=R3

*  SSL certificate verify ok.

* Using HTTP2, server supports multiplexing

* Connection state changed (HTTP/2 confirmed)

* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0

* Using Stream ID: 1 (easy handle 0x1f002c20e10)

} [5 bytes data]

> GET / HTTP/2

> Host: derp.mydomain.com

> user-agent: curl/7.78.0

> accept: */*

>

{ [5 bytes data]

* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):

{ [130 bytes data]

* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!

} [5 bytes data]

< HTTP/2 200

< content-type: text/html; charset=utf-8

< content-length: 166

< date: Tue, 28 Sep 2021 15:07:56 GMT

<

{ [5 bytes data]

100   166  100   166    0     0   6575      0 --:--:-- --:--:-- --:--:--  6916<html><body>

<h1>DERP</h1>

<p>

  This is a

  <a href="https://tailscale.com/">Tailscale</a>

  <a href="https://pkg.go.dev/tailscale.com/derp">DERP</a>

  server.

</p>

* Connection #0 to host derp.mydomain.com left intact

I also briefly tested with completely open traffic (all TCP and UDP from everywhere), and the outcome is the same.

I’m running derper like this:

derper -hostname derp.mydomain.com -c test

This creates a test file that looks like this:

{
        "PrivateKey":"privkey:f................4"
}

Is there any option I’m missing to allow this DERP server to be functional?