refactor(ports): add netbird port definitions
This commit is contained in:
@@ -18,6 +18,10 @@
|
||||
wireguard = 51820;
|
||||
tailscale = 41641;
|
||||
headscale = 3009;
|
||||
netbird-stun = 3478;
|
||||
netbird-proxy = 8443;
|
||||
netbird-metrics = 9090;
|
||||
netbird-health = 9000;
|
||||
|
||||
# Containers & web apps
|
||||
gitea = 3030;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
./postgres.nix
|
||||
./restic.nix
|
||||
./sound.nix
|
||||
./tailscale.nix
|
||||
./udev.nix
|
||||
./wireguard.nix
|
||||
];
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{config, ...}: {
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
authKeyFile = config.age.secrets.tailscale-key.path;
|
||||
useRoutingFeatures = "both";
|
||||
extraUpFlags = [
|
||||
"--login-server=https://va.m3tam3re.com"
|
||||
"--accept-routes"
|
||||
"--ssh"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -11,6 +11,24 @@
|
||||
littlelink-m3tam3re = {file = ../../secrets/littlelink-m3tam3re.age;};
|
||||
minio-root-cred = {file = ../../secrets/minio-root-cred.age;};
|
||||
n8n-env = {file = ../../secrets/n8n-env.age;};
|
||||
netbird-auth-secret = {
|
||||
file = ../../secrets/netbird-auth-secret.age;
|
||||
};
|
||||
netbird-db-password = {
|
||||
file = ../../secrets/netbird-db-password.age;
|
||||
};
|
||||
netbird-encryption-key = {
|
||||
file = ../../secrets/netbird-encryption-key.age;
|
||||
};
|
||||
netbird-dashboard-env = {
|
||||
file = ../../secrets/netbird-dashboard-env.age;
|
||||
};
|
||||
netbird-server-env = {
|
||||
file = ../../secrets/netbird-server-env.age;
|
||||
};
|
||||
netbird-proxy-env = {
|
||||
file = ../../secrets/netbird-proxy-env.age;
|
||||
};
|
||||
paperless-key = {file = ../../secrets/paperless-key.age;};
|
||||
restreamer-env = {file = ../../secrets/restreamer-env.age;};
|
||||
searx = {file = ../../secrets/searx.age;};
|
||||
|
||||
236
hosts/m3-atlas/services/containers/netbird.nix
Normal file
236
hosts/m3-atlas/services/containers/netbird.nix
Normal file
@@ -0,0 +1,236 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "netbird";
|
||||
|
||||
servicePort = config.m3ta.ports.get "netbird";
|
||||
|
||||
domain = "v.m3ta.dev";
|
||||
proxyDomain = "p.m3ta.dev";
|
||||
|
||||
ipBase = "10.89.0";
|
||||
ipOffset = 50;
|
||||
|
||||
# Database configuration
|
||||
dbName = "netbird";
|
||||
dbUser = "netbird";
|
||||
dbHost = "${ipBase}.1";
|
||||
|
||||
# NetBird config als Nix attribute set
|
||||
netbirdConfig = {
|
||||
server = {
|
||||
listenAddress = ":80";
|
||||
exposedAddress = "https://${domain}:443";
|
||||
stunPorts = [3478];
|
||||
metricsPort = 9090;
|
||||
healthcheckAddress = ":9000";
|
||||
logLevel = "info";
|
||||
logFile = "console";
|
||||
dataDir = "/var/lib/netbird";
|
||||
|
||||
auth = {
|
||||
issuer = "https://${domain}/oauth2";
|
||||
localAuthDisabled = true;
|
||||
signKeyRefreshEnabled = true;
|
||||
dashboardRedirectURIs = [
|
||||
"https://${domain}/nb-auth"
|
||||
"https://${domain}/nb-silent-auth"
|
||||
];
|
||||
cliRedirectURIs = ["http://localhost:53000/"];
|
||||
};
|
||||
|
||||
reverseProxy = {
|
||||
trustedHTTPProxies = ["${ipBase}.1/32"];
|
||||
};
|
||||
|
||||
# Proxy Feature
|
||||
proxy = {
|
||||
enabled = true;
|
||||
domain = proxyDomain;
|
||||
};
|
||||
|
||||
store = {
|
||||
engine = "postgres";
|
||||
postgres = {
|
||||
host = dbHost;
|
||||
port = 5432;
|
||||
database = dbName;
|
||||
username = dbUser;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# YAML generieren
|
||||
yamlFormat = pkgs.formats.yaml {};
|
||||
configYamlBase = yamlFormat.generate "netbird-config-base.yaml" netbirdConfig;
|
||||
|
||||
# Script das Secrets zur Runtime injiziert
|
||||
configGenScript = pkgs.writeShellScript "netbird-gen-config" ''
|
||||
set -euo pipefail
|
||||
|
||||
AUTH_SECRET=$(cat "$1")
|
||||
DB_PASSWORD=$(cat "$2")
|
||||
ENCRYPTION_KEY=$(cat "$3")
|
||||
|
||||
${pkgs.yq-go}/bin/yq eval "
|
||||
.server.authSecret = \"$AUTH_SECRET\" |
|
||||
.server.store.encryptionKey = \"$ENCRYPTION_KEY\" |
|
||||
.server.store.postgres.password = \"$DB_PASSWORD\"
|
||||
" ${configYamlBase}
|
||||
'';
|
||||
in {
|
||||
age.secrets."${serviceName}-auth-secret".file = ../../../../secrets/${serviceName}-auth-secret.age;
|
||||
age.secrets."${serviceName}-db-password".file = ../../../../secrets/${serviceName}-db-password.age;
|
||||
age.secrets."${serviceName}-encryption-key".file = ../../../../secrets/${serviceName}-encryption-key.age;
|
||||
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
|
||||
systemd.services."${serviceName}-config" = {
|
||||
description = "Generate NetBird config with secrets";
|
||||
wantedBy = ["multi-user.target"];
|
||||
before = ["podman-${serviceName}-server.service"];
|
||||
requiredBy = ["podman-${serviceName}-server.service"];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = pkgs.writeShellScript "netbird-write-config" ''
|
||||
mkdir -p /var/lib/${serviceName}
|
||||
${configGenScript} \
|
||||
${config.age.secrets."${serviceName}-auth-secret".path} \
|
||||
${config.age.secrets."${serviceName}-db-password".path} \
|
||||
${config.age.secrets."${serviceName}-encryption-key".path} \
|
||||
> /var/lib/${serviceName}/config.yaml
|
||||
chmod 600 /var/lib/${serviceName}/config.yaml
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
"${serviceName}-dashboard" = {
|
||||
image = "netbirdio/dashboard:latest";
|
||||
autoStart = true;
|
||||
environmentFiles = [config.age.secrets."${serviceName}-dashboard-env".path];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString ipOffset}"
|
||||
"--network=web"
|
||||
];
|
||||
};
|
||||
|
||||
"${serviceName}-server" = {
|
||||
image = "netbirdio/netbird-server:latest";
|
||||
autoStart = true;
|
||||
ports = ["3478:3478/udp"];
|
||||
environmentFiles = [config.age.secrets."${serviceName}-server-env".path];
|
||||
volumes = [
|
||||
"${serviceName}_data:/var/lib/netbird"
|
||||
"/var/lib/${serviceName}/config.yaml:/etc/netbird/config.yaml:ro"
|
||||
];
|
||||
cmd = ["--config" "/etc/netbird/config.yaml"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 1)}"
|
||||
"--network=web"
|
||||
];
|
||||
};
|
||||
|
||||
"${serviceName}-proxy" = {
|
||||
image = "netbirdio/reverse-proxy:latest";
|
||||
autoStart = true;
|
||||
ports = ["51820:51820/udp"];
|
||||
volumes = [
|
||||
"${serviceName}_proxy_certs:/certs"
|
||||
];
|
||||
environmentFiles = [config.age.secrets."${serviceName}-proxy-env".path];
|
||||
cmd = [
|
||||
"--domain=p.m3ta.dev"
|
||||
"--mgmt=https://${domain}:443"
|
||||
"--addr=:8443"
|
||||
"--cert-dir=/certs"
|
||||
"--acme-certs"
|
||||
"--trusted-proxies=${ipBase}.1/32"
|
||||
];
|
||||
dependsOn = ["${serviceName}-server"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 2)}"
|
||||
"--network=web"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.traefik.dynamicConfigOptions = {
|
||||
# HTTP Services und Routers
|
||||
http = {
|
||||
services = {
|
||||
"${serviceName}-dashboard".loadBalancer.servers = [
|
||||
{url = "http://${ipBase}.${toString ipOffset}:80/";}
|
||||
];
|
||||
|
||||
"${serviceName}-server".loadBalancer.servers = [
|
||||
{url = "http://${ipBase}.${toString (ipOffset + 1)}:80/";}
|
||||
];
|
||||
|
||||
"${serviceName}-server-h2c".loadBalancer.servers = [
|
||||
{url = "h2c://${ipBase}.${toString (ipOffset + 1)}:80";}
|
||||
];
|
||||
};
|
||||
|
||||
routers = {
|
||||
# gRPC (Signal + Management)
|
||||
"${serviceName}-grpc" = {
|
||||
rule = "Host(`${domain}`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))";
|
||||
entrypoints = "websecure";
|
||||
tls.certResolver = "godaddy";
|
||||
service = "${serviceName}-server-h2c";
|
||||
priority = 100;
|
||||
};
|
||||
# Backend (relay, WebSocket, API, OAuth2)
|
||||
"${serviceName}-backend" = {
|
||||
rule = "Host(`${domain}`) && (PathPrefix(`/relay`) || PathPrefix(`/ws-proxy/`) || PathPrefix(`/api`) || PathPrefix(`/oauth2`))";
|
||||
entrypoints = "websecure";
|
||||
tls.certResolver = "godaddy";
|
||||
service = "${serviceName}-server";
|
||||
priority = 100;
|
||||
};
|
||||
|
||||
# Dashboard (catch-all, niedrigste Priorität)
|
||||
"${serviceName}-dashboard" = {
|
||||
rule = "Host(`${domain}`)";
|
||||
entrypoints = "websecure";
|
||||
tls.certResolver = "godaddy";
|
||||
service = "${serviceName}-dashboard";
|
||||
priority = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# TCP für Proxy TLS Passthrough
|
||||
tcp = {
|
||||
services."${serviceName}-proxy-tls".loadBalancer.servers = [
|
||||
{address = "${ipBase}.${toString (ipOffset + 2)}:8443";}
|
||||
];
|
||||
|
||||
routers."${serviceName}-proxy-passthrough" = {
|
||||
entryPoints = ["websecure"];
|
||||
rule = "HostSNI(`*`)";
|
||||
service = "${serviceName}-proxy-tls";
|
||||
priority = 1;
|
||||
tls.passthrough = true;
|
||||
};
|
||||
};
|
||||
|
||||
# ServersTransport für Proxy Protocol v2 (optional)
|
||||
serversTransports."pp-v2" = {
|
||||
proxyProtocol.version = 2;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
3478 # STUN
|
||||
51820 # WireGuard für Proxy
|
||||
];
|
||||
}
|
||||
@@ -3,15 +3,13 @@
|
||||
./containers
|
||||
./gitea.nix
|
||||
./gitea-actions-runner.nix
|
||||
./headscale.nix
|
||||
./minio.nix
|
||||
./mysql.nix
|
||||
./n8n.nix
|
||||
./outline.nix
|
||||
./netbird.nix
|
||||
./paperless.nix
|
||||
./postgres.nix
|
||||
./searx.nix
|
||||
./tailscale.nix
|
||||
./traefik.nix
|
||||
./vaultwarden.nix
|
||||
./wastebin.nix
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# Define a new option for the admin user
|
||||
options.services.headscale = {
|
||||
adminUser = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "m3tam3re@m3ta.loc";
|
||||
description = "Username for the headscale admin user";
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
adminUser = config.services.headscale.adminUser;
|
||||
|
||||
aclConfig = {
|
||||
# Groups definition
|
||||
groups = {
|
||||
"group:admins" = ["${adminUser}"];
|
||||
};
|
||||
|
||||
acls = [
|
||||
# Allow all connections within the tailnet
|
||||
{
|
||||
action = "accept";
|
||||
src = ["*"];
|
||||
dst = ["*:*"];
|
||||
}
|
||||
# Allow admin to connect to their own services
|
||||
{
|
||||
action = "accept";
|
||||
src = ["${adminUser}"];
|
||||
dst = ["${adminUser}:*"];
|
||||
}
|
||||
];
|
||||
# Auto-approvers section for routes
|
||||
autoApprovers = {
|
||||
routes = {
|
||||
"0.0.0.0/0" = ["${adminUser}"];
|
||||
"10.0.0.0/8" = ["${adminUser}"];
|
||||
"192.168.0.0/16" = ["${adminUser}"];
|
||||
};
|
||||
|
||||
exitNode = ["${adminUser}"];
|
||||
};
|
||||
};
|
||||
# Convert to HuJSON format with comments
|
||||
aclHuJson = ''
|
||||
// Headscale ACL Policy - Generated by NixOS
|
||||
// Admin user: ${adminUser}
|
||||
|
||||
${builtins.toJSON aclConfig}
|
||||
'';
|
||||
aclFile = pkgs.writeText "acl-policy.hujson" aclHuJson;
|
||||
in {
|
||||
services = {
|
||||
headscale = {
|
||||
enable = true;
|
||||
adminUser = "m3tam3re@m3ta.loc";
|
||||
port = 3009;
|
||||
settings = {
|
||||
server_url = "https://va.m3tam3re.com";
|
||||
dns = {
|
||||
base_domain = "m3ta.loc";
|
||||
nameservers.global = ["8.8.8.8"];
|
||||
};
|
||||
logtail.enabled = false;
|
||||
policy.path = "${aclFile}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Create a systemd service to ensure the admin user exists
|
||||
systemd.services.headscale-ensure-admin = lib.mkIf config.services.headscale.enable {
|
||||
description = "Ensure Headscale admin user exists";
|
||||
after = ["headscale.service"];
|
||||
requires = ["headscale.service"];
|
||||
wantedBy = ["multi-user.target"];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = "headscale";
|
||||
Group = "headscale";
|
||||
};
|
||||
|
||||
script = ''
|
||||
# Check if user exists and create if needed
|
||||
if ! ${pkgs.headscale}/bin/headscale users list | grep -q "${adminUser}"; then
|
||||
echo "Creating headscale admin user: ${adminUser}"
|
||||
${pkgs.headscale}/bin/headscale users create "${adminUser}"
|
||||
else
|
||||
echo "Headscale admin user ${adminUser} already exists"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Traefik configuration for headscale
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.headscale.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:3009/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.headscale = {
|
||||
rule = "Host(`va.m3tam3re.com`)";
|
||||
tls = {
|
||||
certResolver = "godaddy";
|
||||
};
|
||||
service = "headscale";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,16 @@
|
||||
{config, ...}: {
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
services.n8n = {
|
||||
enable = true;
|
||||
environment.WEBHOOK_URL = "https://wf.m3tam3re.com";
|
||||
};
|
||||
# Temporary fix for upstream module
|
||||
systemd.services.n8n.serviceConfig.LoadCredential = lib.mkForce [];
|
||||
systemd.services.n8n.environment.N8N_RUNNERS_AUTH_TOKEN_FILE = lib.mkForce null;
|
||||
|
||||
systemd.services.n8n.serviceConfig = {
|
||||
EnvironmentFile = ["${config.age.secrets.n8n-env.path}"];
|
||||
};
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
services.outline = {
|
||||
enable = true;
|
||||
port = 3019;
|
||||
publicUrl = "https://ol.m3ta.dev";
|
||||
databaseUrl = "postgresql://outline:outline@127.0.0.1:5432/outline";
|
||||
storage = {
|
||||
storageType = "local";
|
||||
};
|
||||
};
|
||||
systemd.services.outline.serviceConfig = {
|
||||
Environment = [
|
||||
"PGSSLMODE=disable"
|
||||
];
|
||||
};
|
||||
# Traefik configuration specific to littlelink
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.outline.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:3019/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.outline = {
|
||||
rule = "Host(`ol.m3ta.dev`)";
|
||||
tls = {
|
||||
certResolver = "godaddy";
|
||||
};
|
||||
service = "outline";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
# Podman network connections for Baserow
|
||||
host baserow baserow 10.89.0.0/24 scram-sha-256
|
||||
host kestra kestra 10.89.0.0/24 scram-sha-256
|
||||
host netbird netbird 10.89.0.0/24 scram-sha-256
|
||||
|
||||
# Deny all other connections
|
||||
local all all reject
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
authKeyFile = config.age.secrets.tailscale-key.path;
|
||||
useRoutingFeatures = "both";
|
||||
extraUpFlags = [
|
||||
"--login-server=${config.services.headscale.settings.server_url}"
|
||||
"--advertise-exit-node"
|
||||
"--accept-routes"
|
||||
"--ssh=true"
|
||||
];
|
||||
};
|
||||
services.networkd-dispatcher = lib.mkIf config.services.tailscale.enable {
|
||||
enable = true;
|
||||
rules."50-tailscale" = {
|
||||
onState = ["routable"];
|
||||
script = ''
|
||||
NETDEV=$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")
|
||||
${pkgs.ethtool}/bin/ethtool -K "$NETDEV" rx-udp-gro-forwarding on rx-gro-list off
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,22 +1,24 @@
|
||||
{
|
||||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./containers
|
||||
./mem0.nix
|
||||
./n8n.nix
|
||||
./postgres.nix
|
||||
./sound.nix
|
||||
./tailscale.nix
|
||||
./udev.nix
|
||||
./wireguard.nix
|
||||
];
|
||||
services = {
|
||||
hypridle.enable = true;
|
||||
espanso = {
|
||||
enable = true;
|
||||
package = pkgs.espanso-wayland;
|
||||
};
|
||||
printing.enable = true;
|
||||
gvfs.enable = true;
|
||||
trezord.enable = true;
|
||||
gnome.gnome-keyring.enable = true;
|
||||
qdrant.enable = true;
|
||||
stirling-pdf.enable = true;
|
||||
avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
{lib, ...}: {
|
||||
services.n8n = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
systemd.services.n8n = {
|
||||
environment = {
|
||||
N8N_SECURE_COOKIE = "false";
|
||||
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS = "false";
|
||||
};
|
||||
};
|
||||
# Temporary fix for upstream module
|
||||
systemd.services.n8n.serviceConfig.LoadCredential = lib.mkForce [];
|
||||
systemd.services.n8n.environment.N8N_RUNNERS_AUTH_TOKEN_FILE = lib.mkForce null;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{config, ...}: {
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
authKeyFile = config.age.secrets.tailscale-key.path;
|
||||
useRoutingFeatures = "both";
|
||||
extraUpFlags = [
|
||||
"--login-server=https://va.m3tam3re.com"
|
||||
"--accept-routes"
|
||||
"--ssh"
|
||||
"--reset"
|
||||
];
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user