1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (pkgs) chrony;
8
9 stateDir = "/var/lib/chrony";
10
11 keyFile = "/etc/chrony.keys";
12
13 cfg = config.services.chrony;
14
15 configFile = pkgs.writeText "chrony.conf" ''
16 ${concatMapStringsSep "\n" (server: "server " + server) cfg.servers}
17
18 ${optionalString
19 cfg.initstepslew.enabled
20 "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.initstepslew.servers}"
21 }
22
23 driftfile ${stateDir}/chrony.drift
24
25 keyfile ${keyFile}
26
27 ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"}
28
29 ${cfg.extraConfig}
30 '';
31
32 chronyFlags = "-n -m -u chrony -f ${configFile} ${toString cfg.extraFlags}";
33
34in
35
36{
37
38 ###### interface
39
40 options = {
41
42 services.chrony = {
43
44 enable = mkOption {
45 default = false;
46 description = ''
47 Whether to synchronise your machine's time using chrony.
48 Make sure you disable NTP if you enable this service.
49 '';
50 };
51
52 servers = mkOption {
53 default = config.networking.timeServers;
54 description = ''
55 The set of NTP servers from which to synchronise.
56 '';
57 };
58
59 initstepslew = mkOption {
60 default = {
61 enabled = true;
62 threshold = 1000; # by default, same threshold as 'ntpd -g' (1000s)
63 servers = cfg.servers;
64 };
65 description = ''
66 Allow chronyd to make a rapid measurement of the system clock error at
67 boot time, and to correct the system clock by stepping before normal
68 operation begins.
69 '';
70 };
71
72 extraConfig = mkOption {
73 type = types.lines;
74 default = "";
75 description = ''
76 Extra configuration directives that should be added to
77 <literal>chrony.conf</literal>
78 '';
79 };
80
81 extraFlags = mkOption {
82 default = [];
83 example = [ "-s" ];
84 type = types.listOf types.str;
85 description = "Extra flags passed to the chronyd command.";
86 };
87 };
88
89 };
90
91
92 ###### implementation
93
94 config = mkIf cfg.enable {
95
96 # Make chronyc available in the system path
97 environment.systemPackages = [ pkgs.chrony ];
98
99 users.extraGroups = singleton
100 { name = "chrony";
101 gid = config.ids.gids.chrony;
102 };
103
104 users.extraUsers = singleton
105 { name = "chrony";
106 uid = config.ids.uids.chrony;
107 group = "chrony";
108 description = "chrony daemon user";
109 home = stateDir;
110 };
111
112 systemd.services.timesyncd.enable = mkForce false;
113
114 systemd.services.chronyd =
115 { description = "chrony NTP daemon";
116
117 wantedBy = [ "multi-user.target" ];
118 wants = [ "time-sync.target" ];
119 before = [ "time-sync.target" ];
120 after = [ "network.target" ];
121 conflicts = [ "ntpd.service" "systemd-timesyncd.service" ];
122
123 path = [ pkgs.chrony ];
124
125 preStart =
126 ''
127 mkdir -m 0755 -p ${stateDir}
128 touch ${keyFile}
129 chmod 0640 ${keyFile}
130 chown chrony:chrony ${stateDir} ${keyFile}
131 '';
132
133 serviceConfig =
134 { ExecStart = "${pkgs.chrony}/bin/chronyd ${chronyFlags}";
135 };
136 };
137
138 };
139
140}