From a24fd5bd93254fb82de05c0de4905a55198f1fd9 Mon Sep 17 00:00:00 2001 From: Luka Dekanozishvili Date: Sat, 31 Jan 2026 14:28:52 +0100 Subject: [PATCH] feat: deployed frontend, postgres, rev-proxy, tailscale config, initialisation scripts --- configuration.nix | 2 + flake.lock | 132 ++++++++++++++++-- flake.nix | 22 +-- pkgs/backend.nix | 1 + pkgs/extra.nix | 2 +- pkgs/frontend.nix | 42 ++++++ pkgs/postgres.nix | 55 +++++--- pkgs/powerdns.nix | 106 ++++++-------- pkgs/reverse-proxy.nix | 33 +++++ pkgs/{server-ssh.nix => ssh.nix} | 9 +- pkgs/stalwart.nix | 53 ++----- pkgs/tailscale.nix | 12 +- pkgs/virtualisation.nix | 5 - scripts/deploy-frontend.sh | 10 ++ scripts/pdns-init-config-dns.sh | 96 +++++++++++++ .../virtualisation/restart-netbird-relay.nix | 18 --- scripts/zfs-healthcheck/service.nix | 38 ----- scripts/zfs-healthcheck/uptime-kuma.sh | 29 ---- .../restart-powerdns.nix | 8 +- .../update-containers.nix | 2 +- 20 files changed, 413 insertions(+), 262 deletions(-) create mode 100644 pkgs/frontend.nix create mode 100644 pkgs/reverse-proxy.nix rename pkgs/{server-ssh.nix => ssh.nix} (69%) create mode 100755 scripts/deploy-frontend.sh create mode 100755 scripts/pdns-init-config-dns.sh delete mode 100644 scripts/virtualisation/restart-netbird-relay.nix delete mode 100755 scripts/zfs-healthcheck/service.nix delete mode 100755 scripts/zfs-healthcheck/uptime-kuma.sh rename scripts/virtualisation/restart-pihole.nix => services/restart-powerdns.nix (61%) rename {scripts/virtualisation => services}/update-containers.nix (94%) diff --git a/configuration.nix b/configuration.nix index 923792a..e81fcb2 100644 --- a/configuration.nix +++ b/configuration.nix @@ -9,6 +9,7 @@ environment.systemPackages = with pkgs; [ hexname-backend + deno ]; users.users = { @@ -21,6 +22,7 @@ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM/4F45h/xkq+MIRDzhHqDm5uWM4KTpYi3Tv/DtSo28t luka@gram" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF7OvW6MffYFshZyarEaWvWjEmhodn/P+NLcnqbbMpma luka@conway" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIT+vMzh2ngUeqnVJS8Zl1m1HQMBkDOqoGdoARPyJgDM u0_a380@localhost" # s + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmMXGO8HuFS9SRbIDRDGMVgyiR0hy7uL9VkL5BOcgkw luka@thinkway" # w ]; }; root = { diff --git a/flake.lock b/flake.lock index 9fd5f6b..fe700fe 100755 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,24 @@ { "nodes": { + "deno2nix": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1767824708, + "narHash": "sha256-UL8Jdh4UoBc25nyq9xkAMnqT1886DzymPbhI4/+/KUQ=", + "owner": "Makesesama", + "repo": "deno2nix", + "rev": "e1b0a16c6148991f3d9e902b68aa1cb532173b8a", + "type": "github" + }, + "original": { + "owner": "Makesesama", + "repo": "deno2nix", + "type": "github" + } + }, "fenix": { "inputs": { "nixpkgs": [ @@ -41,6 +60,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "hexname-backend": { "inputs": { "flake-utils": "flake-utils", @@ -48,11 +85,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1769444495, - "narHash": "sha256-8dC6d0XedjH+3YIxUb9PMzr1WhHzwxi5tsFLTkM0bss=", + "lastModified": 1769526729, + "narHash": "sha256-/ew2cd+lz9xOkTLsYZLqYKfnOoxqlAhpRR7jAqOUljc=", "ref": "refs/heads/main", - "rev": "5be98605494183210469cf5ad3be211dd0e3f18e", - "revCount": 20, + "rev": "59180721d3b95f28c17eff9e3a18e54b0a1fa588", + "revCount": 23, "type": "git", "url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git" }, @@ -61,6 +98,25 @@ "url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git" } }, + "hexname-frontend": { + "inputs": { + "deno2nix": "deno2nix", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1769709099, + "narHash": "sha256-Y5uALgdWMSRp8rqFFiv+iQCcs/HLoYvl0KxFaqNqlGE=", + "ref": "refs/heads/main", + "rev": "bbbb5e9f5ba8f5c18415b4ca5c03d57e45937095", + "revCount": 18, + "type": "git", + "url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Frontend.git" + }, + "original": { + "type": "git", + "url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Frontend.git" + } + }, "naersk": { "inputs": { "fenix": "fenix", @@ -85,11 +141,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1769330179, - "narHash": "sha256-yxgb4AmkVHY5OOBrC79Vv6EVd4QZEotqv+6jcvA212M=", + "lastModified": 1769527094, + "narHash": "sha256-xV20Alb7ZGN7qujnsi5lG1NckSUmpIb05H2Xar73TDc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "48698d12cc10555a4f3e3222d9c669b884a49dfe", + "rev": "afce96367b2e37fc29afb5543573cd49db3357b7", "type": "github" }, "original": { @@ -101,11 +157,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1769318308, - "narHash": "sha256-Mjx6p96Pkefks3+aA+72lu1xVehb6mv2yTUUqmSet6Q=", + "lastModified": 1769598131, + "narHash": "sha256-e7VO/kGLgRMbWtpBqdWl0uFg8Y2XWFMdz0uUJvlML8o=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1cd347bf3355fce6c64ab37d3967b4a2cb4b878c", + "rev": "fa83fd837f3098e3e678e6cf017b2b36102c7211", "type": "github" }, "original": { @@ -117,11 +173,43 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1769170682, - "narHash": "sha256-oMmN1lVQU0F0W2k6OI3bgdzp2YOHWYUAw79qzDSjenU=", + "lastModified": 1767767207, + "narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c5296fdd05cfa2c187990dd909864da9658df755", + "rev": "5912c1772a44e31bf1c63c0390b90501e5026886", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", "type": "github" }, "original": { @@ -134,7 +222,8 @@ "root": { "inputs": { "hexname-backend": "hexname-backend", - "nixpkgs": "nixpkgs_2", + "hexname-frontend": "hexname-frontend", + "nixpkgs": "nixpkgs_4", "nixpkgs-stable": "nixpkgs-stable" } }, @@ -169,6 +258,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index ae4c581..c21e61b 100755 --- a/flake.nix +++ b/flake.nix @@ -6,13 +6,14 @@ nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.11"; hexname-backend.url = "git+ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git"; + hexname-frontend.url = "git+ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Frontend.git"; }; - outputs = { nixpkgs, nixpkgs-stable, hexname-backend, ... } @ inputs: { + outputs = { nixpkgs, nixpkgs-stable, hexname-backend, hexname-frontend, ... } @ inputs: { nixosConfigurations = { hexname-ns1 = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; - specialArgs = { inherit inputs; inherit hexname-backend; }; + specialArgs = { inherit inputs hexname-backend hexname-frontend; }; modules = [ ######## Boilerplate ######## ./configuration.nix @@ -21,15 +22,18 @@ ./pkgs/extra.nix ######## HexName configuration ######## - ./pkgs/powerdns.nix + # ./pkgs/reverse-proxy.nix + ./pkgs/nginx.nix ./pkgs/backend.nix - # ./pkgs/postgres.nix + + ./pkgs/powerdns.nix + ./pkgs/postgres.nix ######## Networking ######## - ./pkgs/server-ssh.nix - ./pkgs/nginx.nix + ./pkgs/ssh.nix + ./pkgs/tailscale.nix ./pkgs/virtualisation.nix - # ./pkgs/stalwart.nix + ./pkgs/stalwart.nix ######## Sysadmin ######## ./pkgs/neovim.nix @@ -39,8 +43,8 @@ ######## etc. ######## ######## Scripts ######## - #./scripts/virtualisation/update-containers.nix # Runs podman pull weekly - #./scripts/virtualisation/restart-pihole.nix + ./services/update-containers.nix # Runs podman pull weekly + ./services/restart-powerdns.nix ]; }; }; diff --git a/pkgs/backend.nix b/pkgs/backend.nix index ed12b63..be74148 100644 --- a/pkgs/backend.nix +++ b/pkgs/backend.nix @@ -27,6 +27,7 @@ User = "hexname-backend"; Group = "hexname"; Type = "simple"; + Restart = "always"; ExecStart = "${pkgs.hexname-backend}/bin/dns-backend"; }; }; diff --git a/pkgs/extra.nix b/pkgs/extra.nix index afcc630..0c2ded6 100644 --- a/pkgs/extra.nix +++ b/pkgs/extra.nix @@ -44,7 +44,7 @@ gc = { automatic = true; - dates = "Mon *-*-* 16:00:00"; + dates = "Sat *-*-* 10:00:00"; options = "--delete-older-than 90d"; }; }; diff --git a/pkgs/frontend.nix b/pkgs/frontend.nix new file mode 100644 index 0000000..2f54998 --- /dev/null +++ b/pkgs/frontend.nix @@ -0,0 +1,42 @@ +{ pkgs, hexname-frontend, ... }: + +{ + nixpkgs.overlays = [ + (self: super: { + hexname-frontend = hexname-frontend.packages.${super.stdenv.hostPlatform.system}.default; + }) + ]; + + users.groups.hexname = {}; + users.users = { + hexname-frontend = { + group = "hexname"; + isSystemUser = true; + createHome = true; + home = "/var/lib/hexname/frontend"; + }; + }; + + systemd.services.hexname-frontend = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + ENV_PATH = "/etc/env/hexname/frontend.env"; + NODE_ENV = "production"; + }; + serviceConfig = { + User = "hexname-backend"; + Group = "hexname"; + Type = "simple"; + Restart = "always"; + # ExecStart = "${hexname-frontend.packages.${pkgs.system}.default}/bin/hexname-frontend"; + ExecStart = "env $(cat $ENV_PATH | xargs) ${pkgs.hexname-frontend}/bin/hexname-frontend"; + }; + # script = '' + # source /etc/env/hexname/frontend.env + # ${hexname-frontend.packages.${pkgs.system}.default}/bin/hexname-frontend + # ''; + }; +} + + diff --git a/pkgs/postgres.nix b/pkgs/postgres.nix index 3512758..84a8165 100644 --- a/pkgs/postgres.nix +++ b/pkgs/postgres.nix @@ -3,30 +3,49 @@ { services.postgresql = { enable = true; + settings = { + # Set hashing algorithm + password_encryption = "scram-sha-256"; - # settings = { - # listen_addresses = lib.mkForce "127.0.0.1,10.89.0.10"; - # }; + # Replication conf + wal_level = "logical"; + max_wal_senders = "5"; + max_replication_slots = "5"; + }; # Allow root to log in as postgres in the DB (for the PowerDNS container) - identMap = '' - postgres root postgres - ''; + # identMap = '' + # postgres root postgres + # ''; - authentication = lib.mkForce '' - # TYPE DATABASE USER ADDRESS AUTH-METHOD [auth-options] - host hexname-backend hexname-backend 127.0.0.1/24 scram-sha-256 - # host all powerdns-user 127.0.0.1/24 scram-sha-256 - # local all root trust - ''; - - ensureUsers = [ { name = "hexname-backend"; } ]; - # No need to define the DB since `diesel` creates everything + # authentication = lib.mkForce '' + # # TYPE DATABASE USER ADDRESS AUTH-METHOD [auth-options] + # # host hexname-backend hexname-backend 127.0.0.1/24 scram-sha-256 + # # host postgres postgres 127.0.0.1/24 scram-sha-256 + # host all all 127.0.0.1/24 scram-sha-256 + # # host all powerdns-user 127.0.0.1/24 scram-sha-256 + # # local all root trust + # ''; # This password is only the initial one - don't get too excited - initialScript = pkgs.writeText "set-initial-password-script" '' - alter user hexname-backend with password 'shuaze-gagyof'; - ''; + initialScript = "/etc/env/hexname/init-db-dns.sql"; + # initialScript = pkgs.writeText "set-initial-password-script" '' + # CREATE USER powerdns WITH PASSWORD 'shuaze-gagyof'; + # CREATE USER hexname_backend WITH PASSWORD 'shuaze-gagyof2' CREATEDB; + # CREATE USER replication_user SUPERUSER WITH PASSWORD 'shuaze-gagyof3'; + + # CREATE DATABASE powerdns OWNER "powerdns"; + # CREATE DATABASE hexname_backend OWNER "hexname-backend"; + # CREATE DATABASE hexname_backend OWNER "hexname-backend"; + + # \c powerdns; + # CREATE PUBLICATION powerdns_pub FOR ALL TABLES; + + # CREATE SUBSCRIPTION hexname_ns2 + # CONNECTION 'host=publisher_ip_address port=5432 user=replication_user password=' ' dbname=powerdns' + # PUBLICATION powerdns_pub; + # ''; + # ALTER USER "postgres" WITH PASSWORD 'shuaze-gagyof'; }; } diff --git a/pkgs/powerdns.nix b/pkgs/powerdns.nix index 41b6ab7..840f3a2 100644 --- a/pkgs/powerdns.nix +++ b/pkgs/powerdns.nix @@ -2,39 +2,17 @@ let domain = "hexname.com"; - dbIp = "10.89.0.25"; - pdnsIp = "10.89.0.53"; + # pdnsIp = "10.89.0.53"; in { virtualisation.oci-containers.containers = { - hexname-postgres = { - hostname = "pgsql"; - image = "postgres:18-alpine"; - ports = [ - "127.0.0.1:5432:5432" - ]; - volumes = [ - "pgsql:/var/lib/postgresql/data:Z" - "/etc/localtime:/etc/localtime:ro" - ]; - environment = { - POSTGRES_USER = "hexname-backend"; - POSTGRES_PASSWORD = "EZQVObWjoEM7bldX2wu5oyJkgBIMfoU8OZZf"; - }; - networks = [ "hexname-net" ]; - extraOptions = [ - "--dns=10.89.0.1" - "--ip=${dbIp}" - ]; - }; - hexname-powerdns = { image = "pschiffe/pdns-pgsql:latest"; hostname = "ns1.${domain}"; - ports = [ - "127.0.0.1:8081:8081/tcp" - ]; - networks = [ "hexname-net" ]; + # ports = [ + # "127.0.0.1:8081:8081/tcp" + # ]; + # networks = [ "hexname-net" ]; volumes = [ "/etc/localtime:/etc/localtime:ro" @@ -46,62 +24,60 @@ in PDNS_api = "yes"; PDNS_disable_axfr = "yes"; #PDNS_webserver = "yes"; - PDNS_webserver_address = "0.0.0.0"; + PDNS_webserver_address = "127.0.0.1"; PDNS_webserver_port = "8081"; - PDNS_local_address = "${pdnsIp}:53"; - PDNS_webserver_allow_from = "10.89.0.0/24"; + PDNS_local_address = "0.0.0.0:53"; + PDNS_webserver_allow_from = "127.0.0.1/24"; PDNS_version_string = "anonymous"; PDNS_default_ttl = "3600"; # PDNS_gpgsql_password=... # PDNS_api_key=... - # PDNS_gpgsql_host = "127.0.0.1"; - # PDNS_gpgsql_port = "5432"; - # PDNS_gpgsql_dbname = "powerdns"; - # PDNS_gpgsql_user = "postgres"; - # PDNS_gpgsql_password = "powerdns"; + PDNS_gpgsql_host = "127.0.0.1"; + PDNS_gpgsql_port = "5432"; + PDNS_gpgsql_dbname = "powerdns"; + PDNS_gpgsql_user = "powerdns"; + PDNS_gpgsql_dnssec = "yes"; }; extraOptions = [ - # "--network=host" - "--ip=${pdnsIp}" - "--add-host=pgsql:${dbIp}" + "--network=host" ]; - dependsOn = [ "hexname-postgres" ]; + # dependsOn = [ "hexname-postgres" ]; }; }; - systemd.services.podman-network-hexname = { - description = "Podman network for HexName/PowerDNS"; - after = [ "podman.service" ]; - wantedBy = [ "multi-user.target" "podman-hexname-postgres.target" "podman-hexname-powerdns.target" ]; - serviceConfig.Type = "oneshot"; - path = [ pkgs.podman ] ; - script = '' - podman network inspect hexname-net >/dev/null 2>&1 || \ - podman network create hexname-net --subnet 10.89.0.0/24 - ''; - }; + # systemd.services.podman-network-hexname = { + # description = "Podman network for HexName/PowerDNS"; + # after = [ "podman.service" ]; + # wantedBy = [ "multi-user.target" "podman-hexname-postgres.target" "podman-hexname-powerdns.target" ]; + # serviceConfig.Type = "oneshot"; + # path = [ pkgs.podman ] ; + # script = '' + # podman network inspect hexname-net >/dev/null 2>&1 || \ + # podman network create hexname-net --subnet 10.89.0.0/24 + # ''; + # }; # Bind port 53 and send all requests to the container - networking.nftables.enable = true; - networking.nftables.tables.dns = { - family = "inet"; - content = '' - chain prerouting { - type nat hook prerouting priority -100; + # networking.nftables.enable = true; + # networking.nftables.tables.dns = { + # family = "inet"; + # content = '' + # chain prerouting { + # type nat hook prerouting priority -100; - udp dport 53 dnat ip to ${pdnsIp}:53 - tcp dport 53 dnat ip to ${pdnsIp}:53 - } + # udp dport 53 dnat ip to ${pdnsIp}:53 + # tcp dport 53 dnat ip to ${pdnsIp}:53 + # } - chain postrouting { - type nat hook postrouting priority 100; - ip saddr 10.89.0.0/24 masquerade - } - ''; - }; + # chain postrouting { + # type nat hook postrouting priority 100; + # ip saddr 10.89.0.0/24 masquerade + # } + # ''; + # }; networking.firewall.allowedTCPPorts = [ 53 ]; networking.firewall.allowedUDPPorts = [ 53 ]; diff --git a/pkgs/reverse-proxy.nix b/pkgs/reverse-proxy.nix new file mode 100644 index 0000000..674f71d --- /dev/null +++ b/pkgs/reverse-proxy.nix @@ -0,0 +1,33 @@ +{ config, pkgs, lib, ... }: + +let + domain = "hexname.com"; +in +{ + services.nginx.virtualHosts = { + "${domain}" = { + forceSSL = true; + enableACME = true; + locations."/api" = { + proxyPass = "http://127.0.0.1:8080"; + proxyWebsockets = true; + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + # add_header Strict-Transport-Security 'max-age=300; includeSubDomains; preload; always;' + ''; + }; + locations."/" = { + root = "/var/www/hexname/build"; + tryFiles = "$uri $uri.html $uri/ /200.html"; + }; + }; + "www.${domain}" = { # Redirect www to root + forceSSL = true; + enableACME = true; + globalRedirect = domain; + }; + }; +} + diff --git a/pkgs/server-ssh.nix b/pkgs/ssh.nix similarity index 69% rename from pkgs/server-ssh.nix rename to pkgs/ssh.nix index 81318f2..ac8f7f8 100644 --- a/pkgs/server-ssh.nix +++ b/pkgs/ssh.nix @@ -8,7 +8,7 @@ settings = { PasswordAuthentication = false; AllowUsers = [ "luka" ]; - UseDns = false; # Disable checking of rDNS records to speed up login + UseDns = false; # Disable checking of rDNS records X11Forwarding = false; PermitRootLogin = "prohibit-password"; }; @@ -20,11 +20,6 @@ # ignoreIP = [ ]; }; - networking.firewall = { - enable = true; - - # allowedTCPPorts = [ ]; - # allowedUDPPorts = []; - }; + networking.firewall.enable = true; } diff --git a/pkgs/stalwart.nix b/pkgs/stalwart.nix index e652fac..2377bd4 100644 --- a/pkgs/stalwart.nix +++ b/pkgs/stalwart.nix @@ -2,7 +2,7 @@ let domain = "hexname.com"; - stalwartDomain = "mail.${domain}"; + stalwartDomain = "mx.${domain}"; roundcubeDomain = "email.${domain}"; dataDir = "/var/lib/stalwart-mail"; @@ -59,22 +59,22 @@ in principals = [ { name = "contact-us@${domain}"; - email = [ "contact-us@${domain}" "@${domain}" ]; - secret = "$6$E8AhTdIdgl2ag6/x$reYvoPByjvkPK/Uwm3/481BBBkuBKQxd3rgSgQw3PawJ4G8TOt0jlIXdOo5xuDv1DQAdn52lUAgx0U9GSVoc7/"; + email = [ "contact-us@${domain}" "privacy@${domain}" ]; + secret = "$6$iyUwAnKuGTz31jeu$QPfoaUQPccVDWjCWs4PY43dBI6oG4eNb7buNlGBlnNJrvQOePYKyF8RXN8FI5H6y2x191kOa4U8aDD4K/ssKn/"; class = "individual"; } { name = "no-reply@${domain}"; email = [ "no-reply@${domain}" ]; - secret = "$6$V/u1LImVZAyynuLO$l/mMaLWQ5t0jWz6XWNlHcha8nuTQbjQfES.Nj73mNS0xQjv3vu5z03fLMAt3hxAb5BwE3jgtfmh.PknBjM1M//"; + secret = "$6$FpTIF6mjoBRXyZAO$9lqf/u3NyJNHYNutFY0WmPkbfkq8J.SIkhzya3izl7AbCRE72TlyKeGx/OOyPuI1QTMV10NgOEGzL8jboOWhZ1"; class = "individual"; } ]; }; authentication.fallback-admin = { - user = "superdupermegaadmin"; - secret = "$6$LPDx0LFqtpAVJO2s$GPR/4Rguhmspy8OLLKI2oZxVgvWrlHRckd6WN2RZNMxkSN9YMiPJ/pfq.XD/VTKsqCu2GCnzerQOv5bivBCph."; + user = "unguessable-username"; + secret = "$6$1sRTqTbiXuGNE3zt$oLcXi.kPsy72W5SDMwWSitpJyKlZSKSzhr1QO3DBn6Q9LSE.YpWUbT2Thu5Kbs0bmTMvqAPFI7x/qa1wm9Bj91"; }; email.folders = let @@ -92,28 +92,6 @@ in trash = mkFolder "Trash"; }; - session.rcpt = { - catch-all = true; - script = "'reject-addresses'"; - }; - - sieve.trusted.scripts.reject-addresses.contents = '' - require ["envelope", "reject"]; - - if anyof ( - envelope :is "to" "no-reply@${domain}" - envelope :is "to" "info@${domain}", - envelope :is "to" "contact@${domain}", - envelope :is "to" "support@${domain}" - envelope :is "to" "marketing@${domain}", - envelope :is "to" "sales@${domain}" - ) { - reject "403 This address does not accept incoming mails."; - } - - redirect "contact-us@${domain}"; - ''; - # Change the DNS records manually to these addresses to # keep postmaster free for non-automated emails # https://github.com/stalwartlabs/mail-server/discussions/877 @@ -164,7 +142,7 @@ in storage.blob = "fs"; # We have DANE and don't want a certificate for each domain - # session.mta-sts.mode = "none"; + session.mta-sts.mode = "none"; certificate.default = { cert = "%{file:${credPath}/cert.pem}%"; @@ -249,24 +227,9 @@ in security.acme.certs.${stalwartDomain} = { # Keep a stable private key for TLSA records (DANE) # https://community.letsencrypt.org/t/please-avoid-3-0-1-and-3-0-2-dane-tlsa-records-with-le-certificates/7022/14 - # extraLegoRenewFlags = [ "--reuse-key" ]; + extraLegoRenewFlags = [ "--reuse-key" ]; # Restart Stalwart to apply new certificates reloadServices = [ "stalwart-mail.service" ]; }; - - # services.restic = { - # backupPrepareCommand = '' - # ${pkgs.coreutils}/bin/install -b -m 700 -d /tmp/stalwart-db-secondary /tmp/stalwart-db-backup - # ${lib.getExe' rocksdb.tools "ldb"} --db=${dataDir}/db --secondary_path=/tmp/stalwart-db-secondary backup --backup_dir=/tmp/stalwart-db-backup - # ''; - # backupCleanupCommand = '' - # rm -rf /tmp/stalwart-db-secondary - # rm -rf /tmp/stalwart-db-backup - # ''; - # paths = [ - # "/tmp/stalwart-db-backup" - # "${dataDir}/blobs" - # ]; - # }; } diff --git a/pkgs/tailscale.nix b/pkgs/tailscale.nix index 827a218..23425a7 100644 --- a/pkgs/tailscale.nix +++ b/pkgs/tailscale.nix @@ -1,23 +1,19 @@ { pkgs, ... }: { - environment.systemPackages = with pkgs; [ tailscale ]; - services.tailscale = { enable = true; openFirewall = true; - useRoutingFeatures = "both"; # Act as a client and a server (exit node) - - # extraSetFlags = [ - # "--advertise-exit-node" - # ]; + useRoutingFeatures = "client"; disableUpstreamLogging = true; disableTaildrop = true; }; + environment.systemPackages = with pkgs; [ tailscale ]; + # Enable IP forwarding for subnet routers - boot.kernel.sysctl."net.ipv4.ip_forward" = 1; + # boot.kernel.sysctl."net.ipv4.ip_forward" = 1; # TODO: this fixes MagicDNS but breaks DNS resolution on LAN (Pihole) # services.resolved.enable = true; diff --git a/pkgs/virtualisation.nix b/pkgs/virtualisation.nix index 8b82721..54eceb7 100644 --- a/pkgs/virtualisation.nix +++ b/pkgs/virtualisation.nix @@ -4,11 +4,6 @@ virtualisation.podman = { enable = true; - # Disable netavark - # defaultNetwork.settings = { - # dns_enabled = false; - # }; - # Auto-prune old containers autoPrune = { enable = true; diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh new file mode 100755 index 0000000..ca3c2e7 --- /dev/null +++ b/scripts/deploy-frontend.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd /home/luka/HexName-Frontend +git pull + +deno task build +sudo rm -rf /var/www/hexname/build +sudo cp -r build/ /var/www/hexname/ + diff --git a/scripts/pdns-init-config-dns.sh b/scripts/pdns-init-config-dns.sh new file mode 100755 index 0000000..1864e69 --- /dev/null +++ b/scripts/pdns-init-config-dns.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +set -euo pipefail + +API_URL="http://127.0.0.1:8081/api/v1/servers/localhost/zones/hexname.com." +API_KEY="${API_KEY:?API_KEY not set}" + +declare -A RRSETS + +add_record() { + local type="$1" + local ttl="$2" + local name="$3" + local content="$4" + + local key="${name}|${type}|${ttl}" + RRSETS["$key"]+="${content}"$'\n' +} + +flush_rrsets() { + local rrsets_json="[]" + + for key in "${!RRSETS[@]}"; do + IFS='|' read -r name type ttl <<<"$key" + + local records_json + records_json=$(printf '%s' "${RRSETS[$key]}" \ + | sed '/^$/d' \ + | jq -R '{content: ., disabled: false}' \ + | jq -s '.') + + rrsets_json=$(jq \ + --arg name "$name" \ + --arg type "$type" \ + --argjson ttl "$ttl" \ + --argjson records "$records_json" \ + '. + [{ + name: $name, + type: $type, + ttl: $ttl, + changetype: "REPLACE", + records: $records + }]' <<<"$rrsets_json") + done + + jq -n --argjson rrsets "$rrsets_json" '{ rrsets: $rrsets }' \ + | curl -sS -X PATCH \ + -H "X-API-Key: $API_KEY" \ + -H "Content-Type: application/json" \ + --data-binary @- \ + "$API_URL" +} + +add_record "NS" 604800 "hexname.com." "ns1.hexname.com." +add_record "NS" 604800 "hexname.com." "ns2.hexname.com." +add_record "A" 604800 "hexname.com." "188.245.239.209" +add_record "A" 604800 "ns1.hexname.com." "188.245.239.209" +add_record "A" 604800 "ns2.hexname.com." "91.99.69.65" + +# Mailserver records +add_record "A" 3600 "mx.hexname.com." "188.245.239.209" +add_record "A" 3600 "email.hexname.com." "188.245.239.209" +add_record "A" 3600 "mta-sts.hexname.com." "188.245.239.209" +add_record "CNAME" 3600 "mail.hexname.com." "mx.hexname.com." +add_record "MX" 3600 "hexname.com." "10 mx.hexname.com." + +add_record "TXT" 3600 "_mta-sts.hexname.com." "\"v=STSv1; id=20260127182600Z;\"" + +add_record "TXT" 3600 "202601e._domainkey.hexname.com." "\"v=DKIM1; k=ed25519; h=sha256; p=C30gZd1CbkUpIGInw/wZgZQD0pmUEnwTp+svCLm1oCk=\"" +add_record "TXT" 3600 "202601r._domainkey.hexname.com." "\"v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnyQRHisJtMpgRCAKAE5mfq63n1hvguiNheRrGWcLjEziA9r3M8oaxM71gDNeDEZj19yXlYBWlZZiPsdkMNsumFaElTt3E810JjZxvWslvRgCQ9qMK6lE4ytJZHXJD1a+g82/j4Pfu3C0iz0GfMvngXf03pDl5jWeScwfSFgvKx/0tRdzCAzwkSZfZaSKCh5bcvVwoxzXqHjz3zxwxDJGlUPoERymd18/7NkdRRfJZoqAo/aHdsh5JsYa8APtNIHjSjp2vUBPQnNrtx9+lI0qRnwdyrim8v8CRKin+QUW0sstWGuyqZxgxOGXO2Ek2fqTrpzVu2fu6pzGqJdbTVf5BQIDAQAB\"" + +add_record "TXT" 3600 "mx.hexname.com." "\"v=spf1 a ra=spf-reports -all\"" +add_record "TXT" 3600 "hexname.com." "\"v=spf1 mx ra=spf-reports -all\"" +add_record "TXT" 3600 "_dmarc.hexname.com." "\"v=DMARC1; p=reject; rua=mailto:dmarc-reports@hexname.com; ruf=mailto:dmarc-reports@hexname.com\"" +add_record "TXT" 3600 "_smtp._tls.hexname.com." "\"v=TLSRPTv1; rua=mailto:tls-reports@hexname.com\"" +add_record "SRV" 3600 "_imaps._tcp.hexname.com." "0 1 993 mx.hexname.com." +add_record "SRV" 3600 "_imap._tcp.hexname.com." "0 1 143 mx.hexname.com." +add_record "SRV" 3600 "_submissions._tcp.hexname.com." "0 1 465 mx.hexname.com." +add_record "SRV" 3600 "_submission._tcp.hexname.com." "0 1 587 mx.hexname.com." +add_record "TLSA" 3600 "_25._tcp.mx.hexname.com." "3 1 1 88151fff33b6c5b820d83b3030d55376f57085a154652a27089d9d9a71fe6a7e" + +# Create the zone +curl -d '{ + "name": "hexname.com.", + "kind": "Native", + "masters": [], + "nameservers": [ + "ns1.hexname.com.", + "ns2.hexname.com." + ] + }' -X POST -H "X-API-Key: $API_KEY" http://127.0.0.1:8081/api/v1/servers/localhost/zones + +flush_rrsets + +# Secure/update DDNSEC +sudo podman exec -it hexname-powerdns pdnsutil zone secure hexname.com + diff --git a/scripts/virtualisation/restart-netbird-relay.nix b/scripts/virtualisation/restart-netbird-relay.nix deleted file mode 100644 index 3e6dd46..0000000 --- a/scripts/virtualisation/restart-netbird-relay.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ pkgs, ... }: - -{ - systemd.timers.restart-netbird-relay = { - timerConfig = { - Unit = "update-containers.service"; - OnCalendar = "Tue 02:40"; # 10 mins after podman pull - }; - wantedBy = [ "timers.target" ]; - }; - systemd.services.restart-netbird-relay = { - serviceConfig = { - Type = "oneshot"; - ExecStart = "${pkgs.systemd}/bin/systemctl try-restart podman-netbird-relay.service"; - }; - }; -} - diff --git a/scripts/zfs-healthcheck/service.nix b/scripts/zfs-healthcheck/service.nix deleted file mode 100755 index d852c39..0000000 --- a/scripts/zfs-healthcheck/service.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ config, pkgs, ... }: - -let - scriptPath = "${config.vars.homeDir}/nixos/scripts"; - after = [ "network.target" "NetworkManager.service" "uptime-kuma.service" ]; - environment = { - VAR_IP = config.vars.privateIp; - }; -in -{ - systemd.services = { - "zfs-uptime-kuma" = { - inherit environment after; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "oneshot"; - User = "root"; - }; - path = with pkgs; [ bash curl zfs jq ]; - script = '' - bash ${scriptPath}/zfs-healthcheck/uptime-kuma.sh - ''; - }; - }; - - systemd.timers = { - "zfs-uptime-kuma" = { - wantedBy = [ "timers.target" ]; - partOf = [ "zfs-uptime-kuma.service" ]; - timerConfig = { - Persistent = true; # Execute immediately if missed - OnUnitActiveSec = "7m"; # Run every x minutes - Unit = "zfs-uptime-kuma.service"; - }; - }; - }; -} - diff --git a/scripts/zfs-healthcheck/uptime-kuma.sh b/scripts/zfs-healthcheck/uptime-kuma.sh deleted file mode 100755 index cf3ddb2..0000000 --- a/scripts/zfs-healthcheck/uptime-kuma.sh +++ /dev/null @@ -1,29 +0,0 @@ -#! /bin/sh -set -euo pipefail -set -x - -push_token=$(< /etc/env/zfs/push-token); - -start_time=$(date -u +%s%3N) -health=$(zpool list -H -o health) - -status="up" - -echo "$health" | while IFS= read -r line; do - if [ "$line" != "ONLINE" ]; then - status="down" - break - fi -done - -end_time=$(date -u +%s%3N) -duration=$(("$end_time" - "$start_time")) - -msg=$(printf '%s' "$health" | tr '\n' ',' | tr -d "'" | jq -sRr @uri) -url="http://$VAR_IP:4000/api/push/$push_token?ping=$duration&status=$status&msg='$msg'" - -output=$(curl --fail --no-progress-meter --retry 1 $url 2>&1) -if [ $? -ne 0 ]; then - echo "Ping failed: $output" >&2 -fi - diff --git a/scripts/virtualisation/restart-pihole.nix b/services/restart-powerdns.nix similarity index 61% rename from scripts/virtualisation/restart-pihole.nix rename to services/restart-powerdns.nix index 060c4c5..bd77268 100644 --- a/scripts/virtualisation/restart-pihole.nix +++ b/services/restart-powerdns.nix @@ -1,17 +1,17 @@ { pkgs, ... }: { - systemd.timers.restart-pihole = { + systemd.timers.restart-powerdns = { timerConfig = { Unit = "update-containers.service"; - OnCalendar = "Tue 02:40"; # 10 mins after podman pull + OnCalendar = "Sat 10:51"; # 10 mins after podman pull }; wantedBy = [ "timers.target" ]; }; - systemd.services.restart-pihole = { + systemd.services.restart-powerdns = { serviceConfig = { Type = "oneshot"; - ExecStart = "${pkgs.systemd}/bin/systemctl try-restart podman-pihole.service"; + ExecStart = "${pkgs.systemd}/bin/systemctl try-restart podman-powerdns.service"; }; }; } diff --git a/scripts/virtualisation/update-containers.nix b/services/update-containers.nix similarity index 94% rename from scripts/virtualisation/update-containers.nix rename to services/update-containers.nix index d5a2d94..cb90696 100644 --- a/scripts/virtualisation/update-containers.nix +++ b/services/update-containers.nix @@ -4,7 +4,7 @@ systemd.timers.update-containers = { timerConfig = { Unit = "update-containers.service"; - OnCalendar = "Mon 02:30"; + OnCalendar = "Sat 10:41"; }; wantedBy = [ "timers.target" ]; };