From 41a4b98cc52ca8b4b149b619c07596ab68f94d51 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Mon, 14 Apr 2025 11:20:36 +0200 Subject: [PATCH] feat(compute01): Deploy docuseal on docuseal.dgnum.eu --- machines/nixos/compute01/_configuration.nix | 1 + machines/nixos/compute01/docuseal/default.nix | 26 ++ machines/nixos/compute01/docuseal/module.nix | 231 ++++++++++++++++++ meta/dns.nix | 1 + 4 files changed, 259 insertions(+) create mode 100644 machines/nixos/compute01/docuseal/default.nix create mode 100644 machines/nixos/compute01/docuseal/module.nix diff --git a/machines/nixos/compute01/_configuration.nix b/machines/nixos/compute01/_configuration.nix index f456e0b..6e8be11 100644 --- a/machines/nixos/compute01/_configuration.nix +++ b/machines/nixos/compute01/_configuration.nix @@ -18,6 +18,7 @@ lib.extra.mkConfig { # INFO: This list needs to stay sorted alphabetically "arkheon" "dgsi" + "docuseal" "ds-fr" "extranix" "grafana" diff --git a/machines/nixos/compute01/docuseal/default.nix b/machines/nixos/compute01/docuseal/default.nix new file mode 100644 index 0000000..ea67e95 --- /dev/null +++ b/machines/nixos/compute01/docuseal/default.nix @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2025 Tom Hubrecht +# +# SPDX-License-Identifier: EUPL-1.2 + +let + host = "docuseal.dgnum.eu"; + port = 2500; +in + +{ + nixpkgs.overlays = [ + (self: _: { + docuseal = self.callPackage ../../../../pkgs/by-name/docuseal { }; + }) + ]; + + services.docuseal = { + enable = true; + + inherit host port; + }; + + dgn-web.simpleProxies.docuseal = { + inherit host port; + }; +} diff --git a/machines/nixos/compute01/docuseal/module.nix b/machines/nixos/compute01/docuseal/module.nix new file mode 100644 index 0000000..5c3f8bf --- /dev/null +++ b/machines/nixos/compute01/docuseal/module.nix @@ -0,0 +1,231 @@ +# SPDX-FileCopyrightText: 2025 Tom Hubrecht +# +# SPDX-License-Identifier: EUPL-1.2 + +{ + config, + lib, + pkgs, + utils, + ... +}: + +let + inherit (lib) + getExe' + mkEnableOption + mkIf + mkOption + mkPackageOption + optional + optionalAttrs + ; + + inherit (lib.types) + attrsOf + bool + nullOr + oneOf + package + path + port + str + ; + + inherit (utils) escapeSystemdExecArgs; + + cfg = config.services.docuseal; +in +{ + options.services.docuseal = { + enable = mkEnableOption "docuseal, an open source DocuSign alternative"; + + package = mkPackageOption pkgs "docuseal" { }; + + host = mkOption { + type = str; + description = '' + Hostname of the web server. + ''; + }; + + port = mkOption { + type = port; + default = 3000; + description = '' + Listening port for the web server. + ''; + }; + + environment = mkOption { + type = attrsOf ( + nullOr (oneOf [ + package + path + str + ]) + ); + description = '' + Evironment variables available to Docuseal. + ''; + }; + + environmentFile = mkOption { + type = nullOr path; + default = null; + description = '' + Path to a file containing environment variables. + Required secrets are `SECRET_KEY_BASE` and `OTP_SECRET_KEY`, + which can be generated using `rails secret`. + ''; + }; + + redis = { + createLocally = mkOption { + type = bool; + default = true; + description = '' + Whether to create a local redis automatically. + ''; + }; + }; + + interactScript = mkOption { + type = package; + default = pkgs.writeShellApplication { + name = "docuseal"; + + runtimeInputs = [ + cfg.package + config.systemd.package + pkgs.util-linux + ]; + text = '' + MainPID=$(systemctl show -p MainPID --value docuseal.service) + + nsenter -e -a -w -t "$MainPID" -G follow -S follow "$@" + ''; + }; + description = '' + Script to run docuseal tasks. + ''; + }; + }; + + config = mkIf cfg.enable { + services = { + docuseal.environment = + { + RAILS_ENV = "production"; + WORKDIR = "/var/lib/docuseal"; + DATABASE_URL = "postgresql:///docuseal?host=/run/postgresql"; + HOST = cfg.host; + PORT = builtins.toString cfg.port; + } + // (optionalAttrs cfg.redis.createLocally { + REDIS_URL = "unix://${config.services.redis.servers.docuseal.unixSocket}"; + }); + + postgresql = { + enable = true; + + ensureDatabases = [ "docuseal" ]; + + ensureUsers = [ + { + name = "docuseal"; + ensureDBOwnership = true; + } + ]; + }; + + redis.servers.docuseal = mkIf cfg.redis.createLocally { + enable = true; + }; + }; + + environment.systemPackages = [ cfg.interactScript ]; + + systemd.services.docuseal = { + description = "Docuseal"; + + after = [ + "network.target" + "postgresql.target" + ] ++ (optional cfg.redis.createLocally "redis.service"); + + wantedBy = [ "multi-user.target" ]; + + inherit (cfg) environment; + + path = [ cfg.package ]; + + serviceConfig = + { + CacheDirectory = "docuseal"; + CacheDirectoryMode = "0700"; + DynamicUser = true; + EnvironmentFile = optional (cfg.environmentFile != null) cfg.environmentFile; + ExecStart = escapeSystemdExecArgs [ + (getExe' cfg.package "bundle") + "exec" + "puma" + "-C" + "${cfg.package}/config/puma.rb" + "--dir" + cfg.package + ]; + LogsDirectory = "docuseal"; + LogsDirectoryMode = "0700"; + StateDirectory = "docuseal"; + StateDirectoryMode = "0700"; + SupplementaryGroups = optional cfg.redis.createLocally "redis-docuseal"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + User = "docuseal"; + UMask = "0077"; + WorkingDirectory = "/var/lib/docuseal"; + # Proc filesystem + ProcSubset = "pid"; + ProtectProc = "invisible"; + # Capabilities + CapabilityBoundingSet = ""; + # Security + NoNewPrivileges = true; + # Sandboxing + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = cfg.port >= 1024; + ProtectClock = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + "AF_NETLINK" + ]; + RestrictNamespaces = true; + LockPersonality = true; + MemoryDenyWriteExecute = false; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + PrivateMounts = true; + # System Call Filtering + SystemCallArchitectures = "native"; + } + // optionalAttrs (cfg.port < 1024) { + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + }; + }; + }; +} diff --git a/meta/dns.nix b/meta/dns.nix index e90d90d..fe9e10d 100644 --- a/meta/dns.nix +++ b/meta/dns.nix @@ -74,6 +74,7 @@ let "code" # Collabora Online "demarches" # Démarches Normaliennes "docs" # Outline + "docuseal" # Docuseal "grafana" # Grafana "netbox-v2" # Netbox "nms" # LibreNMS