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