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