# Extension points — fatedier/frp

> Canonical page: https://codevetter.com/unpack/frp/extension-points

# Extension points — fatedier/frp

Scanned commit d20a232996007dfe6ab425abc0a39a3ae9a0889b (2026-09-10). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

frp is built around registries. New proxy types plug in through three coordinated tables: proxyConfigTypeMap in pkg/config/v1, server-side RegisterProxyFactory (init() per type in server/proxy), and client-side RegisterProxyFactory (init() in client/proxy). Client connection-handling plugins register via pkg/plugin/client's Register/Create; server hooks come from external HTTP plugin processes managed by pkg/plugin/server. frpc CLI subcommands are generated automatically from the proxy type list. Config extensibility goes through source.Source implementations aggregated by source.Aggregator, and embedding is supported via pkg/virtual.Client plus ServiceOptions hooks (ConnectorCreator, HandleWorkConnCb). Feature gates (pkg/policy/featuregate) guard experimental features.
- server/proxy uses a reflect.Type-keyed factory registry: each type file (tcp.go, udp.go, http.go, https.go, tcpmux.go, stcp.go, sudp.go, xtcp.go) calls RegisterProxyFactory in init(); adding a server proxy type means adding a config type + factory init. — [server/proxy/proxy.go#L43-47](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/server/proxy/proxy.go#L43-L47) [server/proxy/tcp.go#L26-28](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/server/proxy/tcp.go#L26-L28)
- client/proxy mirrors the pattern: RegisterProxyFactory keyed by configurer reflect.Type, invoked from NewProxy which first builds a BaseProxy with limiter/encryption key/msgTransporter. — [client/proxy/proxy.go#L42-89](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/proxy/proxy.go#L42-L89) [client/proxy/general_tcp.go#L23](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/proxy/general_tcp.go#L23) [client/proxy/xtcp.go#L36](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/proxy/xtcp.go#L36)
- Client plugins register a CreatorFn by name via plugin.Register (panics on duplicate) and are instantiated lazily in BaseProxy.Run when baseCfg.Plugin.Type is set; the Plugin interface is Handle(ctx, *ConnectionInfo) + Close. — [pkg/plugin/client/plugin.go#L30-55](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/plugin/client/plugin.go#L30-L55) [client/proxy/proxy.go#L109-121](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/proxy/proxy.go#L109-L121)
- Server plugin ops are an open enum: Manager.Register bins each Plugin by IsSupport(op) into per-op slices for Login, NewProxy, CloseProxy, Ping, NewWorkConn, NewUserConn; new ops require extending the manager dispatch. — [pkg/plugin/server/manager.go#L27-44](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/plugin/server/manager.go#L27-L44) [pkg/plugin/server/manager.go#L108-127](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/plugin/server/manager.go#L108-L127)
- frpc single-proxy subcommands are generated in a loop over proxyTypes, so a new type automatically gains a CLI command and (for stcp/sudp/xtcp) a nested visitor command. — [cmd/frpc/sub/proxy.go#L45-87](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/cmd/frpc/sub/proxy.go#L45-L87)
- Config sources are pluggable: source.Aggregator merges a ConfigSource (in-memory/file) with an optional StoreSource; Service consumes aggregator.Load() at boot and on reload, so new persistence backends slot in as Source implementations. — [pkg/config/source/aggregator.go](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/config/source/aggregator.go) [pkg/config/source/source.go](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/config/source/source.go) [cmd/frpc/sub/root.go#L137-168](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/cmd/frpc/sub/root.go#L137-L168)
- Embedding hooks: client.ServiceOptions exposes ConnectorCreator (custom transports/virtual clients) and HandleWorkConnCb (intercept work conns); pkg/virtual.Client demonstrates running frpc against an in-process InternalListener. — [client/service.go#L83-96](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/service.go#L83-L96) [pkg/virtual/client.go](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/virtual/client.go)
- pkg/sdk/client provides a programmatic client API for running proxies from Go code rather than config files. — [pkg/sdk/client](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/sdk/client)
- Admin routes are registered centrally in each Service's registerRouteHandlers, so new endpoints slot into the gorilla/mux subRouter (with auth middleware already applied); server has a separate encoded-path subrouter for /api/v2 names. — [server/api_router.go#L27-71](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/server/api_router.go#L27-L71) [client/api_router.go#L26-64](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/api_router.go#L26-L64)
- Feature gates: ClientCommonConfig.FeatureGates map plus pkg/policy/featuregate control rollout of features like VirtualNet; reload path validates gate-dependent config against runtime capabilities. — [pkg/config/v1/client.go#L68-70](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/config/v1/client.go#L68-L70) [pkg/policy/featuregate/feature_gate.go](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/policy/featuregate/feature_gate.go) [client/service.go#L514-520](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/service.go#L514-L520)
- vhost.Routers + vhost.NewHTTPReverseProxy/NewHTTPSMuxer are the extension seam for HTTP(S) routing behavior; group controllers (TCP/HTTP/HTTPS/TCPMux) encapsulate shared-port load balancing. — [server/service.go#L296-349](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/server/service.go#L296-L349) [pkg/util/vhost](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/util/vhost) [server/group](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/server/group)
- Message/protocol extension: msg.Dispatcher.RegisterHandler maps message structs to handlers on both sides; adding a control message means defining it in pkg/msg and registering handlers in client/control.go and server/control.go. — [client/control.go#L232-237](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/client/control.go#L232-L237) [server/control.go#L727-734](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/server/control.go#L727-L734) [pkg/msg/msg.go](https://github.com/fatedier/frp/blob/d20a232996007dfe6ab425abc0a39a3ae9a0889b/pkg/msg/msg.go)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
