From 2831fdb0f27e2b3e6eb32f907681a07337a752ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 1 Feb 2025 17:57:32 +0800
Subject: [PATCH 1/4] feat(crowdsec): Add proper support for acquisitions

---
 modules/crowdsec/default.nix | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
index 915ca0b..0d0ff1c 100644
--- a/modules/crowdsec/default.nix
+++ b/modules/crowdsec/default.nix
@@ -28,6 +28,12 @@ let
 
     $sudo ${crowdsec}/bin/cscli "$@"
   '';
+
+  acquisitions = ''
+    ---
+    ${lib.concatMapStringsSep "\n---\n" builtins.toJSON cfg.acquisitions}
+    ---
+  '';
 in
 {
   imports = [ ./remediations ];
@@ -82,6 +88,24 @@ in
         '';
       };
 
+      acquisitions = lib.mkOption {
+        type = listOf settingsFormat.type;
+        default = [ ];
+        description = ''
+          Log acquisitions.
+        '';
+      };
+
+      extraGroups = lib.mkOption {
+        type = listOf str;
+        default = [ ];
+        description = ''
+          Additional groups to make the service part of.
+
+          Required to permit reading from various log sources.
+        '';
+      };
+
       hubConfigurations = {
         collections = lib.mkOption {
           type = listOf str;
@@ -190,7 +214,13 @@ in
           plugin_dir = lib.mkDefault "/var/empty/";
         };
 
-        crowdsec_service.acquisition_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/acquis.yaml";
+        crowdsec_service.acquisition_path =
+          # Using an if/else here because `mkMerge` does not work in
+          # YAML-type options
+          if cfg.acquisitions == [ ] then
+            "${cfg.package}/share/crowdsec/config/acquis.yaml"
+          else
+            pkgs.writeText "acquis.yaml" acquisitions;
 
         cscli = {
           prometheus_uri = lib.mkDefault "127.0.0.1:6060";
@@ -339,7 +369,7 @@ in
           serviceConfig = {
             User = "crowdsec";
             Group = "crowdsec";
-            SupplementaryGroups = [ "systemd-journal" ];
+            SupplementaryGroups = cfg.extraGroups;
 
             StateDirectory = "crowdsec";
           };

From 68450870cf3776f4f855cfdf117b24069777d3c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 1 Feb 2025 17:58:15 +0800
Subject: [PATCH 2/4] feat(crowdsec-service): Add nginx monitoring

---
 configuration/services/crowdsec.nix | 50 ++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
index 110602c..4891cad 100644
--- a/configuration/services/crowdsec.nix
+++ b/configuration/services/crowdsec.nix
@@ -1,4 +1,4 @@
-{ pkgs, ... }:
+{ config, lib, ... }:
 {
   security.crowdsec = {
     enable = true;
@@ -7,21 +7,39 @@
       "1.64.239.213"
     ];
 
-    settings.crowdsec_service.acquisition_path = pkgs.writeText "crowdsec-acquisitions.yaml" ''
-      ---
-      source: journalctl
-      journalctl_filter:
-        - "SYSLOG_IDENTIFIER=Nextcloud"
-      labels:
-        type: syslog
-      ---
-      source: journalctl
-      journalctl_filter:
-        - "SYSLOG_IDENTIFIER=sshd-session"
-      labels:
-        type: syslog
-      ---
-    '';
+    extraGroups = [
+      "systemd-journal"
+      "nginx"
+    ];
+
+    acquisitions = [
+      {
+        source = "journalctl";
+        labels.type = "syslog";
+        journalctl_filter = [
+          "SYSLOG_IDENTIFIER=Nextcloud"
+        ];
+      }
+
+      {
+        source = "journalctl";
+        labels.type = "syslog";
+        journalctl_filter = [
+          "SYSLOG_IDENTIFIER=sshd-session"
+        ];
+      }
+
+      {
+        labels.type = "nginx";
+        filenames =
+          [
+            "/var/log/nginx/*.log"
+          ]
+          ++ lib.mapAttrsToList (
+            vHost: _: "/var/log/nginx/${vHost}/access.log"
+          ) config.services.nginx.virtualHosts;
+      }
+    ];
 
     remediationComponents.firewallBouncer = {
       enable = true;

From 78c81a10284d2202be058c8e51f24baa539cb116 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 1 Feb 2025 18:16:52 +0800
Subject: [PATCH 3/4] feat(acme): Switch to porkbun

---
 configuration/nginx.nix | 13 ++++++++++---
 configuration/sops.nix  | 12 ++++++++----
 keys/production.yaml    | 10 ++++++----
 keys/staging.yaml       | 10 ++++++----
 4 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/configuration/nginx.nix b/configuration/nginx.nix
index b38118b..0b72cc1 100644
--- a/configuration/nginx.nix
+++ b/configuration/nginx.nix
@@ -47,10 +47,17 @@
     acceptTerms = true;
 
     certs."tlater.net" = {
-      extraDomainNames = [ "*.tlater.net" ];
-      dnsProvider = "hetzner";
+      extraDomainNames = [
+        "*.tlater.net"
+        "tlater.com"
+        "*.tlater.com"
+      ];
+      dnsProvider = "porkbun";
       group = "nginx";
-      credentialFiles."HETZNER_API_KEY_FILE" = config.sops.secrets."hetzner-api".path;
+      credentialFiles = {
+        PORKBUN_API_KEY_FILE = config.sops.secrets."porkbun/api-key".path;
+        PORKBUN_SECRET_API_KEY_FILE = config.sops.secrets."porkbun/secret-api-key".path;
+      };
     };
   };
 
diff --git a/configuration/sops.nix b/configuration/sops.nix
index bc21834..bbfb888 100644
--- a/configuration/sops.nix
+++ b/configuration/sops.nix
@@ -34,16 +34,20 @@
       "heisenbridge/as-token" = { };
       "heisenbridge/hs-token" = { };
 
-      "hetzner-api" = {
-        owner = "acme";
-      };
-
       # Nextcloud
       "nextcloud/tlater" = {
         owner = "nextcloud";
         group = "nextcloud";
       };
 
+      # Porkbub/ACME
+      "porkbun/api-key" = {
+        owner = "acme";
+      };
+      "porkbun/secret-api-key" = {
+        owner = "acme";
+      };
+
       # Restic
       "restic/local-backups" = {
         owner = "root";
diff --git a/keys/production.yaml b/keys/production.yaml
index 6dd4c21..19df9bd 100644
--- a/keys/production.yaml
+++ b/keys/production.yaml
@@ -1,4 +1,6 @@
-hetzner-api: ENC[AES256_GCM,data:OsUfo86AzcBe/OELkfB5brEfsZ4gkbeehxwIVUBwQgE=,iv:Bt/cjlZ6oZEVUOQjWMDL7/mfL3HWLFAw1tEGeLMgeKg=,tag:TMU2XiHlMgP4aes10mIQYQ==,type:str]
+porkbun:
+    api-key: ENC[AES256_GCM,data:p3lqvGc8m2U/12rBPjoNR7hxQyD52CyEen/V8q59k5CSJZSqzZS8M5vEXFBsUMjz2lrmKM4pgtz4wa2fWK6Ty4LJCaI=,iv:OQC3FpwTtPmqHvDbA41mWF7LGYwC/jD2ZMBsE8ktNOg=,tag:kq5hUR7TBgczuGcXpsdu2A==,type:str]
+    secret-api-key: ENC[AES256_GCM,data:zV5PTKf45Zab8uW8mbuXmPNzciq6tV9OF0wUND7YnRk/DjZneYWItAsNBVoM+iHA+XsUPDoeKo6hoJiGkH/cCQ8WvuM=,iv:yr1M5DlgI8k6BgzNz3HRnqspHOrQuf2PmoZS1HGp0v8=,tag:JkNNziMMfKFZV2hnx5lXRg==,type:str]
 battery-manager:
     email: ENC[AES256_GCM,data:rYLUACXR/n+bLBmZ,iv:sUBEkh2+7qGjHZ5R23e/hoCiyTA7GTL4bJvXmxjZ5Sw=,tag:fdPMllaQQfRgX0WZKIre4g==,type:str]
     password: ENC[AES256_GCM,data:7cokZa6Q6ahSeiFPz+cV,iv:vz405P0IcG9FsAQXlY7mi78GuushQUKJm2irG6buGzc=,tag:JLHG2jTkJDGbinAq9dXRsQ==,type:str]
@@ -32,8 +34,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2024-04-15T23:13:18Z"
-    mac: ENC[AES256_GCM,data:3/v+WgSWJ+VcBSBe1Wkis3z+tMmSjbKzLFqBB8xugc6DvgQG8J+1HRrPucLnpNNtEdmpyoTa72U6fPm6JnyUsuj5pLEghLprOJkqQNdRI06fllhw+9d3e3twx6D4oIIsVH6/io4ElXrGsGQTsfNbYhgn+987wa3WP5N25fBac3U=,iv:FL3tzPutOMN6IPkQfXIu/JOZT+OzUSqpMSQrUeXZQHE=,tag:jL1BTsYTA9XjrsjFszxZhA==,type:str]
+    lastmodified: "2025-02-01T10:16:20Z"
+    mac: ENC[AES256_GCM,data:oFJNljU0RJdgsdK7qRXKCqRs7kPXgHqSyYcexEs8kXFnn68mKHNKKfl7skepCPKk0U7h6JqJQ+EOnAA0eo6mraBAMKLSXUcucTzqsfcI+V04rYcP2nGPMUiNDGdKHCcb6OmBhfvKw7+elnonPxKsBlyK31AqB9RFDKaTKXpcNMw=,iv:Q9t7ZkUrevHm5I4JBW95TfvZ88dl2Fq3Yq/E642dV6s=,tag:p2XWfii168qq29wX/RCJuQ==,type:str]
     pgp:
         - created_at: "2025-01-21T17:55:44Z"
           enc: |-
@@ -91,4 +93,4 @@ sops:
             -----END PGP MESSAGE-----
           fp: 0af7641adb8aa843136cf6d047f71da3e5ad79f9
     unencrypted_suffix: _unencrypted
-    version: 3.8.1
+    version: 3.9.2
diff --git a/keys/staging.yaml b/keys/staging.yaml
index 091424d..67e47ad 100644
--- a/keys/staging.yaml
+++ b/keys/staging.yaml
@@ -1,4 +1,6 @@
-hetzner-api: ENC[AES256_GCM,data:1Zjp003j60g=,iv:+vDcyiqYm4A9CMIrW4oGZKdZiczatBcvfL4qYYhKwCg=,tag:Xeu8JuRm+b+5RO+wFR2M8w==,type:str]
+porkbun:
+    api-key: ENC[AES256_GCM,data:A5J1sqwq6hs=,iv:77Mar3IX7mq7z7x6s9sSeGNVYc1Wv78HptJElEC7z3Q=,tag:eM/EF9TxKu+zcbJ1SYXiuA==,type:str]
+    secret-api-key: ENC[AES256_GCM,data:8Xv+jWYaWMI=,iv:li4tdY0pch5lksftMmfMVS729caAwfaacoztaQ49az0=,tag:KhfElBGzVH4ByFPfuQsdhw==,type:str]
 battery-manager:
     email: ENC[AES256_GCM,data:LM/EGzWHfVQ=,iv:jFaoUQuUfuGoOyj/GFpdI8TerH/c8D9fjvio+IEt2Tc=,tag:IWLiN011JEnHRLIXWQgfmA==,type:str]
     password: ENC[AES256_GCM,data:SUxjqS7SJHM=,iv:LvdKk88S+nSImh6/ZezbFGLCUBu1Lpdu+neF2xyHdBg=,tag:rcMyZuW4FVNbcbz00wQKBg==,type:str]
@@ -32,8 +34,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2024-04-15T23:13:27Z"
-    mac: ENC[AES256_GCM,data:JhEVrKF2Jsqpdztcr3g5lMrgEFeLXfBRQTwQJ6PmLSNyDORcTU09TJPNWTPDnR5okDrvIU/wlzi5DZ8A0ebNhrKf6l0tNFBT9LSvQFHU5SBxqY/m8uEJKSrEC4IL5lugOOISDka2KSvYXVCXrumMHE5FnmOS/CgOZaZk6LUjPYA=,iv:ygygnSedcTo2Vsc56s2qrz1qkWchvSgvoiMTebRxQQ8=,tag:vf6z8rxsXmqzwpDy9Avifw==,type:str]
+    lastmodified: "2025-02-01T10:16:31Z"
+    mac: ENC[AES256_GCM,data:N4RQHOyWvSXW16fepQvRznNbmGerct03kptyiY3IoTpYaJ+43cyFjW15ZqfpaRFyV66QIeqmceqV8c4eP8YSndj6e55e04w0RCyqREXQlFPR6Eh5elaBenokoJhjF6BCsq+xX1C+LUEcxiR/dgy5cwA3mAD/dLCm+G11a06EG6k=,iv:wt5fEOVP6CXHCzmMH9hNCQDDgPa66bLMOa39Eipux9Y=,tag:kWZPnWD1stANVAmWmvOjCg==,type:str]
     pgp:
         - created_at: "2025-01-21T17:55:30Z"
           enc: |-
@@ -71,4 +73,4 @@ sops:
             -----END PGP MESSAGE-----
           fp: 2f5caa73e7ceea4fcc8d2881fde587e6737d2dbc
     unencrypted_suffix: _unencrypted
-    version: 3.8.1
+    version: 3.9.2

From ca3d21b3ad843784903546859a27971e6b9a9168 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 7 Nov 2024 20:26:43 +0100
Subject: [PATCH 4/4] WIP: feat: Add minecraft server

---
 configuration/default.nix            |  6 +-
 configuration/services/minecraft.nix | 83 ++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 5 deletions(-)
 create mode 100644 configuration/services/minecraft.nix

diff --git a/configuration/default.nix b/configuration/default.nix
index c9c71ec..d4c422f 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -22,6 +22,7 @@
     ./services/foundryvtt.nix
     ./services/gitea.nix
     ./services/metrics
+    ./services/minecraft.nix
     ./services/nextcloud.nix
     ./services/webserver.nix
     ./services/wireguard.nix
@@ -70,8 +71,6 @@
         8448
         # starbound
         21025
-        # Minecraft
-        25565
 
         config.services.coturn.listening-port
         config.services.coturn.tls-listening-port
@@ -80,9 +79,6 @@
       ];
 
       allowedUDPPorts = [
-        # More minecraft
-        25565
-
         config.services.coturn.listening-port
         config.services.coturn.tls-listening-port
         config.services.coturn.alt-listening-port
diff --git a/configuration/services/minecraft.nix b/configuration/services/minecraft.nix
new file mode 100644
index 0000000..0477f44
--- /dev/null
+++ b/configuration/services/minecraft.nix
@@ -0,0 +1,83 @@
+{
+  pkgs,
+  lib,
+  config,
+  ...
+}:
+{
+  services.minecraft-server = {
+    enable = true;
+    eula = true;
+    # jvmOpts are set using a file for forge
+    # jvmOpts = "-Xmx8G -Xms8G";
+    openFirewall = true;
+
+    declarative = true;
+
+    whitelist = {
+      tlater = "140d177a-966f-41b8-a4c0-e305babd291b";
+      romino25 = "59cd1648-14a4-4bcf-8f5a-2e1bde678f2c";
+      lasi25 = "0ab6e3d1-544a-47e7-8538-2e6c248e49a4";
+    };
+
+    serverProperties = {
+      allow-flight = true;
+      difficulty = "hard";
+      motd = "tlater.net";
+      spawn-protection = 1;
+      white-list = true;
+      enable-query = true;
+      enable-status = true;
+
+      # Allows the server to write chunks without hogging the main
+      # thread...
+      sync-chunk-writes = false;
+      # Disables chat reporting, because we don't need any of that
+      # drama on a lil' friends-only server.
+      enforce-secure-profile = false;
+    };
+
+    package = pkgs.writeShellApplication {
+      name = "minecraft-server";
+      runtimeInputs = with pkgs; [ jdk17_headless ];
+
+      text = ''
+        exec /var/lib/minecraft/run.sh $@
+      '';
+    };
+  };
+
+  systemd.services.minecraft-server = {
+    path = with pkgs; [ jdk17_headless ];
+
+    # Since we read from our own HTTP server, we need to wait for it
+    # to be up
+    after = [ "nginx.service" ];
+
+    serviceConfig = {
+      # Use packwiz to install mods
+      ExecStartPre = [
+        "${pkgs.jdk17_headless}/bin/java -jar ${config.services.minecraft-server.dataDir}/packwiz-installer-bootstrap.jar -g -s server 'https://minecraft.${config.services.nginx.domain}/cobblemon-pack/pack.toml'"
+      ];
+      # Forge requires some bonus JVM options, which they include in a
+      # little `run.sh` script
+      ExecStart = lib.mkForce "${config.services.minecraft-server.dataDir}/run.sh --nogui";
+    };
+  };
+
+  systemd.tmpfiles.settings."10-minecraft" = {
+    "/srv/minecraft".d = {
+      user = "nginx";
+      group = "minecraft";
+      mode = "0775";
+    };
+  };
+
+  services.nginx.virtualHosts."minecraft.${config.services.nginx.domain}" = {
+    forceSSL = true;
+    useACMEHost = "tlater.net";
+    enableHSTS = true;
+
+    root = "/srv/minecraft";
+  };
+}