1 { config, lib, pkgs, ... }:
6 cfg = config.services.chrony;
7 chronyPkg = cfg.package;
9 stateDir = cfg.directory;
10 driftFile = "${stateDir}/chrony.drift";
11 keyFile = "${stateDir}/chrony.keys";
12 rtcFile = "${stateDir}/chrony.rtc";
14 configFile = pkgs.writeText "chrony.conf" ''
15 ${concatMapStringsSep "\n" (server: "server " + server + " " + cfg.serverOption + optionalString (cfg.enableNTS) " nts") cfg.servers}
18 (cfg.initstepslew.enabled && (cfg.servers != []))
19 "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.servers}"
22 driftfile ${driftFile}
24 ${optionalString (cfg.enableRTCTrimming) "rtcfile ${rtcFile}"}
25 ${optionalString (cfg.enableNTS) "ntsdumpdir ${stateDir}"}
27 ${optionalString (cfg.enableRTCTrimming) "rtcautotrim ${builtins.toString cfg.autotrimThreshold}"}
28 ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"}
34 [ "-n" "-u" "chrony" "-f" "${configFile}" ]
35 ++ optional cfg.enableMemoryLocking "-m"
45 Whether to synchronise your machine's time using chrony.
46 Make sure you disable NTP if you enable this service.
50 package = mkPackageOption pkgs "chrony" { };
53 default = config.networking.timeServers;
54 defaultText = literalExpression "config.networking.timeServers";
55 type = types.listOf types.str;
57 The set of NTP servers from which to synchronise.
61 serverOption = mkOption {
63 type = types.enum [ "iburst" "offline" ];
65 Set option for server directives.
67 Use "iburst" to rapidly poll on startup. Recommended if your machine
68 is consistently online.
70 Use "offline" to prevent polling on startup. Recommended if your
71 machine boots offline or is otherwise frequently offline.
75 enableMemoryLocking = mkOption {
77 default = config.environment.memoryAllocator.provider != "graphene-hardened" && config.environment.memoryAllocator.provider != "graphene-hardened-light";
78 defaultText = ''config.environment.memoryAllocator.provider != "graphene-hardened" && config.environment.memoryAllocator.provider != "graphene-hardened-light"'';
80 Whether to add the `-m` flag to lock memory.
84 enableRTCTrimming = mkOption {
88 Enable tracking of the RTC offset to the system clock and automatic trimming.
89 See also [](#opt-services.chrony.autotrimThreshold)
92 This is not compatible with the `rtcsync` directive, which naively syncs the RTC time every 11 minutes.
94 Tracking the RTC drift will allow more precise timekeeping,
95 especially on intermittently running devices, where the RTC is very relevant.
100 autotrimThreshold = mkOption {
101 type = types.ints.positive;
105 Maximum estimated error threshold for the `rtcautotrim` command.
106 When reached, the RTC will be trimmed.
107 Only used when [](#opt-services.chrony.enableRTCTrimming) is enabled.
111 enableNTS = mkOption {
115 Whether to enable Network Time Security authentication.
116 Make sure it is supported by your selected NTP server(s).
125 Allow chronyd to make a rapid measurement of the system clock error
126 at boot time, and to correct the system clock by stepping before
127 normal operation begins.
131 threshold = mkOption {
132 type = types.either types.float types.int;
133 default = 1000; # by default, same threshold as 'ntpd -g' (1000s)
135 The threshold of system clock error (in seconds) above which the
136 clock will be stepped. If the correction required is less than the
137 threshold, a slew is used instead.
142 directory = mkOption {
144 default = "/var/lib/chrony";
145 description = "Directory where chrony state is stored.";
148 extraConfig = mkOption {
152 Extra configuration directives that should be added to
157 extraFlags = mkOption {
160 type = types.listOf types.str;
161 description = "Extra flags passed to the chronyd command.";
166 config = mkIf cfg.enable {
167 meta.maintainers = with lib.maintainers; [ thoughtpolice vifino ];
169 environment.systemPackages = [ chronyPkg ];
171 users.groups.chrony.gid = config.ids.gids.chrony;
175 uid = config.ids.uids.chrony;
177 description = "chrony daemon user";
181 services.timesyncd.enable = mkForce false;
183 # If chrony controls and tracks the RTC, writing it externally causes clock error.
184 systemd.services.save-hwclock = lib.mkIf cfg.enableRTCTrimming {
185 enable = lib.mkForce false;
188 systemd.services.systemd-timedated.environment = { SYSTEMD_TIMEDATED_NTP_SERVICES = "chronyd.service"; };
190 systemd.tmpfiles.rules = [
191 "d ${stateDir} 0750 chrony chrony - -"
192 "f ${driftFile} 0640 chrony chrony - -"
193 "f ${keyFile} 0640 chrony chrony - -"
194 ] ++ lib.optionals cfg.enableRTCTrimming [
195 "f ${rtcFile} 0640 chrony chrony - -"
198 systemd.services.chronyd =
200 description = "chrony NTP daemon";
202 wantedBy = [ "multi-user.target" ];
203 wants = [ "time-sync.target" ];
204 before = [ "time-sync.target" ];
205 after = [ "network.target" "nss-lookup.target" ];
206 conflicts = [ "ntpd.service" "systemd-timesyncd.service" ];
208 path = [ chronyPkg ];
210 unitConfig.ConditionCapability = "CAP_SYS_TIME";
213 ExecStart = "${chronyPkg}/bin/chronyd ${builtins.toString chronyFlags}";
217 ProtectProc = "invisible";
218 # Access write directories
219 ReadWritePaths = [ "${stateDir}" ];
222 CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_DAC_OVERRIDE" "CAP_NET_BIND_SERVICE" "CAP_SETGID" "CAP_SETUID" "CAP_SYS_RESOURCE" "CAP_SYS_TIME" ];
224 DeviceAllow = [ "char-pps rw" "char-ptp rw" "char-rtc rw" ];
225 DevicePolicy = "closed";
227 NoNewPrivileges = true;
229 ProtectSystem = "full";
232 PrivateDevices = false;
233 PrivateUsers = false;
234 ProtectHostname = true;
235 ProtectClock = false;
236 ProtectKernelTunables = true;
237 ProtectKernelModules = true;
238 ProtectKernelLogs = true;
239 ProtectControlGroups = true;
240 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
241 RestrictNamespaces = true;
242 LockPersonality = true;
243 MemoryDenyWriteExecute = true;
244 RestrictRealtime = true;
245 RestrictSUIDSGID = true;
247 PrivateMounts = true;
248 # System Call Filtering
249 SystemCallArchitectures = "native";
250 SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @resources" "@clock" "@setuid" "capset" "@chown" ];
256 assertion = !(cfg.enableRTCTrimming && builtins.any (line: (builtins.match "^ *rtcsync" line) != null) (lib.strings.splitString "\n" cfg.extraConfig));
258 The chrony module now configures `rtcfile` and `rtcautotrim` for you.
259 These options conflict with `rtcsync` and cause chrony to crash.
260 Unless you are very sure the former isn't what you want, please remove
261 `rtcsync` from `services.chrony.extraConfig`.
262 Alternatively, disable this behaviour by `services.chrony.enableRTCTrimming = false;`