about summary refs log tree commit diff
path: root/configuration.nix
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2022-05-24 17:18:30 +0300
committerVika <vika@fireburn.ru>2022-05-24 17:18:30 +0300
commit5610a5f0bf1a9df02bd3d5b55e2cdebef2440360 (patch)
tree8394bcf1dcc204043d7adeb8dde2e2746977606e /configuration.nix
parent2f93873122b47e42f7ee1c38f1f04d052a63599c (diff)
flake.nix: reorganize
 - Kittybox's source code is moved to a subfolder
   - This improves build caching by Nix since it doesn't take changes
     to other files into account
 - Package and test definitions were spun into separate files
   - This makes my flake.nix much easier to navigate
   - This also makes it somewhat possible to use without flakes (but
     it is still not easy, so use flakes!)
 - Some attributes were moved in compliance with Nix 2.8's changes to
   flake schema
Diffstat (limited to 'configuration.nix')
-rw-r--r--configuration.nix158
1 files changed, 158 insertions, 0 deletions
diff --git a/configuration.nix b/configuration.nix
new file mode 100644
index 0000000..411b7b2
--- /dev/null
+++ b/configuration.nix
@@ -0,0 +1,158 @@
+kittybox:
+{ config, pkgs, lib, ... }:
+with lib;
+let
+  cfg = config.services.kittybox;
+in {
+  options = {
+    services.kittybox = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable Kittybox, the IndieWeb blogging solution.
+        '';
+      };
+      package = mkOption {
+        type = types.package;
+        default = kittybox.packages.${config.nixpkgs.localSystem.system}.kittybox;
+        defaultText = "<kittybox package from the upstream flake>";
+        description = "Which Kittybox derivation to use.";
+      };
+
+      bind = mkOption {
+        type = types.nullOr types.str;
+        default = "127.0.0.1";
+        description = "The host for Kittybox to bind to.";
+        example = "192.168.1.100";
+      };
+      port = mkOption {
+        type = types.int;
+        default = 8080;
+        description = "The port for Kittybox to listen at.";
+        example = 16420;
+      };
+      logLevel = mkOption {
+        type = types.str;
+        default = "warn";
+        example = "info";
+        description = "Specify the server verbosity level. Uses RUST_LOG environment variable internally.";
+      };
+      backendUri = mkOption {
+        type = types.str;
+        default = "file:///var/lib/kittybox/data";
+        example = "redis://192.168.1.200:6379";
+        description = ''
+          Set the backend used for storing data. Available backends are:
+           - file:// - static folder backend (recommended)
+           - redis:// - Redis backend
+
+          Make sure that if you are using the file backend, the state
+          directory is accessible by Kittybox. By default, the unit config
+          uses DynamicUser=true, which prevents the unit from accessing
+          data outside of its directory. It is recommended to use a
+          bind-mount to /var/lib/private/kittybox if you require the state
+          directory to reside elsewhere.
+        '';
+      };
+      tokenEndpoint = mkOption {
+        type = types.str;
+        example = "https://tokens.indieauth.com/token";
+        description = "Token endpoint to use for authenticating Micropub requests. Use the example if you are unsure.";
+      };
+      authorizationEndpoint = mkOption {
+        type = types.str;
+        example = "https://indieauth.com/auth";
+        description = "Authorization endpoint to use to authenticate the user. You can use the default if you are unsure.";
+      };
+      mediaEndpoint = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "The URL of a media endpoint to announce when asked by a Micropub client. Strongly recommended if you plan to upload images.";
+      };
+      microsubServer = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "https://aperture.p3k.io/microsub/69420";
+        description = ''
+          The URL of your Microsub server, which saves feeds for you
+          and allows you to browse Web content from one place. Try
+          https://aperture.p3k.io/ if you don't have one yet!
+        '';
+      };
+      webmentionEndpoint = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "https://webmention.io/example.com/webmention";
+        description = ''
+          The URL of your webmention endpoint, which allows you to
+          receive notifications about your site's content being featured
+          or interacted with elsewhere on the IndieWeb.
+
+          By default Kittybox expects the Webmention endpoint to post
+          updates using an internal token. kittybox-webmention is an
+          endpoint capable of that.
+        '';
+      };
+      internalTokenFile = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "/run/secrets/kittybox-shared-secret";
+        description = "A shared secret that will, when passed, allow unlimited editing access to database. Keep it safe.";
+      };
+      cookieSecretFile = mkOption {
+        type = types.str;
+        default = "/var/lib/kittybox/cookie_secret_key";
+        example = "/run/secrets/kittybox-cookie-secret";
+        description = "A secret file to encrypt cookies with the contents of. Should be at least 32 bytes in length. A random persistent file will be generated if this variable is left untouched.";
+      };
+    };
+  };
+  config = lib.mkIf cfg.enable {
+    systemd.services.kittybox = {
+      description = "An IndieWeb-enabled blog engine";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      restartTriggers = [
+        cfg.package
+        cfg.backendUri cfg.tokenEndpoint
+        cfg.authorizationEndpoint
+        cfg.internalTokenFile
+        cfg.bind cfg.port
+        cfg.cookieSecretFile
+      ];
+
+      environment = {
+        SERVE_AT = "${cfg.bind}:${builtins.toString cfg.port}";
+        AUTHORIZATION_ENDPOINT = cfg.authorizationEndpoint;
+        TOKEN_ENDPOINT = cfg.tokenEndpoint;
+        MEDIA_ENDPOINT = cfg.mediaEndpoint;
+        MICROSUB_ENDPOINT = cfg.microsubServer;
+        WEBMENTION_ENDPOINT = cfg.webmentionEndpoint;
+        #REDIS_URI = if (cfg.redisUri == null) then "redis://127.0.0.1:6379/" else cfg.redisUri;
+        BACKEND_URI = cfg.backendUri;
+        RUST_LOG = "${cfg.logLevel}";
+        COOKIE_SECRET_FILE = "${cfg.cookieSecretFile}";
+      };
+
+      script = ''
+        ${lib.optionalString (cfg.internalTokenFile != null) ''
+          if [[ -f ${cfg.internalTokenFile} ]]; then
+            export KITTYBOX_INTERNAL_TOKEN=$(${pkgs.coreutils}/bin/cat ${cfg.internalTokenFile})
+          fi
+        ''}
+        if [[ ${cfg.cookieSecretFile} == /var/lib/kittybox/cookie_secret_key && ! -f /var/lib/kittybox/cookie_secret_key ]]; then
+            cat /dev/urandom | tr -Cd '[:alnum:]' | head -c 128 > /var/lib/kittybox/cookie_secret_key
+        fi
+        exec ${cfg.package}/bin/kittybox
+      '';
+
+      serviceConfig = {
+        DynamicUser = true;
+        StateDirectory = "kittybox";
+      };
+    };
+  };
+}