fatedier/frp · error

subdomain is not supported because this feature is not enabl

Error message

subdomain is not supported because this feature is not enabled in server

What it means

Server-side validation error from validateDomainConfigForServer: an incoming proxy declares subdomain = "..." but the frps server has no subDomainHost configured. Client-declared subdomains are expanded as <subdomain>.<subDomainHost>, which is impossible without a host; frps therefore rejects the proxy registration. This runs when frps validates proxies against its own ServerConfig.

Source

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

		return errors.New("subdomain and custom domains should not be both empty")
	}
	return nil
}

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)

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. On the frps side, set subDomainHost = "frps.example.com" in the server config and restart frps.
  2. On the client side, replace subdomain with customDomains = ["web.frps.example.com"] and add DNS records pointing at frps.
  3. If subdomain routing is not wanted, remove subdomain from the client proxy entirely (but http-type proxies then need customDomains).

Example fix

# before (frps.toml)
bindPort = 7000
# no subDomainHost

# after (frps.toml)
bindPort = 7000
subDomainHost = "frps.example.com"
Defensive patterns

Strategy: validation

Validate before calling

// frps side, before serving
if serverCfg.SubDomainHost == "" {
    // reject/disable subdomain expectations: log or fail fast
    log.Warn("subDomainHost not set; client proxies using subdomain will be rejected")
}

Type guard

func subdomainAllowed(s *v1.ServerConfig) bool {
    return s != nil && s.SubDomainHost != ""
}

Try / catch

if err := validation.ValidateProxyConfigurerForServer(p, serverCfg); err != nil {
    if strings.Contains(err.Error(), "subdomain is not supported because this feature is not enabled in server") {
        // set subDomainHost on frps or switch the client to customDomains
    }
    return err
}

Prevention

When it happens

Trigger: frps config has no subDomainHost set (or it is an empty string) while an frpc http/https/tcpmux proxy registers with subdomain set; the new proxy fails validation and is rejected at registration time.

Common situations: Client and server configs drift: the client config was written for a server with subdomain routing enabled, but points at (or was updated to) a server without subDomainHost; new frps deployments where the operator forgot to set subDomainHost; typos like subdomainHost vs subdomainHost casing in TOML leaving it unset.

Related errors


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