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