1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.varnish;
10
11 # Varnish has very strong opinions and very complicated code around handling
12 # the stateDir. After a lot of back and forth, we decided that we a)
13 # do not want a configurable option here, as most of the handling depends
14 # on the version and the compile time options. Putting everything into
15 # /var/run (RAM backed) is absolutely recommended by Varnish anyways.
16 # We do need to pay attention to the version-dependend variations, though!
17 stateDir =
18 if
19 (lib.versionOlder cfg.package.version "7")
20 # Remove after Varnish 6.0 is gone. In 6.0 varnishadm always appends the
21 # hostname (by default) and can't be nudged to not use any name. This has
22 # long changed by 7.5 and can be used without the host name.
23 then
24 "/var/run/varnish/${config.networking.hostName}"
25 # Newer varnish uses this:
26 else
27 "/var/run/varnishd";
28
29 commandLine =
30 "-f ${pkgs.writeText "default.vcl" cfg.config}"
31 +
32 lib.optionalString (cfg.extraModules != [ ])
33 " -p vmod_path='${
34 lib.makeSearchPathOutput "lib" "lib/varnish/vmods" ([ cfg.package ] ++ cfg.extraModules)
35 }' -r vmod_path";
36in
37{
38 imports = [
39 (lib.mkRemovedOptionModule [
40 "services"
41 "varnish"
42 "stateDir"
43 ] "The `stateDir` option never was functional or useful. varnish uses compile-time settings.")
44 ];
45
46 options = {
47 services.varnish = {
48 enable = lib.mkEnableOption "Varnish Server";
49
50 enableConfigCheck = lib.mkEnableOption "checking the config during build time" // {
51 default = true;
52 };
53
54 package = lib.mkPackageOption pkgs "varnish" { };
55
56 http_address = lib.mkOption {
57 type = lib.types.str;
58 default = "*:6081";
59 description = ''
60 HTTP listen address and port.
61 '';
62 };
63
64 config = lib.mkOption {
65 type = lib.types.lines;
66 description = ''
67 Verbatim default.vcl configuration.
68 '';
69 };
70
71 extraModules = lib.mkOption {
72 type = lib.types.listOf lib.types.package;
73 default = [ ];
74 example = lib.literalExpression "[ pkgs.varnishPackages.geoip ]";
75 description = ''
76 Varnish modules (except 'std').
77 '';
78 };
79
80 extraCommandLine = lib.mkOption {
81 type = lib.types.str;
82 default = "";
83 example = "-s malloc,256M";
84 description = ''
85 Command line switches for varnishd (run 'varnishd -?' to get list of options)
86 '';
87 };
88 };
89
90 };
91
92 config = lib.mkIf cfg.enable {
93 systemd.services.varnish = {
94 description = "Varnish";
95 wantedBy = [ "multi-user.target" ];
96 after = [ "network.target" ];
97 serviceConfig = {
98 Type = "simple";
99 PermissionsStartOnly = true;
100 ExecStart = "${cfg.package}/sbin/varnishd -a ${cfg.http_address} -n ${stateDir} -F ${cfg.extraCommandLine} ${commandLine}";
101 Restart = "always";
102 RestartSec = "5s";
103 User = "varnish";
104 Group = "varnish";
105 RuntimeDirectory = lib.removePrefix "/var/run/" stateDir;
106 AmbientCapabilities = "cap_net_bind_service";
107 NoNewPrivileges = true;
108 LimitNOFILE = 131072;
109 };
110 };
111
112 environment.systemPackages = [ cfg.package ];
113
114 # check .vcl syntax at compile time (e.g. before nixops deployment)
115 system.checks = lib.mkIf cfg.enableConfigCheck [
116 (pkgs.runCommand "check-varnish-syntax" { } ''
117 ${cfg.package}/bin/varnishd -C ${commandLine} 2> $out || (cat $out; exit 1)
118 '')
119 ];
120
121 users.users.varnish = {
122 group = "varnish";
123 uid = config.ids.uids.varnish;
124 };
125
126 users.groups.varnish.gid = config.ids.uids.varnish;
127 };
128}