summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes3
-rw-r--r--CHANGELOG.md83
-rw-r--r--cog.toml1
-rw-r--r--flake.lock182
-rw-r--r--flake.nix73
-rw-r--r--hosts/server1/configuration.nix5
-rw-r--r--hosts/server1/hardware.nix1
-rw-r--r--notes/deploy.md6
-rw-r--r--system/default.nix6
-rw-r--r--system/disks/default.nix84
-rw-r--r--system/file_system_layouts/default.nix49
-rw-r--r--system/impermanence/default.nix23
-rw-r--r--system/impermanence/mods/acme.nix5
-rw-r--r--system/impermanence/mods/fail2ban.nix10
-rw-r--r--system/impermanence/mods/keycloak.nix5
-rw-r--r--system/impermanence/mods/mail.nix34
-rw-r--r--system/impermanence/mods/minecraft.nix10
-rw-r--r--system/impermanence/mods/nix-sync.nix10
-rw-r--r--system/impermanence/mods/openssh.nix21
-rw-r--r--system/impermanence/mods/users.nix28
-rw-r--r--system/mail/default.nix40
-rw-r--r--system/secrets/default.nix14
-rw-r--r--system/secrets/keycloak/passwd.tix17
-rw-r--r--system/secrets/secrets.nix14
-rw-r--r--system/services/default.nix7
-rw-r--r--system/services/fail2ban/default.nix4
-rw-r--r--system/services/keycloak/default.nix2
-rw-r--r--system/services/mail/default.nix43
-rw-r--r--system/services/mail/users.nix (renamed from system/mail/users.nix)bin486 -> 486 bytes
-rw-r--r--system/services/minecraft/default.nix2
-rw-r--r--system/services/nginx/default.nix10
-rw-r--r--system/services/nginx/hosts.nixbin1027 -> 989 bytes
-rw-r--r--system/services/nix-sync/default.nix159
-rw-r--r--system/services/openssh/default.nix17
-rw-r--r--system/services/opensshd/default.nix13
-rw-r--r--system/users/default.nix93
36 files changed, 846 insertions, 228 deletions
diff --git a/.gitattributes b/.gitattributes
index 80f5bb9..b9e9c86 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,2 @@
-system/mail/users.nix filter=git-crypt diff=git-crypt
+system/services/mail/users.nix filter=git-crypt diff=git-crypt
 system/services/nginx/hosts.nix filter=git-crypt diff=git-crypt
-system/services/acme/domains.nix filter=git-crypt diff=git-crypt
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3ec31bd..1827e42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,89 @@
 All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
 
 - - -
+## v0.3.0 - 2023-07-10
+#### Bug Fixes
+- **(host/server1)** Use working path to disk - (26b6c91) - Soispha
+- **(system/disks)** Change partitioning scheme to support gpt/bios boot - (40458f4) - Soispha
+- **(system/impermanence/m/mail)** Add rspamd dir - (a0d04e5) - Soispha
+- **(system/impermanence/m/users)** Make /home readable - (8c1dd93) - Soispha
+- **(system/secrets)** Update after redeploy - (778f8ad) - Soispha
+- **(system/secrets)** Ensure that ssh host key is available in stage 2 - (5bb8cb3) - Soispha
+- **(system/services/keycloak)** Use agenix to store passwd - (265eb9d) - Soispha
+- **(system/services/nix-sync)** Nix build needs access to /proc/stat - (123a8d9) - Soispha
+- **(treewide)** Move all persistent dirs to impermanence to set permissions - (7815ef2) - Soispha
+#### Documentation
+- **(notes)** Add section about redeployment - (3ea6a58) - Soispha
+#### Features
+- **(flake)** Add agenix module - (78b566e) - Soispha
+- **(system/disks)** Add disko - (d176a33) - Soispha
+#### Miscellaneous Chores
+- **(.gitattributes)** Remove removed acme path - (81cf12b) - Soispha
+#### Refactoring
+- **(system/impermanence)** Move to own directory - (2a6b022) - Soispha
+
+- - -
+
+## v0.2.0 - 2023-07-07
+#### Bug Fixes
+- **(system)** Import everything - (a1758ed) - Soispha
+- **(system)** Import everything - (07f1e4a) - Soispha
+- **(system/fs-layout)** Remove persistent dir as it's now in /srv - (ce36bb2) - Soispha
+- **(system/fs_layout/impermanence)** Make sshd dir 755 - (4fdf20b) - Soispha
+- **(system/services)** Move acmeWebRoot back to /var/lib/acme - (532412a) - Soispha
+- **(system/services)** Inherit acmeRoot manually - (80e5776) - Soispha
+- **(system/services/acme)** Leave certs generation to nixos - (1f6ff65) - Soispha
+- **(system/services/git-sync)** Use correct systemd options - (77e512a) - Soispha
+- **(system/services/git-sync)** Switch to str to avoid impurity - (a8ffaea) - Soispha
+- **(system/services/git-sync)** Purge assertion, as we're always on linux - (74a735b) - Soispha
+- **(system/services/mail)** Tell git-crypt new users.nix location - (cdea671) - sils
+- **(system/services/nginx)** Set the correct acme webRoot - (252d983) - Soispha
+- **(system/services/nginx)** Create nix-sync cache through impermanence - (869d74c) - Soispha
+- **(system/services/nginx)** Remove slash from acme webroot - (bec5cf4) - Soispha
+- **(system/services/nginx)** Actually enable git-sync - (374c499) - Soispha
+- **(system/services/nginx/hosts)** Inherit acmeRoot setting - (990cb3c) - Soispha
+- **(system/services/nix-sync)** Guard deletion of `repo.path` - (16da0f2) - Soispha
+- **(system/services/nix-sync)** Pull before rebuilding - (3df8d67) - Soispha
+- **(system/services/nix-sync)** Generate the needed repo paths - (5bed7c8) - Soispha
+- **(system/services/nix-sync)** Rebuild website on gc - (393f0e6) - Soispha
+- **(system/services/nix-sync)** Really remove last reference to git-sync - (0b36dbd) - Soispha
+- **(system/services/nix-sync)** Small typos in ExecStart - (0ac9885) - Soispha
+- **(system/services/nix-sync)** Use cache directory - (6e18fa4) - Soispha
+- **(system/services/nix-sync)** Use correct git urls - (9f9a140) - Soispha
+- **(system/services/nix-sync)** Generate root independent of path - (a505c18) - Soispha
+- **(system/services/nix-sync)** Add the cachePath rw - (dd84945) - Soispha
+- **(system/services/nix-sync)** Add '/etc/nginx/websites' to kept dirs - (6a5b874) - Soispha
+- **(system/services/nix-sync)** Remove slash from cachePath - (33398b1) - Soispha
+- **(system/services/nix-sync)** Add some required paths to unit - (e6b778b) - Soispha
+- **(system/services/nix-sync)** Generate user and group if set to default - (39abbf7) - Soispha
+- **(system/services/nix-sync)** Rename units to nix-sync-<domain> - (844ff55) - Soispha
+- **(system/services/nix-sync)** Use correct shell escape for paths - (3c42c6b) - Soispha
+- **(system/services/nix-sync)** Use correct writeScript function - (4ef4b09) - Soispha
+- **(system/services/nix-sync)** Fully rename to nix-sync - (c35eeac) - Soispha
+- **(system/services/openssh)** Set correct permissions on ssh dir - (f3f8e43) - Soispha
+- **(system/services/openssh)** Rename to 'openssh' as the 'd' is a typo - (99d4b3b) - Soispha
+#### Build system
+- **(cog)** Remove 'prod' from whitelist as it's deprecated - (661a2d4) - Soispha
+- **(flake)** Update - (2f10834) - Soispha
+#### Documentation
+- **(system/services/nix-sync)** Change last remnant from git-sync - (1fe7e31) - Soispha
+#### Features
+- **(system/file_system_layout)** Add impermanence - (1c4672d) - Soispha
+- **(system/services/nix-sync)** Split unit into a timer and unit - (42d44c6) - Soispha
+- **(system/services/nix-sync)** Remodel git-sync to make it useful - (3f2fedf) - Soispha
+#### Miscellaneous Chores
+- **(.gitattributes)** Remove removed acme path - (99ae5c9) - Soispha
+#### Refactoring
+- **(system/impermanence)** Move to own directory - (2c6c07e) - Soispha
+- **(system/services/mail)** Move mail to services as it's one - (32ab086) - Soispha
+- **(system/services/nginx)** Adapt to new nix-sync module - (9b88691) - Soispha
+- **(system/services/nix-sync)** Consolidate into repoCachePath - (1c93755) - Soispha
+#### Style
+- **(system/fs_layouts)** Merge attrsets - (d0a8582) - Soispha
+- **(system/services/nginx)** Use nested attr set for acme options - (9fc5517) - Soispha
+
+- - -
+
 ## v0.1.0 - 2023-06-19
 #### Bug Fixes
 - **(acme)** Store certs permanently. - (ab3c9aa) - sils
