grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / misc / n8n.nix
blob623c9a3be8a9256e93ba185915f83ddf893249d1
1 { config, pkgs, lib, ... }:
2 let
3   cfg = config.services.n8n;
4   format = pkgs.formats.json {};
5   configFile = format.generate "n8n.json" cfg.settings;
6 in
8   options.services.n8n = {
9     enable = lib.mkEnableOption "n8n server";
11     openFirewall = lib.mkOption {
12       type = lib.types.bool;
13       default = false;
14       description = "Open ports in the firewall for the n8n web interface.";
15     };
17     settings = lib.mkOption {
18       type = format.type;
19       default = {};
20       description = ''
21         Configuration for n8n, see <https://docs.n8n.io/hosting/environment-variables/configuration-methods/>
22         for supported values.
23       '';
24     };
26     webhookUrl = lib.mkOption {
27       type = lib.types.str;
28       default = "";
29       description = ''
30         WEBHOOK_URL for n8n, in case we're running behind a reverse proxy.
31         This cannot be set through configuration and must reside in an environment variable.
32       '';
33     };
35   };
37   config = lib.mkIf cfg.enable {
38     services.n8n.settings = {
39       # We use this to open the firewall, so we need to know about the default at eval time
40       port = lib.mkDefault 5678;
41     };
43     systemd.services.n8n = {
44       description = "N8N service";
45       after = [ "network.target" ];
46       wantedBy = [ "multi-user.target" ];
47       environment = {
48         # This folder must be writeable as the application is storing
49         # its data in it, so the StateDirectory is a good choice
50         N8N_USER_FOLDER = "/var/lib/n8n";
51         HOME = "/var/lib/n8n";
52         N8N_CONFIG_FILES = "${configFile}";
53         WEBHOOK_URL = "${cfg.webhookUrl}";
55         # Don't phone home
56         N8N_DIAGNOSTICS_ENABLED = "false";
57         N8N_VERSION_NOTIFICATIONS_ENABLED = "false";
58       };
59       serviceConfig = {
60         Type = "simple";
61         ExecStart = "${pkgs.n8n}/bin/n8n";
62         Restart = "on-failure";
63         StateDirectory = "n8n";
65         # Basic Hardening
66         NoNewPrivileges = "yes";
67         PrivateTmp = "yes";
68         PrivateDevices = "yes";
69         DevicePolicy = "closed";
70         DynamicUser = "true";
71         ProtectSystem = "strict";
72         ProtectHome = "read-only";
73         ProtectControlGroups = "yes";
74         ProtectKernelModules = "yes";
75         ProtectKernelTunables = "yes";
76         RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
77         RestrictNamespaces = "yes";
78         RestrictRealtime = "yes";
79         RestrictSUIDSGID = "yes";
80         MemoryDenyWriteExecute = "no"; # v8 JIT requires memory segments to be Writable-Executable.
81         LockPersonality = "yes";
82       };
83     };
85     networking.firewall = lib.mkIf cfg.openFirewall {
86       allowedTCPPorts = [ cfg.settings.port ];
87     };
88   };