aboutsummaryrefslogtreecommitdiffstats
path: root/modules/by-name
diff options
context:
space:
mode:
Diffstat (limited to 'modules/by-name')
-rw-r--r--modules/by-name/et/etesync/module.nix72
-rw-r--r--modules/by-name/et/etesync/secret_file.age17
-rw-r--r--modules/by-name/gi/git-server/css.nix116
-rw-r--r--modules/by-name/gi/git-server/module.nix178
-rw-r--r--modules/by-name/ng/nginx/module.nix68
-rw-r--r--modules/by-name/ng/nginx/redirects.nix6
-rw-r--r--modules/by-name/ni/nix-sync/hosts.nix48
-rw-r--r--modules/by-name/ni/nix-sync/internal_module.nix299
-rw-r--r--modules/by-name/ni/nix-sync/module.nix61
-rw-r--r--modules/by-name/op/openssh/module.nix31
-rw-r--r--modules/by-name/pe/peertube/module.nix113
-rw-r--r--modules/by-name/pe/peertube/secrets/general.age15
-rw-r--r--modules/by-name/pe/peertube/secrets/smtp.age16
13 files changed, 1040 insertions, 0 deletions
diff --git a/modules/by-name/et/etesync/module.nix b/modules/by-name/et/etesync/module.nix
new file mode 100644
index 0000000..0f6c565
--- /dev/null
+++ b/modules/by-name/et/etesync/module.nix
@@ -0,0 +1,72 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.vhack.etesync;
+in {
+ options.vhack.etesync = {
+ enable = lib.mkEnableOption ''
+ a secure, end-to-end encrypted, and privacy respecting sync for your contacts, calendars, tasks and notes.
+ '';
+ };
+
+ config = lib.mkIf cfg.enable {
+ services.etebase-server = {
+ enable = true;
+ port = 8001;
+ settings = {
+ global.secret_file = "${config.age.secrets.etebase-server.path}";
+ allowed_hosts = {
+ allowed_host1 = "etebase.vhack.eu";
+ allowed_host2 = "dav.vhack.eu";
+ };
+ };
+ };
+
+ age.secrets.etebase-server = {
+ file = ./secret_file.age;
+ mode = "700";
+ owner = "etebase-server";
+ group = "etebase-server";
+ };
+
+ environment.persistence."/srv".directories = [
+ {
+ directory = "/var/lib/etebase-server";
+ user = "etebase-server";
+ group = "etebase-server";
+ mode = "0700";
+ }
+ ];
+
+ services.nginx = {
+ enable = true;
+ recommendedTlsSettings = true;
+ recommendedOptimisation = true;
+ recommendedGzipSettings = true;
+ recommendedProxySettings = true;
+
+ virtualHosts = {
+ "etebase.vhack.eu" = {
+ enableACME = true;
+ forceSSL = true;
+
+ locations = {
+ # TODO: Maybe fix permissions to use pregenerated static files which would
+ # improve performance.
+ #"/static" = {
+ # root = config.services.etebase-server.settings.global.static_root;
+ #};
+ "/" = {
+ proxyPass = "http://127.0.0.1:${builtins.toString config.services.etebase-server.port}";
+ };
+ };
+ serverAliases = [
+ "dav.vhack.eu"
+ ];
+ };
+ };
+ };
+ };
+}
diff --git a/modules/by-name/et/etesync/secret_file.age b/modules/by-name/et/etesync/secret_file.age
new file mode 100644
index 0000000..8d8e3c2
--- /dev/null
+++ b/modules/by-name/et/etesync/secret_file.age
@@ -0,0 +1,17 @@
+-----BEGIN AGE ENCRYPTED FILE-----
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0UiswNDhQNWpsaFZUQTdY
+U3F2TFlrSzhMbmRBWEIyTGQ2VGVramdPTDI4CjRGSnlqUm5rWWJ2Vk5neE56azdt
+WitpbXlPWngxSGtEalBKWkRZdHF5QjQKLT4gWDI1NTE5IDRSSW1jcHhocjBIM0tM
+ZjRxNUhZWkhkd1c5aVlucTMxTTVhSHRIMHMyU0EKbWlQZ0xKRXUvOWluSkZQRWdp
+UjNMQWR3MHNwbUVYbm4vSGJQOGtrb2ZxVQotPiBzc2gtZWQyNTUxOSBPRDhUNGcg
+SEpCY1JWZm5yMG1lL3QwUERPVUFqRWo5ZVJEb1JqNGVLS3pXVkhaYk1SYwpjb3dW
+UWcrMkdmYTlvckFOYmsvcGwvY1dvc1oxY1FaY2p4eURCK3BIR044Ci0+ICgreWhl
+KG9RLWdyZWFzZSAobEpLXVEgNVA3IGQKekx5YVFkeFRBUlJiUis2cFVyWlBPNncK
+LS0tIFJxa0hDZUIyYm5uYlhiZjRnNHRLNTRrRW01d1hCL2dCZnByL1M2SkFyQXMK
+gsR7erKGQrBhXlcnR73PbnC+PzOQlsBOg6a6DosGyixbnEgZ4DfyeK5Ep1oPB81Q
+zcS9AV7h+8NlpmVM4G+0JCIC8I3TTCEQyOPwiu+GVXr4GYy/3stg+pK1htkt2V2M
+WraPl//K3kvFln1KRt5lbsVXLX8SYZS4UJDzK25oJElwdNuqXHqwMkTmXjEgnbvS
+pjgaNak5ooxHiZfCtzismLx5iL+P/+oohegUPvW16fQTq/eKp3mIjeBZmrWNnTuL
+/xlhk0vp0+jS3+TqgGWSwAAqoCp/+TewUZ9f+GhU0/pkU3HP4+tx35rKN2wxerQj
+nMbQ8SphigUeMpc501oDRw6X5ZAasoww
+-----END AGE ENCRYPTED FILE-----
diff --git a/modules/by-name/gi/git-server/css.nix b/modules/by-name/gi/git-server/css.nix
new file mode 100644
index 0000000..3d73ea0
--- /dev/null
+++ b/modules/by-name/gi/git-server/css.nix
@@ -0,0 +1,116 @@
+{cgitPkg, pkgs}: let
+ /*
+ Adapted from `https://git.qyliss.net/nixlib/sys/atuin.nix`, originally distributed under
+ the MIT license.
+ */
+ cgitCss =
+ pkgs.runCommand "cgit-extra.css" {
+ licenseHeader = ''
+ /*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * See <https://www.gnu.org/licenses/>.
+ */
+
+ '';
+
+ # Adapted from
+ # <https://git.causal.agency/src/plain/www/git.causal.agency/custom.css>,
+ # distributed as a Larger Work under a Secondary License,
+ # as permitted by the terms of the
+ # Mozilla Public License Version 2.0.
+ extraCss = ''
+ * { line-height: 1.25em; }
+
+ article {
+ font-family: sans-serif;
+ max-width: 70ch;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ div#cgit {
+ margin: auto;
+ font-family: monospace;
+ -moz-tab-size: 4;
+ tab-size: 4;
+ display: table;
+ }
+
+ div#cgit table#header {
+ margin-left: auto;
+ margin-right: auto;
+ }
+ div#cgit table#header td.logo {
+ display: none;
+ }
+ div#cgit table#header td.main {
+ font-size: 1em;
+ font-weight: bold;
+ }
+ div#cgit table#header td.sub {
+ border-top: none;
+ }
+ div#cgit table.tabs {
+ margin-left: auto;
+ margin-right: auto;
+ border-bottom: none;
+ }
+ div#cgit div.content {
+ border-bottom: none;
+ min-width: 108ch;
+ }
+ div#cgit div.content div#summary {
+ display: table;
+ margin-left: auto;
+ margin-right: auto;
+ }
+ div#cgit div.notes {
+ border: none;
+ background: transparent;
+ padding: 0;
+ }
+ div#cgit table.list {
+ margin-left: auto;
+ margin-right: auto;
+ }
+ div#cgit table.list th a {
+ color: inherit;
+ }
+ div#cgit table.list tr:nth-child(even) {
+ background: inherit;
+ }
+ div#cgit table.list tr:hover {
+ background: inherit;
+ }
+ div#cgit table.list tr.nohover-highlight:hover:nth-child(even) {
+ background: inherit;
+ }
+ div#cgit div.footer {
+ font-size: 1em;
+ margin-top: 0;
+ }
+
+ div#cgit table.blob td.linenumbers:nth-last-child(3) {
+ display: none;
+ }
+
+ div#cgit table.blob td.linenumbers a:target {
+ color: goldenrod;
+ text-decoration: underline;
+ outline: none;
+ }
+ '';
+ passAsFile = ["licenseHeader" "extraCss"];
+ } ''
+ cat $licenseHeaderPath ${cgitPkg}/cgit/cgit.css $extraCssPath > $out
+ '';
+in
+ cgitCss
diff --git a/modules/by-name/gi/git-server/module.nix b/modules/by-name/gi/git-server/module.nix
new file mode 100644
index 0000000..a374f4c
--- /dev/null
+++ b/modules/by-name/gi/git-server/module.nix
@@ -0,0 +1,178 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ cfg = config.vhack.git-server;
+
+ cgitCss = import ./css.nix {
+ inherit pkgs;
+ cgitPkg =
+ config.services.cgit."${cfg.domain}".package;
+ };
+in {
+ options.vhack.git-server = {
+ enable = lib.mkEnableOption ''
+ a lightweight git-server, realised with cgit and gitolite.
+ '';
+
+ domain = lib.mkOption {
+ type = lib.types.str;
+ default = "git.vhack.eu";
+ description = ''
+ The domain this git instance will run under.
+ '';
+ };
+
+ gitolite = {
+ adminPubkey = lib.mkOption {
+ description = ''
+ The initial key to use for gitolite. This will only be used for the initial
+ clone of the `gitolite-admin` repository.
+ '';
+ type = lib.types.str;
+ default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe4o1PM6VasT3KZNl5NYvgkkBrPOg36dqsywd10FztS openpgp:0x21D20D6A";
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ programs.git = {
+ enable = true;
+ config = {
+ init = {
+ defaultBranch = "main";
+ };
+ };
+ };
+
+ # Needed for the nginx proxy and the virtual host
+ vhack.nginx.enable = true;
+
+ services = {
+ gitolite = {
+ inherit (cfg.gitolite) adminPubkey;
+ enable = true;
+ dataDir = "/srv/gitolite";
+ user = "git";
+ group = "git";
+ extraGitoliteRc = ''
+ $RC{UMASK} = 0027; # Enable group access, important for cgit.
+
+ # Enable modifing git variables (for cgit.owner and such things)
+ # These must be enable in the gitolite-admin repo (option user-configs = ...)
+ push( @{$RC{ENABLE}}, 'config' );
+ push( @{$RC{ENABLE}}, 'git-config' );
+
+ push( @{$RC{ENABLE}}, 'expand-deny-messages' );
+ push( @{$RC{ENABLE}}, 'Motd' );
+
+ push( @{$RC{ENABLE}}, 'cgit' );
+ '';
+ };
+
+ cgit."${cfg.domain}" = {
+ enable = true;
+ package = pkgs.cgit-pink;
+ scanPath = "${config.services.gitolite.dataDir}/repositories";
+ user = "git";
+ group = "git";
+ settings = {
+ branch-sort = "age";
+
+ # Allow users to download a repo checkout with these compression formats
+ snapshots = ["tar.gz" "zip"];
+ # The template used to generate the clone url for https clone.
+ clone-url = [
+ "https://${cfg.domain}/$CGIT_REPO_URL"
+ "ssh://git@${cfg.domain}/$CGIT_REPO_URL"
+ ];
+ enable-http-clone = true;
+
+ # TODO: We might want to add an logo and readme here <2024-07-31>
+ # logo = "<url>";
+ # root-readme = "/some/readme/file"
+ root-desc = "The cgit instance of ${cfg.domain}!";
+ root-title = "${
+ lib.strings.toUpper (builtins.substring 0 1 cfg.domain) + builtins.substring 1 (builtins.stringLength cfg.domain) cfg.domain
+ } cgit instace";
+
+ # Set the default maximum statistics period. Valid values are "week",
+ # "month", "quarter" and "year".
+ max-stats = "week";
+
+ readme = [
+ ":README.md"
+ ":readme.md"
+ ":README.mkd"
+ ":readme.mkd"
+ ":README.rst"
+ ":readme.rst"
+ ":README.html"
+ ":readme.html"
+ ":README.htm"
+ ":readme.htm"
+ ":README.txt"
+ ":readme.txt"
+ ":README"
+ ":readme"
+ ":INSTALL.md"
+ ":install.md"
+ ":INSTALL.mkd"
+ ":install.mkd"
+ ":INSTALL.rst"
+ ":install.rst"
+ ":INSTALL.html"
+ ":install.html"
+ ":INSTALL.htm"
+ ":install.htm"
+ ":INSTALL.txt"
+ ":install.txt"
+ ":INSTALL"
+ ":install"
+ ];
+
+ enable-blame = true;
+ enable-commit-graph = true;
+ enable-subject-links = true;
+ enable-follow-links = true;
+ enable-index-links = true;
+ enable-index-owner = true;
+
+ # NOTE: This allows cgit to take configuration from the bare git repositories:
+ # All `repo.<key>` can be set by setting `cgit.<key>` in the git config. E.g.:
+ # setting the owner (i.e. `repo.owner`) would be done by setting the
+ # `cgit.owner` config. All repo options are outline in the cgitrc (5) man page.
+ enable-git-config = true;
+
+ # Remove the `.git` suffix from scanned repositories (this must be set _before_ `scan-path`)
+ remove-suffix = true;
+
+ css = "/custom_cgit.css";
+
+ # This is a number of path elements to treat as section.
+ # `-1` means that we treat the last element as name, all others as sections
+ section-from-path = -1;
+
+ project-list = "${config.services.gitolite.dataDir}/projects.list";
+
+ # TODO: We might want to use the kernel.org `libravatar.lua` email-filter <2024-07-31>
+ source-filter = "${config.services.cgit."${cfg.domain}".package}/lib/cgit/filters/syntax-highlighting.py";
+ about-filter = "${config.services.cgit."${cfg.domain}".package}/lib/cgit/filters/about-formatting.sh";
+ };
+ };
+
+ nginx.virtualHosts."${cfg.domain}" = {
+ enableACME = true;
+ forceSSL = true;
+
+ locations = {
+ "= /custom_cgit.css" = {
+ alias = cgitCss.outPath;
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/modules/by-name/ng/nginx/module.nix b/modules/by-name/ng/nginx/module.nix
new file mode 100644
index 0000000..6a82147
--- /dev/null
+++ b/modules/by-name/ng/nginx/module.nix
@@ -0,0 +1,68 @@
+{
+ lib,
+ config,
+ ...
+}: let
+ importedRedirects = import ./redirects.nix {};
+ mkRedirect = {
+ key,
+ value,
+ }: {
+ name = key;
+ value = {
+ forceSSL = true;
+ enableACME = true;
+ locations."/".return = "301 ${value}";
+ };
+ };
+
+ redirects = builtins.listToAttrs (builtins.map mkRedirect importedRedirects);
+
+ cfg = config.vhack.nginx;
+in {
+ options.vhack.nginx = {
+ enable = lib.mkEnableOption ''
+ a default nginx config.
+ '';
+
+ selfsign = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Whether to selfsign the acme certificates. This should only
+ really be useful for tests.
+ '';
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ security.acme = {
+ acceptTerms = true;
+ defaults = {
+ email = "admin@vhack.eu";
+ webroot = "/var/lib/acme/acme-challenge";
+
+ # Avoid spamming the acme server, if we run in a test, and only really want self-signed
+ # certificates
+ server = lib.mkIf cfg.selfsign "https://127.0.0.1";
+ };
+ };
+
+ networking.firewall = {
+ allowedTCPPorts = [80 443];
+ };
+ services.nginx = {
+ enable = true;
+ # The merge here is fine, as no domain should be specified twice
+ virtualHosts =
+ {
+ "gallery.s-schoeffel.de" = {
+ forceSSL = true;
+ enableACME = true;
+ root = "/srv/gallery.s-schoeffel.de";
+ };
+ }
+ // redirects;
+ };
+ };
+}
diff --git a/modules/by-name/ng/nginx/redirects.nix b/modules/by-name/ng/nginx/redirects.nix
new file mode 100644
index 0000000..a021e72
--- /dev/null
+++ b/modules/by-name/ng/nginx/redirects.nix
@@ -0,0 +1,6 @@
+{...}: [
+ {
+ key = "source.vhack.eu";
+ value = "https://codeberg.org/vhack.eu/nixos-server";
+ }
+]
diff --git a/modules/by-name/ni/nix-sync/hosts.nix b/modules/by-name/ni/nix-sync/hosts.nix
new file mode 100644
index 0000000..98dbbf1
--- /dev/null
+++ b/modules/by-name/ni/nix-sync/hosts.nix
@@ -0,0 +1,48 @@
+{...}: let
+ extraWkdSettings = {
+ locations."/.well-known/openpgpkey/hu/".extraConfig = ''
+ default_type application/octet-stream;
+
+ # Came from: https://www.uriports.com/blog/setting-up-openpgp-web-key-directory/
+ # No idea if it is actually necessary
+ # add_header Access-Control-Allow-Origin * always;
+ '';
+ };
+in [
+ {
+ domain = "vhack.eu";
+ url = "https://codeberg.org/vhack.eu/website.git";
+ }
+ {
+ domain = "b-peetz.de";
+ url = "https://codeberg.org/bpeetz/b-peetz.de.git";
+ }
+
+ # Trinitrix
+ {
+ domain = "trinitrix.vhack.eu";
+ url = "https://codeberg.org/trinitrix/website.git";
+ }
+
+ # WKD
+ {
+ domain = "openpgpkey.b-peetz.de";
+ url = "https://codeberg.org/vhack.eu/gpg_wkd.git";
+ extraSettings = extraWkdSettings;
+ }
+ {
+ domain = "openpgpkey.s-schoeffel.de";
+ url = "https://codeberg.org/vhack.eu/gpg_wkd.git";
+ extraSettings = extraWkdSettings;
+ }
+ {
+ domain = "openpgpkey.sils.li";
+ url = "https://codeberg.org/vhack.eu/gpg_wkd.git";
+ extraSettings = extraWkdSettings;
+ }
+ {
+ domain = "openpgpkey.vhack.eu";
+ url = "https://codeberg.org/vhack.eu/gpg_wkd.git";
+ extraSettings = extraWkdSettings;
+ }
+]
diff --git a/modules/by-name/ni/nix-sync/internal_module.nix b/modules/by-name/ni/nix-sync/internal_module.nix
new file mode 100644
index 0000000..a3ab0af
--- /dev/null
+++ b/modules/by-name/ni/nix-sync/internal_module.nix
@@ -0,0 +1,299 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ cfg = config.services.nix-sync;
+ esa = lib.strings.escapeShellArg;
+
+ mkTimer = name: repo: {
+ description = "Nix sync ${name} timer";
+ wantedBy = ["timers.target"];
+ timerConfig = {
+ OnUnitActiveSec = repo.interval;
+ };
+ wants = ["network-online.target"];
+ after = ["network-online.target"];
+ };
+
+ parents = path: let
+ split_path = builtins.split "/" path;
+ filename = builtins.elemAt split_path (builtins.length split_path - 1);
+ path_build =
+ lib.strings.removeSuffix "/" (builtins.replaceStrings [filename] [""] path);
+ final_path =
+ if filename == ""
+ then parents path_build
+ else path_build;
+ in
+ final_path;
+
+ mkUnit = name: repo: let
+ optionalPathSeparator =
+ if lib.strings.hasPrefix "/" repo.path
+ then ""
+ else "/";
+ /*
+ * `ln` tries to create a symlink in the directory, if the target ends with a '/',
+ * thus remove it.
+ */
+ repoPath = lib.strings.removeSuffix "/" repo.path;
+
+ 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};
+
+ git fetch
+ origin="$(git rev-parse @{u})";
+ branch="$(git rev-parse @)";
+
+ if ! [ "$origin" = "$branch" ]; then
+ git pull --rebase;
+
+ 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 repoPath};
+ ln -s "$out_path" ${esa repoPath};
+ rm "$out_paths";
+ fi
+ '';
+ execStartPreScript = ''
+ 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 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 repoPath};
+ rm "$out_paths";
+ fi
+
+ if ! [ -L ${esa repoPath} ]; then
+ cd ${esa repoCachePath};
+
+ git pull --rebase;
+
+ 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")";
+
+ if [ -d ${esa repoPath} ]; then
+ rm -d ${esa repoPath};
+ else
+ mkdir --parents "$(dirname ${esa repoPath})";
+ fi
+ [ -e ${esa repoPath} ] && rm ${esa repoPath};
+
+ ln -s "$out_path" ${esa repoPath};
+ rm "$out_paths";
+ fi
+ '';
+ in {
+ description = "Nix Sync ${name}";
+ wantedBy = ["default.target"];
+ after = ["network.target"];
+ path = with pkgs; [openssh git nix mktemp coreutils dash];
+ preStart = execStartPreScript;
+
+ serviceConfig = {
+ TimeoutSec = 0;
+ ExecStart = execStartScript;
+ Restart = "on-abort";
+ # User and group
+ User = cfg.user;
+ Group = cfg.group;
+ # Runtime directory and mode
+ RuntimeDirectory = "nix-sync";
+ RuntimeDirectoryMode = "0750";
+ # Cache directory and mode
+ CacheDirectory = "nix-sync";
+ CacheDirectoryMode = "0750";
+ # Logs directory and mode
+ LogsDirectory = "nix-sync";
+ LogsDirectoryMode = "0750";
+ # Proc filesystem
+ ProcSubset = "all";
+ ProtectProc = "invisible";
+ # New file permissions
+ UMask = "0027"; # 0640 / 0750
+ # Capabilities
+ AmbientCapabilities = ["CAP_CHOWN"];
+ CapabilityBoundingSet = ["CAP_CHOWN"];
+ # Security
+ NoNewPrivileges = true;
+ # Sandboxing (sorted by occurrence in https://www.freedesktop.org/software/systemd/man/systemd.exec.html)
+ ReadWritePaths = ["${esa (parents repo.path)}" "-${esa (parents repoCachePath)}" "-${esa cfg.cachePath}"];
+ ReadOnlyPaths = ["/nix"]; # TODO: Should be irrelevant, as we have ProtectSystem=Strict <2024-06-01>
+ ProtectSystem = "strict";
+ ProtectHome = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ ProtectHostname = true;
+ ProtectClock = true;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectKernelLogs = true;
+ ProtectControlGroups = true;
+ RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
+ RestrictNamespaces = true;
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ RemoveIPC = true;
+ PrivateMounts = true;
+ # System Call Filtering
+ SystemCallArchitectures = "native";
+ SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"];
+ };
+ };
+
+ services =
+ lib.mapAttrs' (name: repo: {
+ 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 = {
+ name = lib.mkOption {
+ internal = true;
+ default = name;
+ type = lib.types.str;
+ description = "The name that should be given to this unit.";
+ };
+
+ path = lib.mkOption {
+ type = lib.types.str;
+ description = "The path at which to sync the repository";
+ };
+
+ uri = lib.mkOption {
+ type = lib.types.str;
+ 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
+ <link xlink:href="https://git-scm.com/docs/git-clone#_git_urls"/>
+ for the supported URIs.
+ '';
+ };
+
+ extraSettings = lib.mkOption {
+ type = lib.types.attrsOf lib.types.anything;
+ example = lib.literalExpression ''
+ {
+ locations."/.well-known/openpgpkey/hu/" = {
+ extraConfig = \'\'
+ default_type application/octet-stream;
+
+ add_header Access-Control-Allow-Origin * always;
+ \'\';
+ };
+ }
+ '';
+ description = ''
+ Extra config to add the the nginx virtual host.
+ '';
+ };
+
+ interval = lib.mkOption {
+ type = lib.types.int;
+ default = 500;
+ description = ''
+ The interval, specified in seconds, at which the synchronization will
+ be triggered.
+ '';
+ };
+ };
+ });
+in {
+ options = {
+ services.nix-sync = {
+ enable = lib.mkEnableOption "nix-sync services";
+
+ user = lib.mkOption {
+ type = lib.types.str;
+ default = "nix-sync";
+ description = lib.mdDoc "User account under which nix-sync units runs.";
+ };
+
+ group = lib.mkOption {
+ type = lib.types.str;
+ default = "nix-sync";
+ description = lib.mdDoc "Group account under which nix-sync units runs.";
+ };
+
+ cachePath = lib.mkOption {
+ type = lib.types.str;
+ default = "/var/lib/nix-sync";
+ description = lib.mdDoc ''
+ Where to cache git directories. Should not end with a slash ("/")
+ '';
+ };
+
+ repositories = lib.mkOption {
+ type = with lib.types; attrsOf repositoryType;
+ description = ''
+ The repositories that should be synchronized.
+ '';
+ };
+ };
+ };
+
+ 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;
+
+ inherit services 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.";
+ };
+}
diff --git a/modules/by-name/ni/nix-sync/module.nix b/modules/by-name/ni/nix-sync/module.nix
new file mode 100644
index 0000000..0a92888
--- /dev/null
+++ b/modules/by-name/ni/nix-sync/module.nix
@@ -0,0 +1,61 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.vhack.nix-sync;
+
+ mkNixSyncRepository = {
+ domain,
+ root ? "",
+ url,
+ extraSettings ? {},
+ }: {
+ name = "${domain}";
+ value = {
+ path = "/etc/nginx/websites/${domain}/${root}";
+ uri = "${url}";
+ inherit extraSettings;
+ };
+ };
+ nixSyncRepositories = builtins.listToAttrs (builtins.map mkNixSyncRepository domains);
+
+ mkVirtHost = {
+ domain,
+ root ? "",
+ url,
+ extraSettings ? {},
+ }: {
+ name = "${domain}";
+ value =
+ lib.recursiveUpdate {
+ forceSSL = true;
+ enableACME = true;
+ root = "/etc/nginx/websites/${domain}/${root}";
+ }
+ extraSettings;
+ };
+ virtHosts = builtins.listToAttrs (builtins.map mkVirtHost domains);
+
+ domains = import ./hosts.nix {};
+in {
+ imports = [
+ ./internal_module.nix
+ ];
+
+ options.vhack.nix-sync = {
+ enable = lib.mkEnableOption ''
+ a website git ops solution.
+ '';
+ };
+
+ config = lib.mkIf cfg.enable {
+ services.nix-sync = {
+ enable = true;
+ repositories = nixSyncRepositories;
+ };
+
+ vhack.nginx.enable = true;
+ services.nginx.virtualHosts = virtHosts;
+ };
+}
diff --git a/modules/by-name/op/openssh/module.nix b/modules/by-name/op/openssh/module.nix
new file mode 100644
index 0000000..30d16a6
--- /dev/null
+++ b/modules/by-name/op/openssh/module.nix
@@ -0,0 +1,31 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.vhack.openssh;
+in {
+ options.vhack.openssh = {
+ enable = lib.mkEnableOption ''
+ a sane openssh implementation.
+ '';
+ };
+
+ config = lib.mkIf cfg.enable {
+ 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/modules/by-name/pe/peertube/module.nix b/modules/by-name/pe/peertube/module.nix
new file mode 100644
index 0000000..29d1d07
--- /dev/null
+++ b/modules/by-name/pe/peertube/module.nix
@@ -0,0 +1,113 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ cfg = config.vhack.peertube;
+in {
+ options.vhack.peertube = {
+ enable = lib.mkEnableOption ''
+ the peertube video platform.
+ '';
+ };
+
+ config = lib.mkIf cfg.enable {
+ services.peertube = {
+ enable = true;
+
+ configureNginx = true;
+ localDomain = "peertube.vhack.eu";
+ enableWebHttps = true;
+ listenWeb = 443;
+
+ smtp = {
+ createLocally = true;
+ passwordFile = "${config.age.secrets.peertubeSmtp.path}";
+ };
+ database = {
+ createLocally = true;
+ };
+ redis = {
+ enableUnixSocket = true;
+ createLocally = true;
+ };
+
+ secrets.secretsFile = "${config.age.secrets.peertubeGeneral.path}";
+
+ settings = {
+ signup = {
+ enabled = true;
+
+ limit = 10; # When the limit is reached, registrations are disabled. -1 == unlimited
+
+ minimum_age = 18; # Used to configure the signup form
+
+ # Users fill a form to register so moderators can accept/reject the registration
+ requires_approval = true;
+ requires_email_verification = true;
+ };
+ user = {
+ video_quota = "10GB";
+ video_quota_daily = "2GB";
+ };
+ auto_blacklist = {
+ videos = {
+ of_users = {
+ enabled = true;
+ };
+ };
+ };
+ listen.hostname = "127.0.0.1";
+ instance.name = "PeerTube at Vhack.eu";
+
+ admin.email = "admin@vhack.eu";
+
+ smtp = let
+ emailAddress = "peertube@vhack.eu";
+ in {
+ sendmail = "${pkgs.postfix}/bin/sendmail";
+
+ transport = "sendmail";
+ hostname = "server1.vhack.eu";
+ port = 587;
+ username = emailAddress;
+ tls = true;
+ disable_starttls = true;
+ from_address = emailAddress;
+ };
+ };
+ };
+
+ # The `configureNginx` option does not do this for some reason
+ # TODO(@bpeetz): Find out why <2024-06-27>
+ services.nginx.virtualHosts."${config.services.peertube.localDomain}" = {
+ enableACME = true;
+ forceSSL = true;
+ };
+
+ age.secrets = {
+ peertubeGeneral = {
+ file = ./secrets/general.age;
+ mode = "700";
+ owner = "peertube";
+ group = "peertube";
+ };
+ peertubeSmtp = {
+ file = ./secrets/smtp.age;
+ mode = "700";
+ owner = "peertube";
+ group = "peertube";
+ };
+ };
+
+ environment.persistence."/srv".directories = [
+ {
+ directory = "/var/lib/peertube";
+ user = "peertube";
+ group = "peertube";
+ mode = "0700";
+ }
+ ];
+ };
+}
diff --git a/modules/by-name/pe/peertube/secrets/general.age b/modules/by-name/pe/peertube/secrets/general.age
new file mode 100644
index 0000000..854ab1a
--- /dev/null
+++ b/modules/by-name/pe/peertube/secrets/general.age
@@ -0,0 +1,15 @@
+-----BEGIN AGE ENCRYPTED FILE-----
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlNjR4TDVUZmY2Y0hYT2hk
+YmtPcFIxSXplNWF4M0V1Kzh2b2VoSTFCK0dzCmpwT2tDa3FpR082V2pyelBoS05o
+RmlWRVdNdVhZbkRVUEVnaDlPdlN1bDAKLT4gWDI1NTE5IFlvaTFPc2JHcWczbEJy
+eVZDS2NaUzBvbnpadk5ySVFxRTlNVXhrd2N0a3MKanJ0NEZWaTg3dE5Cbm9uNHNS
+ZCs2dmU4RkFZOHNyNlJKa0cyd2VqSlFPQQotPiBzc2gtZWQyNTUxOSBPRDhUNGcg
+NXhFSHdWUk1sbEUyb3FTdGpIaHlyTUJlMnlzNXBEY2lzTXpuM09WVDBrOApmM05W
+d1VBSGlhMmlDYlhZS1hSdlJBUVkrVWs0bTJseS9BUmZGY1l5K0NBCi0+IEQkNi1l
+LWdyZWFzZSAhIUlaOnNsZCAsUVRVKiBfRig2KGg+NSA6CmI0Q0N0cmlFbnNGSFZQ
+WThEV0RHS0V2NTVaZnIyK2tUQXZTOHdsRkhyRlExdCtOeHRML2hFNDNxd08xQjlG
+V3oKMThoQnF4Y3FDU3hMZjhwRUNvVWRRR3I4c1k5QnhJS1dRR2dod0EKLS0tIEZT
+dHhnVXdHV3QzYThXWFJQL2szeTZ4SWM4czZYQWxJOFFIVjBZSnJ0K00KH8WdXv68
+rjAqo5RoWu91aVg5Bl2HKuiFbaGcnlkiMPZ9wGfpq4mpCc/yc4NTa6HhkaI5tA61
+PjKurnkiLXywcdyUTPuaykk+wANynLucbwfq/Mv3aLcG01soh+dFNKZV/g==
+-----END AGE ENCRYPTED FILE-----
diff --git a/modules/by-name/pe/peertube/secrets/smtp.age b/modules/by-name/pe/peertube/secrets/smtp.age
new file mode 100644
index 0000000..1979ea7
--- /dev/null
+++ b/modules/by-name/pe/peertube/secrets/smtp.age
@@ -0,0 +1,16 @@
+-----BEGIN AGE ENCRYPTED FILE-----
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtU05NMDN0Q2MrVGEraHpH
+Tkwyd0NuVEQwcjljd0NUNUpsSER0V0RldWxNCjlnRHZWNmprVDYxQm90Q3pFVHR5
+enJyUTZhSVdUL1I1aC9Ya2NkMElQaFUKLT4gWDI1NTE5IHprWjRDZVlMK3Rmd1A5
+K0pZRVBIYldsOW0wQXp4SmJzM1pXdzAvZVpiWEUKd1cwR2ZNZTh6WXhQNGZBVmdN
+VWpxZGxPZXJBT1dqUFd1aU4xaHAxckZLcwotPiBzc2gtZWQyNTUxOSBPRDhUNGcg
+akdaS3I3VHplOENIZDg5TSt2SmRCSGpjaUZoUHVYTFJRR2wzc1RHYWNnVQpFN1Ew
+MTZDNGNyKzB1aEdTMHpKaWlFLzE0blJpZ3RhOTZReTNucUp6SEdZCi0+IHloQSUq
+LWdyZWFzZQo5VitXYjNxck5FbnkwYlBvUyt6R2ROVG9JOWtQNGJma1ZYd29oVlFx
+blFzSytWNDA4d3lqWE9JTUVreCs2Wi92ClZCdFgwYmRmc1VsU0NhTVR4b2dtZkpK
+ZTU2M24zVjd0UTRrelFXYnFEZwotLS0gT2ZlRGJsZWNPcEwxK2drdDhVSndDV3Fj
+SENsN2piWWEzSFI2OW8xbk12cwrFU4dzHxb5M3miGDpWLh3XbwzsrqWlFWLLu0Ht
+SDvqJGrwAPsnVn4YLSG42q1BodYfcQVvVwqRCVbkubEUDcecDTdaYDvjaS3tmDZW
+u5Nabp1ujYuIewOEZ8w41napS0C553qq0mL5sYZH1C23ViW81va4X1XOJTCnmbz6
+lbh+lK8ZbZz3cer49nR8OHTtpjA9hrf4Pf/W2nMR+0exy4zDYw==
+-----END AGE ENCRYPTED FILE-----