about summary refs log tree commit diff
path: root/modules
diff options
context:
space:
mode:
authorAzat Bahawi <azat@bahawi.net>2023-09-20 15:26:47 +0300
committerAzat Bahawi <azat@bahawi.net>2023-09-20 15:26:47 +0300
commit837fc97b30a41d766dd53a2370f6cb1d26364f9a (patch)
tree63ae83af789930c9a2035b9f9e43fbee166ab27b /modules
parent2023-09-16 (diff)
2023-09-20
Diffstat (limited to 'modules')
-rw-r--r--modules/common/emacs/default.nix2
-rw-r--r--modules/common/emacs/doom/config.el11
-rw-r--r--modules/common/vscode.nix2
-rw-r--r--modules/nixos/clickhouse.nix18
-rw-r--r--modules/nixos/default.nix2
-rw-r--r--modules/nixos/git/default.nix4
-rw-r--r--modules/nixos/nsd.nix1
-rw-r--r--modules/nixos/plausible-nixpkgs-override.nix312
-rw-r--r--modules/nixos/plausible.nix144
9 files changed, 481 insertions, 15 deletions
diff --git a/modules/common/emacs/default.nix b/modules/common/emacs/default.nix
index ed25536..1d205b9 100644
--- a/modules/common/emacs/default.nix
+++ b/modules/common/emacs/default.nix
@@ -92,7 +92,7 @@ in {
                     jre # :lang plantuml
                     libtool # :term vterm
                     libxml2 # :lang data
-                    nixd # :lang (nix +lsp)
+                    nil # :lang (nix +lsp)
                     nodePackages.bash-language-server # :lang (sh +lsp)
                     nodePackages.eslint # :lang (json +lsp)
                     nodePackages.js-beautify # :lang web
diff --git a/modules/common/emacs/doom/config.el b/modules/common/emacs/doom/config.el
index e7e0bd4..015954b 100644
--- a/modules/common/emacs/doom/config.el
+++ b/modules/common/emacs/doom/config.el
@@ -79,17 +79,6 @@
 (setq lsp-haskell-formatting-provider "ormolu")
 
 ;;
-;;; Nix
-;;
-
-(after! lsp-mode
-  (add-to-list 'lsp-language-id-configuration '(nix-mode . "nix"))
-  (lsp-register-client
-    (make-lsp-client :new-connection (lsp-stdio-connection '("nixd"))
-                     :major-modes '(nix-mode)
-                     :server-id 'nix)))
-
-;;
 ;;; YAML
 ;;
 
diff --git a/modules/common/vscode.nix b/modules/common/vscode.nix
index d90d301..ab55acc 100644
--- a/modules/common/vscode.nix
+++ b/modules/common/vscode.nix
@@ -178,7 +178,7 @@ in {
 
         nix = {
           enableLanguageServer = true;
-          serverPath = "${pkgs.rnix-lsp}/bin/rnix-lsp";
+          serverPath = "${pkgs.nil}/bin/nil";
         };
 
         python = with pkgs.python311Packages; {
diff --git a/modules/nixos/clickhouse.nix b/modules/nixos/clickhouse.nix
new file mode 100644
index 0000000..4fae683
--- /dev/null
+++ b/modules/nixos/clickhouse.nix
@@ -0,0 +1,18 @@
+{
+  config,
+  lib,
+  ...
+}:
+with lib; let
+  cfg = config.nixfiles.modules.clickhouse;
+in {
+  options.nixfiles.modules.clickhouse = {
+    enable = mkEnableOption "Clickhouse";
+  };
+
+  config = mkIf cfg.enable {
+    services.clickhouse = {
+      enable = true;
+    };
+  };
+}
diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix
index 466e2e0..5b9a3be 100644
--- a/modules/nixos/default.nix
+++ b/modules/nixos/default.nix
@@ -6,6 +6,7 @@ _: {
     ./beets.nix
     ./bluetooth.nix
     ./chromium.nix
+    ./clickhouse.nix
     ./common
     ./discord.nix
     ./docker.nix
@@ -41,6 +42,7 @@ _: {
     ./ntfy.nix
     ./nullmailer.nix
     ./openssh.nix
+    ./plausible.nix
     ./podman.nix
     ./postgresql.nix
     ./profiles
diff --git a/modules/nixos/git/default.nix b/modules/nixos/git/default.nix
index 5fe4391..9fb43db 100644
--- a/modules/nixos/git/default.nix
+++ b/modules/nixos/git/default.nix
@@ -73,9 +73,9 @@ in {
             fastcgi_param QUERY_STRING $args;
             fastcgi_param HTTP_HOST $server_name;
 
-            # This makes `go get ...` work.
+            # This makes `go get ...` work and adds analytics.
             sub_filter '</head>'
-                '<meta name="go-import" content="$host$uri git https://$host$uri"></head>';
+                '<meta name="go-import" content="$host$uri git https://$host$uri"><script defer data-domain="${cfg.server.domain}" src="https://plausible.shire.net/js/script.js"></script></head>';
             sub_filter_once on;
           '';
           "~* ^.+(cgit.css|robots.txt)$".extraConfig = ''
diff --git a/modules/nixos/nsd.nix b/modules/nixos/nsd.nix
index 0060a14..2266ea5 100644
--- a/modules/nixos/nsd.nix
+++ b/modules/nixos/nsd.nix
@@ -137,6 +137,7 @@ in {
                       grafana = manwe;
                       loki = manwe;
                       ntfy = manwe;
+                      plausible = manwe;
                       prometheus = manwe;
                       radicale = manwe;
                       rss-bridge = manwe;
diff --git a/modules/nixos/plausible-nixpkgs-override.nix b/modules/nixos/plausible-nixpkgs-override.nix
new file mode 100644
index 0000000..67fffdc
--- /dev/null
+++ b/modules/nixos/plausible-nixpkgs-override.nix
@@ -0,0 +1,312 @@
+{
+  lib,
+  pkgs,
+  config,
+  ...
+}:
+with lib; let
+  cfg = config.services.plausible;
+in {
+  options.services.plausible = {
+    enable = mkEnableOption (lib.mdDoc "plausible");
+
+    package = mkPackageOptionMD pkgs "plausible" {};
+
+    releaseCookiePath = mkOption {
+      type = with types; either str path;
+      description = lib.mdDoc ''
+        The path to the file with release cookie. (used for remote connection to the running node).
+      '';
+    };
+
+    adminUser = {
+      name = mkOption {
+        default = "admin";
+        type = types.str;
+        description = lib.mdDoc ''
+          Name of the admin user that plausible will created on initial startup.
+        '';
+      };
+
+      email = mkOption {
+        type = types.str;
+        example = "admin@localhost";
+        description = lib.mdDoc ''
+          Email-address of the admin-user.
+        '';
+      };
+
+      passwordFile = mkOption {
+        type = types.either types.str types.path;
+        description = lib.mdDoc ''
+          Path to the file which contains the password of the admin user.
+        '';
+      };
+
+      activate = mkEnableOption (lib.mdDoc "activating the freshly created admin-user");
+    };
+
+    database = {
+      clickhouse = {
+        setup = mkEnableOption (lib.mdDoc "creating a clickhouse instance") // {default = true;};
+        url = mkOption {
+          default = "http://localhost:8123/default";
+          type = types.str;
+          description = lib.mdDoc ''
+            The URL to be used to connect to `clickhouse`.
+          '';
+        };
+      };
+      postgres = {
+        setup = mkEnableOption (lib.mdDoc "creating a postgresql instance") // {default = true;};
+        dbname = mkOption {
+          default = "plausible";
+          type = types.str;
+          description = lib.mdDoc ''
+            Name of the database to use.
+          '';
+        };
+        socket = mkOption {
+          default = "/run/postgresql";
+          type = types.str;
+          description = lib.mdDoc ''
+            Path to the UNIX domain-socket to communicate with `postgres`.
+          '';
+        };
+      };
+    };
+
+    server = {
+      disableRegistration = mkOption {
+        default = true;
+        type = types.bool;
+        description = lib.mdDoc ''
+          Whether to prohibit creating an account in plausible's UI.
+        '';
+      };
+      secretKeybaseFile = mkOption {
+        type = types.either types.path types.str;
+        description = lib.mdDoc ''
+          Path to the secret used by the `phoenix`-framework. Instructions
+          how to generate one are documented in the
+          [
+          framework docs](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Secret.html#content).
+        '';
+      };
+      port = mkOption {
+        default = 8000;
+        type = types.port;
+        description = lib.mdDoc ''
+          Port where the service should be available.
+        '';
+      };
+      baseUrl = mkOption {
+        type = types.str;
+        description = lib.mdDoc ''
+          Public URL where plausible is available.
+
+          Note that `/path` components are currently ignored:
+          [
+            https://github.com/plausible/analytics/issues/1182
+          ](https://github.com/plausible/analytics/issues/1182).
+        '';
+      };
+    };
+
+    mail = {
+      email = mkOption {
+        default = "hello@plausible.local";
+        type = types.str;
+        description = lib.mdDoc ''
+          The email id to use for as *from* address of all communications
+          from Plausible.
+        '';
+      };
+      smtp = {
+        hostAddr = mkOption {
+          default = "localhost";
+          type = types.str;
+          description = lib.mdDoc ''
+            The host address of your smtp server.
+          '';
+        };
+        hostPort = mkOption {
+          default = 25;
+          type = types.port;
+          description = lib.mdDoc ''
+            The port of your smtp server.
+          '';
+        };
+        user = mkOption {
+          default = null;
+          type = types.nullOr types.str;
+          description = lib.mdDoc ''
+            The username/email in case SMTP auth is enabled.
+          '';
+        };
+        passwordFile = mkOption {
+          default = null;
+          type = with types; nullOr (either str path);
+          description = lib.mdDoc ''
+            The path to the file with the password in case SMTP auth is enabled.
+          '';
+        };
+        enableSSL = mkEnableOption (lib.mdDoc "SSL when connecting to the SMTP server");
+        retries = mkOption {
+          type = types.ints.unsigned;
+          default = 2;
+          description = lib.mdDoc ''
+            Number of retries to make until mailer gives up.
+          '';
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = cfg.adminUser.activate -> cfg.database.postgres.setup;
+        message = ''
+          Unable to automatically activate the admin-user if no locally managed DB for
+          postgres (`services.plausible.database.postgres.setup') is enabled!
+        '';
+      }
+    ];
+
+    services = {
+      postgresql = mkIf cfg.database.postgres.setup {
+        enable = true;
+      };
+
+      clickhouse = mkIf cfg.database.clickhouse.setup {
+        enable = true;
+      };
+
+      epmd.enable = true;
+    };
+
+    environment.systemPackages = [cfg.package];
+
+    systemd.services = mkMerge [
+      {
+        plausible = {
+          inherit (cfg.package.meta) description;
+          documentation = ["https://plausible.io/docs/self-hosting"];
+          wantedBy = ["multi-user.target"];
+          after =
+            optional cfg.database.clickhouse.setup "clickhouse.service"
+            ++ optionals cfg.database.postgres.setup [
+              "postgresql.service"
+              "plausible-postgres.service"
+            ];
+          requires =
+            optional cfg.database.clickhouse.setup "clickhouse.service"
+            ++ optionals cfg.database.postgres.setup [
+              "postgresql.service"
+              "plausible-postgres.service"
+            ];
+
+          environment =
+            {
+              # NixOS specific option to avoid that it's trying to write into its store-path.
+              # See also https://github.com/lau/tzdata#data-directory-and-releases
+              STORAGE_DIR = "/var/lib/plausible/elixir_tzdata";
+
+              # Configuration options from
+              # https://plausible.io/docs/self-hosting-configuration
+              PORT = toString cfg.server.port;
+              DISABLE_REGISTRATION = boolToString cfg.server.disableRegistration;
+
+              RELEASE_TMP = "/var/lib/plausible/tmp";
+              # Home is needed to connect to the node with iex
+              HOME = "/var/lib/plausible";
+
+              ADMIN_USER_NAME = cfg.adminUser.name;
+              ADMIN_USER_EMAIL = cfg.adminUser.email;
+
+              DATABASE_SOCKET_DIR = cfg.database.postgres.socket;
+              DATABASE_NAME = cfg.database.postgres.dbname;
+              CLICKHOUSE_DATABASE_URL = cfg.database.clickhouse.url;
+
+              BASE_URL = cfg.server.baseUrl;
+
+              MAILER_EMAIL = cfg.mail.email;
+              SMTP_HOST_ADDR = cfg.mail.smtp.hostAddr;
+              SMTP_HOST_PORT = toString cfg.mail.smtp.hostPort;
+              SMTP_RETRIES = toString cfg.mail.smtp.retries;
+              SMTP_HOST_SSL_ENABLED = boolToString cfg.mail.smtp.enableSSL;
+
+              SELFHOST = "true";
+            }
+            // (optionalAttrs (cfg.mail.smtp.user != null) {
+              SMTP_USER_NAME = cfg.mail.smtp.user;
+            });
+
+          path =
+            [cfg.package]
+            ++ optional cfg.database.postgres.setup config.services.postgresql.package;
+          script = ''
+            export RELEASE_COOKIE="$(< $CREDENTIALS_DIRECTORY/RELEASE_COOKIE )"
+            export ADMIN_USER_PWD="$(< $CREDENTIALS_DIRECTORY/ADMIN_USER_PWD )"
+            export SECRET_KEY_BASE="$(< $CREDENTIALS_DIRECTORY/SECRET_KEY_BASE )"
+
+            ${lib.optionalString (cfg.mail.smtp.passwordFile != null)
+              ''export SMTP_USER_PWD="$(< $CREDENTIALS_DIRECTORY/SMTP_USER_PWD )"''}
+
+            # setup
+            ${cfg.package}/createdb.sh
+            ${cfg.package}/migrate.sh
+            export IP_GEOLOCATION_DB=${pkgs.dbip-country-lite}/share/dbip/dbip-country-lite.mmdb
+            ${cfg.package}/bin/plausible eval "(Plausible.Release.prepare() ; Plausible.Auth.create_user(\"$ADMIN_USER_NAME\", \"$ADMIN_USER_EMAIL\", \"$ADMIN_USER_PWD\"))"
+            ${optionalString cfg.adminUser.activate ''
+              psql -d plausible <<< "UPDATE users SET email_verified=true where email = '$ADMIN_USER_EMAIL';"
+            ''}
+
+            exec plausible start
+          '';
+
+          serviceConfig = {
+            DynamicUser = true;
+            PrivateTmp = true;
+            WorkingDirectory = "/var/lib/plausible";
+            StateDirectory = "plausible";
+            LoadCredential =
+              [
+                "ADMIN_USER_PWD:${cfg.adminUser.passwordFile}"
+                "SECRET_KEY_BASE:${cfg.server.secretKeybaseFile}"
+                "RELEASE_COOKIE:${cfg.releaseCookiePath}"
+              ]
+              ++ lib.optionals (cfg.mail.smtp.passwordFile != null) ["SMTP_USER_PWD:${cfg.mail.smtp.passwordFile}"];
+          };
+        };
+      }
+      (mkIf cfg.database.postgres.setup {
+        # `plausible' requires the `citext'-extension.
+        plausible-postgres = {
+          after = ["postgresql.service"];
+          partOf = ["plausible.service"];
+          serviceConfig = {
+            Type = "oneshot";
+            User = config.services.postgresql.superUser;
+            RemainAfterExit = true;
+          };
+          script = with cfg.database.postgres; ''
+            PSQL() {
+              ${config.services.postgresql.package}/bin/psql --port=5432 "$@"
+            }
+            # check if the database already exists
+            if ! PSQL -lqt | ${pkgs.coreutils}/bin/cut -d \| -f 1 | ${pkgs.gnugrep}/bin/grep -qw ${dbname} ; then
+              PSQL -tAc "CREATE ROLE plausible WITH LOGIN;"
+              PSQL -tAc "CREATE DATABASE ${dbname} WITH OWNER plausible;"
+              PSQL -d ${dbname} -tAc "CREATE EXTENSION IF NOT EXISTS citext;"
+            fi
+          '';
+        };
+      })
+    ];
+  };
+
+  meta.maintainers = with maintainers; [ma27];
+  meta.doc = ./plausible.md;
+}
diff --git a/modules/nixos/plausible.nix b/modules/nixos/plausible.nix
new file mode 100644
index 0000000..856b318
--- /dev/null
+++ b/modules/nixos/plausible.nix
@@ -0,0 +1,144 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgsPr,
+  ...
+}:
+with lib; let
+  cfg = config.nixfiles.modules.plausible;
+in {
+  disabledModules = ["services/web-apps/plausible.nix"];
+  imports = [
+    # TODO Wait for https://github.com/NixOS/nixpkgs/pull/253687
+    ./plausible-nixpkgs-override.nix
+  ];
+
+  options.nixfiles.modules.plausible = {
+    enable = mkEnableOption "Plausible Analytics";
+
+    port = mkOption {
+      description = "Port.";
+      type = with types; port;
+      default = 8000;
+    };
+
+    domain = mkOption {
+      description = "Domain name sans protocol scheme.";
+      type = with types; nullOr str;
+      default = "plausible.${config.networking.domain}";
+    };
+  };
+
+  config = let
+    db = "plausible";
+  in
+    mkIf cfg.enable {
+      secrets = {
+        plausible-key = {
+          file = "${inputs.self}/secrets/plausible-key";
+          mode = "0444"; # The user is dynamic so the file must be world-readable.
+        };
+        plausible-admin-password = {
+          file = "${inputs.self}/secrets/plausible-admin-password";
+          mode = "0444"; # The user is dynamic so the file must be world-readable.
+        };
+        plausible-smtp-password = {
+          file = "${inputs.self}/secrets/smtp-password";
+          mode = "0444"; # The user is dynamic so the file must be world-readable.
+        };
+        plausible-release-cookie = {
+          file = "${inputs.self}/secrets/plausible-release-cookie";
+          mode = "0444"; # The user is dynamic so the file must be world-readable.
+        };
+      };
+
+      nixfiles.modules = {
+        nginx = {
+          enable = true;
+          upstreams.plausible.servers."127.0.0.1:${toString cfg.port}" = {};
+          virtualHosts.${cfg.domain} = {
+            locations."/" = {
+              proxyPass = "http://plausible";
+              proxyWebsockets = true;
+            };
+            extraConfig = nginxInternalOnly;
+          };
+        };
+        postgresql = {
+          enable = true;
+          extraPostStart = [
+            ''
+              $PSQL "${db}" -tAc 'GRANT ALL ON SCHEMA "public" TO "${db}"'
+              $PSQL "${db}" -tAc 'CREATE EXTENSION IF NOT EXISTS citext'
+            ''
+          ];
+        };
+        clickhouse.enable = true;
+      };
+
+      services.postgresql = {
+        ensureDatabases = [db];
+        ensureUsers = [
+          {
+            name = db;
+            ensurePermissions."DATABASE \"${db}\"" = "ALL";
+          }
+        ];
+      };
+
+      services.plausible = {
+        enable = true;
+
+        # TODO Wait for https://github.com/NixOS/nixpkgs/pull/253687
+        package = (pkgsPr 253687 "sha256-36nXNVmZDgf//MrM6/VC7W4Vm013tJ6MlXvYQElhRRw=").plausible;
+
+        adminUser = {
+          name = "admin";
+          email = "admin@${my.domain.shire}";
+          passwordFile = config.secrets.plausible-admin-password.path;
+          activate = false;
+        };
+
+        mail = {
+          email = "admin+plausible@${my.domain.shire}";
+          smtp = {
+            hostAddr = my.domain.shire;
+            hostPort = 465;
+            enableSSL = true;
+            user = "azahi@${my.domain.shire}";
+            passwordFile = config.secrets.plausible-smtp-password.path;
+          };
+        };
+
+        database = {
+          clickhouse = {
+            setup = false;
+            url = "http://127.0.0.1:8123/default";
+          };
+
+          postgres = {
+            setup = true;
+            dbname = db;
+          };
+        };
+
+        server = {
+          baseUrl = "https://${cfg.domain}";
+          disableRegistration = true;
+          inherit (cfg) port;
+          secretKeybaseFile = config.secrets.plausible-key.path;
+        };
+
+        releaseCookiePath = config.secrets.plausible-release-cookie.path;
+      };
+
+      systemd.services.plausible = rec {
+        after = [
+          "postgresql.service"
+          "clickhouse.service"
+        ];
+        requires = after;
+      };
+    };
+}

Consider giving Nix/NixOS a try! <3