{"record":{"id":"1a1b47267a9305b0","repo":"tailscale/tailscale","slug":"no-certificate-for-hostname-q-this-server-only-s","errorCode":null,"errorMessage":"no certificate for hostname %q; this server only serves IP address certificates","messagePattern":"no certificate for hostname %q; this server only serves IP address certificates","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/derper/ipcert.go","lineNumber":183,"sourceCode":"\t}\n\tta, ok := hi.Conn.LocalAddr().(*net.TCPAddr)\n\tif !ok {\n\t\treturn netip.Addr{}, false\n\t}\n\tip := ta.AddrPort().Addr().Unmap()\n\treturn ip, ip.IsValid()\n}\n\nfunc (m *ipCertManager) getCertificate(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {\n\tconnIP, connIPOK := connLocalIP(hi)\n\tif hi.ServerName != \"\" {\n\t\tsniIP, err := netip.ParseAddr(hi.ServerName)\n\t\tif err != nil {\n\t\t\t// The SNI is a DNS name; let the hostname provider handle it.\n\t\t\tif m.nextTLS != nil && m.nextTLS.GetCertificate != nil {\n\t\t\t\treturn m.nextTLS.GetCertificate(hi)\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"no certificate for hostname %q; this server only serves IP address certificates\", hi.ServerName)\n\t\t}\n\t\tif !connIPOK || sniIP.Unmap() != connIP {\n\t\t\treturn nil, fmt.Errorf(\"requested certificate for IP %v does not match the connection's IP address\", sniIP)\n\t\t}\n\t}\n\tif !connIPOK {\n\t\treturn nil, errors.New(\"unable to determine the connection's local IP address\")\n\t}\n\tctx := hi.Context()\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn m.certForIP(ctx, connIP)\n}\n\n// certForIP returns the current certificate for ip, obtaining one\n// first if there is no unexpired certificate for it. Concurrent\n// callers for the same IP share a single issuance.","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/cmd/derper/ipcert.go#L165-L201","documentation":"ipCertManager.getCertificate received a TLS ClientHello whose SNI (hi.ServerName) is a DNS name, but this manager only issues certificates for the server's own IP addresses, and no downstream hostname provider is chained (m.nextTLS is nil or has no GetCertificate). The handshake is aborted, so clients see a TLS alert instead of a certificate.","triggerScenarios":"Running derper in IP-address cert mode as the top-level certProvider while clients reach it via a DNS hostname: the client puts that hostname in SNI, netip.ParseAddr fails (it is not an IP literal), and there is no next provider to delegate to. Typical when a DNS A record points at the derper IP but the config only enables IP certs.","commonSituations":"Adding a friendly DNS name to a derper deployed with only IP cert mode; health checks or monitoring probes that send Hostname/SNI; tailscale DERPMap entries configured with a DNS hostname while the server serves IP certs.","solutions":["Run derper with a DNS-name cert mode as well (e.g. --hostname plus ACME), so ipCertManager chains to the hostname provider via next.","Point clients at the IP address (DERPMap node with IP, and TLS SNI set to the IP string) instead of a DNS name.","If you must keep the DNS name, move the derper to a host where it can get a hostname certificate and disable IP-only mode."],"exampleFix":"# before: only IP certs; DNS SNI handshakes fail\nderper --certdir=/var/lib/derper --stun ...  (IP cert mode only)\n\n# after: chain a hostname cert provider behind the IP cert manager\nderper --hostname=derp.example.com --certmode=letsencrypt ...  # DNS names now served by the next provider","handlingStrategy":"validation","validationCode":"// Client side: only send an SNI you know the server can serve.\nhost := \"203.0.113.10\"\nif net.ParseIP(host) == nil && ipOnlyServer {\n    host = serverIP // use the IP literal instead of a DNS name\n}\nconn, err := tls.Dial(\"tcp\", host+\":443\", &tls.Config{ServerName: host})","typeGuard":"func isIPLiteral(s string) bool { return netip.ParseAddr(s).IsValid() } // valid SNI for an IP-cert derper","tryCatchPattern":"cert, err := mgr.GetCertificate(hi)\nif err != nil && strings.Contains(err.Error(), \"only serves IP address certificates\") {\n    // route the connection to a hostname-capable provider or reject early\n    return nil, err\n}","preventionTips":["When serving only IP certs, give clients the raw IP (DERPMap nodes accept IPs).","If a DNS name must work, also configure a hostname cert provider so nextTLS delegation exists.","Health checks should either skip SNI or use the IP string."],"tags":["go","tls","sni","derper","certconfig"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}