fatedier/frp · critical

create server listener error

Error message

create server listener error, %v

What it means

During frps startup, when tcpmuxHTTPConnectPort > 0 the server tries to net.Listen on ProxyBindAddr:TCPMuxHTTPConnectPort. Any bind failure (port in use, permission denied, bad address) aborts service creation with this error, so frps exits before serving anything.

Solutions

  1. Free the port or pick another tcpmuxHTTPConnectPort
  2. If binding <1024, run with adequate capability (setcap/cap_net_bind_service) or choose a high port
  3. Verify ProxyBindAddr is a local interface IP or 0.0.0.0

Example fix

# before
tcpmuxHTTPConnectPort = 443   # permission denied as non-root

# after
tcpmuxHTTPConnectPort = 12443
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight the port before frps tries to bind it.
func portFree(network, addr string) bool {
    l, err := net.Listen(network, addr)
    if err != nil { return false }
    l.Close()
    return true
}
if !portFree("tcp", fmt.Sprintf("%s:%d", cfg.ProxyBindAddr, cfg.TCPMuxHTTPConnectPort)) {
    return fmt.Errorf("tcpmux port %d already in use", cfg.TCPMuxHTTPConnectPort)
}

Prevention

When it happens

Trigger: Another process already listening on the tcpmux httpconnect port; binding a privileged port (<1024) as non-root; ProxyBindAddr set to an IP not present on the machine.

Common situations: Port collision with another frps instance or service; hardened/container environments blocking low ports; typo in bind address.

Related errors


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

Appendix: source

Thrown at server/service.go:196

		sshTunnelListener: netpkg.NewInternalListener(),
		httpVhostRouter:   vhost.NewRouters(),
		auth:              authRuntime,
		webServer:         webServer,
		tlsConfig:         tlsConfig,
		cfg:               cfg,
		ctx:               context.Background(),
	}
	if webServer != nil {
		webServer.RouteRegister(svr.registerRouteHandlers)
	}

	// Create tcpmux httpconnect multiplexer.
	if cfg.TCPMuxHTTPConnectPort > 0 {
		var l net.Listener
		address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort))
		l, err = net.Listen("tcp", address)
		if err != nil {
			return nil, fmt.Errorf("create server listener error, %v", err)
		}

		svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout)
		if err != nil {
			return nil, fmt.Errorf("create vhost tcpMuxer error, %v", err)
		}
		log.Infof("tcpmux httpconnect multiplexer listen on %s, passthrough: %v", address, cfg.TCPMuxPassthrough)
	}

	// Init all plugins
	for _, p := range cfg.HTTPPlugins {
		svr.pluginManager.Register(plugin.NewHTTPPluginOptions(p))
		log.Infof("plugin [%s] has been registered", p.Name)
	}
	svr.rc.PluginManager = svr.pluginManager

	// Init group controller
	svr.rc.TCPGroupCtl = group.NewTCPGroupCtl(svr.rc.TCPPortManager)

View on GitHub (pinned to 6c8a8d0a97)