1 { config, lib, pkgs, ... }:
7 cfg = config.services.nats;
9 format = pkgs.formats.json { };
11 configFile = format.generate "nats.conf" cfg.settings;
13 validateConfig = file:
14 pkgs.runCommand "validate-nats-conf" {
15 nativeBuildInputs = [ pkgs.nats-server ];
17 nats-server --config "${configFile}" -t
18 ln -s "${configFile}" "$out"
26 enable = mkEnableOption "NATS messaging system";
31 description = "User account under which NATS runs.";
37 description = "Group under which NATS runs.";
40 serverName = mkOption {
45 Name of the NATS server, must be unique if clustered.
49 jetstream = mkEnableOption "JetStream";
55 Port on which to listen.
60 default = "/var/lib/nats";
63 The NATS data directory. Only used if JetStream is enabled, for
64 storing stream metadata and messages.
66 If left as the default value this directory will automatically be
67 created before the NATS server starts, otherwise the sysadmin is
68 responsible for ensuring the directory exists with appropriate
69 ownership and permissions.
76 example = literalExpression ''
85 Declarative NATS configuration. See the
87 NATS documentation](https://docs.nats.io/nats-server/configuration) for a list of options.
95 config = mkIf cfg.enable {
96 services.nats.settings = {
97 server_name = cfg.serverName;
99 jetstream = optionalAttrs cfg.jetstream { store_dir = cfg.dataDir; };
102 systemd.services.nats = {
103 description = "NATS messaging system";
104 wantedBy = [ "multi-user.target" ];
105 after = [ "network.target" ];
107 serviceConfig = mkMerge [
108 (mkIf (cfg.dataDir == "/var/lib/nats") {
109 StateDirectory = "nats";
110 StateDirectoryMode = "0750";
114 ExecStart = "${pkgs.nats-server}/bin/nats-server -c ${validateConfig configFile}";
115 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
116 ExecStop = "${pkgs.coreutils}/bin/kill -SIGINT $MAINPID";
117 Restart = "on-failure";
123 CapabilityBoundingSet = "";
124 LimitNOFILE = 800000; # JetStream requires 2 FDs open per stream.
125 LockPersonality = true;
126 MemoryDenyWriteExecute = true;
127 NoNewPrivileges = true;
128 PrivateDevices = true;
133 ProtectControlGroups = true;
135 ProtectHostname = true;
136 ProtectKernelLogs = true;
137 ProtectKernelModules = true;
138 ProtectKernelTunables = true;
139 ProtectProc = "invisible";
140 ProtectSystem = "strict";
142 ReadWritePaths = [ cfg.dataDir ];
143 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
144 RestrictNamespaces = true;
145 RestrictRealtime = true;
146 RestrictSUIDSGID = true;
147 SystemCallFilter = [ "@system-service" "~@privileged" ];
153 users.users = mkIf (cfg.user == "nats") {
155 description = "NATS daemon user";
162 users.groups = mkIf (cfg.group == "nats") { nats = { }; };