fatedier/frp
The repo builds two binaries from a single Go module: frps (server, cmd/frps) and frpc (client, cmd/frpc), both driven by cobra. server/service.go constructs a Service that multiplexes control-plane listeners (TCP mux, KCP, QUIC, WebSocket, raw TLS, internal SSH pipe) on shared ports and owns the ControlManager, proxy.Manager, plugin.Manager, ports.Manager and vhost routers. client/service.go constructs a Service that dials frps through a pluggable Connector and keeps a Control session alive with backoff retries. Shared protocol and config code lives under pkg/ (msg, proto/wire, config/v1, auth, transport, util). State is entirely in-memory except an optional client-side JSON store for dynamic proxies. Two Vue 3 apps under web/ provide dashboards and are embedded via the assets package, or excluded with the 'noweb' build tag.
- frps entrypoint is cmd/frps/root.go: cobra rootCmd.RunE loads config via config.LoadServerConfig, validates with validation.NewConfigValidator, then calls runServer -> server.NewService -> svr.Run.
- frpc entrypoint is cmd/frpc/sub/root.go: runClient -> config.LoadClientConfigResult -> source.NewAggregator -> client.NewService -> svr.Run; a --config_dir flag runs one Service per file via runMultipleClients.
- server.Service multiplexes the bind port with golib mux.Mux: default listener for TCP control, a prefix-matched websocket listener ('GET /~frp'), and a TLS listener that sniffs first byte 0x16 / FRPTLSHeadByte.
- Optional listeners are created for KCP (netpkg.ListenKcp on KCPBindPort), QUIC (quic.ListenAddr with ALPN 'frp'), SSH tunnel gateway (ssh.NewGateway), and a tcpmux HTTPConnect multiplexer on TCPMuxHTTPConnectPort.
- The wire protocol has two versions: acceptConnection calls wire.CheckMagic to detect v2, then negotiates crypto/UDP-codec via ClientHello/ServerHello frames before reading the first msg.
- The client dials frps through a Connector interface (client/connector.go) supporting tcp, kcp, quic (one quic.Conn, streams converted via QuicStreamToNetConn), websocket/wss, and tls; ServiceOptions.ConnectorCreator allows swapping in a virtual pipe connector.
- Server state is in-memory: registry.ClientRegistry tracks logical clients by user.clientID, proxy.Manager tracks live proxies, ports.Manager allocates TCP/UDP remote ports honoring AllowPorts, and vhost.Routers route HTTP(S) vhosts.
- The only persistent state is the optional client-side StoreSource: a JSON file (store.path) holding dynamic proxies/visitors, merged with file config by source.Aggregator.
- Dashboards are Vue 3 apps web/frps and web/frpc (npm workspaces under web/), embedded into Go via the assets package; Makefile adds a 'noweb' build tag when web/*/dist is absent.
- Build produces CGO_ENABLED=0 binaries with build tags 'frps'/'frpc' plus optional 'noweb' (Makefile frps/frpc targets); go.mod pins go 1.25.0 with quic-go, kcp-go, yamux, gorilla/mux, go-oidc, prometheus, wireguard as key deps.
- server/http and client/http packages implement admin API controllers behind gorilla/mux routers registered by registerRouteHandlers on each Service's webServer (httppkg.Server).
- Both services disable quic-go receive-buffer warnings and ECN via env vars in package init, and set crypto.DefaultSalt = 'frp' for golib crypto.