AdguardTeam/AdGuardHome · error

creating dnscrypt cert: %w

Error message

creating dnscrypt cert: %w

What it means

The parsed DNSCrypt ResolverConfig was rejected by rc.NewCert(), which builds the dnscrypt.ServerCert from the provider name, keys, and secret. Failure means the cryptographic material is invalid or inconsistent — bad hex keys, secret length wrong, or an unsupported certificate file type/signature mismatch.

Source

Thrown at internal/home/dns.go:392

	if extTLSConf.DNSCryptConfigFile == "" {
		return nil, fmt.Errorf("dnscrypt_config_file: %w", errors.ErrEmptyValue)
	}

	f, err := os.Open(extTLSConf.DNSCryptConfigFile)
	if err != nil {
		return nil, fmt.Errorf("opening dnscrypt config: %w", err)
	}
	defer func() { err = errors.WithDeferred(err, f.Close()) }()

	rc := &dnscrypt.ResolverConfig{}
	err = yaml.NewDecoder(f).Decode(rc)
	if err != nil {
		return nil, fmt.Errorf("decoding dnscrypt config: %w", err)
	}

	cert, err := rc.NewCert()
	if err != nil {
		return nil, fmt.Errorf("creating dnscrypt cert: %w", err)
	}

	return &dnsforward.DNSCryptConfig{
		ResolverCert:   cert,
		UDPListenAddrs: ipsToUDPAddrs(addrs, extTLSConf.PortDNSCrypt),
		TCPListenAddrs: ipsToTCPAddrs(addrs, extTLSConf.PortDNSCrypt),
		ProviderName:   rc.ProviderName,
	}, nil
}

// dnsEncryption contains different types of TLS encryption addresses.
type dnsEncryption struct {
	https string
	tls   string
	quic  string
}

// getDNSEncryption returns the TLS encryption addresses that AdGuard Home

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Regenerate the full keypair and config together: dnscrypt generate-cert --provider-name 2.dnscrypt-cert.example.com and use ALL emitted values
  2. Verify public_key/private_key are exactly 64 hex chars each and cert_secret is 32 hex chars
  3. Ensure provider_name matches the '<version>.dnscrypt-cert.<domain>' pattern
  4. Confirm cert_file_type matches the certificate format (0=plain, 1=rsa, 2=edge, 3=rsa8)

Example fix

# regenerate a consistent set
dnscrypt generate-cert \
  --provider-name 2.dnscrypt-cert.example.com \
  --out dnscrypt.yaml
# then point tls.dnscrypt_config_file at the new file and restart
Defensive patterns

Strategy: validation

Validate before calling

// structural pre-check of key material
import "encoding/hex"
func keysConsistent(rc dnscrypt.ResolverConfig) error {
    if len(rc.PublicKey) != 64 || len(rc.PrivateKey) != 64 { return fmt.Errorf("keys must be 64 hex chars") }
    if _, err := hex.DecodeString(rc.PublicKey); err != nil { return fmt.Errorf("bad public_key hex") }
    if _, err := hex.DecodeString(rc.PrivateKey); err != nil { return fmt.Errorf("bad private_key hex") }
    return nil
}

Type guard

func validProviderName(name string) bool {
    parts := strings.Split(name, ".")
    return len(parts) >= 4 && parts[1] == "dnscrypt-cert"
}

Try / catch

if _, err := rc.NewCert(); err != nil {
    // regenerate the whole config — partial key edits never recover
    log.Error("dnscrypt cert invalid; regenerate keypair", slogutil.KeyError, err)
}

Prevention

When it happens

Trigger: rc.NewCert() errors when public_key/private_key are not valid 32-byte hex, cert_secret has the wrong length, provider_name is malformed (must look like 2.dnscrypt-cert.<domain>), or cert_file_type is not 0/1/2/3.

Common situations: Regenerating only one of the key pair, copying keys with typos/truncated hex, rotating keys without updating provider name, or wrong cert_file_type after changing hash algorithm.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/34683e5900533778. Report an issue: GitHub.