From 79fed32f01d83497b7a357cb354047d2a6a6acaa Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Tue, 10 Feb 2026 19:55:28 +0800 Subject: [PATCH] Add wg port configuration --- proxy/cmd/proxy/cmd/root.go | 15 +++++++++++++++ proxy/internal/roundtrip/netbird.go | 15 +++++++++------ proxy/internal/roundtrip/netbird_test.go | 2 +- proxy/server.go | 6 +++++- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/proxy/cmd/proxy/cmd/root.go b/proxy/cmd/proxy/cmd/root.go index edca019e8..cc21f3bf4 100644 --- a/proxy/cmd/proxy/cmd/root.go +++ b/proxy/cmd/proxy/cmd/root.go @@ -51,6 +51,7 @@ var ( certFile string certKeyFile string certLockMethod string + wgPort int ) var rootCmd = &cobra.Command{ @@ -83,6 +84,7 @@ func init() { rootCmd.Flags().StringVar(&certFile, "cert-file", envStringOrDefault("NB_PROXY_CERTIFICATE_FILE", "tls.crt"), "TLS certificate filename within the certificate directory") rootCmd.Flags().StringVar(&certKeyFile, "cert-key-file", envStringOrDefault("NB_PROXY_CERTIFICATE_KEY_FILE", "tls.key"), "TLS certificate key filename within the certificate directory") rootCmd.Flags().StringVar(&certLockMethod, "cert-lock-method", envStringOrDefault("NB_PROXY_CERT_LOCK_METHOD", "auto"), "Certificate lock method for cross-replica coordination: auto, flock, or k8s-lease") + rootCmd.Flags().IntVar(&wgPort, "wg-port", envIntOrDefault("NB_PROXY_WG_PORT", 0), "WireGuard listen port (0 = random). Fixed port only works with single-account deployments") } // Execute runs the root command. @@ -151,6 +153,7 @@ func runServer(cmd *cobra.Command, args []string) error { ForwardedProto: forwardedProto, TrustedProxies: parsedTrustedProxies, CertLockMethod: nbacme.CertLockMethod(certLockMethod), + WireguardPort: wgPort, } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) @@ -181,3 +184,15 @@ func envStringOrDefault(key string, def string) string { } return v } + +func envIntOrDefault(key string, def int) int { + v, exists := os.LookupEnv(key) + if !exists { + return def + } + parsed, err := strconv.Atoi(v) + if err != nil { + return def + } + return parsed +} diff --git a/proxy/internal/roundtrip/netbird.go b/proxy/internal/roundtrip/netbird.go index 612158b3e..12c53ead2 100644 --- a/proxy/internal/roundtrip/netbird.go +++ b/proxy/internal/roundtrip/netbird.go @@ -61,6 +61,7 @@ type managementClient interface { type NetBird struct { mgmtAddr string proxyID string + wgPort int logger *log.Logger mgmtClient managementClient @@ -162,16 +163,15 @@ func (n *NetBird) AddPeer(ctx context.Context, accountID types.AccountID, d doma } }) - // Create embedded NetBird client with the generated private key - // The peer has already been created via CreateProxyPeer RPC with the public key - wgPort := 0 + // Create embedded NetBird client with the generated private key. + // The peer has already been created via CreateProxyPeer RPC with the public key. client, err := embed.New(embed.Options{ DeviceName: deviceNamePrefix + n.proxyID, ManagementURL: n.mgmtAddr, PrivateKey: privateKey.String(), LogLevel: log.WarnLevel.String(), BlockInbound: true, - WireguardPort: &wgPort, + WireguardPort: &n.wgPort, }) if err != nil { n.clientsMux.Unlock() @@ -478,14 +478,17 @@ func (n *NetBird) ListClientsForStartup() map[types.AccountID]*embed.Client { return result } -// NewNetBird creates a new NetBird transport. -func NewNetBird(mgmtAddr, proxyID string, logger *log.Logger, notifier statusNotifier, mgmtClient managementClient) *NetBird { +// NewNetBird creates a new NetBird transport. Set wgPort to 0 for a random +// OS-assigned port. A fixed port only works with single-account deployments; +// multiple accounts will fail to bind the same port. +func NewNetBird(mgmtAddr, proxyID string, wgPort int, logger *log.Logger, notifier statusNotifier, mgmtClient managementClient) *NetBird { if logger == nil { logger = log.StandardLogger() } return &NetBird{ mgmtAddr: mgmtAddr, proxyID: proxyID, + wgPort: wgPort, logger: logger, clients: make(map[types.AccountID]*clientEntry), statusNotifier: notifier, diff --git a/proxy/internal/roundtrip/netbird_test.go b/proxy/internal/roundtrip/netbird_test.go index 13952c3a8..b1cdc7ab2 100644 --- a/proxy/internal/roundtrip/netbird_test.go +++ b/proxy/internal/roundtrip/netbird_test.go @@ -23,7 +23,7 @@ func (m *mockMgmtClient) CreateProxyPeer(_ context.Context, _ *proto.CreateProxy // mockNetBird creates a NetBird instance for testing without actually connecting. // It uses an invalid management URL to prevent real connections. func mockNetBird() *NetBird { - return NewNetBird("http://invalid.test:9999", "test-proxy", nil, nil, &mockMgmtClient{}) + return NewNetBird("http://invalid.test:9999", "test-proxy", 0, nil, nil, &mockMgmtClient{}) } func TestNetBird_AddPeer_CreatesClientForNewAccount(t *testing.T) { diff --git a/proxy/server.go b/proxy/server.go index 62c732fd8..1ae12dc42 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -96,6 +96,10 @@ type Server struct { // When set, forwarding headers from these sources are preserved and // appended to instead of being stripped. TrustedProxies []netip.Prefix + // WireguardPort is the port for the WireGuard interface. Use 0 for a + // random OS-assigned port. A fixed port only works with single-account + // deployments; multiple accounts will fail to bind the same port. + WireguardPort int } // NotifyStatus sends a status update to management about tunnel connectivity @@ -188,7 +192,7 @@ func (s *Server) ListenAndServe(ctx context.Context, addr string) (err error) { // Initialize the netbird client, this is required to build peer connections // to proxy over. - s.netbird = roundtrip.NewNetBird(s.ManagementAddress, s.ID, s.Logger, s, s.mgmtClient) + s.netbird = roundtrip.NewNetBird(s.ManagementAddress, s.ID, s.WireguardPort, s.Logger, s, s.mgmtClient) // When generating ACME certificates, start a challenge server. tlsConfig := &tls.Config{}