From: Preston Pan Date: Fri, 13 Feb 2026 01:37:56 +0000 (-0800) Subject: fix vps, maddy, everything works X-Git-Url: https://ret2pop.net/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fmain;p=monorepo.git fix vps, maddy, everything works --- diff --git a/about.org b/about.org index 833abfd..acf4cc6 100644 --- a/about.org +++ b/about.org @@ -33,13 +33,11 @@ Here are all the methods you should use to contact me: Here you can find [[file:resume.pdf][my resume]] in both pdf and [[file:resume.org][html]] which contains it all. I am always open for new job opportunities! *** IRC - ret2pop on nullring.xyz, 6697. Go to #nullring; this channel is the most active, probably. -- ret2pop on libera.chat - - Note: I will not always be online and I don't use a bouncer on this server. Email me to coordinate a time if you really need to reach me this way. *** Matrix -contact me on matrix at ~ret2pop:social.nullring.xyz~. +contact me on matrix at ~@ret2pop:matrix.nullring.xyz~. *** Email - ret2pop@gmail.com -- preston@nullring.xyz +- ret2pop@nullring.xyz *** Amateur Radio (In case the world ends) My callsign is ~VE7PPN~. *** Linkedin diff --git a/config/nix.org b/config/nix.org index d0643cf..151b39b 100644 --- a/config/nix.org +++ b/config/nix.org @@ -552,6 +552,10 @@ the yaml file specified. Yes, this is safe to include in the repo. livekit = { format = "yaml"; }; + mail_password = { + format = "yaml"; + owner = "maddy"; + }; conduit_secrets = { format = "yaml"; }; @@ -564,6 +568,10 @@ the yaml file specified. Yes, this is safe to include in the repo. discord_token = { format = "yaml"; }; + ntfy = { + format = "yaml"; + owner = "ntfy-sh"; + }; }; }; } @@ -871,7 +879,7 @@ is almost no point to cracking it with hashcat. ** Conduit This is a modern matrix server that is meant to be lightweight while still federating and hosting the same protocol. There is also a configuration -for lk-jwt which is important for configuring p2p calls in matrix. +for lk-jwt and livekit which is important for configuring p2p calls in matrix. #+begin_src nix :tangle ../nix/modules/conduit.nix { config, lib, ... }: { @@ -1147,18 +1155,54 @@ I run my own git server in order to have a mirror in case github goes down. }; } #+end_src -** TODO Ntfy +** Ntfy #+begin_src nix :tangle ../nix/modules/ntfy-sh.nix - { lib, config, ... }: + { pkgs, lib, config, ... }: { services.ntfy-sh = { - # enable = lib.mkDefault config.monorepo.profiles.server.enable; - enable = false; + enable = lib.mkDefault config.monorepo.profiles.server.enable; settings = { base-url = "https://ntfy.${config.monorepo.vars.remoteHost}"; listen-http = "127.0.0.1:2586"; envrionmentFile = "/run/secrets/ntfy"; + auth-file = "/var/lib/ntfy-sh/user.db"; + auth-default-access = "deny-all"; + enable-login = true; + }; + }; + systemd.services.ntfy-sh = { + serviceConfig = { + EnvironmentFile = "/run/secrets/ntfy"; }; + postStart = lib.mkForce '' + # 1. Wait for the server to initialize the database + echo "Waiting for ntfy auth database to appear..." + TIMEOUT=30 + while [ ! -f /var/lib/ntfy-sh/user.db ]; do + sleep 1 + TIMEOUT=$((TIMEOUT-1)) + if [ $TIMEOUT -le 0 ]; then + echo "Timed out waiting for database creation!" + exit 1 + fi + done + + echo "Database found. Configuring admin user..." + + # 2. Define the username + ADMIN_USER="ret2pop" + + # 3. Check if user exists, create if missing + # We pipe the password twice because 'ntfy user add' asks for confirmation + if ! ${pkgs.ntfy-sh}/bin/ntfy user list | grep -q "$ADMIN_USER"; then + echo "Creating admin user $ADMIN_USER..." + printf "$ADMIN_PASSWORD\n$ADMIN_PASSWORD" | \ + ${pkgs.ntfy-sh}/bin/ntfy user add --role=admin "$ADMIN_USER" + echo "User created." + else + echo "Admin user already exists." + fi + ''; }; } #+end_src @@ -1312,6 +1356,16 @@ to the outside world under a domain. }; }; + "ntfy.${config.monorepo.vars.remoteHost}" = { + serverName = "ntfy.${config.monorepo.vars.remoteHost}"; + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://localhost:2586"; + proxyWebsockets = true; + }; + }; + "${config.monorepo.vars.remoteHost}" = { serverName = "${config.monorepo.vars.remoteHost}"; serverAliases = [ "${config.monorepo.vars.internetName}.${config.monorepo.vars.orgHost}" ]; @@ -1348,6 +1402,8 @@ world. This was the easiest frontend to set up on NixOS. projectroot = "/srv/git/"; extraConfig = '' our $export_ok = "git-daemon-export-ok"; + our $site_name = "NullRing Git Server"; + our $site_header = "NullRing Projects"; ''; }; } @@ -1391,16 +1447,22 @@ I need CUDA on some computers because I run local LLMs. ] else []); } #+end_src -** TODO Maddy +** Maddy +There is a non declarative part of setting dkims and spf. #+begin_src nix :tangle ../nix/modules/maddy.nix { lib, config, options, ... }: { services.maddy = { enable = lib.mkDefault config.monorepo.profiles.server.enable; openFirewall = true; - hostName = "${config.monorepo.vars.remoteHost}"; + hostname = "${config.monorepo.vars.orgHost}"; primaryDomain = "mail.${config.monorepo.vars.orgHost}"; + localDomains = [ + "$(primary_domain)" + "${config.monorepo.vars.orgHost}" + ]; tls = { + loader = "file"; certificates = [ { keyPath = "/var/lib/acme/mail.${config.monorepo.vars.orgHost}/key.pem"; @@ -1411,20 +1473,33 @@ I need CUDA on some computers because I run local LLMs. config = builtins.replaceStrings [ "imap tcp://0.0.0.0:143" "submission tcp://0.0.0.0:587" - "smtp tcp://0.0.0.0:25" ] [ "imap tls://0.0.0.0:993 tcp://0.0.0.0:143" "submission tls://0.0.0.0:465 tcp://0.0.0.0:587" - "smtps tls://0.0.0.0:465 smtp tcp://0.0.0.0:25" ] options.services.maddy.config.default; ensureCredentials = { - "${config.monorepo.vars.userName}@localhost" = { + "${config.monorepo.vars.internetName}@${config.monorepo.vars.orgHost}" = { passwordFile = "/run/secrets/mail_password"; }; }; }; } #+end_src +** Fail2Ban +This is a service that bans bots that try to sign in on my server. +#+begin_src nix :tangle ../nix/modules/fail2ban.nix + { lib, config, ... }: + { + services.fail2ban = { + enable = lib.mkDefault config.monorepo.profiles.server.enable; + # Ban IP after 5 failures for 1 hour + maxretry = 5; + bantime = "1h"; + banaction = "iptables-allports"; + banaction-allports = "iptables-allports"; + }; + } +#+end_src ** Impermanence This is my impermanence profile, which removes all files on reboot except for the ones listed below. #+begin_src nix :tangle ../nix/modules/impermanence.nix @@ -1559,6 +1634,9 @@ because they enhance security. ./docker.nix ./impermanence.nix ./coturn.nix + ./maddy.nix + ./ntfy-sh.nix + ./fail2ban.nix ]; environment.etc."wpa_supplicant.conf".text = '' @@ -1741,38 +1819,38 @@ because they enhance security. powersave = false; }; ensureProfiles = { - # profiles = { - # home-wifi = { - # connection = { - # id = "TELUS6572"; - # permissions = ""; - # type = "wifi"; - # }; - # ipv4 = { - # dns-search = ""; - # method = "auto"; - # }; - # ipv6 = { - # addr-gen-mode = "stable-privacy"; - # dns-search = ""; - # method = "auto"; - # }; - # wifi = { - # mac-address-blacklist = ""; - # mode = "infrastructure"; - # ssid = "TELUS6572"; - # }; - # wifi-security = { - # auth-alg = "open"; - # key-mgmt = "wpa-psk"; - # # when someone actually steals my internet then I will be concerned. - # # This password only matters if you actually show up to my house in real life. - # # That would perhaps allow for some nasty networking related shenanigans. - # # I guess we'll cross that bridge when I get there. - # psk = "b4xnrv6cG6GX"; - # }; - # }; - # }; + profiles = { + home-wifi = { + connection = { + id = "TELUS6572"; + permissions = ""; + type = "wifi"; + }; + ipv4 = { + dns-search = ""; + method = "auto"; + }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + dns-search = ""; + method = "auto"; + }; + wifi = { + mac-address-blacklist = ""; + mode = "infrastructure"; + ssid = "TELUS6572"; + }; + wifi-security = { + auth-alg = "open"; + key-mgmt = "wpa-psk"; + # when someone actually steals my internet then I will be concerned. + # This password only matters if you actually show up to my house in real life. + # That would perhaps allow for some nasty networking related shenanigans. + # I guess we'll cross that bridge when I get there. + psk = "b4xnrv6cG6GX"; + }; + }; + }; }; }; firewall = { @@ -1905,6 +1983,7 @@ because they enhance security. vim curl nmap + exiftool (writeShellScriptBin "new-repo" '' #!/bin/bash @@ -1923,12 +2002,31 @@ because they enhance security. users.groups.conduit = lib.mkDefault {}; users.groups.livekit = lib.mkDefault {}; users.groups.matterbridge = lib.mkDefault {}; + users.groups.maddy = lib.mkDefault {}; + users.groups.ntfy-sh = lib.mkDefault {}; users.users = { + conduit = { + isSystemUser = lib.mkDefault true; + group = "conduit"; + }; matterbridge = { isSystemUser = lib.mkDefault true; group = "matterbridge"; }; + + maddy = { + isSystemUser = lib.mkDefault true; + group = "maddy"; + extraGroups = [ "acme" "nginx" ]; + }; + + ntfy-sh = { + isSystemUser = lib.mkDefault true; + group = "ntfy-sh"; + extraGroups = [ "acme" "nginx" ]; + }; + ngircd = { isSystemUser = lib.mkDefault true; group = "ngircd"; @@ -3868,28 +3966,6 @@ standard. }; } #+end_src -*** Pantalaimon -This is used with ement as a proxy in order to connect to a remote -matrix server while having encryption. -#+begin_src nix :tangle ../nix/modules/home/pantalaimon.nix - { lib, config, ... }: - { - services.pantalaimon = { - enable = lib.mkDefault config.monorepo.profiles.graphics.enable; - settings = { - Default = { - LogLevel = "Debug"; - SSL = true; - }; - local-matrix = { - Homeserver = "https://matrix.${config.monorepo.vars.orgHost}"; - ListenAddress = "127.0.0.1"; - ListenPort = "8008"; - }; - }; - }; - } -#+end_src *** User This configuration is the backbone configuration for the default user. It specifies some generally useful packages and something every home should have, as well as some dependencies @@ -3942,7 +4018,7 @@ for these configurations. # Apps # octaveFull - vesktop grim swww vim kotatogram-desktop tg qwen-code element-desktop jami + vesktop grim swww vim kotatogram-desktop tg qwen-code element-desktop thunderbird jami # Sound/media pavucontrol alsa-utils imagemagick ffmpeg helvum @@ -4140,7 +4216,7 @@ as several other useful services. zramSwap = { enable = true; algorithm = "zstd"; - memoryPercent = 50; # Creates ~16GB of compressed swap space + memoryPercent = 50; }; monorepo = { vars.device = "/dev/nvme0n1"; @@ -4167,7 +4243,8 @@ I want cuda in home manager too. } #+end_src ** Spontaneity -Spontaneity is my VPS instance. +Spontaneity is my VPS instance. Note that much of this is not fully reproducible; you must change the IPs yourself and you must change +some DNS records to match what you have on your system after deployment. #+begin_src nix :tangle ../nix/systems/spontaneity/default.nix { config, lib, ... }: let @@ -4196,7 +4273,28 @@ Spontaneity is my VPS instance. }; boot.loader.grub.device = "nodev"; + boot.kernel.sysctl = { + "net.ipv6.conf.ens3.autoconf" = 0; + # Keep accept_ra = 1 so you still get the default gateway/route! + "net.ipv6.conf.ens3.accept_ra" = 1; + }; + + systemd.network.enable = true; + systemd.network.networks."40-ens3" = { + matchConfig.Name = "ens3"; + networkConfig = { + # This is the magic combo for Vultr: + IPv6AcceptRA = true; # Accept routes (so we know where the internet is) + IPv6PrivacyExtensions = false; # No random privacy IPs + }; + ipv6AcceptRAConfig = { + UseAutonomousPrefix = false; # Do NOT generate an IP address from the RA + }; + }; networking = { + useDHCP = lib.mkForce false; + networkmanager.enable = lib.mkForce false; + tempAddresses = "disabled"; extraHosts = '' 127.0.0.1 livekit.${config.monorepo.vars.orgHost} 127.0.0.1 matrix.${config.monorepo.vars.orgHost} @@ -4207,6 +4305,7 @@ Spontaneity is my VPS instance. prefixLength = 24; } ]; + interfaces.ens3.useDHCP = lib.mkForce false; interfaces.ens3.ipv6.addresses = [ { address = ipv6addr; @@ -4247,6 +4346,16 @@ Spontaneity is my VPS instance. "${config.monorepo.vars.orgHost}" = { a.data = ipv4addr; aaaa.data = ipv6addr; + + mx.data = [ + { + preference = 10; + exchange = "mail.${config.monorepo.vars.orgHost}"; + } + ]; + txt = { + data = "v=spf1 ip4:${ipv4addr} ip6:${ipv6addr} -all"; + }; }; }; subDomains = { @@ -4254,9 +4363,24 @@ Spontaneity is my VPS instance. "notes.${config.monorepo.vars.remoteHost}" = { a.data = "45.76.87.125"; }; + + "_dmarc.${config.monorepo.vars.orgHost}" = { + txt = { + data = "v=DMARC1; p=none"; + }; + }; + + "default._domainkey.${config.monorepo.vars.orgHost}" = { + txt = { + data = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsC9GpfjvQlldPrHAC7Yt+ZF0aduUIVV4j2+KUkF0j6NsrpOgvU6COWKQSod/B/qyPBLWf+w5P5YiJ9XnOgw6Db/I9C67eusEHnV/cbvokXLQjSBvXee1OEdrT9i+6iUgDeGWP4CrD1DcwvXzAcCI9exy3yALHVlbkyYvi0KAYofs8dVQ3JCwSCMlol71lA6ULJ2zbCIWeSOv9/C6QZ5HOIeeoFLesX6O/YvF4FYxWbSHy244TXYuczQKuayjKgD6e8gIT5WJRQj8IAWOQ2podWw6hSuB3Ig+ekoOfnl5ivJGOMbAzFTj8FtbS4ncyidLU1kIOeuLfiILeDDLlIeYTwIDAQAB"; + }; + }; + + "ntfy.${config.monorepo.vars.remoteHost}" = {}; "matrix.${config.monorepo.vars.remoteHost}" = {}; "www.${config.monorepo.vars.remoteHost}" = {}; - "mail.${config.monorepo.vars.remoteHost}" = {}; + "mail.${config.monorepo.vars.remoteHost}" = { + }; "livekit.${config.monorepo.vars.orgHost}" = {}; "${config.monorepo.vars.orgHost}" = {}; diff --git a/nix/fake-update-dns.sh b/nix/fake-update-dns.sh new file mode 100644 index 0000000..a236cb2 --- /dev/null +++ b/nix/fake-update-dns.sh @@ -0,0 +1,3 @@ +#!/bin/sh +export CLOUDFLARE_TOKEN="$(cat /run/user/1000/secrets/cloudflare-dns | tr -d '\n')" +poetry run octodns-sync --config-file result diff --git a/nix/modules/configuration.nix b/nix/modules/configuration.nix index 35944e0..0845cea 100644 --- a/nix/modules/configuration.nix +++ b/nix/modules/configuration.nix @@ -24,6 +24,9 @@ ./docker.nix ./impermanence.nix ./coturn.nix + ./maddy.nix + ./ntfy-sh.nix + ./fail2ban.nix ]; environment.etc."wpa_supplicant.conf".text = '' @@ -206,38 +209,38 @@ country=CA powersave = false; }; ensureProfiles = { - # profiles = { - # home-wifi = { - # connection = { - # id = "TELUS6572"; - # permissions = ""; - # type = "wifi"; - # }; - # ipv4 = { - # dns-search = ""; - # method = "auto"; - # }; - # ipv6 = { - # addr-gen-mode = "stable-privacy"; - # dns-search = ""; - # method = "auto"; - # }; - # wifi = { - # mac-address-blacklist = ""; - # mode = "infrastructure"; - # ssid = "TELUS6572"; - # }; - # wifi-security = { - # auth-alg = "open"; - # key-mgmt = "wpa-psk"; - # # when someone actually steals my internet then I will be concerned. - # # This password only matters if you actually show up to my house in real life. - # # That would perhaps allow for some nasty networking related shenanigans. - # # I guess we'll cross that bridge when I get there. - # psk = "b4xnrv6cG6GX"; - # }; - # }; - # }; + profiles = { + home-wifi = { + connection = { + id = "TELUS6572"; + permissions = ""; + type = "wifi"; + }; + ipv4 = { + dns-search = ""; + method = "auto"; + }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + dns-search = ""; + method = "auto"; + }; + wifi = { + mac-address-blacklist = ""; + mode = "infrastructure"; + ssid = "TELUS6572"; + }; + wifi-security = { + auth-alg = "open"; + key-mgmt = "wpa-psk"; + # when someone actually steals my internet then I will be concerned. + # This password only matters if you actually show up to my house in real life. + # That would perhaps allow for some nasty networking related shenanigans. + # I guess we'll cross that bridge when I get there. + psk = "b4xnrv6cG6GX"; + }; + }; + }; }; }; firewall = { @@ -370,6 +373,7 @@ country=CA vim curl nmap + exiftool (writeShellScriptBin "new-repo" '' #!/bin/bash @@ -388,12 +392,31 @@ country=CA users.groups.conduit = lib.mkDefault {}; users.groups.livekit = lib.mkDefault {}; users.groups.matterbridge = lib.mkDefault {}; + users.groups.maddy = lib.mkDefault {}; + users.groups.ntfy-sh = lib.mkDefault {}; users.users = { + conduit = { + isSystemUser = lib.mkDefault true; + group = "conduit"; + }; matterbridge = { isSystemUser = lib.mkDefault true; group = "matterbridge"; }; + + maddy = { + isSystemUser = lib.mkDefault true; + group = "maddy"; + extraGroups = [ "acme" "nginx" ]; + }; + + ntfy-sh = { + isSystemUser = lib.mkDefault true; + group = "ntfy-sh"; + extraGroups = [ "acme" "nginx" ]; + }; + ngircd = { isSystemUser = lib.mkDefault true; group = "ngircd"; diff --git a/nix/modules/fail2ban.nix b/nix/modules/fail2ban.nix new file mode 100644 index 0000000..5d289a0 --- /dev/null +++ b/nix/modules/fail2ban.nix @@ -0,0 +1,11 @@ +{ lib, config, ... }: +{ + services.fail2ban = { + enable = lib.mkDefault config.monorepo.profiles.server.enable; + # Ban IP after 5 failures for 1 hour + maxretry = 5; + bantime = "1h"; + banaction = "iptables-allports"; + banaction-allports = "iptables-allports"; + }; +} diff --git a/nix/modules/gitweb.nix b/nix/modules/gitweb.nix index c98e4c6..69cb951 100644 --- a/nix/modules/gitweb.nix +++ b/nix/modules/gitweb.nix @@ -5,6 +5,8 @@ projectroot = "/srv/git/"; extraConfig = '' our $export_ok = "git-daemon-export-ok"; +our $site_name = "NullRing Git Server"; +our $site_header = "NullRing Projects"; ''; }; } diff --git a/nix/modules/home/user.nix b/nix/modules/home/user.nix index 356a0fe..55e16fc 100644 --- a/nix/modules/home/user.nix +++ b/nix/modules/home/user.nix @@ -45,7 +45,7 @@ # Apps # octaveFull - vesktop grim swww vim kotatogram-desktop tg qwen-code element-desktop jami + vesktop grim swww vim kotatogram-desktop tg qwen-code element-desktop thunderbird jami # Sound/media pavucontrol alsa-utils imagemagick ffmpeg helvum diff --git a/nix/modules/maddy.nix b/nix/modules/maddy.nix index ab98f87..42f24f9 100644 --- a/nix/modules/maddy.nix +++ b/nix/modules/maddy.nix @@ -3,9 +3,14 @@ services.maddy = { enable = lib.mkDefault config.monorepo.profiles.server.enable; openFirewall = true; - hostName = "${config.monorepo.vars.remoteHost}"; + hostname = "${config.monorepo.vars.orgHost}"; primaryDomain = "mail.${config.monorepo.vars.orgHost}"; + localDomains = [ + "$(primary_domain)" + "${config.monorepo.vars.orgHost}" + ]; tls = { + loader = "file"; certificates = [ { keyPath = "/var/lib/acme/mail.${config.monorepo.vars.orgHost}/key.pem"; @@ -16,14 +21,12 @@ config = builtins.replaceStrings [ "imap tcp://0.0.0.0:143" "submission tcp://0.0.0.0:587" - "smtp tcp://0.0.0.0:25" ] [ "imap tls://0.0.0.0:993 tcp://0.0.0.0:143" "submission tls://0.0.0.0:465 tcp://0.0.0.0:587" - "smtps tls://0.0.0.0:465 smtp tcp://0.0.0.0:25" ] options.services.maddy.config.default; ensureCredentials = { - "${config.monorepo.vars.userName}@localhost" = { + "${config.monorepo.vars.internetName}@${config.monorepo.vars.orgHost}" = { passwordFile = "/run/secrets/mail_password"; }; }; diff --git a/nix/modules/nginx.nix b/nix/modules/nginx.nix index a3c079b..87f11c1 100644 --- a/nix/modules/nginx.nix +++ b/nix/modules/nginx.nix @@ -143,6 +143,16 @@ }; }; + "ntfy.${config.monorepo.vars.remoteHost}" = { + serverName = "ntfy.${config.monorepo.vars.remoteHost}"; + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://localhost:2586"; + proxyWebsockets = true; + }; + }; + "${config.monorepo.vars.remoteHost}" = { serverName = "${config.monorepo.vars.remoteHost}"; serverAliases = [ "${config.monorepo.vars.internetName}.${config.monorepo.vars.orgHost}" ]; diff --git a/nix/modules/ntfy-sh.nix b/nix/modules/ntfy-sh.nix index 9311af2..0eeac78 100644 --- a/nix/modules/ntfy-sh.nix +++ b/nix/modules/ntfy-sh.nix @@ -1,12 +1,48 @@ -{ lib, config, ... }: +{ pkgs, lib, config, ... }: { services.ntfy-sh = { -# enable = lib.mkDefault config.monorepo.profiles.server.enable; - enable = false; + enable = lib.mkDefault config.monorepo.profiles.server.enable; settings = { base-url = "https://ntfy.${config.monorepo.vars.remoteHost}"; listen-http = "127.0.0.1:2586"; envrionmentFile = "/run/secrets/ntfy"; + auth-file = "/var/lib/ntfy-sh/user.db"; + auth-default-access = "deny-all"; + enable-login = true; }; }; + systemd.services.ntfy-sh = { + serviceConfig = { + EnvironmentFile = "/run/secrets/ntfy"; + }; + postStart = lib.mkForce '' + # 1. Wait for the server to initialize the database + echo "Waiting for ntfy auth database to appear..." + TIMEOUT=30 + while [ ! -f /var/lib/ntfy-sh/user.db ]; do + sleep 1 + TIMEOUT=$((TIMEOUT-1)) + if [ $TIMEOUT -le 0 ]; then + echo "Timed out waiting for database creation!" + exit 1 + fi + done + + echo "Database found. Configuring admin user..." + + # 2. Define the username + ADMIN_USER="ret2pop" + + # 3. Check if user exists, create if missing + # We pipe the password twice because 'ntfy user add' asks for confirmation + if ! ${pkgs.ntfy-sh}/bin/ntfy user list | grep -q "$ADMIN_USER"; then + echo "Creating admin user $ADMIN_USER..." + printf "$ADMIN_PASSWORD\n$ADMIN_PASSWORD" | \ + ${pkgs.ntfy-sh}/bin/ntfy user add --role=admin "$ADMIN_USER" + echo "User created." + else + echo "Admin user already exists." + fi + ''; + }; } diff --git a/nix/modules/secrets.nix b/nix/modules/secrets.nix index d1c711c..f7deb5d 100644 --- a/nix/modules/secrets.nix +++ b/nix/modules/secrets.nix @@ -87,6 +87,10 @@ channel="-5290629325" livekit = { format = "yaml"; }; + mail_password = { + format = "yaml"; + owner = "maddy"; + }; conduit_secrets = { format = "yaml"; }; @@ -99,6 +103,10 @@ channel="-5290629325" discord_token = { format = "yaml"; }; + ntfy = { + format = "yaml"; + owner = "ntfy-sh"; + }; }; }; } diff --git a/nix/secrets/vps_secrets.yaml b/nix/secrets/vps_secrets.yaml index d60ced3..87c513b 100644 --- a/nix/secrets/vps_secrets.yaml +++ b/nix/secrets/vps_secrets.yaml @@ -9,6 +9,7 @@ znc_password_salt: ENC[AES256_GCM,data:e7YZkNB32RiqgCPGoehwsfZzOHM=,iv:GrhwBRBZ1 telegram_token: ENC[AES256_GCM,data:hfstqM3NphVnK86LYp8EYe09kflMzQ1/SO5rm5UIkWN7wdl7mbq+sw3svc4YhQ==,iv:o6TbrGBCly0s3US9041cKmpLpThB/umhBEdZE9E3v54=,tag:WJ/KS4Uc9wtIcjpyfmzLfA==,type:str] discord_token: ENC[AES256_GCM,data:1mJ0lKTz2SmaP3PIn3ThWX6Mjbv3tywtLtF65SVkkCEtI79wcPeqK83l6jb3yG+ugntNR7lfQxLgbbURnTil3jc7yVOsYreL,iv:ExZ8xFkH6RR7rHATh8oBEEZWfV5Rt1YVEx8gUicQrV0=,tag:wKJ3P8ie/ppHU9VStQlk0Q==,type:str] mail_password: ENC[AES256_GCM,data:W24/1l9YrV+M1enkAgRv2uZuhUIYAjpcRkX7tbc=,iv:F8oLCpthhecllJvGSmHUaFgmBKDg/g3o85CPJ/nCcxU=,tag:bPxcZNXdQ/jkK+saaIKbSw==,type:str] +ntfy: ENC[AES256_GCM,data:wKCZ/7GXRWPoVRoXDBD0E0sR6ZRQjSE8USwqHQFOT/QiqIx+aI0awcRuORyGbCE=,iv:aBO9I/528sX6ncnBHMBDVB6mLbc45A7xXiu9p7Kh0Ao=,tag:Xgp3UURxPYcO5DlN53sBVw==,type:str] sops: age: - recipient: age1acpuyy2qnduyxzwvusd8urr6a78e3f37ylhvh2pngyqytf5r8ans5vkest @@ -20,7 +21,7 @@ sops: dDZONnI0bG5heTYzaDkxeGo3VlFmdm8K377mvFFxtFSURAWeFvLDJTkm8wppKr/B Y4qrdU3xBaTwqlsC/7lElQClaUbM+YMF/padENsD6IfyoGN8lGUQQw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-02-11T01:17:40Z" - mac: ENC[AES256_GCM,data:9z5nlQA2Wjw7kgk+i2BMFIePGRdNbagYZ6fQpdyQQTEERl/TK7E8hozIIo48lmhdqXkjK8Vsgon/lnl2QbLfh8sTlpYGfewUaAzERrxW0JPEeY+JqcTaWO/16SNDd5dcd1aYWZILPcjPnz2/wwI3TMWpQG85lEDSXyLMommNdDc=,iv:uzLQtiZ7AJM/eS8/pLvty9YvErCMpx8xhk/d6jxKouQ=,tag:6ebxZG7BlF4ZxnJpp4QBVg==,type:str] + lastmodified: "2026-02-12T08:21:04Z" + mac: ENC[AES256_GCM,data:537FYu1bJ+0KgbdtKt7kw3Wx4JT2Nb71L36cMZLEFUpwE+pvpe3+iYV/J28TzYVHwByoQ1Q4LYRc/EQqSlT0oaV7yOpfLNS+cb7devATEHhGVrDUThmnF8YvyQFiQsyq/PFNqQ3RLEmSeAsJBWrFB5r8uqRJZKAW/URfFjYqdj0=,iv:tXRflj6rvxewU0QhbsOUSmAHkfWExDZMA6Z8Z65/y0w=,tag:h+y17+ilWPQ4+I/WZIbWAQ==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0 diff --git a/nix/systems/affinity/default.nix b/nix/systems/affinity/default.nix index 9918089..755d6d8 100644 --- a/nix/systems/affinity/default.nix +++ b/nix/systems/affinity/default.nix @@ -8,7 +8,7 @@ zramSwap = { enable = true; algorithm = "zstd"; - memoryPercent = 50; # Creates ~16GB of compressed swap space + memoryPercent = 50; }; monorepo = { vars.device = "/dev/nvme0n1"; diff --git a/nix/systems/spontaneity/default.nix b/nix/systems/spontaneity/default.nix index 7d637bf..7bdcf74 100644 --- a/nix/systems/spontaneity/default.nix +++ b/nix/systems/spontaneity/default.nix @@ -25,7 +25,28 @@ }; boot.loader.grub.device = "nodev"; + boot.kernel.sysctl = { + "net.ipv6.conf.ens3.autoconf" = 0; + # Keep accept_ra = 1 so you still get the default gateway/route! + "net.ipv6.conf.ens3.accept_ra" = 1; + }; + + systemd.network.enable = true; + systemd.network.networks."40-ens3" = { + matchConfig.Name = "ens3"; + networkConfig = { + # This is the magic combo for Vultr: + IPv6AcceptRA = true; # Accept routes (so we know where the internet is) + IPv6PrivacyExtensions = false; # No random privacy IPs + }; + ipv6AcceptRAConfig = { + UseAutonomousPrefix = false; # Do NOT generate an IP address from the RA + }; + }; networking = { + useDHCP = lib.mkForce false; + networkmanager.enable = lib.mkForce false; + tempAddresses = "disabled"; extraHosts = '' 127.0.0.1 livekit.${config.monorepo.vars.orgHost} 127.0.0.1 matrix.${config.monorepo.vars.orgHost} @@ -36,6 +57,7 @@ prefixLength = 24; } ]; + interfaces.ens3.useDHCP = lib.mkForce false; interfaces.ens3.ipv6.addresses = [ { address = ipv6addr; @@ -76,6 +98,16 @@ "${config.monorepo.vars.orgHost}" = { a.data = ipv4addr; aaaa.data = ipv6addr; + + mx.data = [ + { + preference = 10; + exchange = "mail.${config.monorepo.vars.orgHost}"; + } + ]; + txt = { + data = "v=spf1 ip4:${ipv4addr} ip6:${ipv6addr} -all"; + }; }; }; subDomains = { @@ -83,9 +115,24 @@ "notes.${config.monorepo.vars.remoteHost}" = { a.data = "45.76.87.125"; }; + + "_dmarc.${config.monorepo.vars.orgHost}" = { + txt = { + data = "v=DMARC1; p=none"; + }; + }; + + "default._domainkey.${config.monorepo.vars.orgHost}" = { + txt = { + data = "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsC9GpfjvQlldPrHAC7Yt+ZF0aduUIVV4j2+KUkF0j6NsrpOgvU6COWKQSod/B/qyPBLWf+w5P5YiJ9XnOgw6Db/I9C67eusEHnV/cbvokXLQjSBvXee1OEdrT9i+6iUgDeGWP4CrD1DcwvXzAcCI9exy3yALHVlbkyYvi0KAYofs8dVQ3JCwSCMlol71lA6ULJ2zbCIWeSOv9/C6QZ5HOIeeoFLesX6O/YvF4FYxWbSHy244TXYuczQKuayjKgD6e8gIT5WJRQj8IAWOQ2podWw6hSuB3Ig+ekoOfnl5ivJGOMbAzFTj8FtbS4ncyidLU1kIOeuLfiILeDDLlIeYTwIDAQAB"; + }; + }; + + "ntfy.${config.monorepo.vars.remoteHost}" = {}; "matrix.${config.monorepo.vars.remoteHost}" = {}; "www.${config.monorepo.vars.remoteHost}" = {}; - "mail.${config.monorepo.vars.remoteHost}" = {}; + "mail.${config.monorepo.vars.remoteHost}" = { + }; "livekit.${config.monorepo.vars.orgHost}" = {}; "${config.monorepo.vars.orgHost}" = {}; diff --git a/nix/update-dns.sh b/nix/update-dns.sh new file mode 100644 index 0000000..d3b0819 --- /dev/null +++ b/nix/update-dns.sh @@ -0,0 +1,3 @@ +#!/bin/sh +export CLOUDFLARE_TOKEN="$(cat /run/user/1000/secrets/cloudflare-dns | tr -d '\n')" +poetry run octodns-sync --config-file result --doit