1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8
9 cfg = config.services.memcached;
10
11 memcached = pkgs.memcached;
12
13in
14
15{
16
17 ###### interface
18
19 options = {
20
21 services.memcached = {
22 enable = lib.mkEnableOption "Memcached";
23
24 user = lib.mkOption {
25 type = lib.types.str;
26 default = "memcached";
27 description = "The user to run Memcached as";
28 };
29
30 listen = lib.mkOption {
31 type = lib.types.str;
32 default = "127.0.0.1";
33 description = "The IP address to bind to.";
34 };
35
36 port = lib.mkOption {
37 type = lib.types.port;
38 default = 11211;
39 description = "The port to bind to.";
40 };
41
42 enableUnixSocket = lib.mkEnableOption "Unix Domain Socket at /run/memcached/memcached.sock instead of listening on an IP address and port. The `listen` and `port` options are ignored";
43
44 maxMemory = lib.mkOption {
45 type = lib.types.ints.unsigned;
46 default = 64;
47 description = "The maximum amount of memory to use for storage, in megabytes.";
48 };
49
50 maxConnections = lib.mkOption {
51 type = lib.types.ints.unsigned;
52 default = 1024;
53 description = "The maximum number of simultaneous connections.";
54 };
55
56 extraOptions = lib.mkOption {
57 type = lib.types.listOf lib.types.str;
58 default = [ ];
59 description = "A list of extra options that will be added as a suffix when running memcached.";
60 };
61 };
62
63 };
64
65 ###### implementation
66
67 config = lib.mkIf config.services.memcached.enable {
68
69 users.users = lib.optionalAttrs (cfg.user == "memcached") {
70 memcached.description = "Memcached server user";
71 memcached.isSystemUser = true;
72 memcached.group = "memcached";
73 };
74 users.groups = lib.optionalAttrs (cfg.user == "memcached") { memcached = { }; };
75
76 environment.systemPackages = [ memcached ];
77
78 systemd.services.memcached = {
79 description = "Memcached server";
80
81 wantedBy = [ "multi-user.target" ];
82 after = [ "network.target" ];
83
84 serviceConfig = {
85 ExecStart =
86 let
87 networking =
88 if cfg.enableUnixSocket then
89 "-s /run/memcached/memcached.sock"
90 else
91 "-l ${cfg.listen} -p ${toString cfg.port}";
92 in
93 "${memcached}/bin/memcached ${networking} -m ${toString cfg.maxMemory} -c ${toString cfg.maxConnections} ${lib.concatStringsSep " " cfg.extraOptions}";
94
95 User = cfg.user;
96
97 # Filesystem access
98 ProtectSystem = "strict";
99 ProtectHome = true;
100 PrivateTmp = true;
101 PrivateDevices = true;
102 ProtectKernelTunables = true;
103 ProtectKernelModules = true;
104 ProtectControlGroups = true;
105 RuntimeDirectory = "memcached";
106 # Caps
107 CapabilityBoundingSet = "";
108 NoNewPrivileges = true;
109 # Misc.
110 LockPersonality = true;
111 RestrictRealtime = true;
112 PrivateMounts = true;
113 MemoryDenyWriteExecute = true;
114 };
115 };
116 };
117 imports = [
118 (lib.mkRemovedOptionModule [ "services" "memcached" "socket" ] ''
119 This option was replaced by a fixed unix socket path at /run/memcached/memcached.sock enabled using services.memcached.enableUnixSocket.
120 '')
121 ];
122
123}