From a9022a4f55a93503cd70e06b759ba4055c6985bc Mon Sep 17 00:00:00 2001 From: m3tm3re Date: Fri, 27 Feb 2026 16:03:12 +0100 Subject: [PATCH] refactor(netbird): use port registry and named IP variables --- .../m3-atlas/services/containers/default.nix | 1 + .../m3-atlas/services/containers/netbird.nix | 65 ++++++++++-------- hosts/m3-atlas/services/default.nix | 1 - secrets/netbird-dashboard-env.age | Bin 1583 -> 1539 bytes secrets/netbird-proxy-env.age | 36 +++++----- 5 files changed, 56 insertions(+), 47 deletions(-) diff --git a/hosts/m3-atlas/services/containers/default.nix b/hosts/m3-atlas/services/containers/default.nix index 6b38c84..f3399fd 100644 --- a/hosts/m3-atlas/services/containers/default.nix +++ b/hosts/m3-atlas/services/containers/default.nix @@ -5,6 +5,7 @@ ./kestra.nix ./littlelink.nix ./matomo.nix + ./netbird.nix # ./n8n.nix # ./pangolin.nix ./restreamer.nix diff --git a/hosts/m3-atlas/services/containers/netbird.nix b/hosts/m3-atlas/services/containers/netbird.nix index ab23af2..605cc70 100644 --- a/hosts/m3-atlas/services/containers/netbird.nix +++ b/hosts/m3-atlas/services/containers/netbird.nix @@ -6,7 +6,12 @@ }: let serviceName = "netbird"; - servicePort = config.m3ta.ports.get "netbird"; + stunPort = config.m3ta.ports.get "netbird-stun"; + proxyTlsPort = config.m3ta.ports.get "netbird-proxy"; + metricsPort = config.m3ta.ports.get "netbird-metrics"; + healthPort = config.m3ta.ports.get "netbird-health"; + postgresPort = config.m3ta.ports.get "postgres"; + wireguardPort = config.m3ta.ports.get "wireguard"; domain = "v.m3ta.dev"; proxyDomain = "p.m3ta.dev"; @@ -14,26 +19,30 @@ ipBase = "10.89.0"; ipOffset = 50; + dashboardIp = "${ipBase}.${toString ipOffset}"; + serverIp = "${ipBase}.${toString (ipOffset + 1)}"; + proxyIp = "${ipBase}.${toString (ipOffset + 2)}"; + # Database configuration dbName = "netbird"; dbUser = "netbird"; dbHost = "${ipBase}.1"; - # NetBird config als Nix attribute set + # NetBird config as Nix attribute set netbirdConfig = { server = { listenAddress = ":80"; exposedAddress = "https://${domain}:443"; - stunPorts = [3478]; - metricsPort = 9090; - healthcheckAddress = ":9000"; + stunPorts = [stunPort]; + metricsPort = metricsPort; + healthcheckAddress = ":${toString healthPort}"; logLevel = "info"; logFile = "console"; dataDir = "/var/lib/netbird"; auth = { issuer = "https://${domain}/oauth2"; - localAuthDisabled = true; + # localAuthDisabled = true; signKeyRefreshEnabled = true; dashboardRedirectURIs = [ "https://${domain}/nb-auth" @@ -46,7 +55,7 @@ trustedHTTPProxies = ["${ipBase}.1/32"]; }; - # Proxy Feature + # Proxy feature proxy = { enabled = true; domain = proxyDomain; @@ -56,7 +65,7 @@ engine = "postgres"; postgres = { host = dbHost; - port = 5432; + port = postgresPort; database = dbName; username = dbUser; }; @@ -64,11 +73,11 @@ }; }; - # YAML generieren + # Generate YAML from Nix attribute set yamlFormat = pkgs.formats.yaml {}; configYamlBase = yamlFormat.generate "netbird-config-base.yaml" netbirdConfig; - # Script das Secrets zur Runtime injiziert + # Script that injects secrets at runtime configGenScript = pkgs.writeShellScript "netbird-gen-config" '' set -euo pipefail @@ -89,7 +98,7 @@ in { age.secrets."${serviceName}-dashboard-env".file = ../../../../secrets/${serviceName}-dashboard-env.age; age.secrets."${serviceName}-server-env".file = ../../../../secrets/${serviceName}-server-env.age; age.secrets."${serviceName}-proxy-env".file = ../../../../secrets/${serviceName}-proxy-env.age; - # Systemd oneshot Service der die Config generiert + # Oneshot systemd service that generates the config with injected secrets systemd.services."${serviceName}-config" = { description = "Generate NetBird config with secrets"; wantedBy = ["multi-user.target"]; @@ -117,7 +126,7 @@ in { autoStart = true; environmentFiles = [config.age.secrets."${serviceName}-dashboard-env".path]; extraOptions = [ - "--ip=${ipBase}.${toString ipOffset}" + "--ip=${dashboardIp}" "--network=web" ]; }; @@ -125,7 +134,7 @@ in { "${serviceName}-server" = { image = "netbirdio/netbird-server:latest"; autoStart = true; - ports = ["3478:3478/udp"]; + ports = ["${toString stunPort}:${toString stunPort}/udp"]; environmentFiles = [config.age.secrets."${serviceName}-server-env".path]; volumes = [ "${serviceName}_data:/var/lib/netbird" @@ -133,7 +142,7 @@ in { ]; cmd = ["--config" "/etc/netbird/config.yaml"]; extraOptions = [ - "--ip=${ipBase}.${toString (ipOffset + 1)}" + "--ip=${serverIp}" "--network=web" ]; }; @@ -141,41 +150,41 @@ in { "${serviceName}-proxy" = { image = "netbirdio/reverse-proxy:latest"; autoStart = true; - ports = ["51820:51820/udp"]; + ports = ["${toString wireguardPort}:${toString wireguardPort}/udp"]; volumes = [ "${serviceName}_proxy_certs:/certs" ]; environmentFiles = [config.age.secrets."${serviceName}-proxy-env".path]; cmd = [ - "--domain=p.m3ta.dev" + "--domain=${proxyDomain}" "--mgmt=https://${domain}:443" - "--addr=:8443" + "--addr=:${toString proxyTlsPort}" "--cert-dir=/certs" "--acme-certs" "--trusted-proxies=${ipBase}.1/32" ]; dependsOn = ["${serviceName}-server"]; extraOptions = [ - "--ip=${ipBase}.${toString (ipOffset + 2)}" + "--ip=${proxyIp}" "--network=web" ]; }; }; services.traefik.dynamicConfigOptions = { - # HTTP Services und Routers + # HTTP services and routers http = { services = { "${serviceName}-dashboard".loadBalancer.servers = [ - {url = "http://${ipBase}.${toString ipOffset}:80/";} + {url = "http://${dashboardIp}:80/";} ]; "${serviceName}-server".loadBalancer.servers = [ - {url = "http://${ipBase}.${toString (ipOffset + 1)}:80/";} + {url = "http://${serverIp}:80/";} ]; "${serviceName}-server-h2c".loadBalancer.servers = [ - {url = "h2c://${ipBase}.${toString (ipOffset + 1)}:80";} + {url = "h2c://${serverIp}:80";} ]; }; @@ -197,7 +206,7 @@ in { priority = 100; }; - # Dashboard (catch-all, niedrigste Priorität) + # Dashboard (catch-all, lowest priority) "${serviceName}-dashboard" = { rule = "Host(`${domain}`)"; entrypoints = "websecure"; @@ -208,10 +217,10 @@ in { }; }; - # TCP für Proxy TLS Passthrough + # TCP for proxy TLS passthrough tcp = { services."${serviceName}-proxy-tls".loadBalancer.servers = [ - {address = "${ipBase}.${toString (ipOffset + 2)}:8443";} + {address = "${proxyIp}:${toString proxyTlsPort}";} ]; routers."${serviceName}-proxy-passthrough" = { @@ -223,14 +232,14 @@ in { }; }; - # ServersTransport für Proxy Protocol v2 (optional) + # ServersTransport for Proxy Protocol v2 (optional) serversTransports."pp-v2" = { proxyProtocol.version = 2; }; }; networking.firewall.allowedUDPPorts = [ - 3478 # STUN - 51820 # WireGuard für Proxy + stunPort # STUN + wireguardPort # WireGuard for proxy ]; } diff --git a/hosts/m3-atlas/services/default.nix b/hosts/m3-atlas/services/default.nix index 4769978..6a49f8d 100644 --- a/hosts/m3-atlas/services/default.nix +++ b/hosts/m3-atlas/services/default.nix @@ -6,7 +6,6 @@ ./minio.nix ./mysql.nix ./n8n.nix - ./netbird.nix ./paperless.nix ./postgres.nix ./searx.nix diff --git a/secrets/netbird-dashboard-env.age b/secrets/netbird-dashboard-env.age index 62f84975095923f608cb3c5b9bb7eadcc0085e25..bcba6fb0f1a11df9c86e5eea72d60cc7d596f2b9 100644 GIT binary patch delta 1475 zcmZ3_)66qLr`{+qpeQRVSUV*$xwy(K$+s!;TFCy0~%qT0!GczaDxT-SI zC?!0vARy3}E7vQh%CFEhN8cpO%c(d@+c+;QAkoMnbdSu$ik!d-3y(l9$28BN zjQr3rr@YV*4?q9pg6txnFeeXpXO|3L*TOunN`K?ZFb}f`eV@?D@r>g2E+r`j2CfFV zeuc^Iu0hUK#!*K8;rb~NsrmVZ9uiDDcX24J$Lx^>MZ=D~n1>vaAY;;PMO)FHA`@@(nid$;@#IHpua_EKIB_ zF?Vz+Ha2rAHg~fu*H1Sz2{Xwow~R`uEOO2>DlE#c@N`Pd3UPHQb>S*6NefF&PtEhO zG&N86NvpSTcQMP)FZC|Zun5e}F{|^GTOz|r*v8?w`uLyE8j5H6+$tZRY3$8SCk91GU zt;`Jaa`ee_boMF83X2LdP4`bXDNXY=aS3)zOpW47a}7;0&k9O3)~)|HS$VNEXsDui8S}oH}os0NaynXJ7=fYrMt^~ zbI)ijHOrlJdU>F4$>+@arO94Ak5q1^++H#N{>}A&+XWN5dPIWeZ#ET6_dfYq=v>8v zY>D(HasJOICm;FQS~A~wRfxuw&4Ewv8Lz&vH;}7-&7JrcIXcTWC(2K}9VugSr~Gk~ zaBa^9W-lq3d8%R;_U_%p{v%JxXG!0>GnH$F?k1F*vTxb4^~s947te4yF0bx<{Wuix&%mgKTj%g6Csi+;(ClVMXIWY1+hzUPU%vT?4jo7&I%CUUYUl(7^;oEunnr!FB%k>J3JY}xce0SCq z^PEYIuM2-V-Lx*1r*C)9ow_SC*FFDewc(+|tM&=9I?A)w9jL!9zQI|;`%cy`&E@|+ z_8oT5a(;NVE`awC>;24P;e{oQiaW$ugD1@DQZ;^ay8p$}jWTUtE3Us=xi5Mf<0Z|# xjSp>qavrXk{Qt%6^;NC&Q_|%xi8&cwd8phjYt`?Tcj6t}$DI+02kbx20|06JKvMt! delta 1519 zcmZqXS;r`{wdB&ftCsl-p;qC7Y(G2O>EFx4kGG9uVKKh?=S%g@jyy~HpmJv7R& zoXb5W%cUYGIoBj0G{h*=UE3qeIVaE4C90sfuq4MY)5$C{qrfe~#knx0m`m4Ap}06h zH#Nn`)YQ;Y!8E%(x!6&`H7%zs)w`g=&)nU_JlWmP&@C*=-?hp+%gH+}tHLWaEzCV5 zDbOrU-#6Ql%QP>|#J#XQt;D6!tjgH8z}3+|Ey*<3qRcTYBq_g2Zazs~9?rh* zrDYagei3=0-u^|2r2#2^+95`n`L4NT-nkiJi9Y$Ro*}MW#%59JiQ!S@F5Z)H8 zDXu2vCZX=RW^PGo>Ds}80f|+4UV)MRImP9$P%0`;RB#E*aWyaJDvHSPF7(K7D#!~o z%yx`2C@S*zDy#P|&8*Ni^*3>}3^htl5BDoGD@)a`^6^P5atbj?sw~v@OD`@c$OtUW zGvo@+s|ZfX2o3csD>Y8_4M|T=EcFcY3Qo<{&&f^m%Qw~zaM2DnatW#Ob;(GIEX_76 z3^WY4@G(txPAg6iwhZK|%*rb)%d$vw%1R9LNi=l}F{m#uPOGSNDYEqOFD=k7_B8eP zF}5tU%q$77bn;0l%X4>3F)+z4DylFDOAj=T;xaI+2yjg;w@k}4EY7bgFL3cmGcpXw zH;WAO56Ce!u`EpqHmz{a@HO_X$jvROaPl!MwhT@6a7_;{NzC`HNaHf|)Xol#wD2)2 zG%!qeDynxY%LuHA)OAFb$3<2=sJI&T>!nD);sGDKF;AiSP}}@F>f6&&kRws7y=t$}2W4 zNlVVk^bX32$SVqVEzF5Zv-Hf$NK5oF%qvO{aLY0dFmeh^uMCYc_sPrR;?mXCRd5XR z39Q#n_V;xvb=Nk^uL$&u$}!h2D{v_*%QH-O*A7ffNsP!3@J!7%a^(7VBz|SF$@wk1tPGf0n)bufEFV5-~gOWWo0b&xc9< z^E@;8=@E8?v{>HGg1p#M3wzX}-gcL?iTO#ydY-R0R(!dS_qcP5`aO-wG3yHt9rz|R z)gi2|$}z(3P37q|RrRWmCGWiKZ4i~O;}-gN&!3}yp4dUI8^$@6^Z)8B+M~VRBQW?i zTd4MiOQ&|5zB8L0d-=K1q0eT&PAPaUXgGAYJaq9+#RH44q-ptbq@>>wUbkUQ_roJ0 zQyF8GrOSPL!s@4AOSszX*mPs-l&Qz8_Q*XnTG1SPTVmb){o9w%%4hl-W$^k;Y;sPl z<4P6Tb_KS)U4L2APsj$$Z}0f{Pj#lr1)Zmjj|7NbRN!}y77HToap0KmaFgo3uiT*CsA+DAJq}smC&it z)?j*akxbs)7492$^iME-*)1EuP(RV{=*&$UzOOu;HsOQ88r^z1R#l^EIsY0Nc5arD zJ+6B7qtc0HyIos0G*6I|40yG1$!yVsi79ta=FMfkA-Qs~;m2ghL)SIbdbuwwwN>0K zp!+L5k7uTd;YXj$%l8^9gFgx_blNaQEx=RY5X<`0?#J}cGj^YMFyNGUy8ZU5kK5V2 s_FX$8Uv=YGc*%R8CA^Z3vM;{Qzy8uC^4wqboW7U)R=(rTTdO+(0J7^ ssh-ed25519 4NLKrw z/cBQjeEEhzQCSOweODXfH1+u0x4fPFzMmuJ60sT6Vk -7fA+XIqnsXFHlCD5w8s0ttHRYijt0/97PtJrx/xNVeA --> ssh-ed25519 5kwcsA p/tSvBiYUFw1CEypUFkZkan6Fg4cTpy4vT7weDAtZQI -zcphfvNyNUa0XYmVrIA7qTJ4btWD/LwZoGv8i3pWktU --> ssh-ed25519 9d4YIQ Xjyuwljm4+dJn/CUP4NgFl4fK1ah4z71rHAVrJ9ggTw -2ae/e/rdDNqt40E29E4qxvkEIC0GWAKX0pMbY7guHn4 --> ssh-ed25519 3Bcr1w Cra9xUKcyk5e0+VrdtCZUuGo/tRhicxlSNHheDfFslw -+AQBO1F8Yk/u0KuQ8uG168m1xOczr+I4kvNIyeHu11o +-> ssh-ed25519 4NLKrw SsQNRQTJVF4hcSVRmnYd7dHK+SCuMIPOIzFWyZp9WBg +sZz8th/4uY3T2UOs5C5exXhLmFo7AGrj+QxQwnuJ/ng +-> ssh-ed25519 5kwcsA uxdOaVZDDQLyV+vUJhG4mv16zfn3eOZWx9PpwoQje2M +gk7vrd7V9mwVXzh987C8A8QeQTxDfPBNT75QPMACnoE +-> ssh-ed25519 9d4YIQ G1OGiK+CYjXs3DPb2OHLoKAA2T5tNm/0ciFR3mZmmFA +qHW4cvm29OdKpt5Ia5boWx479z2vGKDwddTKeMc57Hc +-> ssh-ed25519 3Bcr1w lef+8thtDVWKeydqHku+8BzSxLCOyQ5o91RfwJU8Lyk +mWaQo4uxW1X+freu16rUPYWgZtt0P1L7lHuXJ32DXx8 -> ssh-rsa DQlE7w -qvtWc6kq/Q8W5aBlfj3o0/GFZC2pnyw58rggC//ciWvacz8lVUWSqYbP9JdRg8eK -04UnbS6FyUYRVJuD8hZYF5RRbPFOMzZE69jb2N/B3OnrtCr21ohXluPP3+rH8Egz -pC4ETTJYPuNPG+clEGcEcilLrgrI3ZvajJbDGhAx2kOTN1g3u4SnkSA6b1c5otsX -UAJsDzCOr4eKAdnf2ZGtuhzcrwDb8lCJ0rKz/ZQtWhWXRhYzalrWZHyH5KdMkOTq -ZTrPMLyzAaL3Civv9uZ6cveQp8TGSZHnA5hmz/4lwfMrRcJzJUgjjDdgiNwK34pw -IkInu6D6k5x7kRcFvKcOu8zJUELtXV6/uzswy3uJn9CiQsMC5GSri65iuARIi3JC -nUNxx8yVfUFk+PMoAWLXZ2A3Gd3GQ5tlQNrfcLubnpwHuD7bYMdskkSTktIW+RDj -p4ckgCxRFG4K5sYQEtM5j4mQg+hEKCjQTFzcgRY74AFZepXoWYuQ+d/ExMANPUMi +mdrcYIsmXXPsHXSyAZ9RJtBuKMxHphbuPhagAq2A8/w7hgEQLDLCaSh939uBiIX/ +YsRtVwN/YuvPoWCyl3Dns02gzaAEsxwfvA7dMbxR1ErHhlFLL/71zJMtA6gbDjZB +vzkUGHmkCp1M54je8GH7Tn3RxoE9ylqWX8Ja8xmw8xpgaqTc1eTOmiX056IyXsGi +kn/f3C/qBZO46CdjlTQL83Ntw+4yKMozUndwakxkMV/nQTbv+sX/vNiz6mYLItgI +LkD18niPLO2rjLNBOo2MAHBZqMB5PJze3ZxN4LOgnqHiv64sGPE2JA0LcnWSkp/O +LFzPlH01Bqmy9Wi8x0SIsKt7z5vJRuoUmlJ5D+QVwOmxO6KVs+BrUZE6KzrJsXZJ +12oqsiDyz4fJ+XJuDC4sYcl3bXnjIGEMD7sZIR+8F4RjK+IZJzRh/rX7YeFfVYAq +xJXAmXSPA9lBK4fkBHSi2X9QhSoOgXzHpK6I2ny5tgl2dYHHTvikuure1D646xVq ---- HfrVJutjDYDbddvlCyZ9RNEmgp/dTcjR3y1U+OLZ7Wg -8k\,vW/=|:jDfd#gxIwo~U4ٶ԰ \ No newline at end of file +--- 6IeZk49jY+uLeHciC2dG1d/joRo4DnVPpgytWzPJjus +T@]F |0\OC|@"0Ɯ?4D]+@Iz*({bB^ٴ