From 6d7db643bce729e0e441e666dfef7d9c2d889e7d Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sun, 1 Feb 2026 10:52:59 +0100 Subject: [PATCH 1/4] feat: add dev host --- hosts/dev/configuration.nix | 65 ++++++++++++++++++++++++++++++++ hosts/dev/modules/dev-tools.nix | 36 ++++++++++++++++++ hosts/fw/dev | 1 + hosts/fw/modules/dev-microvm.nix | 61 ++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 hosts/dev/configuration.nix create mode 100644 hosts/dev/modules/dev-tools.nix create mode 120000 hosts/fw/dev create mode 100644 hosts/fw/modules/dev-microvm.nix diff --git a/hosts/dev/configuration.nix b/hosts/dev/configuration.nix new file mode 100644 index 0000000..19d5363 --- /dev/null +++ b/hosts/dev/configuration.nix @@ -0,0 +1,65 @@ +{ config, lib, pkgs, ... }: + +let + # === CONFIGURABLE SETTINGS === + projectsDir = "projects"; # Relative to /home/dominik + + repositories = [ + { url = "gitea@git.cloonar.com:Cloonar/wohnservice-wien-typo3.git"; path = "projects/cloonar/wohnservice-wien"} + # Add repos here: { url = "git@..."; path = "relative/path"; } + ]; + # === END CONFIGURABLE === + + cloneScript = pkgs.writeShellScript "clone-repos" '' + set -eu + HOME_DIR="/home/dominik" + PROJECTS_DIR="$HOME_DIR/${projectsDir}" + + mkdir -p "$PROJECTS_DIR" + chown dominik:users "$PROJECTS_DIR" + + ${lib.concatMapStrings (repo: '' + if [ ! -d "$PROJECTS_DIR/${repo.path}" ]; then + ${pkgs.sudo}/bin/sudo -u dominik ${pkgs.git}/bin/git clone ${repo.url} "$PROJECTS_DIR/${repo.path}" || true + fi + '') repositories} + ''; +in +{ + imports = [ + ./modules/dev-tools.nix + ]; + + networking.hostName = "dev"; + system.stateVersion = "22.05"; + time.timeZone = "Europe/Vienna"; + + # User configuration + users.users.dominik = { + isNormalUser = true; + home = "/home/dominik"; + extraGroups = [ "wheel" "docker" ]; + openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius" + ]; + }; + users.groups.users = {}; + + services.openssh.enable = true; + programs.zsh.enable = true; + users.defaultUserShell = pkgs.zsh; + + # Clone repos as dominik user on boot + systemd.services.clone-repos = { + description = "Clone configured git repositories"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = cloneScript; + RemainAfterExit = true; + }; + }; +} diff --git a/hosts/dev/modules/dev-tools.nix b/hosts/dev/modules/dev-tools.nix new file mode 100644 index 0000000..27e0bf8 --- /dev/null +++ b/hosts/dev/modules/dev-tools.nix @@ -0,0 +1,36 @@ +{ pkgs, ... }: +{ + nixpkgs.overlays = [ + (import ../../utils/overlays/packages.nix) + ]; + + environment.systemPackages = with pkgs; [ + # Development tools + ddev + docker-compose + git + git-lfs + + # PHP + php + + # Node.js + nodejs_22 + + # AI coding + claude-code + + # Utilities + jq + unzip + vim + wget + curl + htop + tmux + ]; + + # Docker for ddev + virtualisation.docker.enable = true; + users.users.dominik.extraGroups = [ "docker" ]; +} diff --git a/hosts/fw/dev b/hosts/fw/dev new file mode 120000 index 0000000..009de10 --- /dev/null +++ b/hosts/fw/dev @@ -0,0 +1 @@ +../dev \ No newline at end of file diff --git a/hosts/fw/modules/dev-microvm.nix b/hosts/fw/modules/dev-microvm.nix new file mode 100644 index 0000000..965141e --- /dev/null +++ b/hosts/fw/modules/dev-microvm.nix @@ -0,0 +1,61 @@ +{ lib, pkgs, config, ... }: +let + hostname = "dev"; +in +{ + microvm.vms.dev = { + config = { + imports = [ + ../dev/configuration.nix + ./network-prefix.nix + ]; + + networkPrefix = config.networkPrefix; + + microvm = { + mem = 4096; + vcpu = 2; + + shares = [ + { + source = "/nix/store"; + mountPoint = "/nix/.ro-store"; + tag = "ro-store"; + proto = "virtiofs"; + } + { + source = "/var/lib/microvms/persist/dev"; + mountPoint = "/persist"; + tag = "persist"; + proto = "virtiofs"; + } + { + source = "/var/lib/microvms/persist/dev/home"; + mountPoint = "/home"; + tag = "home"; + proto = "virtiofs"; + } + ]; + + volumes = [{ + image = "rootfs.img"; + mountPoint = "/"; + size = 51200; + }]; + + interfaces = [{ + type = "tap"; + id = "vm-${hostname}"; + mac = "02:00:00:00:02:01"; + }]; + }; + + systemd.network.networks."10-lan" = { + matchConfig.PermanentMACAddress = "02:00:00:00:02:01"; + address = [ "${config.networkPrefix}.97.15/24" ]; + gateway = [ "${config.networkPrefix}.97.1" ]; + dns = [ "${config.networkPrefix}.97.1" ]; + }; + }; + }; +} From 91fabfe8575e98b16a55e0cbc5f2af1e6d63d2a3 Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sun, 1 Feb 2026 14:03:32 +0100 Subject: [PATCH 2/4] feat: dev fix mkcert and ddev reachability --- hosts/dev/channel | 1 + hosts/dev/configuration.nix | 50 ++++++++++++++++++++++++++++++--- hosts/dev/modules/dev-tools.nix | 21 ++++++++++++-- hosts/dev/utils | 1 + 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 hosts/dev/channel create mode 120000 hosts/dev/utils diff --git a/hosts/dev/channel b/hosts/dev/channel new file mode 100644 index 0000000..57f31e7 --- /dev/null +++ b/hosts/dev/channel @@ -0,0 +1 @@ +https://channels.nixos.org/nixos-25.11 diff --git a/hosts/dev/configuration.nix b/hosts/dev/configuration.nix index 19d5363..bca1d31 100644 --- a/hosts/dev/configuration.nix +++ b/hosts/dev/configuration.nix @@ -1,17 +1,17 @@ { config, lib, pkgs, ... }: let - # === CONFIGURABLE SETTINGS === projectsDir = "projects"; # Relative to /home/dominik repositories = [ - { url = "gitea@git.cloonar.com:Cloonar/wohnservice-wien-typo3.git"; path = "projects/cloonar/wohnservice-wien"} + { url = "gitea@git.cloonar.com:Cloonar/wohnservice-wien-typo3.git"; path = "cloonar/wohnservice-wien"; } # Add repos here: { url = "git@..."; path = "relative/path"; } ]; - # === END CONFIGURABLE === cloneScript = pkgs.writeShellScript "clone-repos" '' set -eu + export PATH="${pkgs.openssh}/bin:$PATH" + export GIT_SSH_COMMAND="${pkgs.openssh}/bin/ssh" HOME_DIR="/home/dominik" PROJECTS_DIR="$HOME_DIR/${projectsDir}" @@ -20,7 +20,7 @@ let ${lib.concatMapStrings (repo: '' if [ ! -d "$PROJECTS_DIR/${repo.path}" ]; then - ${pkgs.sudo}/bin/sudo -u dominik ${pkgs.git}/bin/git clone ${repo.url} "$PROJECTS_DIR/${repo.path}" || true + ${pkgs.sudo}/bin/sudo -u dominik -E ${pkgs.git}/bin/git clone ${repo.url} "$PROJECTS_DIR/${repo.path}" || true fi '') repositories} ''; @@ -31,12 +31,17 @@ in ]; networking.hostName = "dev"; + networking.firewall = { + enable = true; + allowedTCPPorts = [ 22 80 443 ]; + }; system.stateVersion = "22.05"; time.timeZone = "Europe/Vienna"; # User configuration users.users.dominik = { isNormalUser = true; + uid = 1000; home = "/home/dominik"; extraGroups = [ "wheel" "docker" ]; openssh.authorizedKeys.keys = [ @@ -50,6 +55,22 @@ in programs.zsh.enable = true; users.defaultUserShell = pkgs.zsh; + # Auto-attach to tmux on SSH login + environment.interactiveShellInit = '' + if [[ -n "$SSH_CONNECTION" ]] && [[ -z "$TMUX" ]]; then + tmux attach-session -t main 2>/dev/null || tmux new-session -s main + fi + ''; + + # Passwordless sudo for dominik + security.sudo.extraRules = [{ + users = [ "dominik" ]; + commands = [{ + command = "ALL"; + options = [ "NOPASSWD" ]; + }]; + }]; + # Clone repos as dominik user on boot systemd.services.clone-repos = { description = "Clone configured git repositories"; @@ -62,4 +83,25 @@ in RemainAfterExit = true; }; }; + + # Create ddev global config to bind on all interfaces (allows access from other devices) + systemd.services.ddev-config = { + description = "Create ddev global config"; + after = [ "local-fs.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "dominik"; + Group = "users"; + }; + script = '' + mkdir -p /home/dominik/.ddev + if [ ! -f /home/dominik/.ddev/global_config.yaml ]; then + cat > /home/dominik/.ddev/global_config.yaml << 'EOF' +router_bind_all_interfaces: true +EOF + fi + ''; + }; } diff --git a/hosts/dev/modules/dev-tools.nix b/hosts/dev/modules/dev-tools.nix index 27e0bf8..fb3fc2e 100644 --- a/hosts/dev/modules/dev-tools.nix +++ b/hosts/dev/modules/dev-tools.nix @@ -1,7 +1,7 @@ { pkgs, ... }: { nixpkgs.overlays = [ - (import ../../utils/overlays/packages.nix) + (import ../utils/overlays/packages.nix) ]; environment.systemPackages = with pkgs; [ @@ -10,6 +10,8 @@ docker-compose git git-lfs + mkcert + screen # PHP php @@ -27,9 +29,24 @@ wget curl htop - tmux ]; + # Persistent SSH sessions with tmux + programs.tmux = { + enable = true; + clock24 = true; + historyLimit = 50000; + terminal = "screen-256color"; + extraConfig = '' + # Enable mouse support + set -g mouse on + + # Start windows and panes at 1, not 0 + set -g base-index 1 + setw -g pane-base-index 1 + ''; + }; + # Docker for ddev virtualisation.docker.enable = true; users.users.dominik.extraGroups = [ "docker" ]; diff --git a/hosts/dev/utils b/hosts/dev/utils new file mode 120000 index 0000000..6b18391 --- /dev/null +++ b/hosts/dev/utils @@ -0,0 +1 @@ +../../utils \ No newline at end of file From cb67ba33ac4a6dbc306ffba7be5303455d314ce9 Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sun, 1 Feb 2026 14:06:46 +0100 Subject: [PATCH 3/4] feat: fw changes for dev server --- hosts/fw/configuration.nix | 2 + hosts/fw/modules/dev-microvm.nix | 16 +- hosts/fw/modules/dnsmasq.nix | 2 + hosts/fw/modules/unbound.nix | 349 ------------------------------- 4 files changed, 18 insertions(+), 351 deletions(-) delete mode 100644 hosts/fw/modules/unbound.nix diff --git a/hosts/fw/configuration.nix b/hosts/fw/configuration.nix index f41b36c..0c7af8d 100644 --- a/hosts/fw/configuration.nix +++ b/hosts/fw/configuration.nix @@ -34,6 +34,7 @@ ./modules/microvm.nix ./modules/gitea-vm.nix ./modules/forgejo-runner.nix + ./modules/dev-microvm.nix # ./modules/vscode-server.nix # Add VS Code Server microvm ./modules/ai-mailer.nix @@ -94,6 +95,7 @@ "mongodb" "ai-mailer" "filebot" + "claude-code" ]; # Intel N100 Graphics Support for hardware transcoding diff --git a/hosts/fw/modules/dev-microvm.nix b/hosts/fw/modules/dev-microvm.nix index 965141e..56c49a7 100644 --- a/hosts/fw/modules/dev-microvm.nix +++ b/hosts/fw/modules/dev-microvm.nix @@ -3,7 +3,19 @@ let hostname = "dev"; in { + # Create persist directories on the host + # UID 1000 = dominik user inside the microvm + systemd.tmpfiles.rules = [ + "d /var/lib/microvm-persist 0755 root root -" + "d /var/lib/microvm-persist/dev 0755 root root -" + "d /var/lib/microvm-persist/dev/home 0755 root root -" + "d /var/lib/microvm-persist/dev/home/dominik 0700 1000 100 -" + ]; + microvm.vms.dev = { + # Use host's pkgs which already has overlays applied + inherit pkgs; + config = { imports = [ ../dev/configuration.nix @@ -24,13 +36,13 @@ in proto = "virtiofs"; } { - source = "/var/lib/microvms/persist/dev"; + source = "/var/lib/microvm-persist/dev"; mountPoint = "/persist"; tag = "persist"; proto = "virtiofs"; } { - source = "/var/lib/microvms/persist/dev/home"; + source = "/var/lib/microvm-persist/dev/home"; mountPoint = "/home"; tag = "home"; proto = "virtiofs"; diff --git a/hosts/fw/modules/dnsmasq.nix b/hosts/fw/modules/dnsmasq.nix index f1e0e79..768f255 100644 --- a/hosts/fw/modules/dnsmasq.nix +++ b/hosts/fw/modules/dnsmasq.nix @@ -97,6 +97,8 @@ "/invidious.cloonar.com/${config.networkPrefix}.97.5" "/fivefilters.cloonar.com/${config.networkPrefix}.97.5" "/n8n.cloonar.com/${config.networkPrefix}.97.5" + "/dev.cloonar.com/${config.networkPrefix}.97.15" + "/.ddev.site/${config.networkPrefix}.97.15" # Wildcard for ddev projects "/home-assistant.cloonar.com/${config.networkPrefix}.97.20" "/mopidy.cloonar.com/${config.networkPrefix}.97.21" "/snapcast.cloonar.com/${config.networkPrefix}.97.21" diff --git a/hosts/fw/modules/unbound.nix b/hosts/fw/modules/unbound.nix deleted file mode 100644 index c5f21c5..0000000 --- a/hosts/fw/modules/unbound.nix +++ /dev/null @@ -1,349 +0,0 @@ -{ config, pkgs, ... }: -let - cids = import ../modules/staticids.nix; - domain = "ns.cloonar.com"; - - adblockLocalZones = pkgs.stdenv.mkDerivation { - name = "unbound-zones-adblock"; - - src = (pkgs.fetchFromGitHub { - owner = "StevenBlack"; - repo = "hosts"; - rev = "3.0.0"; - sha256 = "01g6pc9s1ah2w1cbf6bvi424762hkbpbgja9585a0w99cq0n6bxv"; - } + "/hosts"); - - phases = [ "installPhase" ]; - - installPhase = '' - ${pkgs.gawk}/bin/awk '{sub(/\r$/,"")} {sub(/^127\.0\.0\.1/,"0.0.0.0")} BEGIN { OFS = "" } NF == 2 && $1 == "0.0.0.0" { print "local-zone: \"", $2, "\" static"}' $src | tr '[:upper:]' '[:lower:]' | sort -u > $out - ''; - - }; - cfg = { - remote-control.control-enable = true; - server = { - # include = [ - # "\"${adblockLocalZones}\"" - # ]; - interface = [ "0.0.0.0" "::0" ]; - interface-automatic = "yes"; - access-control = [ - "127.0.0.0/8 allow" - "${config.networkPrefix}.96.0/24 allow" - "${config.networkPrefix}.97.0/24 allow" - "${config.networkPrefix}.98.0/24 allow" - "${config.networkPrefix}.99.0/24 allow" - "${config.networkPrefix}.101.0/24 allow" - "0.0.0.0/0 allow" - ]; - tls-cert-bundle = "/etc/ssl/certs/ca-certificates.crt"; - local-zone = "\"cloonar.com\" transparent"; - local-data = [ - "\"localhost A 127.0.0.1\"" - "\"localhost.cloonar.com A 127.0.0.1\"" - "\"localhost AAAA ::1\"" - "\"localhost.cloonar.com AAAA ::1\"" - "\"fw.cloonar.com A ${config.networkPrefix}.97.1\"" - "\"fw A ${config.networkPrefix}.97.1\"" - - "\"www.7-zip.org A 49.12.202.237\"" - - "\"pc.cloonar.com IN A ${config.networkPrefix}.96.5\"" - "\"omada.cloonar.com IN A ${config.networkPrefix}.97.2\"" - "\"switch.cloonar.com IN A ${config.networkPrefix}.97.10\"" - "\"mopidy.cloonar.com IN A ${config.networkPrefix}.97.21\"" - "\"deconz.cloonar.com IN A ${config.networkPrefix}.97.22\"" - "\"wazuh-manager.cloonar.com IN A ${config.networkPrefix}.97.31\"" - "\"wazuh-indexer.cloonar.com IN A ${config.networkPrefix}.97.32\"" - "\"wazuh.cloonar.com IN A ${config.networkPrefix}.97.33\"" - "\"brn30055c566237.cloonar.com IN A ${config.networkPrefix}.96.100\"" - "\"snapcast.cloonar.com IN A ${config.networkPrefix}.97.21\"" - "\"home-assistant.cloonar.com IN A ${config.networkPrefix}.97.20\"" - "\"web-02.cloonar.com IN A ${config.networkPrefix}.97.5\"" - "\"matrix.cloonar.com IN A ${config.networkPrefix}.97.5\"" - "\"element.cloonar.com IN A ${config.networkPrefix}.97.5\"" - "\"support.cloonar.com IN A ${config.networkPrefix}.97.5\"" - "\"tinder.cloonar.com IN A ${config.networkPrefix}.97.5\"" - "\"git.cloonar.com IN A ${config.networkPrefix}.97.50\"" - "\"sync.cloonar.com IN A ${config.networkPrefix}.97.51\"" - - "\"feeds.cloonar.com IN A 188.34.191.144\"" - # "\"paraclub.cloonar.dev IN A 49.12.244.139\"" - # "\"api.paraclub.cloonar.dev IN A 49.12.244.139\"" - # "\"module.paraclub.cloonar.dev IN A 49.12.244.139\"" - # "\"tandem.paraclub.cloonar.dev IN A 49.12.244.139\"" - - "\"stage.wsw.at IN A 10.254.235.22\"" - "\"prod.wsw.at IN A 10.254.217.23\"" - "\"piwik.wohnservice-wien.at IN A 10.254.240.109\"" - "\"wohnservice-wien.at IN A 10.254.240.109\"" - "\"mieterhilfe.at IN A 10.254.240.109\"" - "\"wohnpartner-wien.at IN A 10.254.240.109\"" - "\"new.wohnberatung-wien.at IN A 10.254.240.109\"" - "\"new.wohnpartner-wien.at IN A 10.254.240.109\"" - "\"wohnberatung-wien.at IN A 10.254.240.109\"" - "\"wienbautvor.at IN A 10.254.240.109\"" - "\"wienwohntbesser.at IN A 10.254.240.109\"" - "\"b.wohnservice-wien.at IN A 10.254.240.109\"" - "\"b.mieterhilfe.at IN A 10.254.240.109\"" - "\"b.wohnpartner-wien.at IN A 10.254.240.109\"" - "\"b.wohnberatung-wien.at IN A 10.254.240.109\"" - "\"b.wienbautvor.at IN A 10.254.240.109\"" - "\"b.wienwohntbesser.at IN A 10.254.240.109\"" - "\"a.wohnservice-wien.at IN A 10.254.240.109\"" - "\"a.wohnpartner-wien.at IN A 10.254.240.109\"" - "\"a.stage.wohnservice-wien.at IN A 10.254.240.110\"" - "\"a.stage.mieterhilfe.at IN A 10.254.240.110\"" - "\"a.stage.wohnpartner-wien.at IN A 10.254.240.110\"" - "\"a.stage.wohnberatung-wien.at IN A 10.254.240.110\"" - "\"a.stage.wienbautvor.at IN A 10.254.240.110\"" - "\"a.stage.wienwohntbesser.at IN A 10.254.240.110\"" - "\"b.stage.wohnservice-wien.at IN A 10.254.240.110\"" - "\"b.stage.mieterhilfe.at IN A 10.254.240.110\"" - "\"b.stage.wohnpartner-wien.at IN A 10.254.240.110\"" - "\"b.stage.new.wohnberatung-wien.at IN A 10.254.240.110\"" - "\"b.stage.new.wohnpartner-wien.at IN A 10.254.240.110\"" - "\"b.stage.wohnberatung-wien.at IN A 10.254.240.110\"" - "\"b.stage.wienbautvor.at IN A 10.254.240.110\"" - "\"b.stage.wienwohntbesser.at IN A 10.254.240.110\"" - "\"upgrade-staging.wohnservice-wien.at IN A 10.254.240.110\"" - "\"upgrade-staging.mieterhilfe.at IN A 10.254.240.110\"" - "\"upgrade-staging.wohnpartner-wien.at IN A 10.254.240.110\"" - "\"upgrade-staging.wohnberatung-wien.at IN A 10.254.240.110\"" - "\"upgrade-staging.wienbautvor.at IN A 10.254.240.110\"" - "\"upgrade-staging.wienwohntbesser.at IN A 10.254.240.110\"" - "\"conf.wrwks.at IN A 10.254.240.105\"" - - "\"web.hilgenberg-gmbh.de IN A 91.107.197.169\"" - "\"web.lenaschilling.at IN A 159.69.3.18\"" - - # gaming - "\"foundry-vtt.cloonar.com IN A ${config.networkPrefix}.97.5\"" - - "\"deconz.cloonar.multimedia IN A ${config.networkPrefix}.97.22\"" - "\"metz.cloonar.multimedia IN A ${config.networkPrefix}.99.10\"" - # "\"ps5.cloonar.multimedia IN A ${config.networkPrefix}.99.12\"" - "\"xbox.cloonar.multimedia IN A ${config.networkPrefix}.99.13\"" - # "\"switch.cloonar.multimedia IN A ${config.networkPrefix}.99.14\"" - #living room - "\"shellyuni-livingroom-1.cloonar.smart IN A ${config.networkPrefix}.100.8\"" - "\"shellyswitch25-livingroom-1.cloonar.smart IN A ${config.networkPrefix}.100.9\"" - "\"shellyplug-s-living-1.cloonar.smart IN A ${config.networkPrefix}.100.10\"" - "\"shellyplug-s-living-2.cloonar.smart IN A ${config.networkPrefix}.100.11\"" - # kitchen - "\"shellyplug-s-kitchen-1.cloonar.smart IN A ${config.networkPrefix}.100.17\"" - "\"shellyrgbw2-kitchen-1.cloonar.smart IN A ${config.networkPrefix}.100.18\"" - #bedroom - "\"shelly1-bedroom-1.cloonar.smart IN A ${config.networkPrefix}.100.33\"" - "\"shellybutton1-bedroom-1.cloonar.smart IN A ${config.networkPrefix}.100.34\"" - "\"shellybutton1-bedroom-2.cloonar.smart IN A ${config.networkPrefix}.100.35\"" # todo - "\"shellyrgbw2-bedroom-1.cloonar.smart IN A ${config.networkPrefix}.100.36\"" - "\"shellyrgbw2-bedroom-2.cloonar.smart IN A ${config.networkPrefix}.100.37\"" - "\"shellyrgbw2-bedroom-3.cloonar.smart IN A ${config.networkPrefix}.100.38\"" - # bath - "\"shellyswitch25-bath-1.cloonar.smart IN A ${config.networkPrefix}.100.49\"" - "\"shelly1pm-bath-1.cloonar.smart IN A ${config.networkPrefix}.100.52\"" - "\"shellyht-bath-1.cloonar.smart IN A ${config.networkPrefix}.100.53\"" # todo - # hallway - "\"shelly1-hallway-1.cloonar.smart IN A ${config.networkPrefix}.100.65\"" - "\"shellyem3.cloonar.smart IN A ${config.networkPrefix}.100.70\"" - "\"shellypro-1.cloonar.smart IN A ${config.networkPrefix}.100.71\"" - "\"shellypro-2.cloonar.smart IN A ${config.networkPrefix}.100.72\"" - # toilet - "\"shelly1-toilet-1.cloonar.smart IN A ${config.networkPrefix}.100.81\"" - "\"shellybulbduo-toilet-1.cloonar.smart IN A ${config.networkPrefix}.100.82\"" - # storage - "\"shelly1-storage-1.cloonar.smart IN A ${config.networkPrefix}.100.97\"" - "\"shellyplug-storage-1.cloonar.smart IN A ${config.networkPrefix}.100.98\"" - "\"brn30055c566237.cloonar.multimedia IN A ${config.networkPrefix}.99.100\"" - - "\"ddl-warez.to IN A 172.67.184.30\"" - "\"cdnjs.cloudflare.com IN A 104.17.24.14\"" - ]; - local-data-ptr = [ - "\"127.0.0.1 localhost\"" - "\"::1 localhost\"" - "\"${config.networkPrefix}.97.1 fw.cloonar.com\"" - "\"${config.networkPrefix}.97.20 home-assistant.cloonar.com\"" - "\"${config.networkPrefix}.97.21 snapcast.cloonar.com\"" - "\"${config.networkPrefix}.97.22 deconz.cloonar.com\"" - "\"${config.networkPrefix}.97.50 git.cloonar.com\"" - - "\"10.254.235.22 stage.wsw.at\"" - "\"10.254.217.23 prod.wsw.at\"" - "\"10.254.240.109 wohnservice-wien.at\"" - "\"10.254.240.110 a.stage.wohnservice-wien.at\"" - - "\"172.67.184.30 ddl-warez.to\"" - "\"104.17.24.14 cdnjs.cloudflare.com\"" - ]; - # ssl-upstream = "yes"; - }; - forward-zone = [ - { - name = "local.ghetto.at."; - forward-tls-upstream = "no"; - forward-addr = [ - "10.43.97.1" - ]; - } - { - name = "ghetto.at.local."; - forward-tls-upstream = "no"; - forward-addr = [ - "10.43.97.1" - ]; - } - { - name = "epicenter.works."; - forward-tls-upstream = "no"; - forward-addr = [ - "10.50.60.1" - ]; - } - { - name = "akvorrat.at."; - forward-tls-upstream = "no"; - forward-addr = [ - "10.50.60.1" - ]; - } - { - name = "epicenter.intra."; - forward-tls-upstream = "no"; - forward-addr = [ - "10.14.1.1" - ]; - } - { - name = "intra.epicenter.works."; - forward-tls-upstream = "no"; - forward-addr = [ - "10.14.1.1" - ]; - } - { - name = "."; - forward-tls-upstream = "yes"; - forward-first = "no"; - forward-addr = [ - "9.9.9.9@853#dns9.quad9.net" - "149.112.112.11@853#dns11.quad9.net" - ]; - } - ]; - }; -in { - users.users.unbound = { - group = "unbound"; - isSystemUser = true; - uid = cids.uids.unbound; - }; - users.groups.unbound = { - gid = cids.gids.unbound; - }; - - security.acme.certs."${domain}" = { - group = "unbound"; - }; - security.acme.certs."fw.cloonar.com" = { - group = "unbound"; - }; - - services.resolved.enable = false; - - services.unbound = { - enable = true; - settings = cfg; - }; - systemd.services.unbound-sync = { - enable = true; - path = with pkgs; [ unbound inotify-tools ]; - script = '' - #!/usr/bin/env bash - set -euo pipefail - - # readFile and readFileUnique as before… - function readFile() { - if [[ "''\$2" == "A" ]] ; then - cat "''\$1" | tail -n +2 | while IFS=, read -r address hwaddr client_id valid_lifetime expire subnet_id fqdn_fwd fqdn_rev hostname state user_context - do - echo "''\${address},''\${hostname}" - done - else - cat "''\$1" | tail -n +2 | while IFS=, read -r address duid valid_lifetime expire subnet_id pref_lifetime lease_type iaid prefix_len fqdn_fwd fqdn_rev hostname hwaddr state user_context hwtype hwaddr_source - do - echo "''\${address},''\${hostname}" - done - fi - } - - function readFileUnique() { - readFile "''\$1" ''\$2 | uniq | while IFS=, read -r address hostname - do - if echo "''\${1}" | grep -Eq '.*\.(cloonar.com|cloonar.multimedia|cloonar.smart)'; then - echo ''\${hostname} ''\$2 ''\${address} - unbound-control local_data ''\${hostname} ''\$2 ''\${address} > /dev/null 2>&1 - if [[ "''\$2" == "A" ]] ; then - echo ''\${address} | while IFS=. read -r ip0 ip1 ip2 ip3 - do - unbound-control local_data ''\${ip3}.''\${ip2}.''\${ip1}.''\${ip0}.ip4.arpa. PTR ''\${hostname} > /dev/null 2>&1 - unbound-control local_data ''\${ip3}.''\${ip2}.''\${ip1}.''\${ip0}.in-addr.arpa. PTR ''\${hostname} > /dev/null 2>&1 - done - fi - else - if [[ "''\$2" == "A" ]] ; then - echo ''\${address} | while IFS=. read -r ip0 ip1 ip2 ip3 - do - if [[ "''\${hostname}" != "" ]]; then - domain=cloonar.com - if [[ "''\${ip2}" == 99 ]]; then - domain=cloonar.multimedia - fi - if [[ "''\${ip2}" == 100 ]]; then - domain=cloonar.smart - fi - if [[ "''\${hostname}" != *. ]]; then - unbound-control local_data ''\${hostname}.''\${domain} ''\$2 ''\${address} > /dev/null 2>&1 - else - unbound-control local_data ''\${hostname}''\${domain} ''\$2 ''\${address} > /dev/null 2>&1 - fi - - fi - unbound-control local_data ''\${ip3}.''\${ip2}.''\${ip1}.''\${ip0}.ip4.arpa. PTR ''\${hostname} > /dev/null 2>&1 - unbound-control local_data ''\${ip3}.''\${ip2}.''\${ip1}.''\${ip0}.in-addr.arpa. PTR ''\${hostname} > /dev/null 2>&1 - done - fi - fi - done - } - - function syncLeases() { - # 1) nuke all of our old lease records from unbound - unbound-control list_local_data \ - | grep -E 'cloonar\.(com|multimedia|smart)|ip4\.arpa|in-addr\.arpa' \ - | while read -r name type data; do - unbound-control local_data_remove "$name" "$type" "$data" \ - > /dev/null 2>&1 - done - - # 2) re-push every current lease - readFileUnique "/var/lib/kea/dhcp4.leases" A - # if you need IPv6: - # readFileUnique "/var/lib/kea/dhcp6.leases" AAAA - } - - while true; do - syncLeases - sleep 10 - done - ''; - wants = [ "network-online.target" "unbound.service" ]; - after = [ "network-online.target" "unbound.service" ]; - partOf = [ "unbound.service" ]; - wantedBy = [ "multi-user.target" ]; - }; - - networking.firewall.allowedUDPPorts = [ 53 5353 ]; -} From 25580ded3bbb9ff805e036fb32b62d2205570315 Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sun, 1 Feb 2026 14:23:27 +0100 Subject: [PATCH 4/4] feat: nb change networking and add projects --- hosts/nb/configuration.nix | 31 +------------ hosts/nb/modules/networking.nix | 63 ++++++++++++++++++++++++++ hosts/nb/users/configs/project_history | 3 ++ hosts/nb/users/dominik.nix | 2 + 4 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 hosts/nb/modules/networking.nix diff --git a/hosts/nb/configuration.nix b/hosts/nb/configuration.nix index 8b20710..57ba254 100644 --- a/hosts/nb/configuration.nix +++ b/hosts/nb/configuration.nix @@ -40,6 +40,7 @@ in { # ./modules/steam.nix ./modules/fingerprint.nix ./modules/set-nix-channel.nix + ./modules/networking.nix ./hardware-configuration.nix ]; @@ -249,36 +250,6 @@ in { }; }; - networking.wireguard.interfaces = { - wg0 = { - ips = [ "10.42.98.201/32" ]; - # publicKey: YdlRGsjh4hS3OMJI+t6SZ2eGXKbs0wZBXWudHW4NyS8= - privateKeyFile = config.sops.secrets.wg-cloonar-key.path; - - peers = [ - { - publicKey = "TKQVDmBnf9av46kQxLQSBDhAeaK8r1zh8zpU64zuc1Q="; - allowedIPs = [ - "10.42.96.0/20" - # wohnservice-wien - "10.254.240.0/24" - "10.254.235.0/24" - # epicenter.works - "10.14.0.0/16" - "10.25.0.0/16" - "188.34.191.144/32" # web-arm - "91.107.201.241" # mail - ]; - endpoint = "vpn.cloonar.com:51820"; # ToDo: route to endpoint not automatically configured https://wiki.archlinux.org/index.php/WireGuard#Loop_routing https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577 - persistentKeepalive = 25; - } - ]; - postSetup = '' - printf "nameserver 10.42.97.1\nsearch cloonar.com" | ${pkgs.openresolv}/bin/resolvconf -a wg0 -m 0 -x - ''; - }; - }; - # pgp services.pcscd.enable = true; programs.gnupg.agent = { diff --git a/hosts/nb/modules/networking.nix b/hosts/nb/modules/networking.nix new file mode 100644 index 0000000..0bf1995 --- /dev/null +++ b/hosts/nb/modules/networking.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +{ + # Enable systemd-resolved with split DNS for ddev.site + services.resolved = { + enable = true; + dnssec = "false"; + extraConfig = '' + DNS=127.0.0.1:5353 + Domains=~ddev.site + ''; + }; + + # Integrate NetworkManager with systemd-resolved + networking.networkmanager.dns = "systemd-resolved"; + + # Local dnsmasq for .ddev.site resolution only (port 5353) + services.dnsmasq = { + enable = true; + settings = { + port = 5353; + listen-address = "127.0.0.1"; + bind-interfaces = true; + no-resolv = true; + address = "/.ddev.site/127.0.0.1"; + }; + }; + + # WireGuard VPN configuration + networking.wireguard.interfaces = { + wg0 = { + ips = [ "10.42.98.201/32" ]; + # publicKey: YdlRGsjh4hS3OMJI+t6SZ2eGXKbs0wZBXWudHW4NyS8= + privateKeyFile = config.sops.secrets.wg-cloonar-key.path; + + peers = [ + { + publicKey = "TKQVDmBnf9av46kQxLQSBDhAeaK8r1zh8zpU64zuc1Q="; + allowedIPs = [ + "10.42.96.0/20" + # wohnservice-wien + "10.254.240.0/24" + "10.254.235.0/24" + # epicenter.works + "10.14.0.0/16" + "10.25.0.0/16" + "188.34.191.144/32" # web-arm + "91.107.201.241" # mail + ]; + endpoint = "vpn.cloonar.com:51820"; # ToDo: route to endpoint not automatically configured https://wiki.archlinux.org/index.php/WireGuard#Loop_routing https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577 + persistentKeepalive = 25; + } + ]; + + # Use resolvectl for systemd-resolved integration + # Note: No postDown needed - systemd-resolved automatically handles interface removal + postSetup = '' + ${pkgs.systemd}/bin/resolvectl dns wg0 10.42.97.1 + ${pkgs.systemd}/bin/resolvectl domain wg0 cloonar.com + ''; + }; + }; +} diff --git a/hosts/nb/users/configs/project_history b/hosts/nb/users/configs/project_history index b38e27f..ec0ad0b 100644 --- a/hosts/nb/users/configs/project_history +++ b/hosts/nb/users/configs/project_history @@ -1,3 +1,6 @@ +/home/dominik/projects/infrastructure/actions +/home/dominik/projects/infrastructure/forgejo-mcp + /home/dominik/projects/cloonar/chatgpt.vim /home/dominik/projects/cloonar/ai.nvim /home/dominik/projects/cloonar/gitea.nvim diff --git a/hosts/nb/users/dominik.nix b/hosts/nb/users/dominik.nix index b9fc281..34c0b2d 100644 --- a/hosts/nb/users/dominik.nix +++ b/hosts/nb/users/dominik.nix @@ -620,6 +620,8 @@ in git clone gitea@git.cloonar.com:ScanA11y/sa-core.git ${persistHome}/projects/scana11y/sa-core 2>/dev/null git clone gitea@git.cloonar.com:Cloonar/ai-image-alt.git ${persistHome}/projects/cloonar/ai-image-alt 2>/dev/null git clone gitea@git.cloonar.com:Cloonar/bookmap.git ${persistHome}/projects/cloonar/bookmap 2>/dev/null + git clone gitea@git.cloonar.com:infrastructure/actions.git ${persistHome}/projects/infrastructure/actions 2>/dev/null + git clone ssh://git@codeberg.org/razormind/forgejo-mcp.git ${persistHome}/projects/infrastructure/forgejo-mcp 2>/dev/null git clone gitea@git.cloonar.com:dominik.polakovics/typo3-basic.git ${persistHome}/cloonar/typo3-basic 2>/dev/null