diff --git a/modules/profiles/base.nix b/modules/profiles/base.nix index 0215180..5ca1609 100644 --- a/modules/profiles/base.nix +++ b/modules/profiles/base.nix @@ -27,7 +27,6 @@ # Services # keep-sorted start ananicy - avahi bpftune firewall locate diff --git a/modules/profiles/personal.nix b/modules/profiles/personal.nix index 219be4c..942d794 100644 --- a/modules/profiles/personal.nix +++ b/modules/profiles/personal.nix @@ -30,6 +30,7 @@ # Services # keep-sorted start + avahi evolution-data-server flatpak geoclue diff --git a/modules/profiles/server.nix b/modules/profiles/server.nix index c77f6fa..ec6e6bc 100644 --- a/modules/profiles/server.nix +++ b/modules/profiles/server.nix @@ -3,6 +3,7 @@ # keep-sorted start config, lib, + vars, # keep-sorted end ... }: let @@ -13,6 +14,8 @@ mkForce # keep-sorted end ; + + inherit (vars) groundDomain username; in { imports = with self.modules.nixos; [ # Profiles @@ -31,6 +34,21 @@ disko.devices = (self.diskoConfigurations.btrfs config.disko.selectedDisk).disko.devices; + # Disable LLMNR; servers do not need local name discovery. + services.resolved.settings.Resolve.LLMNR = "false"; + + # Nightly flake-based system upgrades from the self-hosted knot. + system.autoUpgrade = { + enable = true; + flake = "git+https://knot.${groundDomain}/${username}.dev/infra"; + dates = "04:00"; + allowReboot = true; + rebootWindow = { + lower = "03:00"; + upper = "06:00"; + }; + }; + boot.kernel.sysctl."vm.overcommit_memory" = mkDefault 1; powerManagement.cpuFreqGovernor = "performance"; diff --git a/modules/programs/tui/atuin.nix b/modules/programs/tui/atuin.nix index aae5679..5969a07 100644 --- a/modules/programs/tui/atuin.nix +++ b/modules/programs/tui/atuin.nix @@ -8,7 +8,11 @@ }: let inherit (vars) groundDomain; inherit (config.xdg) cacheHome; + + aiAuthTokenPath = config.sops.secrets."atuin/ai_auth_token".path; in { + sops.secrets."atuin/ai_auth_token" = {}; + programs.atuin = let logLevel = "error"; in { @@ -22,6 +26,13 @@ }; settings = { + ai = { + enabled = true; + endpoint = "https://atuin.${groundDomain}"; + endpoint_protocol = "oss"; + model = "deepseek-v4-flash"; + }; + # keep-sorted start search-mode = "daemon-fuzzy"; update_check = false; @@ -61,6 +72,11 @@ }; programs.fish.interactiveShellInitSnippets = [ + # Load endpoint authentication outside the Nix store. + '' + set -gx ATUIN_AI__API_TOKEN (string trim < ${aiAuthTokenPath}) + '' + # Disable fish history in favor of atuin. '' set -gx fish_history "" diff --git a/modules/services/data/mysql.nix b/modules/services/data/mysql.nix index d712011..8fac001 100644 --- a/modules/services/data/mysql.nix +++ b/modules/services/data/mysql.nix @@ -17,8 +17,8 @@ settings = { mysqld = { - # Firewall limits remote access to WireGuard. - bind-address = "0.0.0.0"; + # Bind only to loopback and WireGuard; containers route via wg0. + bind-address = "127.0.0.1,10.100.0.1"; innodb_buffer_pool_size = "512M"; max_connections = 100; slow_query_log = true; diff --git a/modules/services/network/proton-wireguard.nix b/modules/services/network/proton-wireguard.nix index 1caab85..19337f5 100644 --- a/modules/services/network/proton-wireguard.nix +++ b/modules/services/network/proton-wireguard.nix @@ -76,7 +76,7 @@ PrivateKey = ${secret."${secretPrefix}/private_key"} Address = ${secret."${secretPrefix}/address"} DNS = ${secret."${secretPrefix}/dns"} - MTU = 1420 + MTU = 1280 Table = ${routingTableString} [Peer] diff --git a/modules/services/security/authentik.nix b/modules/services/security/authentik.nix index ef2a542..5d3ca03 100644 --- a/modules/services/security/authentik.nix +++ b/modules/services/security/authentik.nix @@ -54,6 +54,9 @@ settings = { avatars = "gravatar"; + # Bind only to loopback; external access goes through Traefik. + listen.listen_http = "127.0.0.1:9000"; + # Disable unrequired features. disable_startup_analytics = true; disable_update_check = true; diff --git a/modules/services/server/apprise.nix b/modules/services/server/apprise.nix index abaf2cd..4bf963b 100644 --- a/modules/services/server/apprise.nix +++ b/modules/services/server/apprise.nix @@ -12,7 +12,8 @@ }; extraOptions = [ - "--network=host" + # Publish on WireGuard only; containers route via wg0. + "--publish=10.100.0.1:8000:8000" "--tmpfs=/tmp" "--user=1000:1000" @@ -46,5 +47,11 @@ "d /var/lib/apprise/plugin 0750 1000 1000 -" # keep-sorted end ]; + + # Published address exists only after wg0 is up. + systemd.services.podman-apprise = { + after = ["wireguard-wg0.service"]; + wants = ["wireguard-wg0.service"]; + }; }; } diff --git a/modules/services/server/flaresolverr.nix b/modules/services/server/flaresolverr.nix index 79c7960..2246b2a 100644 --- a/modules/services/server/flaresolverr.nix +++ b/modules/services/server/flaresolverr.nix @@ -2,6 +2,9 @@ flake.modules.nixos.flaresolverr = { services.flaresolverr.enable = true; + # Bind only to WireGuard; containers route via wg0. + systemd.services.flaresolverr.environment.HOST = "10.100.0.1"; + networking.firewall.extraInputRules = '' iifname "podman*" tcp dport 8191 accept ''; diff --git a/modules/services/server/traefik.nix b/modules/services/server/traefik.nix index b7806bf..608a056 100644 --- a/modules/services/server/traefik.nix +++ b/modules/services/server/traefik.nix @@ -246,7 +246,7 @@ ]; apprise.loadBalancer.servers = [ - {url = "http://127.0.0.1:8000";} + {url = "http://10.100.0.1:8000";} ]; authentik-outpost.loadBalancer.servers = [ @@ -254,7 +254,7 @@ ]; authentik.loadBalancer.servers = [ - {url = "http://[::1]:9000";} + {url = "http://127.0.0.1:9000";} ]; cloudbeaver.loadBalancer.servers = [ diff --git a/secrets.yaml b/secrets.yaml index 8a0236e..e468d72 100644 --- a/secrets.yaml +++ b/secrets.yaml @@ -89,6 +89,8 @@ atproto_app_password: ENC[AES256_GCM,data:3BOPzIRh130dzmSK6CYH24fE2w==,iv:GbpKDv anubis: signing_key: ENC[AES256_GCM,data:Lo294/P+RGhZLG03UlIWRDOiBexjPPNSZpwoQKfey8BBa/+h4Ix/JKl4u1ljUgIem7fSc6c0X9iktFBBE0nLQw==,iv:z15zaxxkElC22jiA0yZDX0bTDw0QXhdWNI0kdp2VvgQ=,tag:WU2dSUy8q/09JS+qiP/ocw==,type:str] valkey_password: ENC[AES256_GCM,data:Z3vkFpbjSTeBpyZYPyvDAb3wH6hFDmeKUULCkoxqFLbNuNxc4jH/teghDuPR/KhyHGcmZjCBSQ84f1yjKuw8FA==,iv:f27IjYaK6weSS4f+qtQQAnGU+TWRShXHIHo62yS+Wxk=,tag:LB/Cs618F+zSI9OLBET3zQ==,type:str] +atuin: + ai_auth_token: ENC[AES256_GCM,data:0/pRC4POzBEncrml1OxSPstZ+HeS6PhAgUntEEowGQGQht2BCSABRa/nxjYUGnadve6/gHEseRzgzGUgmS2sbg==,iv:MFvLfywu68YgzGJoqUzz1SHpABqqUw2t2e0EFOEAQ3I=,tag:4hLLBFzZCTseR0Z9TXfbXw==,type:str] sops: age: - enc: | @@ -127,8 +129,8 @@ sops: w2ToACYVigKMSlqPNG9bKcK75XI/iAONG48DQm1Nse3yB9/q3jwd+Q== -----END AGE ENCRYPTED FILE----- recipient: age1yl52c6aemw9anmfuqayamvsnkvlu6fmy0kk3gzvrraexxd9pr90qvs8pe5 - lastmodified: "2026-07-18T18:06:39Z" - mac: ENC[AES256_GCM,data:ceIZ/ACXfBn77DzaYmE9yCkMoU3FMRnCxOh35vgesHinIGHN6l8gzux9tUFWMkiDTtF0XgE0YGaFzzuPSy7cWwYRsoitfDQ8xMgCjQB9jTyvcc+1iey5zeA/zueu9FxQy0j60riNELm6Aylk/sXwt4ICbw65F0k+iiS8Z8QBC80=,iv:ryHAK6fDz0+7vyV3BaAOrLdeQVRgmUBkXjb6+nr03f4=,tag:WPwMWC9soEk74C/E2SzK4w==,type:str] + lastmodified: "2026-07-24T04:20:26Z" + mac: ENC[AES256_GCM,data:2DjeYvjJWhpx2ta1QYP0761ElkGqRiCYPA9kUp6ql3m9nQyhSeC1GPHs7NP4+BuMC0BET49LaNK982wK/hfDav1A1tu9E31cs4xUNKXzLekZiszANjEP/EnBgX63VSRz6dryfVuN51i+qc1Nv5oqmChWVe3ehl0vMgp22RIthSE=,iv:OLoCS4+8oh5lCYvII5TsuT1HEpSwWwXLS+Ckfp9LsNs=,tag:vhbu6TsCGpq9xfmpRazFDg==,type:str] pgp: - created_at: "2026-06-02T01:50:38Z" enc: |-