fatedier/frp · error

'.' and '*' are not supported in subdomain

Error message

'.' and '*' are not supported in subdomain

What it means

Server-side validation error from validateDomainConfigForServer: the proxy's subdomain value contains a dot or an asterisk. Subdomains are single labels appended to subDomainHost (e.g. "web" -> web.frps.example.com); dots would create multi-level names that break the wildcard certificate/host mapping, and wildcards are not supported at all. Rejected during frps-side proxy registration validation.

Source

Thrown at pkg/config/v1/validation/proxy.go:98

func validateDomainConfigForServer(c *v1.DomainConfig, s *v1.ServerConfig) error {
	subDomainHost := strings.ToLower(s.SubDomainHost)
	for _, domain := range c.CustomDomains {
		canonicalDomain := strings.ToLower(domain)
		if subDomainHost != "" && len(strings.Split(subDomainHost, ".")) < len(strings.Split(canonicalDomain, ".")) {
			if strings.HasSuffix(canonicalDomain, "."+subDomainHost) {
				return fmt.Errorf("custom domain [%s] should not belong to subdomain host [%s]", domain, s.SubDomainHost)
			}
		}
	}

	if c.SubDomain != "" {
		if s.SubDomainHost == "" {
			return errors.New("subdomain is not supported because this feature is not enabled in server")
		}

		if strings.Contains(c.SubDomain, ".") || strings.Contains(c.SubDomain, "*") {
			return errors.New("'.' and '*' are not supported in subdomain")
		}
	}
	return nil
}

func ValidateProxyConfigurerForClient(c v1.ProxyConfigurer) error {
	base := c.GetBaseConfig()
	if err := validateProxyBaseConfigForClient(base); err != nil {
		return err
	}

	switch v := c.(type) {
	case *v1.TCPProxyConfig:
		return validateTCPProxyConfigForClient(v)
	case *v1.UDPProxyConfig:
		return validateUDPProxyConfigForClient(v)
	case *v1.TCPMuxProxyConfig:
		return validateTCPMuxProxyConfigForClient(v)

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Use a single label without dots or wildcards: subdomain = "web" (yields web.<subDomainHost>).
  2. For deeper hostnames (e.g. dev.web.example.com), use customDomains = ["dev.web.example.com"] with DNS pointing at frps.
  3. For wildcard access, serve customDomains = ["*.web.example.com"] and configure a wildcard TLS certificate on frps (vhost https).

Example fix

# before
[[proxies]]
name = "web"
type = "http"
subdomain = "dev.web"

# after
[[proxies]]
name = "web"
type = "http"
customDomains = ["dev.web.example.com"]
Defensive patterns

Strategy: validation

Validate before calling

func validSubdomainLabel(s string) bool {
    return s != "" && !strings.ContainsAny(s, ".*")
}
if !validSubdomainLabel(p.SubDomain) {
    return fmt.Errorf("subdomain %q must be a single label without '.' or '*'", p.SubDomain)
}

Type guard

func subdomainIsSingleLabel(s string) bool {
    return !strings.Contains(s, ".") && !strings.Contains(s, "*")
}

Try / catch

if err := validation.ValidateProxyConfigurerForServer(p, serverCfg); err != nil {
    if strings.Contains(err.Error(), "'.' and '*' are not supported in subdomain") {
        // switch to customDomains for multi-level or wildcard hostnames
    }
    return err
}

Prevention

When it happens

Trigger: An frpc proxy registers with subdomain = "a.b", subdomain = "*.web", or any value containing '.' or '*' while the server has subDomainHost enabled.

Common situations: Trying to get a nested hostname like dev.web.example.com by writing subdomain = "dev.web" instead of using customDomains; attempting wildcard routing (*.example.com) via subdomain, which requires a wildcard customDomain and matching server cert instead; migrating from another tunnel tool where deep subdomain strings were allowed.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/8932bebd682e4eee. Report an issue: GitHub.