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