2014-04-14 16:26:48 +02:00
|
|
|
{ config, lib, pkgs, ... }:
|
2013-06-07 11:34:05 +02:00
|
|
|
|
2014-04-14 16:26:48 +02:00
|
|
|
with lib;
|
2013-06-07 11:34:05 +02:00
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.redis;
|
|
|
|
redisBool = b: if b then "yes" else "no";
|
|
|
|
condOption = name: value: if value != null then "${name} ${toString value}" else "";
|
|
|
|
|
|
|
|
redisConfig = pkgs.writeText "redis.conf" ''
|
|
|
|
port ${toString cfg.port}
|
|
|
|
${condOption "bind" cfg.bind}
|
|
|
|
${condOption "unixsocket" cfg.unixSocket}
|
2019-08-31 20:08:49 +02:00
|
|
|
daemonize yes
|
|
|
|
supervised systemd
|
2013-06-07 11:34:05 +02:00
|
|
|
loglevel ${cfg.logLevel}
|
|
|
|
logfile ${cfg.logfile}
|
2013-10-28 18:14:49 +01:00
|
|
|
syslog-enabled ${redisBool cfg.syslog}
|
2019-08-31 20:08:49 +02:00
|
|
|
pidfile /run/redis/redis.pid
|
2013-06-07 11:34:05 +02:00
|
|
|
databases ${toString cfg.databases}
|
|
|
|
${concatMapStrings (d: "save ${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}\n") cfg.save}
|
2019-08-31 20:08:49 +02:00
|
|
|
dbfilename dump.rdb
|
|
|
|
dir /var/lib/redis
|
2013-06-07 11:34:05 +02:00
|
|
|
${if cfg.slaveOf != null then "slaveof ${cfg.slaveOf.ip} ${toString cfg.slaveOf.port}" else ""}
|
|
|
|
${condOption "masterauth" cfg.masterAuth}
|
|
|
|
${condOption "requirepass" cfg.requirePass}
|
|
|
|
appendOnly ${redisBool cfg.appendOnly}
|
|
|
|
appendfsync ${cfg.appendFsync}
|
|
|
|
slowlog-log-slower-than ${toString cfg.slowLogLogSlowerThan}
|
|
|
|
slowlog-max-len ${toString cfg.slowLogMaxLen}
|
2013-06-17 20:06:02 +02:00
|
|
|
${cfg.extraConfig}
|
2013-06-07 11:34:05 +02:00
|
|
|
'';
|
|
|
|
in
|
|
|
|
{
|
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
|
|
|
options = {
|
|
|
|
|
|
|
|
services.redis = {
|
|
|
|
|
|
|
|
enable = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.bool;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = false;
|
2019-08-30 15:44:01 +02:00
|
|
|
description = ''
|
|
|
|
Whether to enable the Redis server. Note that the NixOS module for
|
|
|
|
Redis disables kernel support for Transparent Huge Pages (THP),
|
|
|
|
because this features causes major performance problems for Redis,
|
|
|
|
e.g. (https://redis.io/topics/latency).
|
|
|
|
'';
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
package = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.package;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = pkgs.redis;
|
2016-01-17 19:34:55 +01:00
|
|
|
defaultText = "pkgs.redis";
|
2013-06-07 11:34:05 +02:00
|
|
|
description = "Which Redis derivation to use.";
|
|
|
|
};
|
|
|
|
|
|
|
|
port = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.int;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = 6379;
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "The port for Redis to listen to.";
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
2015-10-03 08:22:27 +02:00
|
|
|
vmOverCommit = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Set vm.overcommit_memory to 1 (Suggested for Background Saving: http://redis.io/topics/faq)
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
openFirewall = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Whether to open ports in the firewall for the server.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2013-06-07 11:34:05 +02:00
|
|
|
bind = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = with types; nullOr str;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = null; # All interfaces
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "The IP interface to bind to.";
|
2013-06-07 11:34:05 +02:00
|
|
|
example = "127.0.0.1";
|
|
|
|
};
|
|
|
|
|
|
|
|
unixSocket = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = with types; nullOr path;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = null;
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "The path to the socket to bind to.";
|
2019-08-31 20:08:49 +02:00
|
|
|
example = "/run/redis/redis.sock";
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
logLevel = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.str;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = "notice"; # debug, verbose, notice, warning
|
|
|
|
example = "debug";
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
logfile = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.str;
|
2013-10-28 18:14:49 +01:00
|
|
|
default = "/dev/null";
|
2013-06-07 11:34:05 +02:00
|
|
|
description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
|
|
|
|
example = "/var/log/redis.log";
|
|
|
|
};
|
|
|
|
|
2013-10-28 18:14:49 +01:00
|
|
|
syslog = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.bool;
|
2013-10-28 18:14:49 +01:00
|
|
|
default = true;
|
|
|
|
description = "Enable logging to the system logger.";
|
|
|
|
};
|
|
|
|
|
2013-06-07 11:34:05 +02:00
|
|
|
databases = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.int;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = 16;
|
|
|
|
description = "Set the number of databases.";
|
|
|
|
};
|
|
|
|
|
|
|
|
save = mkOption {
|
2014-07-15 17:03:10 +02:00
|
|
|
type = with types; listOf (listOf int);
|
2013-06-07 11:34:05 +02:00
|
|
|
default = [ [900 1] [300 10] [60 10000] ];
|
|
|
|
description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
|
|
|
|
example = [ [900 1] [300 10] [60 10000] ];
|
|
|
|
};
|
|
|
|
|
|
|
|
slaveOf = mkOption {
|
|
|
|
default = null; # { ip, port }
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "An attribute set with two attributes: ip and port to which this redis instance acts as a slave.";
|
2013-06-07 11:34:05 +02:00
|
|
|
example = { ip = "192.168.1.100"; port = 6379; };
|
|
|
|
};
|
|
|
|
|
|
|
|
masterAuth = mkOption {
|
|
|
|
default = null;
|
|
|
|
description = ''If the master is password protected (using the requirePass configuration)
|
|
|
|
it is possible to tell the slave to authenticate before starting the replication synchronization
|
2013-07-02 06:03:52 +02:00
|
|
|
process, otherwise the master will refuse the slave request.
|
|
|
|
(STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
requirePass = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = with types; nullOr str;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = null;
|
2013-07-02 06:03:52 +02:00
|
|
|
description = "Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)";
|
2013-06-07 11:34:05 +02:00
|
|
|
example = "letmein!";
|
|
|
|
};
|
|
|
|
|
|
|
|
appendOnly = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.bool;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = false;
|
|
|
|
description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
|
|
|
|
};
|
|
|
|
|
|
|
|
appendFsync = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.str;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = "everysec"; # no, always, everysec
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "How often to fsync the append-only log, options: no, always, everysec.";
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
slowLogLogSlowerThan = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.int;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = 10000;
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "Log queries whose execution take longer than X in milliseconds.";
|
2013-06-07 11:34:05 +02:00
|
|
|
example = 1000;
|
|
|
|
};
|
|
|
|
|
|
|
|
slowLogMaxLen = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.int;
|
2013-06-07 11:34:05 +02:00
|
|
|
default = 128;
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "Maximum number of items to keep in slow log.";
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
2013-06-17 20:06:02 +02:00
|
|
|
|
|
|
|
extraConfig = mkOption {
|
2014-05-02 20:49:31 +02:00
|
|
|
type = types.lines;
|
2013-06-17 20:06:02 +02:00
|
|
|
default = "";
|
2014-06-24 21:23:14 +02:00
|
|
|
description = "Extra configuration options for redis.conf.";
|
2013-06-17 20:06:02 +02:00
|
|
|
};
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
|
|
|
config = mkIf config.services.redis.enable {
|
|
|
|
|
2015-10-03 08:22:27 +02:00
|
|
|
boot.kernel.sysctl = mkIf cfg.vmOverCommit {
|
|
|
|
"vm.overcommit_memory" = "1";
|
|
|
|
};
|
|
|
|
|
|
|
|
networking.firewall = mkIf cfg.openFirewall {
|
|
|
|
allowedTCPPorts = [ cfg.port ];
|
|
|
|
};
|
|
|
|
|
2019-10-12 22:25:28 +02:00
|
|
|
users.users.redis = {
|
|
|
|
description = "Redis database user";
|
|
|
|
isSystemUser = true;
|
|
|
|
};
|
2013-06-07 11:34:05 +02:00
|
|
|
|
2013-06-07 11:37:58 +02:00
|
|
|
environment.systemPackages = [ cfg.package ];
|
2013-06-07 11:34:05 +02:00
|
|
|
|
2019-08-30 15:44:01 +02:00
|
|
|
systemd.services.disable-transparent-huge-pages = {
|
|
|
|
description = "Disable Transparent Huge Pages (required by Redis)";
|
|
|
|
before = [ "redis.service" ];
|
|
|
|
wantedBy = [ "redis.service" ];
|
2019-08-31 20:08:49 +02:00
|
|
|
script = "echo never > /sys/kernel/mm/transparent_hugepage/enabled";
|
2019-08-30 15:44:01 +02:00
|
|
|
serviceConfig.Type = "oneshot";
|
|
|
|
};
|
|
|
|
|
2013-06-07 11:34:05 +02:00
|
|
|
systemd.services.redis =
|
2015-02-22 16:46:49 +01:00
|
|
|
{ description = "Redis Server";
|
2013-06-07 11:34:05 +02:00
|
|
|
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [ "network.target" ];
|
|
|
|
|
|
|
|
serviceConfig = {
|
2013-06-07 11:37:58 +02:00
|
|
|
ExecStart = "${cfg.package}/bin/redis-server ${redisConfig}";
|
2019-08-31 20:08:49 +02:00
|
|
|
RuntimeDirectory = "redis";
|
|
|
|
StateDirectory = "redis";
|
|
|
|
Type = "notify";
|
|
|
|
User = "redis";
|
2013-06-07 11:34:05 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|