diff --git a/flake.lock b/flake.lock index de89669..55d50b0 100644 --- a/flake.lock +++ b/flake.lock @@ -94,11 +94,11 @@ ] }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -136,11 +136,11 @@ ] }, "locked": { - "lastModified": 1730837930, - "narHash": "sha256-0kZL4m+bKBJUBQse0HanewWO0g8hDdCvBhudzxgehqc=", + "lastModified": 1732482255, + "narHash": "sha256-GUffLwzawz5WRVfWaWCg78n/HrBJrOG7QadFY6rtV8A=", "owner": "nix-community", "repo": "home-manager", - "rev": "2f607e07f3ac7e53541120536708e824acccfaa8", + "rev": "a9953635d7f34e7358d5189751110f87e3ac17da", "type": "github" }, "original": { @@ -168,11 +168,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730785428, - "narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=", + "lastModified": 1732521221, + "narHash": "sha256-2ThgXBUXAE1oFsVATK1ZX9IjPcS4nKFOAjhPNKuiMn0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7", + "rev": "4633a7c72337ea8fd23a4f2ba3972865e3ec685d", "type": "github" }, "original": { @@ -184,11 +184,11 @@ }, "nur": { "locked": { - "lastModified": 1730885145, - "narHash": "sha256-UPrBEY0No1O3ULb67xYjRh2r3u7MnZovfo1oYSPCIxI=", + "lastModified": 1732704680, + "narHash": "sha256-x3NlO2qzuobU9BrynzydX7X9oskJpysv7BI7DJ5cVSE=", "owner": "nix-community", "repo": "NUR", - "rev": "c0d8828600ef47d475e6ec33513bf9af6eb6b991", + "rev": "31a30f0862fd8b5f88a6597382bb09197356b19e", "type": "github" }, "original": { @@ -210,11 +210,11 @@ ] }, "locked": { - "lastModified": 1730814269, - "narHash": "sha256-fWPHyhYE6xvMI1eGY3pwBTq85wcy1YXqdzTZF+06nOg=", + "lastModified": 1732021966, + "narHash": "sha256-mnTbjpdqF0luOkou8ZFi2asa1N3AA2CchR/RqCNmsGE=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "d70155fdc00df4628446352fc58adc640cd705c2", + "rev": "3308484d1a443fc5bc92012435d79e80458fe43c", "type": "github" }, "original": { diff --git a/hosts/nixos/porthos/secrets/acme/dns-key.age b/hosts/nixos/porthos/secrets/acme/dns-key.age index fce2a84..d7f159e 100644 --- a/hosts/nixos/porthos/secrets/acme/dns-key.age +++ b/hosts/nixos/porthos/secrets/acme/dns-key.age @@ -1,8 +1,9 @@ age-encryption.org/v1 --> ssh-ed25519 cKojmg bQFr9oAnbo1rI/MpUV8wQz/Xj7iZY4ZU+Swf0nSIQFw -zama2XJ0gdvUlD2GHMhmZqHSxHe+dKSfXnHoWDcSw7Y --> ssh-ed25519 jPowng gitUwSKTNKWLSxnwa185O7x/u0ul93g8wPESdZaKRk8 -uvBIfAUkZp5sg6rfeEGvL5ZDV8m2uSEotW02kjPN3Hw ---- SZxe5f/CUZBvPQa2Sz/UBY3L68rMkIGGRuZPk7YE+Vg -r&{~v?}= -}+ SQM[]k MAtmM/Ls|ޅmCiYC}x \ No newline at end of file +-> ssh-ed25519 cKojmg Ec0xt1uJTva8MxUdoTVX5m3uWaIiRlodf345FEM7Uzs +aJIneWFJPB5HVeoUGp57agXih9YeZ6xMEbyQ+zJtWQY +-> ssh-ed25519 jPowng B5XotRgv7s/FUegGhceBj7EoukewNUOIFl4TFRQf1EQ +PgGCBd/Pqwp7ayqi7okHBGF1SfFpwT4KlHJ/np6p2uQ +--- AeLgwGz6k3OABb53cXNaCU/sgI4FlU1s6p8PhAaFOlg +1CԹULfI1Hmb}m šg0`XG>\>8rz+Y`ʢ.JBU!z¸Z50*ٟI] I +ĵo۰g¿tncz[{ +j&NNo{ -eP=L 6.SP:e \ No newline at end of file diff --git a/hosts/nixos/porthos/services.nix b/hosts/nixos/porthos/services.nix index a2339f4..ffd150a 100644 --- a/hosts/nixos/porthos/services.nix +++ b/hosts/nixos/porthos/services.nix @@ -95,6 +95,9 @@ in nextcloud = { enable = true; passwordFile = secrets."nextcloud/password".path; + collabora = { + enable = true; + }; }; nix-cache = { enable = true; @@ -149,11 +152,6 @@ in }; # Because I still need to play sysadmin ssh-server.enable = true; - # Recipe manager - tandoor-recipes = { - enable = true; - secretKeyFile = secrets."tandoor-recipes/secret-key".path; - }; # Torrent client and webui transmission = { enable = true; diff --git a/modules/home/direnv/lib/python.sh b/modules/home/direnv/lib/python.sh index 780fbe6..b4b2bce 100644 --- a/modules/home/direnv/lib/python.sh +++ b/modules/home/direnv/lib/python.sh @@ -53,4 +53,5 @@ layout_uv() { PATH_add "$VIRTUAL_ENV/bin" watch_file pyproject.toml watch_file uv.lock + watch_file .python-version } diff --git a/modules/home/tmux/default.nix b/modules/home/tmux/default.nix index 71ce4ca..ca99fdc 100644 --- a/modules/home/tmux/default.nix +++ b/modules/home/tmux/default.nix @@ -47,6 +47,7 @@ in clock24 = true; # I'm one of those heathens escapeTime = 0; # Let vim do its thing instead historyLimit = 100000; # Bigger buffer + mouse = false; # I dislike mouse support terminal = "tmux-256color"; # I want accurate termcap info plugins = with pkgs.tmuxPlugins; [ @@ -80,6 +81,13 @@ in ]; extraConfig = '' + # Refresh configuration + bind-key -N "Source tmux.conf" R source-file ${config.xdg.configHome}/tmux/tmux.conf \; display-message "Sourced tmux.conf!" + + # Accept sloppy Ctrl key when switching windows, on top of default mapping + bind-key -N "Select the previous window" C-p previous-window + bind-key -N "Select the next window" C-n next -window + # Better vim mode bind-key -T copy-mode-vi 'v' send -X begin-selection ${ diff --git a/modules/home/xdg/default.nix b/modules/home/xdg/default.nix index 270200e..803167f 100644 --- a/modules/home/xdg/default.nix +++ b/modules/home/xdg/default.nix @@ -30,11 +30,10 @@ in }; # A tidy home is a tidy mind dataFile = { - "bash/.keep".text = ""; - "gdb/.keep".text = ""; - "tig/.keep".text = ""; + "tig/.keep".text = ""; # `tig` uses `XDG_DATA_HOME` specifically... }; stateFile = { + "bash/.keep".text = ""; "python/.keep".text = ""; }; }; diff --git a/modules/nixos/services/aria/default.nix b/modules/nixos/services/aria/default.nix index 15bb5e8..4946663 100644 --- a/modules/nixos/services/aria/default.nix +++ b/modules/nixos/services/aria/default.nix @@ -65,9 +65,7 @@ in aria-rpc = { port = cfg.rpcPort; # Proxy websockets for RPC - extraConfig = { - locations."/".proxyWebsockets = true; - }; + websocketsLocations = [ "/" ]; }; }; diff --git a/modules/nixos/services/audiobookshelf/default.nix b/modules/nixos/services/audiobookshelf/default.nix index cb7bc08..9985a26 100644 --- a/modules/nixos/services/audiobookshelf/default.nix +++ b/modules/nixos/services/audiobookshelf/default.nix @@ -30,9 +30,7 @@ in audiobookshelf = { inherit (cfg) port; # Proxy websockets for RPC - extraConfig = { - locations."/".proxyWebsockets = true; - }; + websocketsLocations = [ "/" ]; }; }; diff --git a/modules/nixos/services/drone/runner-docker/default.nix b/modules/nixos/services/drone/runner-docker/default.nix index e53c608..1db263b 100644 --- a/modules/nixos/services/drone/runner-docker/default.nix +++ b/modules/nixos/services/drone/runner-docker/default.nix @@ -39,5 +39,7 @@ in extraGroups = [ "docker" ]; # Give access to the daemon }; users.groups.drone-runner-docker = { }; + + # FIXME: persistence? }; } diff --git a/modules/nixos/services/drone/runner-exec/default.nix b/modules/nixos/services/drone/runner-exec/default.nix index a9bb563..c30a1a2 100644 --- a/modules/nixos/services/drone/runner-exec/default.nix +++ b/modules/nixos/services/drone/runner-exec/default.nix @@ -63,5 +63,7 @@ in group = "drone-runner-exec"; }; users.groups.drone-runner-exec = { }; + + # FIXME: persistence? }; } diff --git a/modules/nixos/services/drone/server/default.nix b/modules/nixos/services/drone/server/default.nix index a3a1e49..b5d5df7 100644 --- a/modules/nixos/services/drone/server/default.nix +++ b/modules/nixos/services/drone/server/default.nix @@ -50,5 +50,7 @@ in inherit (cfg) port; }; }; + + # FIXME: persistence? }; } diff --git a/modules/nixos/services/fail2ban/default.nix b/modules/nixos/services/fail2ban/default.nix index be5f7da..efb07c9 100644 --- a/modules/nixos/services/fail2ban/default.nix +++ b/modules/nixos/services/fail2ban/default.nix @@ -33,5 +33,7 @@ in bantime = "10m"; }; }; + + # FIXME: persistence? }; } diff --git a/modules/nixos/services/forgejo/default.nix b/modules/nixos/services/forgejo/default.nix index 3ba4ead..b7cc0c5 100644 --- a/modules/nixos/services/forgejo/default.nix +++ b/modules/nixos/services/forgejo/default.nix @@ -148,8 +148,8 @@ in }; my.system.persist.directories = [ - config.services.gitea.lfs.contentDir - config.services.gitea.repositoryRoot + config.services.forgejo.lfs.contentDir + config.services.forgejo.repositoryRoot ]; services.fail2ban.jails = { diff --git a/modules/nixos/services/jellyfin/default.nix b/modules/nixos/services/jellyfin/default.nix index b54f9ef..d5de6d5 100644 --- a/modules/nixos/services/jellyfin/default.nix +++ b/modules/nixos/services/jellyfin/default.nix @@ -27,17 +27,13 @@ in my.services.nginx.virtualHosts = { jellyfin = { port = 8096; + websocketsLocations = [ "/socket" ]; extraConfig = { locations."/" = { extraConfig = '' proxy_buffering off; ''; }; - # Too bad for the repetition... - locations."/socket" = { - proxyPass = "http://127.0.0.1:8096/"; - proxyWebsockets = true; - }; }; }; }; diff --git a/modules/nixos/services/komga/default.nix b/modules/nixos/services/komga/default.nix index e1dc780..9412573 100644 --- a/modules/nixos/services/komga/default.nix +++ b/modules/nixos/services/komga/default.nix @@ -36,6 +36,8 @@ in }; }; + # FIXME: persistence? + services.fail2ban.jails = { komga = '' enabled = true diff --git a/modules/nixos/services/nextcloud/collabora.nix b/modules/nixos/services/nextcloud/collabora.nix new file mode 100644 index 0000000..dce1a99 --- /dev/null +++ b/modules/nixos/services/nextcloud/collabora.nix @@ -0,0 +1,52 @@ +# Document editor with Nextcloud +{ config, lib, ... }: +let + cfg = config.my.services.nextcloud.collabora; +in +{ + options.my.services.nextcloud.collabora = with lib; { + enable = mkEnableOption "Collabora integration"; + + port = mkOption { + type = types.port; + default = 9980; + example = 8080; + description = "Internal port for API"; + }; + }; + + config = lib.mkIf cfg.enable { + services.collabora-online = { + enable = true; + inherit (cfg) port; + + aliasGroups = [ + { + host = "https://collabora.${config.networking.domain}"; + # Allow using from nextcloud + aliases = [ "https://${config.services.nextcloud.hostName}" ]; + } + ]; + + settings = { + # Rely on reverse proxy for SSL + ssl = { + enable = false; + termination = true; + }; + }; + }; + + my.services.nginx.virtualHosts = { + collabora = { + inherit (cfg) port; + websocketsLocations = [ + "~ ^/cool/(.*)/ws$" + "^~ /cool/adminws" + ]; + }; + }; + + # FIXME: persistence? + }; +} diff --git a/modules/nixos/services/nextcloud/default.nix b/modules/nixos/services/nextcloud/default.nix index b13a608..e561ce2 100644 --- a/modules/nixos/services/nextcloud/default.nix +++ b/modules/nixos/services/nextcloud/default.nix @@ -4,6 +4,10 @@ let cfg = config.my.services.nextcloud; in { + imports = [ + ./collabora.nix + ]; + options.my.services.nextcloud = with lib; { enable = mkEnableOption "Nextcloud"; maxSize = mkOption { diff --git a/modules/nixos/services/nginx/default.nix b/modules/nixos/services/nginx/default.nix index 721ae76..32c1b7d 100644 --- a/modules/nixos/services/nginx/default.nix +++ b/modules/nixos/services/nginx/default.nix @@ -17,6 +17,16 @@ let ''; }; + websocketsLocations = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ "/socket" ]; + description = '' + Which locations on this virtual host should be configured for + websockets. + ''; + }; + port = mkOption { type = with types; nullOr port; default = null; @@ -60,10 +70,13 @@ let extraConfig = mkOption { type = types.attrs; # FIXME: forward type of virtualHosts example = { - locations."/socket" = { - proxyPass = "http://127.0.0.1:8096/"; - proxyWebsockets = true; - }; + extraConfig = '' + add_header X-Clacks-Overhead "GNU Terry Pratchett"; + ''; + + locations."/".extraConfig = '' + client_max_body_size 1G; + ''; }; default = { }; description = '' @@ -86,7 +99,7 @@ in type = types.str; example = "/var/lib/acme/creds.env"; description = '' - Gandi API key file as an 'EnvironmentFile' (see `systemd.exec(5)`) + OVH API key file as an 'EnvironmentFile' (see `systemd.exec(5)`) ''; }; }; @@ -108,12 +121,7 @@ in }; jellyfin = { port = 8096; - extraConfig = { - locations."/socket" = { - proxyPass = "http://127.0.0.1:8096/"; - proxyWebsockets = true; - }; - }; + websocketsLocations = [ "/socket" ]; }; }; description = '' @@ -195,6 +203,19 @@ in } configured. ''; })) + ++ (lib.flip lib.mapAttrsToList cfg.virtualHosts (_: { subdomain, ... } @ args: + let + proxyPass = [ "port" "socket" ]; + proxyPassUsed = lib.any (v: args.${v} != null) proxyPass; + in + { + assertion = args.websocketsLocations != [ ] -> proxyPassUsed; + message = '' + Subdomain '${subdomain}' can only use 'websocketsLocations' with one of ${ + lib.concatStringsSep ", " (builtins.map (v: "'${v}'") proxyPass) + }. + ''; + })) ++ ( let ports = lib.my.mapFilter @@ -241,6 +262,14 @@ in virtualHosts = let domain = config.networking.domain; + mkProxyPass = { websocketsLocations, ... }: proxyPass: + let + websockets = lib.genAttrs websocketsLocations (_: { + inherit proxyPass; + proxyWebsockets = true; + }); + in + { "/" = { inherit proxyPass; }; } // websockets; mkVHost = ({ subdomain, ... } @ args: lib.nameValuePair "${subdomain}.${domain}" (lib.my.recursiveMerge [ @@ -251,8 +280,7 @@ in } # Proxy to port (lib.optionalAttrs (args.port != null) { - locations."/".proxyPass = - "http://127.0.0.1:${toString args.port}"; + locations = mkProxyPass args "http://127.0.0.1:${toString args.port}"; }) # Serve filesystem content (lib.optionalAttrs (args.root != null) { @@ -260,8 +288,7 @@ in }) # Serve to UNIX socket (lib.optionalAttrs (args.socket != null) { - locations."/".proxyPass = - "http://unix:${args.socket}"; + locations = mkProxyPass args "http://unix:${args.socket}"; }) # Redirect to a different domain (lib.optionalAttrs (args.redirect != null) { @@ -281,6 +308,7 @@ in locations."/" = { extraConfig = + # FIXME: check that X-User is dropped otherwise (args.extraConfig.locations."/".extraConfig or "") + '' # Use SSO auth_request /sso-auth; @@ -414,7 +442,8 @@ in { "${domain}" = { extraDomainNames = [ "*.${domain}" ]; - dnsProvider = "gandiv5"; + dnsProvider = "ovh"; + dnsPropagationCheck = false; # OVH is slow inherit (cfg.acme) credentialsFile; }; }; diff --git a/modules/nixos/services/paperless/default.nix b/modules/nixos/services/paperless/default.nix index d86be58..22ca8ad 100644 --- a/modules/nixos/services/paperless/default.nix +++ b/modules/nixos/services/paperless/default.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: let cfg = config.my.services.paperless; in @@ -80,50 +80,34 @@ in # Misc PAPERLESS_TIME_ZONE = config.time.timeZone; PAPERLESS_ADMIN_USER = cfg.username; - - # Fix classifier hangs - LD_LIBRARY_PATH = "${lib.getLib pkgs.mkl}/lib"; }; # Admin password passwordFile = cfg.passwordFile; + + # Secret key + environmentFile = cfg.secretKeyFile; }; systemd.services = { paperless-scheduler = { requires = [ "postgresql.service" ]; after = [ "postgresql.service" ]; - - serviceConfig = { - EnvironmentFile = cfg.secretKeyFile; - }; }; paperless-consumer = { requires = [ "postgresql.service" ]; after = [ "postgresql.service" ]; - - serviceConfig = { - EnvironmentFile = cfg.secretKeyFile; - }; }; paperless-web = { requires = [ "postgresql.service" ]; after = [ "postgresql.service" ]; - - serviceConfig = { - EnvironmentFile = cfg.secretKeyFile; - }; }; paperless-task-queue = { requires = [ "postgresql.service" ]; after = [ "postgresql.service" ]; - - serviceConfig = { - EnvironmentFile = cfg.secretKeyFile; - }; }; }; @@ -152,11 +136,7 @@ in sso = { enable = true; }; - - # Enable websockets on root - extraConfig = { - locations."/".proxyWebsockets = true; - }; + websocketsLocations = [ "/" ]; }; }; diff --git a/modules/nixos/services/pdf-edit/default.nix b/modules/nixos/services/pdf-edit/default.nix index d59507b..73527d9 100644 --- a/modules/nixos/services/pdf-edit/default.nix +++ b/modules/nixos/services/pdf-edit/default.nix @@ -54,6 +54,8 @@ in }; }; + # FIXME: persistence? + services.fail2ban.jails = { stirling-pdf = '' enabled = true diff --git a/modules/nixos/services/pyload/default.nix b/modules/nixos/services/pyload/default.nix index 4e8e083..1167509 100644 --- a/modules/nixos/services/pyload/default.nix +++ b/modules/nixos/services/pyload/default.nix @@ -56,6 +56,20 @@ in # FIXME: backup # FIXME: persistence - # FIXME: fail2ban + services.fail2ban.jails = { + pyload = '' + enabled = true + filter = pyload + port = http,https + ''; + }; + + environment.etc = { + "fail2ban/filter.d/pyload.conf".text = '' + [Definition] + failregex = ^.*Login failed for user '.*' \[CLIENT: \]$ + journalmatch = _SYSTEMD_UNIT=pyload.service + ''; + }; }; } diff --git a/modules/nixos/services/ssh-server/default.nix b/modules/nixos/services/ssh-server/default.nix index 0cabc6f..008738f 100644 --- a/modules/nixos/services/ssh-server/default.nix +++ b/modules/nixos/services/ssh-server/default.nix @@ -21,12 +21,11 @@ in }; # Persist SSH keys - my.system.persist.files = [ - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - ]; + my.system.persist.files = + let + pubAndPrivKey = key: [ key.path "${key.path}.pub" ]; + in + lib.concatMap pubAndPrivKey systemConfig.services.openssh.hostKeys; # Opens the relevant UDP ports. programs.mosh.enable = true; diff --git a/modules/nixos/services/woodpecker/agent-docker/default.nix b/modules/nixos/services/woodpecker/agent-docker/default.nix index 79d3299..2e74b67 100644 --- a/modules/nixos/services/woodpecker/agent-docker/default.nix +++ b/modules/nixos/services/woodpecker/agent-docker/default.nix @@ -38,5 +38,7 @@ in ]; }; }; + + # FIXME: persistence? }; } diff --git a/modules/nixos/services/woodpecker/agent-exec/default.nix b/modules/nixos/services/woodpecker/agent-exec/default.nix index 24161b0..4210242 100644 --- a/modules/nixos/services/woodpecker/agent-exec/default.nix +++ b/modules/nixos/services/woodpecker/agent-exec/default.nix @@ -62,5 +62,7 @@ in ]; }; }; + + # FIXME: persistence? }; } diff --git a/modules/nixos/system/packages/default.nix b/modules/nixos/system/packages/default.nix index ebea06f..6a78ff6 100644 --- a/modules/nixos/system/packages/default.nix +++ b/modules/nixos/system/packages/default.nix @@ -1,5 +1,5 @@ # Common packages -{ config, lib, pkgs, ... }: +{ config, lib, ... }: let cfg = config.my.system.packages; in @@ -13,10 +13,6 @@ in }; config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs; [ - wget - ]; - programs = { vim = { enable = true; diff --git a/modules/nixos/system/persist/default.nix b/modules/nixos/system/persist/default.nix index fbf63fa..e0a1eeb 100644 --- a/modules/nixos/system/persist/default.nix +++ b/modules/nixos/system/persist/default.nix @@ -47,16 +47,17 @@ in config = lib.mkIf cfg.enable { environment.persistence."${cfg.mountPoint}" = { files = [ - "/etc/machine-id" + "/etc/machine-id" # Machine-specific ID + "/etc/adjtime" # Clock drift factor and offsets ] ++ cfg.files ; directories = [ - "/etc/nixos" - "/var/log" - "/var/lib/nixos" - "/var/lib/systemd/coredump" + "/etc/nixos" # In case it's storage directory of our configuration + "/var/log" # Logs + "/var/lib/nixos" # UID/GID maps + "/var/lib/systemd/coredump" # Coredumps ] ++ cfg.directories ;