diff --git a/flake.lock b/flake.lock
index af4cbfa..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": {
@@ -150,13 +150,29 @@
"type": "github"
}
},
+ "impermanence": {
+ "locked": {
+ "lastModified": 1697303681,
+ "narHash": "sha256-caJ0rXeagaih+xTgRduYtYKL1rZ9ylh06CIrt1w5B4g=",
+ "owner": "nix-community",
+ "repo": "impermanence",
+ "rev": "0f317c2e9e56550ce12323eb39302d251618f5b5",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "master",
+ "repo": "impermanence",
+ "type": "github"
+ }
+ },
"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": {
@@ -168,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": {
@@ -194,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": {
@@ -214,6 +230,7 @@
"flake-parts": "flake-parts",
"futils": "futils",
"home-manager": "home-manager",
+ "impermanence": "impermanence",
"nixpkgs": "nixpkgs",
"nur": "nur",
"pre-commit-hooks": "pre-commit-hooks",
diff --git a/flake.nix b/flake.nix
index a07ee15..5a5b0ef 100644
--- a/flake.nix
+++ b/flake.nix
@@ -43,6 +43,13 @@
};
};
+ impermanence = {
+ type = "github";
+ owner = "nix-community";
+ repo = "impermanence";
+ ref = "master";
+ };
+
nixpkgs = {
type = "github";
owner = "NixOS";
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[]kMAtmM/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/hardware/bluetooth/default.nix b/modules/nixos/hardware/bluetooth/default.nix
index e9b1991..efce5c4 100644
--- a/modules/nixos/hardware/bluetooth/default.nix
+++ b/modules/nixos/hardware/bluetooth/default.nix
@@ -18,6 +18,13 @@ in
services.blueman.enable = true;
}
+ # Persist bluetooth files
+ {
+ my.system.persist.directories = [
+ "/var/lib/bluetooth"
+ ];
+ }
+
# Support for additional bluetooth codecs
(lib.mkIf cfg.loadExtraCodecs {
hardware.pulseaudio = {
diff --git a/modules/nixos/hardware/networking/default.nix b/modules/nixos/hardware/networking/default.nix
index f0806fe..51dcfce 100644
--- a/modules/nixos/hardware/networking/default.nix
+++ b/modules/nixos/hardware/networking/default.nix
@@ -22,6 +22,11 @@ in
config = lib.mkMerge [
(lib.mkIf cfg.wireless.enable {
networking.networkmanager.enable = true;
+
+ # Persist NetworkManager files
+ my.system.persist.directories = [
+ "/etc/NetworkManager/system-connections"
+ ];
})
];
}
diff --git a/modules/nixos/services/aria/default.nix b/modules/nixos/services/aria/default.nix
index 2d1b3e2..4946663 100644
--- a/modules/nixos/services/aria/default.nix
+++ b/modules/nixos/services/aria/default.nix
@@ -65,12 +65,12 @@ in
aria-rpc = {
port = cfg.rpcPort;
# Proxy websockets for RPC
- extraConfig = {
- locations."/".proxyWebsockets = true;
- };
+ websocketsLocations = [ "/" ];
};
};
+ # FIXME: persistence?
+
# NOTE: unfortunately aria2 does not log connection failures for fail2ban
};
}
diff --git a/modules/nixos/services/audiobookshelf/default.nix b/modules/nixos/services/audiobookshelf/default.nix
index da9ec55..9985a26 100644
--- a/modules/nixos/services/audiobookshelf/default.nix
+++ b/modules/nixos/services/audiobookshelf/default.nix
@@ -30,12 +30,12 @@ in
audiobookshelf = {
inherit (cfg) port;
# Proxy websockets for RPC
- extraConfig = {
- locations."/".proxyWebsockets = true;
- };
+ websocketsLocations = [ "/" ];
};
};
+ # FIXME: persistence?
+
services.fail2ban.jails = {
audiobookshelf = ''
enabled = true
diff --git a/modules/nixos/services/blog/default.nix b/modules/nixos/services/blog/default.nix
index e4d2d42..aadc4f0 100644
--- a/modules/nixos/services/blog/default.nix
+++ b/modules/nixos/services/blog/default.nix
@@ -41,5 +41,12 @@ in
# Those are all subdomains, no problem
my.services.nginx.virtualHosts = hostsInfo;
+
+ my.system.persist.directories = [
+ "/var/www/blog"
+ "/var/www/cv"
+ "/var/www/dev"
+ "/var/www/key"
+ ];
};
}
diff --git a/modules/nixos/services/calibre-web/default.nix b/modules/nixos/services/calibre-web/default.nix
index b7bf9df..8a8af33 100644
--- a/modules/nixos/services/calibre-web/default.nix
+++ b/modules/nixos/services/calibre-web/default.nix
@@ -53,6 +53,11 @@ in
];
};
+ my.system.persist.directories = [
+ "/var/lib/${config.services.calibre-web.dataDir}"
+ cfg.libraryPath
+ ];
+
services.fail2ban.jails = {
calibre-web = ''
enabled = true
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/flood/default.nix b/modules/nixos/services/flood/default.nix
index f3fe90b..23154ed 100644
--- a/modules/nixos/services/flood/default.nix
+++ b/modules/nixos/services/flood/default.nix
@@ -28,6 +28,8 @@ in
};
};
+ # FIXME: persistence?
+
# NOTE: unfortunately flood does not log connection failures for fail2ban
};
}
diff --git a/modules/nixos/services/forgejo/default.nix b/modules/nixos/services/forgejo/default.nix
index 511724b..b7cc0c5 100644
--- a/modules/nixos/services/forgejo/default.nix
+++ b/modules/nixos/services/forgejo/default.nix
@@ -147,6 +147,11 @@ in
];
};
+ my.system.persist.directories = [
+ config.services.forgejo.lfs.contentDir
+ config.services.forgejo.repositoryRoot
+ ];
+
services.fail2ban.jails = {
forgejo = ''
enabled = true
diff --git a/modules/nixos/services/gitea/default.nix b/modules/nixos/services/gitea/default.nix
index 95bdf42..76de5dd 100644
--- a/modules/nixos/services/gitea/default.nix
+++ b/modules/nixos/services/gitea/default.nix
@@ -131,6 +131,11 @@ in
];
};
+ my.system.persist.directories = [
+ config.services.gitea.lfs.contentDir
+ config.services.gitea.repositoryRoot
+ ];
+
services.fail2ban.jails = {
gitea = ''
enabled = true
diff --git a/modules/nixos/services/grocy/default.nix b/modules/nixos/services/grocy/default.nix
index 9045b03..67de377 100644
--- a/modules/nixos/services/grocy/default.nix
+++ b/modules/nixos/services/grocy/default.nix
@@ -37,6 +37,9 @@ in
useACMEHost = config.networking.domain;
};
+ # FIXME: backup
+ # FIXME: persistence
+
# NOTE: unfortunately grocy does not log connection failures for fail2ban
};
}
diff --git a/modules/nixos/services/indexers/default.nix b/modules/nixos/services/indexers/default.nix
index 8a42345..332ae30 100644
--- a/modules/nixos/services/indexers/default.nix
+++ b/modules/nixos/services/indexers/default.nix
@@ -33,6 +33,10 @@ in
port = jackettPort;
};
};
+
+ my.system.persist.directories = [
+ config.services.jackett.dataDir
+ ];
})
(lib.mkIf cfg.nzbhydra.enable {
@@ -45,6 +49,10 @@ in
port = nzbhydraPort;
};
};
+
+ my.system.persist.directories = [
+ config.services.nzbhydra2.dataDir
+ ];
})
(lib.mkIf cfg.prowlarr.enable {
@@ -58,6 +66,10 @@ in
};
};
+ my.system.persist.directories = [
+ "/var/lib/${config.systemd.services.prowlarr.serviceConfig.StateDirectory}"
+ ];
+
services.fail2ban.jails = {
prowlarr = ''
enabled = true
diff --git a/modules/nixos/services/jellyfin/default.nix b/modules/nixos/services/jellyfin/default.nix
index e8910a5..d5de6d5 100644
--- a/modules/nixos/services/jellyfin/default.nix
+++ b/modules/nixos/services/jellyfin/default.nix
@@ -27,21 +27,21 @@ 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;
- };
};
};
};
+ my.system.persist.directories = [
+ "/var/lib/${config.systemd.services.jellyfin.serviceConfig.StateDirectory}"
+ ];
+
services.fail2ban.jails = {
jellyfin = ''
enabled = 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/lohr/default.nix b/modules/nixos/services/lohr/default.nix
index 21ed93b..64925a2 100644
--- a/modules/nixos/services/lohr/default.nix
+++ b/modules/nixos/services/lohr/default.nix
@@ -107,5 +107,9 @@ in
};
};
};
+
+ my.system.persist.directories = [
+ "/var/lib/${config.systemd.services.lohr.serviceConfig.StateDirectory}"
+ ];
};
}
diff --git a/modules/nixos/services/matrix/default.nix b/modules/nixos/services/matrix/default.nix
index f423834..cb41a0f 100644
--- a/modules/nixos/services/matrix/default.nix
+++ b/modules/nixos/services/matrix/default.nix
@@ -214,5 +214,9 @@ in
config.services.matrix-synapse.dataDir
];
};
+
+ my.system.persist.directories = [
+ config.services.matrix-synapse.dataDir
+ ];
};
}
diff --git a/modules/nixos/services/mealie/default.nix b/modules/nixos/services/mealie/default.nix
index 664d5ba..4eb6977 100644
--- a/modules/nixos/services/mealie/default.nix
+++ b/modules/nixos/services/mealie/default.nix
@@ -72,6 +72,9 @@ in
};
};
+ # FIXME: backup
+ # FIXME: persistence
+
services.fail2ban.jails = {
mealie = ''
enabled = true
diff --git a/modules/nixos/services/miniflux/default.nix b/modules/nixos/services/miniflux/default.nix
index 400ae00..7bcfe30 100644
--- a/modules/nixos/services/miniflux/default.nix
+++ b/modules/nixos/services/miniflux/default.nix
@@ -49,6 +49,9 @@ in
};
};
+ # FIXME: backup
+ # FIXME: persistence
+
services.fail2ban.jails = {
miniflux = ''
enabled = true
diff --git a/modules/nixos/services/monitoring/default.nix b/modules/nixos/services/monitoring/default.nix
index 49919c1..4415cb5 100644
--- a/modules/nixos/services/monitoring/default.nix
+++ b/modules/nixos/services/monitoring/default.nix
@@ -130,5 +130,10 @@ in
inherit (cfg.grafana) port;
};
};
+
+ my.system.persist.directories = [
+ config.services.grafana.dataDir
+ "/var/lib/${config.services.prometheus.stateDir}"
+ ];
};
}
diff --git a/modules/nixos/services/navidrome/default.nix b/modules/nixos/services/navidrome/default.nix
index c513b91..106e01d 100644
--- a/modules/nixos/services/navidrome/default.nix
+++ b/modules/nixos/services/navidrome/default.nix
@@ -53,6 +53,10 @@ in
};
};
+ my.system.persist.directories = [
+ "/var/lib/${config.systemd.services.navidrome.serviceConfig.StateDirectory}"
+ ];
+
services.fail2ban.jails = {
navidrome = ''
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 e2c4746..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 {
@@ -88,6 +92,11 @@ in
];
};
+ my.system.persist.directories = [
+ config.services.nextcloud.home
+ config.services.nextcloud.datadir
+ ];
+
services.fail2ban.jails = {
nextcloud = ''
enabled = true
diff --git a/modules/nixos/services/nginx/default.nix b/modules/nixos/services/nginx/default.nix
index e305b29..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;
};
};
@@ -457,5 +486,9 @@ in
}
];
};
+
+ my.system.persist.directories = [
+ config.users.user.acme.home
+ ];
};
}
diff --git a/modules/nixos/services/paperless/default.nix b/modules/nixos/services/paperless/default.nix
index f62879a..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 = [ "/" ];
};
};
@@ -166,5 +146,10 @@ in
config.services.paperless.mediaDir
];
};
+
+ my.system.persist.directories = [
+ config.services.paperless-ng.dataDir
+ config.services.paperless-ng.mediaDir
+ ];
};
}
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/podgrab/default.nix b/modules/nixos/services/podgrab/default.nix
index 3ced8d3..ec6ecb2 100644
--- a/modules/nixos/services/podgrab/default.nix
+++ b/modules/nixos/services/podgrab/default.nix
@@ -51,5 +51,10 @@ in
inherit (cfg) port;
};
};
+
+ my.system.persist.directories = [
+ config.systemd.services.podgrab.environment.CONFIG
+ config.systemd.services.podgrab.environment.DATA
+ ];
};
}
diff --git a/modules/nixos/services/postgresql-backup/default.nix b/modules/nixos/services/postgresql-backup/default.nix
index dff5494..3d6c03b 100644
--- a/modules/nixos/services/postgresql-backup/default.nix
+++ b/modules/nixos/services/postgresql-backup/default.nix
@@ -24,5 +24,9 @@ in
(config.services.postgresqlBackup.location + "/*.prev.sql.gz")
];
};
+
+ my.system.persist.directories = [
+ config.services.postgresqlBackup.location
+ ];
};
}
diff --git a/modules/nixos/services/postgresql/default.nix b/modules/nixos/services/postgresql/default.nix
index bbe46d4..cea4c88 100644
--- a/modules/nixos/services/postgresql/default.nix
+++ b/modules/nixos/services/postgresql/default.nix
@@ -18,6 +18,13 @@ in
};
})
+ # Only persist directory if the actual service is enabled
+ (lib.mkIf config.services.postgresql.enable {
+ my.system.persist.directories = [
+ config.services.postgresql.dataDir
+ ];
+ })
+
# Taken from the manual
(lib.mkIf cfg.upgradeScript {
environment.systemPackages =
diff --git a/modules/nixos/services/pyload/default.nix b/modules/nixos/services/pyload/default.nix
index 88889bf..1167509 100644
--- a/modules/nixos/services/pyload/default.nix
+++ b/modules/nixos/services/pyload/default.nix
@@ -53,6 +53,23 @@ in
};
};
- # FIXME: fail2ban
+ # FIXME: backup
+ # FIXME: persistence
+
+ 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/quassel/default.nix b/modules/nixos/services/quassel/default.nix
index 695f9e0..0065195 100644
--- a/modules/nixos/services/quassel/default.nix
+++ b/modules/nixos/services/quassel/default.nix
@@ -46,5 +46,9 @@ in
# Because Quassel does not use the socket, I simply trust its connection
authentication = "host quassel quassel localhost trust";
};
+
+ my.system.persist.directories = [
+ config.services.quassel.dataDir
+ ];
};
}
diff --git a/modules/nixos/services/rss-bridge/default.nix b/modules/nixos/services/rss-bridge/default.nix
index 52b1030..977b431 100644
--- a/modules/nixos/services/rss-bridge/default.nix
+++ b/modules/nixos/services/rss-bridge/default.nix
@@ -22,5 +22,9 @@ in
forceSSL = true;
useACMEHost = config.networking.domain;
};
+
+ my.system.persist.directories = [
+ config.services.rss-bridge.dataDir
+ ];
};
}
diff --git a/modules/nixos/services/sabnzbd/default.nix b/modules/nixos/services/sabnzbd/default.nix
index 9e0d9c3..86202ab 100644
--- a/modules/nixos/services/sabnzbd/default.nix
+++ b/modules/nixos/services/sabnzbd/default.nix
@@ -24,6 +24,10 @@ in
};
};
+ my.system.persist.files = [
+ config.services.sabnzbd.configFile
+ ];
+
services.fail2ban.jails = {
sabnzbd = ''
enabled = true
diff --git a/modules/nixos/services/servarr/default.nix b/modules/nixos/services/servarr/default.nix
index e25d9cf..9cb2a59 100644
--- a/modules/nixos/services/servarr/default.nix
+++ b/modules/nixos/services/servarr/default.nix
@@ -19,6 +19,11 @@ let
enable = true;
group = "media";
};
+
+ # Thankfully those old style services all define users with homes
+ my.system.persist.directories = [
+ config.users.user.${service}.home
+ ];
};
mkRedirection = service: {
diff --git a/modules/nixos/services/ssh-server/default.nix b/modules/nixos/services/ssh-server/default.nix
index 9ae0fa8..008738f 100644
--- a/modules/nixos/services/ssh-server/default.nix
+++ b/modules/nixos/services/ssh-server/default.nix
@@ -20,6 +20,13 @@ in
};
};
+ # Persist SSH keys
+ 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/tandoor-recipes/default.nix b/modules/nixos/services/tandoor-recipes/default.nix
index 3447bee..6282769 100644
--- a/modules/nixos/services/tandoor-recipes/default.nix
+++ b/modules/nixos/services/tandoor-recipes/default.nix
@@ -83,6 +83,9 @@ in
};
};
+ # FIXME: backup
+ # FIXME: persistence
+
# NOTE: unfortunately tandoor-recipes does not log connection failures for fail2ban
};
}
diff --git a/modules/nixos/services/transmission/default.nix b/modules/nixos/services/transmission/default.nix
index ac8b24d..674fa81 100644
--- a/modules/nixos/services/transmission/default.nix
+++ b/modules/nixos/services/transmission/default.nix
@@ -91,6 +91,10 @@ in
allowedUDPPorts = [ cfg.peerPort ];
};
+ my.system.persist.directories = [
+ config.services.transmission.home
+ ];
+
# NOTE: unfortunately transmission does not log connection failures for fail2ban
};
}
diff --git a/modules/nixos/services/vikunja/default.nix b/modules/nixos/services/vikunja/default.nix
index 2753da3..575ddab 100644
--- a/modules/nixos/services/vikunja/default.nix
+++ b/modules/nixos/services/vikunja/default.nix
@@ -100,6 +100,8 @@ in
];
};
+ # FIXME: persistence
+
# NOTE: unfortunately vikunja does not log connection failures for fail2ban
};
}
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/services/woodpecker/server/default.nix b/modules/nixos/services/woodpecker/server/default.nix
index adf533e..5d25284 100644
--- a/modules/nixos/services/woodpecker/server/default.nix
+++ b/modules/nixos/services/woodpecker/server/default.nix
@@ -61,5 +61,7 @@ in
port = cfg.rpcPort;
};
};
+
+ # FIXME: persistence
};
}
diff --git a/modules/nixos/system/default.nix b/modules/nixos/system/default.nix
index e6fb25b..3531847 100644
--- a/modules/nixos/system/default.nix
+++ b/modules/nixos/system/default.nix
@@ -9,6 +9,7 @@
./language
./nix
./packages
+ ./persist
./podman
./polkit
./printing
diff --git a/modules/nixos/system/docker/default.nix b/modules/nixos/system/docker/default.nix
index f051814..cab9fb5 100644
--- a/modules/nixos/system/docker/default.nix
+++ b/modules/nixos/system/docker/default.nix
@@ -23,5 +23,9 @@ in
];
};
};
+
+ my.system.persist.directories = [
+ "/var/lib/docker"
+ ];
};
}
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
new file mode 100644
index 0000000..e0a1eeb
--- /dev/null
+++ b/modules/nixos/system/persist/default.nix
@@ -0,0 +1,66 @@
+# Ephemeral root configuration
+{ config, inputs, lib, ... }:
+let
+ cfg = config.my.system.persist;
+in
+{
+ imports = [
+ inputs.impermanence.nixosModules.impermanence
+ ];
+
+ options.my.system.persist = with lib; {
+ enable = mkEnableOption "stateless system configuration";
+
+ mountPoint = lib.mkOption {
+ type = types.str;
+ default = "/persistent";
+ example = "/etc/nix/persist";
+ description = ''
+ Which mount point should be used to persist this system's files and
+ directories.
+ '';
+ };
+
+ files = lib.mkOption {
+ type = with types; listOf str;
+ default = [ ];
+ example = [
+ "/etc/nix/id_rsa"
+ ];
+ description = ''
+ Additional files in the root to link to persistent storage.
+ '';
+ };
+
+ directories = lib.mkOption {
+ type = with types; listOf str;
+ default = [ ];
+ example = [
+ "/var/lib/libvirt"
+ ];
+ description = ''
+ Additional directories in the root to link to persistent storage.
+ '';
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ environment.persistence."${cfg.mountPoint}" = {
+ files = [
+ "/etc/machine-id" # Machine-specific ID
+ "/etc/adjtime" # Clock drift factor and offsets
+ ]
+ ++ cfg.files
+ ;
+
+ directories = [
+ "/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
+ ;
+ };
+ };
+}
diff --git a/modules/nixos/system/podman/default.nix b/modules/nixos/system/podman/default.nix
index 52630c7..8400dfd 100644
--- a/modules/nixos/system/podman/default.nix
+++ b/modules/nixos/system/podman/default.nix
@@ -44,5 +44,9 @@ in
];
};
};
+
+ my.system.persist.directories = [
+ "/var/lib/containers"
+ ];
};
}