diff --git a/cog.toml b/cog.toml
index 814eccd..6f5f747 100644
--- a/cog.toml
+++ b/cog.toml
@@ -5,7 +5,6 @@ pre_package_bump_hooks = []
 post_package_bump_hooks = []
 
 branch_whitelist = [
-  "prod",
   "main",
 ]
 
diff --git a/flake.lock b/flake.lock
index 2a58f6f..c08cea2 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,5 +1,27 @@
 {
   "nodes": {
+    "agenix": {
+      "inputs": {
+        "darwin": "darwin",
+        "home-manager": "home-manager",
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1689334118,
+        "narHash": "sha256-djk5AZv1yU84xlKFaVHqFWvH73U7kIRstXwUAnDJPsk=",
+        "owner": "ryantm",
+        "repo": "agenix",
+        "rev": "0d8c5325fc81daf00532e3e26c6752f7bcde1143",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ryantm",
+        "repo": "agenix",
+        "type": "github"
+      }
+    },
     "blobs": {
       "flake": false,
       "locked": {
@@ -16,6 +38,57 @@
         "type": "gitlab"
       }
     },
+    "crane": {
+      "inputs": {
+        "flake-compat": [
+          "flake-compat"
+        ],
+        "flake-utils": [
+          "flake-utils"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "rust-overlay": [
+          "rust-overlay"
+        ]
+      },
+      "locked": {
+        "lastModified": 1688772518,
+        "narHash": "sha256-ol7gZxwvgLnxNSZwFTDJJ49xVY5teaSvF7lzlo3YQfM=",
+        "owner": "ipetkov",
+        "repo": "crane",
+        "rev": "8b08e96c9af8c6e3a2b69af5a7fa168750fcf88e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ipetkov",
+        "repo": "crane",
+        "type": "github"
+      }
+    },
+    "darwin": {
+      "inputs": {
+        "nixpkgs": [
+          "agenix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1673295039,
+        "narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
+        "owner": "lnl7",
+        "repo": "nix-darwin",
+        "rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
+        "type": "github"
+      },
+      "original": {
+        "owner": "lnl7",
+        "ref": "master",
+        "repo": "nix-darwin",
+        "type": "github"
+      }
+    },
     "disko": {
       "inputs": {
         "nixpkgs": [
@@ -23,11 +96,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1687968164,
-        "narHash": "sha256-L9jr2zCB6NIaBE3towusjGBigsnE2pMID8wBGkYbTS4=",
+        "lastModified": 1689324677,
+        "narHash": "sha256-83DCDJwBkulQFQESe37+tG0qUb8JkQLJHJ3Qn7iGx7Q=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "8002e7cb899bc2a02a2ebfb7f999fcd7c18b92a1",
+        "rev": "7eb09408393faa5b8f3b3524c39cb93d938e8d04",
         "type": "github"
       },
       "original": {
@@ -39,11 +112,11 @@
     "flake-compat": {
       "flake": false,
       "locked": {
-        "lastModified": 1668681692,
-        "narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
+        "lastModified": 1673956053,
+        "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
         "owner": "edolstra",
         "repo": "flake-compat",
-        "rev": "009399224d5e398d03b22badca40a37ac85412a1",
+        "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
         "type": "github"
       },
       "original": {
@@ -59,11 +132,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1687709756,
-        "narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=",
+        "lastModified": 1689068808,
+        "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7",
+        "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
         "type": "github"
       },
       "original": {
@@ -72,6 +145,27 @@
         "type": "github"
       }
     },
+    "home-manager": {
+      "inputs": {
+        "nixpkgs": [
+          "agenix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1682203081,
+        "narHash": "sha256-kRL4ejWDhi0zph/FpebFYhzqlOBrk0Pl3dzGEKSAlEw=",
+        "owner": "nix-community",
+        "repo": "home-manager",
+        "rev": "32d3e39c491e2f91152c84f8ad8b003420eab0a1",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "home-manager",
+        "type": "github"
+      }
+    },
     "impermanence": {
       "locked": {
         "lastModified": 1684264534,
@@ -89,11 +183,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1688287271,
-        "narHash": "sha256-urPMC+oAUAzNvz0aS7ty6nHbkbMwQx2Xh7W/QZRq3gU=",
+        "lastModified": 1689715163,
+        "narHash": "sha256-HgBowH0RUU+6SpvpXYfTSunAqaME/6d0bqAW+shW6e4=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "7cacbc32ad63e8e7b91018d64f9a92cb3455ee8b",
+        "rev": "0171976ee0a1fa795b105c19a323e67b9c6094d9",
         "type": "github"
       },
       "original": {
@@ -133,20 +227,82 @@
         "type": "indirect"
       }
     },
+    "ragenix": {
+      "inputs": {
+        "agenix": [
+          "agenix"
+        ],
+        "crane": [
+          "crane"
+        ],
+        "flake-utils": [
+          "flake-utils"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "rust-overlay": [
+          "rust-overlay"
+        ]
+      },
+      "locked": {
+        "lastModified": 1682237245,
+        "narHash": "sha256-xbBR7LNK+d5Yi/D6FXQGc1R6u2VV2nwr/Df5iaEbOEQ=",
+        "owner": "yaxitech",
+        "repo": "ragenix",
+        "rev": "281f68c3d477904f79ff1cd5807a8c226cd80a50",
+        "type": "github"
+      },
+      "original": {
+        "owner": "yaxitech",
+        "repo": "ragenix",
+        "type": "github"
+      }
+    },
     "root": {
       "inputs": {
+        "agenix": "agenix",
+        "crane": "crane",
         "disko": "disko",
+        "flake-compat": "flake-compat",
         "flake-utils": "flake-utils",
         "impermanence": "impermanence",
         "nixpkgs": "nixpkgs",
+        "ragenix": "ragenix",
+        "rust-overlay": "rust-overlay",
         "simple-nixos-mailserver": "simple-nixos-mailserver",
         "systems": "systems"
       }
     },
+    "rust-overlay": {
+      "inputs": {
+        "flake-utils": [
+          "flake-utils"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1689735719,
+        "narHash": "sha256-HOEDWJLm+f6HSD4j7n4xc8J4FcqjJ+U7ZnMLQQrZKYg=",
+        "owner": "oxalica",
+        "repo": "rust-overlay",
+        "rev": "31d08cf9f5c3a49475e723c75c6f645171364a74",
+        "type": "github"
+      },
+      "original": {
+        "owner": "oxalica",
+        "repo": "rust-overlay",
+        "type": "github"
+      }
+    },
     "simple-nixos-mailserver": {
       "inputs": {
         "blobs": "blobs",
-        "flake-compat": "flake-compat",
+        "flake-compat": [
+          "flake-compat"
+        ],
         "nixpkgs": [
           "nixpkgs"
         ],
diff --git a/flake.nix b/flake.nix
index 3af5b41..5485ed9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,16 +4,71 @@
   inputs = {
     nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05-small";
 
-    systems.url = "github:nix-systems/x86_64-linux";
+    # inputs for following
+    systems = {
+      url = "github:nix-systems/x86_64-linux"; # only evaluate for this system
+    };
+    flake-compat = {
+      url = "github:edolstra/flake-compat";
+      flake = false;
+    };
+    crane = {
+      url = "github:ipetkov/crane";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+        flake-compat.follows = "flake-compat";
+        flake-utils.follows = "flake-utils";
+        rust-overlay.follows = "rust-overlay";
+      };
+    };
     flake-utils = {
       url = "github:numtide/flake-utils";
-      inputs.systems.follows = "systems";
+      inputs = {
+        systems.follows = "systems";
+      };
+    };
+    rust-overlay = {
+      url = "github:oxalica/rust-overlay";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+        flake-utils.follows = "flake-utils";
+      };
     };
 
+    # modules
+    disko = {
+      url = "github:nix-community/disko";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+      };
+    };
+    agenix = {
+      url = "github:ryantm/agenix";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+      };
+    };
+    impermanence = {
+      url = "github:nix-community/impermanence";
+      inputs = {};
+    };
     simple-nixos-mailserver = {
       url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-23.05";
       inputs = {
         nixpkgs.follows = "nixpkgs";
+        flake-compat.follows = "flake-compat";
+      };
+    };
+
+    # bins
+    ragenix = {
+      url = "github:yaxitech/ragenix";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+        agenix.follows = "agenix";
+        flake-utils.follows = "flake-utils";
+        rust-overlay.follows = "rust-overlay";
+        crane.follows = "crane";
       };
     };
   };
@@ -21,7 +76,13 @@
   outputs = {
     self,
     nixpkgs,
+    # modules
     simple-nixos-mailserver,
+    impermanence,
+    disko,
+    agenix,
+    # bins
+    ragenix,
     ...
   } @ attrs: let
     system = "x86_64-linux";
@@ -33,9 +94,9 @@
       modules = [
         ./hosts/server1/configuration.nix
         simple-nixos-mailserver.nixosModule
-        {
-          mailserver = import ./system/mail {inherit (pkgs) lib;};
-        }
+        disko.nixosModules.default
+        impermanence.nixosModules.impermanence
+        agenix.nixosModules.default
       ];
     };
     devShells."${system}" = {
@@ -48,9 +109,11 @@
           ltex-ls
           cocogitto
           git-crypt
+          ragenix.packages."${system}".default
         ];
       };
     };
   };
 }
 # vim: ts=2
+
diff --git a/hosts/server1/configuration.nix b/hosts/server1/configuration.nix
index 78eacee..f444715 100644
--- a/hosts/server1/configuration.nix
+++ b/hosts/server1/configuration.nix
@@ -1,4 +1,4 @@
-{pkgs, ...}: {
+{...}: {
   imports = [
     ./networking.nix # network configuration that just works
     ./hardware.nix
@@ -11,7 +11,8 @@
   networking.hostName = "server1";
   networking.domain = "vhack.eu";
 
-  system.fileSystemLayouts.mainDisk = "/dev/disk/by-uuid/7d960eb9-9334-4aef-9f7c-9a908a91a6db";
+  # FIXME: Find a better way to specify the disk
+  system.disks.disk = "/dev/vda";
 
   system.stateVersion = "22.11";
 }
diff --git a/hosts/server1/hardware.nix b/hosts/server1/hardware.nix
index 9fabafe..6086362 100644
--- a/hosts/server1/hardware.nix
+++ b/hosts/server1/hardware.nix
@@ -3,6 +3,7 @@
     (modulesPath + "/profiles/qemu-guest.nix")
     (modulesPath + "/profiles/headless.nix")
   ];
+  # FIXME: The name of the grub device depends on the disko settings
   boot.loader.grub.device = "/dev/vda";
   boot.initrd.availableKernelModules = ["ata_piix" "uhci_hcd" "virtio_pci" "sr_mod" "virtio_blk"];
   boot.initrd.kernelModules = [];
diff --git a/notes/deploy.md b/notes/deploy.md
new file mode 100644
index 0000000..61dcbfc
--- /dev/null
+++ b/notes/deploy.md
@@ -0,0 +1,6 @@
+# Full redeployment
+After a complete server purge just load up the newest NixOS ISO, set the root password and run:
+```bash
+ipv4_address=$(dig +short "<hostname>"); # ipv6 seems to fail in this context
+nix run github:numtide/nixos-anywhere -- --flake .#<hostname> root@"$ipv4_address"
+```
diff --git a/system/default.nix b/system/default.nix
index d67ada2..14f0748 100644
--- a/system/default.nix
+++ b/system/default.nix
@@ -1,7 +1,9 @@
-{config, ...}: {
+{...}: {
   imports = [
-    ./file_system_layouts
+    ./disks
+    ./impermanence
     ./packages
+    ./secrets
     ./services
     ./users
   ];
diff --git a/system/disks/default.nix b/system/disks/default.nix
new file mode 100644
index 0000000..5453426
--- /dev/null
+++ b/system/disks/default.nix
@@ -0,0 +1,84 @@
+{
+  config,
+  lib,
+  ...
+}:
+with lib; let
+  cfg = config.system.disks;
+  defaultMountOptions = ["compress-force=zstd:15"];
+in {
+  options.system.disks = {
+    disk = mkOption {
+      type = lib.types.path;
+      example = literalExpression "/dev/disk/by-id/ata-WDC_WD10SDRW-11A0XS0_WD-WXP2A901KJN5";
+      description = lib.mdDoc "Path to the disk";
+    };
+  };
+
+  config = {
+    disko.devices = {
+      disk.main = {
+        device = cfg.disk;
+        content = {
+          type = "table";
+          format = "gpt";
+          partitions = [
+            {
+              name = "boot";
+              start = "0";
+              end = "1M";
+              part-type = "primary";
+              flags = ["bios_grub"];
+            }
+            {
+              name = "root";
+              # leave space for the grub aka BIOS boot
+              start = "1M";
+              end = "100%";
+              part-type = "primary";
+              bootable = true;
+              content = {
+                type = "btrfs";
+                extraArgs = ["-f" "--label nixos"]; # f: Override existing partitions
+                subvolumes = {
+                  "nix" = {
+                    mountpoint = "/nix";
+                    mountOptions = defaultMountOptions;
+                  };
+                  "persistent-storage" = {
+                    mountpoint = "/srv";
+                    mountOptions = defaultMountOptions;
+                  };
+                  "persistent-storage@snapshots" = {
+                    mountpoint = "/srv/.snapshots";
+                    mountOptions = defaultMountOptions;
+                  };
+                  "boot" = {
+                    mountpoint = "/boot";
+                    mountOptions = defaultMountOptions;
+                  };
+                };
+              };
+            }
+          ];
+        };
+      };
+      nodev = {
+        "/" = {
+          fsType = "tmpfs";
+          mountOptions = ["defaults" "size=2G" "mode=755"];
+        };
+      };
+    };
+    fileSystems = {
+      "/srv" = {
+        neededForBoot = true;
+      };
+      "/boot" = {
+        neededForBoot = true;
+      };
+    };
+  };
+}
+# vim: ts=2
+
diff --git a/system/file_system_layouts/default.nix b/system/file_system_layouts/default.nix
deleted file mode 100644
index fe7fc3f..0000000
--- a/system/file_system_layouts/default.nix
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  modulesPath,
-  config,
-  lib,
-  ...
-}:
-with lib; let
-  cfg = config.system.fileSystemLayouts;
-in {
-  options.system.fileSystemLayouts = {
-    mainDisk = mkOption {
-      type = lib.types.path;
-      example = literalExpression "/dev/disk/by-uuid/0442cb6d-f13a-4635-b487-fa76189774c5";
-      description = lib.mdDoc "Path to the main disk";
-    };
-  };
-  config = {
-    fileSystems = {
-      "/" = {
-        device = "tmpfs";
-        fsType = "tmpfs";
-        options = ["defaults" "size=2G" "mode=755"];
-      };
-      "/nix" = {
-        device = cfg.mainDisk;
-        fsType = "btrfs";
-        options = ["subvol=nix" "compress-force=zstd"];
-      };
-      "/srv" = {
-        device = cfg.mainDisk;
-        fsType = "btrfs";
-        options = ["subvol=storage" "compress-force=zstd"];
-      };
-      "/boot" = {
-        device = cfg.mainDisk;
-        options = ["subvol=boot" "compress-force=zstd"];
-      };
-
-      "/etc/nixos" = {
-        device = "/srv/nix-config";
-        options = ["bind"];
-      };
-      "/var/lib/postgresql" = {
-        device = "/srv/postgresql";
-        options = ["bind"];
-      };
-    };
-  };
-}
diff --git a/system/impermanence/default.nix b/system/impermanence/default.nix
new file mode 100644
index 0000000..198eeba
--- /dev/null
+++ b/system/impermanence/default.nix
@@ -0,0 +1,23 @@
+{...}: {
+  # TODO: Only activate them if their module is also active
+  imports = [
+    ./mods/acme.nix
+    ./mods/keycloak.nix
+    ./mods/mail.nix
+    ./mods/minecraft.nix
+    ./mods/nix-sync.nix
+    ./mods/openssh.nix
+    ./mods/users.nix
+  ];
+
+  environment.persistence."/srv" = {
+    hideMounts = true;
+    directories = [
+      "/etc/nixos"
+      "/var/log"
+    ];
+    files = [
+      "/etc/machine-id"
+    ];
+  };
+}
diff --git a/system/impermanence/mods/acme.nix b/system/impermanence/mods/acme.nix
new file mode 100644
index 0000000..b16171e
--- /dev/null
+++ b/system/impermanence/mods/acme.nix
@@ -0,0 +1,5 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    "/var/lib/acme"
+  ];
+}
diff --git a/system/impermanence/mods/fail2ban.nix b/system/impermanence/mods/fail2ban.nix
new file mode 100644
index 0000000..a817876
--- /dev/null
+++ b/system/impermanence/mods/fail2ban.nix
@@ -0,0 +1,10 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    {
+      directory = "/var/lib/fail2ban";
+      user = "fail2ban";
+      group = "fail2ban";
+      mode = "0700";
+    }
+  ];
+}
diff --git a/system/impermanence/mods/keycloak.nix b/system/impermanence/mods/keycloak.nix
new file mode 100644
index 0000000..63b02f5
--- /dev/null
+++ b/system/impermanence/mods/keycloak.nix
@@ -0,0 +1,5 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    "/var/lib/postgresql"
+  ];
+}
diff --git a/system/impermanence/mods/mail.nix b/system/impermanence/mods/mail.nix
new file mode 100644
index 0000000..18151ad
--- /dev/null
+++ b/system/impermanence/mods/mail.nix
@@ -0,0 +1,34 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    {
+      directory = "/var/lib/mail/backup";
+      user = "virtualMail";
+      group = "virtualMail";
+      mode = "0700";
+    }
+    {
+      directory = "/var/lib/mail/sieve";
+      user = "virtualMail";
+      group = "virtualMail";
+      mode = "0700";
+    }
+    {
+      directory = "/var/lib/mail/vmail";
+      user = "virtualMail";
+      group = "virtualMail";
+      mode = "0700";
+    }
+    {
+      directory = "/var/lib/mail/dkim";
+      user = "opendkim";
+      group = "opendkim";
+      mode = "0700";
+    }
+    {
+      directory = "/var/lib/rspamd";
+      user = "rspamd";
+      group = "rspamd";
+      mode = "0700";
+    }
+  ];
+}
diff --git a/system/impermanence/mods/minecraft.nix b/system/impermanence/mods/minecraft.nix
new file mode 100644
index 0000000..2a02626
--- /dev/null
+++ b/system/impermanence/mods/minecraft.nix
@@ -0,0 +1,10 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    {
+      directory = "/var/lib/minecraft";
+      user = "minecraft";
+      group = "minecraft";
+      mode = "0700";
+    }
+  ];
+}
diff --git a/system/impermanence/mods/nix-sync.nix b/system/impermanence/mods/nix-sync.nix
new file mode 100644
index 0000000..11449ea
--- /dev/null
+++ b/system/impermanence/mods/nix-sync.nix
@@ -0,0 +1,10 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    {
+      directory = "/var/lib/nix-sync";
+      user = "nix-sync";
+      group = "nix-sync";
+      mode = "0700";
+    }
+  ];
+}
diff --git a/system/impermanence/mods/openssh.nix b/system/impermanence/mods/openssh.nix
new file mode 100644
index 0000000..0373a83
--- /dev/null
+++ b/system/impermanence/mods/openssh.nix
@@ -0,0 +1,21 @@
+{...}: {
+  /*
+   FIXME:
+    This results in a boot error, as the `/var/lib/sshd` directory is only mounted _after_ the stage 2 init and with it the system activation.
+    Agenix needs the sshd hostkey however to decrypt the secrets and such we have to ensure that this directory is mounted _before_ the system activation.
+    Alas the only way I see to achieve that is to store the ssh hostkey directly on /srv, which is mounted before (it's marked as 'neededForBoot' after all).
+
+    It should be possible to achieve this with impermanence however, as `/var/log` is mounted in the stage 1 init; The problem is that I have no idea _why_ only
+    this is mounted and nothing else.
+
+
+  environment.persistence."/srv".directories = [
+    {
+      directory = "/var/lib/sshd";
+      user = "root";
+      group = "root";
+      mode = "0755";
+    }
+  ];
+  */
+}
diff --git a/system/impermanence/mods/users.nix b/system/impermanence/mods/users.nix
new file mode 100644
index 0000000..0692b00
--- /dev/null
+++ b/system/impermanence/mods/users.nix
@@ -0,0 +1,28 @@
+{...}: {
+  environment.persistence."/srv".directories = [
+    {
+      directory = "/home";
+      user = "root";
+      group = "root";
+      mode = "0755";
+    }
+    {
+      directory = "/home/sils";
+      user = "sils";
+      group = "sils";
+      mode = "0700";
+    }
+    {
+      directory = "/home/soispha";
+      user = "soispha";
+      group = "soispha";
+      mode = "0700";
+    }
+    {
+      directory = "/home/nightingale";
+      user = "nightingale";
+      group = "nightingale";
+      mode = "0700";
+    }
+  ];
+}
diff --git a/system/mail/default.nix b/system/mail/default.nix
deleted file mode 100644
index 1086f6e..0000000
--- a/system/mail/default.nix
+++ /dev/null
@@ -1,40 +0,0 @@
-# vim: ts=2
-{lib, ...}: let
-  all_admins = [
-    "sils@vhack.eu"
-    "soispha@vhack.eu"
-    "nightingale@vhack.eu"
-  ];
-  users = import ./users.nix {};
-in
-  lib.recursiveUpdate {
-    enable = true;
-    fqdn = "server1.vhack.eu";
-
-    useFsLayout = true;
-
-    extraVirtualAliases = {
-      "abuse@vhack.eu" = all_admins;
-      "postmaster@vhack.eu" = all_admins;
-      "admin@vhack.eu" = all_admins;
-    };
-
-    mailDirectory = "/srv/mail/vmail";
-    dkimKeyDirectory = "/srv/mail/dkim";
-    sieveDirectory = "/srv/mail/sieve";
-    backup.snapshotRoot = "/srv/mail/backup";
-
-    enableImap = false;
-    enableImapSsl = true;
-    enablePop3 = false;
-    enablePop3Ssl = true;
-    # SMTP
-    enableSubmission = false;
-    enableSubmissionSsl = true;
-    openFirewall = true;
-
-    keyFile = "/var/lib/acme/server1.vhack.eu/key.pem";
-    certificateScheme = "acme";
-    certificateFile = "/var/lib/acme/server1.vhack.eu/fullchain.pem";
-  }
-  users
diff --git a/system/secrets/default.nix b/system/secrets/default.nix
new file mode 100644
index 0000000..ac42c1c
--- /dev/null
+++ b/system/secrets/default.nix
@@ -0,0 +1,14 @@
+{...}: {
+  age = {
+    secrets = {
+      keycloak = {
+        file = ./keycloak/passwd.tix;
+        mode = "700";
+        owner = "root";
+        group = "root";
+      };
+    };
+  };
+}
+# vim: ts=2
+
diff --git a/system/secrets/keycloak/passwd.tix b/system/secrets/keycloak/passwd.tix
new file mode 100644
index 0000000..c77fc94
--- /dev/null
+++ b/system/secrets/keycloak/passwd.tix
@@ -0,0 +1,17 @@
+-----BEGIN AGE ENCRYPTED FILE-----
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVFBqRWNnVk5vVUQzZ2F1
+UDVyaEpSRUNKblF2V0dUWVhZNGtiM2prdkVjCi9oWjVERXRjdFBMaWRJWnlwc3Qz
+Umxka3dIejR1Ym1lQURXSmcvOGdpOHMKLT4gc3NoLWVkMjU1MTkgT0Q4VDRnIEI5
+SFBBSlFsd0pSRXJ6SFpkaEs1d050am9DYWFjK3Fod25Cajh5dCtBbkUKZVlPY1U5
+eEdpZm4zbGJyT0xTUThWOGFjKy9va0VkNG9CeHF0bExFbEtPcwotPiBlcCNkZ2Mt
+Z3JlYXNlIFMnQCggU18tMjkzXgo4bE54aUFqaTduQXJyNG5OWGs4MS9WUncwTG5C
+N2lmTzRXWEc5MkphMzF0UWRKRDJLVUJPcmVUMy8xRHRodzI3CnpPTVl4MWUzd3U5
+WStDcDBlT1NJb3JETEFJbmlRbUNPSFEKLS0tIDIzY3JNU2R5Z2NNZXZMc0xhWEFi
+Sm41QmlQOWVSMG9JRjQ5YWFwOXVzMGcK2HdQ01iFKzsm9RV3uTOJ9Jo03KvB6quf
+ZWigk17Glf1AXaF000B9+fXRsICJfy4ib5VRDfm/1anmzO80Q9iCbPVqbdb5y6JS
+eJmTTRaXmZ1jCXjYfBoFs7c3z7r2Q44FQFa+HxNZPrL/VYRrlazf8n5m6KzkCROm
+USRt1ibhi+FA2+FRM0QanbIEmtd4AYif/kbOKS8vMIM/IoCiwH5UFouaCUVXfEge
+KTB421WmEwz96sQbetEAhK6PfD2ZNx8G+QR79l6FqVAHUEdAOc3wNH11xhMUB23a
+5ph3IL7cqxns+mWYGW0qJLrWiYB+is1qNJ7pItsbheGWKk9UZl9mbUvmsD59t1uN
+RDkimrsL9MUnM61kfw4To8uJaRVdLUYF+g==
+-----END AGE ENCRYPTED FILE-----
diff --git a/system/secrets/secrets.nix b/system/secrets/secrets.nix
new file mode 100644
index 0000000..5070d38
--- /dev/null
+++ b/system/secrets/secrets.nix
@@ -0,0 +1,14 @@
+let
+  soispha = "age1mshh4ynzhhzhff25tqwkg4j054g3xwrfznh98ycchludj9wjj48qn2uffn";
+  sils = "age1vuhaey7kd9l76y6f9weeqmde3s4kjw38869ju6u3027yece2r3rqssjxst";
+
+  server1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMnqsfIZjelH7rcvFvnLR5zUZuC8thsBupBlvjcMRBUm";
+in {
+  "keycloak/passwd.tix".publicKeys = [
+    soispha
+    sils
+    server1
+  ];
+}
+# vim: ts=2
+
diff --git a/system/services/default.nix b/system/services/default.nix
index 2e2b751..13e1c0a 100644
--- a/system/services/default.nix
+++ b/system/services/default.nix
@@ -1,12 +1,13 @@
 {...}: {
   imports = [
+    ./fail2ban
     ./keycloak
+    ./mail
     ./minecraft
     ./nginx
     ./nix
-    ./opensshd
+    ./nix-sync
+    ./openssh
     ./rust-motd
-    ./fail2ban
-    ./git-sync
   ];
 }
