about summary refs log tree commit diff
path: root/nixos/modules/services/web-servers/fcgiwrap.nix
blob: 29ddd39942c60755461a308e9cbcb29719971d3f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
{ config, lib, pkgs, ... }:

with lib;

let
  forEachInstance = f: flip mapAttrs' config.services.fcgiwrap (name: cfg:
    nameValuePair "fcgiwrap-${name}" (f cfg)
  );

in {
  options.services.fcgiwrap = mkOption {
    description = "Configuration for fcgiwrap instances.";
    default = { };
    type = types.attrsOf (types.submodule ({ config, ... }: { options = {
      process.prefork = mkOption {
        type = types.ints.positive;
        default = 1;
        description = "Number of processes to prefork.";
      };

      process.user = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = ''
          User as which this instance of fcgiwrap will be run.
          Set to `null` (the default) to use a dynamically allocated user.
        '';
      };

      process.group = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Group as which this instance of fcgiwrap will be run.";
      };

      socket.type = mkOption {
        type = types.enum [ "unix" "tcp" "tcp6" ];
        default = "unix";
        description = "Socket type: 'unix', 'tcp' or 'tcp6'.";
      };

      socket.address = mkOption {
        type = types.str;
        default = "/run/fcgiwrap-${config._module.args.name}.sock";
        example = "1.2.3.4:5678";
        description = ''
          Socket address.
          In case of a UNIX socket, this should be its filesystem path.
        '';
      };

      socket.user = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = ''
          User to be set as owner of the UNIX socket.
          Defaults to the process running user.
        '';
      };

      socket.group = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = ''
          Group to be set as owner of the UNIX socket.
          Defaults to the process running group.
        '';
      };

      socket.mode = mkOption {
        type = types.nullOr types.str;
        default = if config.socket.type == "unix" then "0600" else null;
        defaultText = literalExpression ''
          if config.socket.type == "unix" then "0600" else null
        '';
        description = ''
          Mode to be set on the UNIX socket.
          Defaults to private to the socket's owner.
        '';
      };
    }; }));
  };

  config = {
    assertions = concatLists (mapAttrsToList (name: cfg: [
      {
        assertion = cfg.socket.user != null -> cfg.socket.type == "unix";
        message = "Socket owner can only be set for the UNIX socket type.";
      }
      {
        assertion = cfg.socket.group != null -> cfg.socket.type == "unix";
        message = "Socket owner can only be set for the UNIX socket type.";
      }
      {
        assertion = cfg.socket.mode != null -> cfg.socket.type == "unix";
        message = "Socket mode can only be set for the UNIX socket type.";
      }
    ]) config.services.fcgiwrap);

    systemd.services = forEachInstance (cfg: {
      after = [ "nss-user-lookup.target" ];
      wantedBy = optional (cfg.socket.type != "unix") "multi-user.target";

      serviceConfig = {
        ExecStart = ''
          ${pkgs.fcgiwrap}/sbin/fcgiwrap ${cli.toGNUCommandLineShell {} ({
            c = cfg.process.prefork;
          } // (optionalAttrs (cfg.socket.type != "unix") {
            s = "${cfg.socket.type}:${cfg.socket.address}";
          }))}
        '';
      } // (if cfg.process.user != null then {
        User = cfg.process.user;
        Group = cfg.process.group;
      } else {
        DynamicUser = true;
      });
    });

    systemd.sockets = forEachInstance (cfg: mkIf (cfg.socket.type == "unix") {
      wantedBy = [ "sockets.target" ];
      socketConfig = {
        ListenStream = cfg.socket.address;
        SocketUser = cfg.socket.user;
        SocketGroup = cfg.socket.group;
        SocketMode = cfg.socket.mode;
      };
    });
  };
}