diff --git a/system/services/fail2ban/default.nix b/system/services/fail2ban/default.nix
index 5aee097..3e6244b 100644
--- a/system/services/fail2ban/default.nix
+++ b/system/services/fail2ban/default.nix
@@ -1,4 +1,3 @@
-# vim: ts=2
 {...}: {
   services.fail2ban = {
     enable = true;
@@ -8,7 +7,7 @@
       logtarget = SYSLOG
       socket    = /run/fail2ban/fail2ban.sock
       pidfile   = /run/fail2ban/fail2ban.pid
-      dbfile    = /srv/fail2ban/fail2ban.sqlite3
+      dbfile    = /var/lib/fail2ban/db.sqlite3
     '';
     bantime-increment = {
       enable = true;
@@ -28,3 +27,4 @@
     };
   };
 }
+
diff --git a/system/services/keycloak/default.nix b/system/services/keycloak/default.nix
index dfeabc3..5f21b90 100644
--- a/system/services/keycloak/default.nix
+++ b/system/services/keycloak/default.nix
@@ -31,7 +31,7 @@
       createLocally = true;
 
       username = "keycloak";
-      passwordFile = "/srv/keycloak/password";
+      passwordFile = "${config.age.secrets.keycloak.path}";
     };
 
     settings = {
diff --git a/system/services/mail/default.nix b/system/services/mail/default.nix
new file mode 100644
index 0000000..0640fc7
--- /dev/null
+++ b/system/services/mail/default.nix
@@ -0,0 +1,43 @@
+{lib, ...}: let
+  all_admins = [
+    "sils@vhack.eu"
+    "soispha@vhack.eu"
+    "nightingale@vhack.eu"
+  ];
+  users = import ./users.nix {};
+in {
+  mailserver =
+    lib.recursiveUpdate {
+      enable = true;
+      fqdn = "server1.vhack.eu";
+
+      useFsLayout = true;
+
+      extraVirtualAliases = {
+        "abuse@vhack.eu" = all_admins;
+        "postmaster@vhack.eu" = all_admins;
+        "admin@vhack.eu" = all_admins;
+      };
+
+      mailDirectory = "/var/lib/mail/vmail";
+      dkimKeyDirectory = "/var/lib/mail/dkim";
+      sieveDirectory = "/var/lib/mail/sieve";
+      backup.snapshotRoot = "/var/lib/mail/backup";
+
+      enableImap = false;
+      enableImapSsl = true;
+      enablePop3 = false;
+      enablePop3Ssl = true;
+      # SMTP
+      enableSubmission = false;
+      enableSubmissionSsl = true;
+      openFirewall = true;
+
+      keyFile = "/var/lib/acme/server1.vhack.eu/key.pem";
+      certificateScheme = "acme";
+      certificateFile = "/var/lib/acme/server1.vhack.eu/fullchain.pem";
+    }
+    users;
+}
+# vim: ts=2
+
diff --git a/system/mail/users.nix b/system/services/mail/users.nix
index f3264a1..f3264a1 100644
--- a/system/mail/users.nix
+++ b/system/services/mail/users.nix
Binary files differdiff --git a/system/services/minecraft/default.nix b/system/services/minecraft/default.nix
index e69ffb1..e659af0 100644
--- a/system/services/minecraft/default.nix
+++ b/system/services/minecraft/default.nix
@@ -7,7 +7,7 @@
     enable = true;
     declarative = true;
     eula = true;
-    dataDir = "/srv/minecraft";
+    dataDir = "/var/lib/minecraft";
     openFirewall = true;
     jvmOpts = "-Xmx8192M -Xms8192M";
     whitelist = {
diff --git a/system/services/nginx/default.nix b/system/services/nginx/default.nix
index 3eb98d3..b9a0754 100644
--- a/system/services/nginx/default.nix
+++ b/system/services/nginx/default.nix
@@ -2,9 +2,13 @@
   imports = [
     ./hosts.nix
   ];
-  security.acme.acceptTerms = true;
-  security.acme.defaults.email = "admin@vhack.eu";
-  security.acme.defaults.webroot = "/srv/acme/";
+  security.acme = {
+    acceptTerms = true;
+    defaults = {
+      email = "admin@vhack.eu";
+      webroot = "/var/lib/acme/acme-challenge";
+    };
+  };
 
   networking.firewall = {
     allowedTCPPorts = [80 443];
diff --git a/system/services/nginx/hosts.nix b/system/services/nginx/hosts.nix
index 94fae9f..03806c0 100644
--- a/system/services/nginx/hosts.nix
+++ b/system/services/nginx/hosts.nix
Binary files differdiff --git a/system/services/nix-sync/default.nix b/system/services/nix-sync/default.nix
index 18511b3..5c2ed80 100644
--- a/system/services/nix-sync/default.nix
+++ b/system/services/nix-sync/default.nix
@@ -6,47 +6,85 @@
 }: let
   cfg = config.services.nix-sync;
 
+  mkTimer = name: repo: {
+    description = "Nix sync ${name} timer";
+    wantedBy = ["timers.target"];
+    timerConfig = {
+      OnActiveSec = repo.interval;
+    };
+    after = ["network-online.target"];
+  };
+
+  parents = path: let
+    split_path = builtins.split "/" path;
+    filename = builtins.elemAt split_path (builtins.length split_path - 1);
+  in
+    lib.strings.removeSuffix "/" (builtins.replaceStrings [filename] [""] path);
+  esa = lib.strings.escapeShellArg;
   mkUnit = name: repo: let
-    esa = lib.strings.escapeShellArg;
-    execStartScript = lib.writeShellScript "git-sync-exec" ''
-      cd ${esa cfg.cachePath}/${esa repo.path};
+    optionalPathSeparator =
+      if lib.strings.hasPrefix "/" repo.path
+      then ""
+      else "/";
+    repoCachePath = cfg.cachePath + optionalPathSeparator + repo.path;
+    execStartScript = pkgs.writeScript "nix-sync-exec" ''
+      #! /usr/bin/env dash
+      export XDG_CACHE_HOME="$CACHE_DIRECTORY";
+      cd ${esa repoCachePath};
 
-      while true; do
-        origin="$(git rev-parse @{u})";
-        branch="$(git rev-parse @)";
+      git fetch
+      origin="$(git rev-parse @{u})";
+      branch="$(git rev-parse @)";
 
-        if ! [ "$origin" = "$branch" ]; then
-          git pull;
+      if ! [ "$origin" = "$branch" ]; then
+        git pull;
 
-          out_paths=$(mktemp);
-          nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths";
-          [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1)
-          out_path="$(cat "$out_paths")";
-          rm -r ${esa repo.path};
-          ln -s "$out_path" ${esa repo.path};
-          rm "$out-paths";
-        fi
-        sleep ${esa repo.interval};
-      done
+        out_paths=$(mktemp);
+        nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths";
+        [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1)
+        out_path="$(cat "$out_paths")";
+        rm ${esa repo.path};
+        ln -s "$out_path" ${esa repo.path};
+        rm "$out_paths";
+      fi
     '';
     execStartPreScript = ''
-      if ! stat ${esa cfg.cachePath}/${esa repo.path}/.git; then
-          mkdir --parents ${esa cfg.cachePath}/${esa repo.path};
-          git clone ${esa repo.uri} ${esa cfg.cachePath}/${esa repo.path};
+      export XDG_CACHE_HOME="$CACHE_DIRECTORY";
+
+      if ! [ -d ${esa repoCachePath}/.git ]; then
+          mkdir --parents ${esa repoCachePath};
+          git clone ${esa repo.uri} ${esa repoCachePath};
 
           out_paths=$(mktemp);
-          nix build ${esa cfg.cachePath}/${esa repo.path} --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths";
+          nix build ${esa repoCachePath} --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths";
           [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1)
           out_path="$(cat "$out_paths")";
           ln -s "$out_path" ${esa repo.path};
-          rm "$out-paths";
+          rm "$out_paths";
+      fi
+
+      if ! [ -L ${esa repo.path} ]; then
+        cd ${esa repoCachePath};
+
+        git pull;
+
+        out_paths=$(mktemp);
+        nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths";
+        [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1)
+        out_path="$(cat "$out_paths")";
+
+        [ -d ${esa repo.path} ] && rm -d ${esa repo.path};
+        [ -e ${esa repo.path} ] && rm ${esa repo.path};
+
+        ln -s "$out_path" ${esa repo.path};
+        rm "$out_paths";
       fi
     '';
   in {
     description = "Nix Sync ${name}";
     wantedBy = ["default.target"];
     after = ["network.target"];
-    path = with pkgs; [openssh git nix mktemp coreutils];
+    path = with pkgs; [openssh git nix mktemp coreutils dash];
     preStart = execStartPreScript;
 
     serviceConfig = {
@@ -56,16 +94,16 @@
       User = cfg.user;
       Group = cfg.group;
       # Runtime directory and mode
-      RuntimeDirectory = "nginx";
+      RuntimeDirectory = "nix-sync";
       RuntimeDirectoryMode = "0750";
       # Cache directory and mode
-      CacheDirectory = "nginx";
+      CacheDirectory = "nix-sync";
       CacheDirectoryMode = "0750";
       # Logs directory and mode
-      LogsDirectory = "nginx";
+      LogsDirectory = "nix-sync";
       LogsDirectoryMode = "0750";
       # Proc filesystem
-      ProcSubset = "pid";
+      ProcSubset = "all";
       ProtectProc = "invisible";
       # New file permissions
       UMask = "0027"; # 0640 / 0750
@@ -75,7 +113,8 @@
       # Security
       NoNewPrivileges = true;
       # Sandboxing (sorted by occurrence in https://www.freedesktop.org/software/systemd/man/systemd.exec.html)
-      ReadWritePaths = ["${repo.path}" "${cfg.cachePath}/${repo.path}"];
+      ReadWritePaths = ["${esa (parents repo.path)}" "-${esa repoCachePath}" "-${esa cfg.cachePath}"];
+      ReadOnlyPaths = ["/nix"];
       ProtectSystem = "strict";
       ProtectHome = true;
       PrivateTmp = true;
@@ -102,10 +141,23 @@
 
   services =
     lib.mapAttrs' (name: repo: {
-      name = "git-sync-${name}";
+      name = "nix-sync-${name}";
       value = mkUnit name repo;
     })
     cfg.repositories;
+  timers =
+    lib.mapAttrs' (name: repo: {
+      name = "nix-sync-${name}";
+      value = mkTimer name repo;
+    })
+    cfg.repositories;
+
+  # generate the websites directory, so systemd can mount it read write
+  generatedDirectories =
+    lib.mapAttrsToList (
+      _: repo: "d ${esa (parents repo.path)} 0755 ${cfg.user} ${cfg.group}"
+    )
+    cfg.repositories;
 
   repositoryType = lib.types.submodule ({name, ...}: {
     options = {
@@ -123,7 +175,7 @@
 
       uri = lib.mkOption {
         type = lib.types.str;
-        example = "git+ssh://user@example.com:/~[user]/path/to/repo.git";
+        example = "ssh://user@example.com:/~[user]/path/to/repo.git";
         description = ''
           The URI of the remote to be synchronized. This is only used in the
           event that the directory does not already exist. See
@@ -137,24 +189,15 @@
         default = 500;
         description = ''
           The interval, specified in seconds, at which the synchronization will
-          be triggered even without filesystem changes.
+          be triggered.
         '';
       };
     };
   });
 in {
   options = {
-    services.git-sync = {
-      enable = lib.mkEnableOption "git-sync services";
-
-      package = lib.mkOption {
-        type = lib.types.package;
-        default = pkgs.git-sync;
-        defaultText = lib.literalExpression "pkgs.git-sync";
-        description = ''
-          Package containing the <command>git-sync</command> program.
-        '';
-      };
+    services.nix-sync = {
+      enable = lib.mkEnableOption "nix-sync services";
 
       user = lib.mkOption {
         type = lib.types.str;
@@ -172,7 +215,7 @@ in {
         type = lib.types.str;
         default = "/var/lib/nix-sync";
         description = lib.mdDoc ''
-          Where to cache git directories.
+          Where to cache git directories. Should not end with a slash ("/")
         '';
       };
 
@@ -186,7 +229,35 @@ in {
   };
 
   config = lib.mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = !lib.strings.hasSuffix "/" cfg.cachePath;
+        message = "Your cachePath ('${cfg.cachePath}') ends with a slash ('/'), please use: '${lib.strings.removeSuffix "/" cfg.cachePath}'.";
+      }
+    ];
+
+    systemd.tmpfiles.rules =
+      generatedDirectories;
+
     systemd.services = services;
+    systemd.timers = timers;
+    users.users =
+      if cfg.user == "nix-sync"
+      then {
+        nix-sync = {
+          group = "${cfg.group}";
+          isSystemUser = true;
+        };
+      }
+      else lib.warnIf (cfg.user != "nix-sync") "The user (${cfg.user}) is not \"nix-sync\", thus you are responible for generating it.";
+    users.groups =
+      if cfg.group == "nix-sync"
+      then {
+        nix-sync = {
+          members = ["${cfg.user}"];
+        };
+      }
+      else lib.warnIf (cfg.group != "nix-sync") "The group (${cfg.group}) is not \"nix-sync\", thus you are responible for generating it.";
   };
 }
 # vim: ts=2
diff --git a/system/services/openssh/default.nix b/system/services/openssh/default.nix
new file mode 100644
index 0000000..46b7ffd
--- /dev/null
+++ b/system/services/openssh/default.nix
@@ -0,0 +1,17 @@
+{...}: {
+  services.openssh = {
+    enable = true;
+    settings.PasswordAuthentication = false;
+    hostKeys = [
+      {
+        # See the explanation for this in /system/impermanence/mods/openssh.nix
+        # path = "/var/lib/sshd/ssh_host_ed25519_key";
+
+        # FIXME: Remove this workaround
+        path = "/srv/var/lib/sshd/ssh_host_ed25519_key";
+        rounds = 1000;
+        type = "ed25519";
+      }
+    ];
+  };
+}
diff --git a/system/services/opensshd/default.nix b/system/services/opensshd/default.nix
deleted file mode 100644
index 1bb37ee..0000000
--- a/system/services/opensshd/default.nix
+++ /dev/null
@@ -1,13 +0,0 @@
-{...}: {
-  services.openssh = {
-    enable = true;
-    settings.PasswordAuthentication = false;
-    hostKeys = [
-      {
-        path = "/srv/sshd/ssh_host_ed25519_key";
-        rounds = 1000;
-        type = "ed25519";
-      }
-    ];
-  };
-}
diff --git a/system/users/default.nix b/system/users/default.nix
index 3555221..7ea88c5 100644
--- a/system/users/default.nix
+++ b/system/users/default.nix
@@ -1,54 +1,53 @@
 {pkgs, ...}: {
-  users.mutableUsers = false;
-  users.defaultUserShell = pkgs.zsh;
+  users = {
+    mutableUsers = false;
+    defaultUserShell = pkgs.zsh;
+    users = {
+      root = {
+        initialHashedPassword = null; # to lock root
+        openssh.authorizedKeys.keys = [];
+      };
 
-  users.users = {
-    root = {
-      #uid = 0;
-      initialHashedPassword = null; # to lock root
-      openssh.authorizedKeys.keys = [
-      ];
-    };
-
-    sils = {
-      name = "sils";
-      isNormalUser = true;
-      home = "/srv/home/sils";
-      initialHashedPassword = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC";
-      uid = 1000;
-      extraGroups = [
-        "wheel"
-      ];
-      openssh.authorizedKeys.keys = [
-        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG63gxw8JePmrC8Fni0pLV4TnPBhCPmSV9FYEdva+6s7 sils"
-      ];
-    };
+      sils = {
+        name = "sils";
+        isNormalUser = true;
+        home = "/home/sils";
+        initialHashedPassword = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC";
+        uid = 1000;
+        extraGroups = [
+          "wheel"
+        ];
+        openssh.authorizedKeys.keys = [
+          "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG63gxw8JePmrC8Fni0pLV4TnPBhCPmSV9FYEdva+6s7 sils"
+        ];
+      };
 
-    soispha = {
-      name = "soispha";
-      isNormalUser = true;
-      home = "/srv/home/soispha";
-      initialHashedPassword = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1";
-      uid = 1001;
-      extraGroups = [
-        "wheel"
-      ];
-      openssh.authorizedKeys.keys = [
-        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGBFuTNNn71Rhfnop2cdz3r/RhWWlCePnSBOhTBbu2ME soispha"
-      ];
-    };
+      soispha = {
+        name = "soispha";
+        isNormalUser = true;
+        home = "/home/soispha";
+        initialHashedPassword = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1";
+        uid = 1001;
+        extraGroups = [
+          "wheel"
+        ];
+        openssh.authorizedKeys.keys = [
+          "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGBFuTNNn71Rhfnop2cdz3r/RhWWlCePnSBOhTBbu2ME soispha"
+        ];
+      };
 
-    nightingale = {
-      name = "nightingale";
-      isNormalUser = true;
-      home = "/srv/home/nightingale";
-      initialHashedPassword = null; # TODO CHANGE
-      uid = 1002;
-      extraGroups = [
-        "wheel"
-      ];
-      openssh.authorizedKeys.keys = [
-      ];
+      nightingale = {
+        name = "nightingale";
+        isNormalUser = true;
+        home = "/home/nightingale";
+        initialHashedPassword = null; # TODO CHANGE
+        uid = 1002;
+        extraGroups = [
+          "wheel"
+        ];
+        openssh.authorizedKeys.keys = [
+        ];
+      };
     };
   };
 }