1 { config, lib, pkgs, ... }:
6 cfg = config.services.elasticsearch;
8 es7 = builtins.compareVersions cfg.package.version "7" >= 0;
11 network.host: ${cfg.listenAddress}
12 cluster.name: ${cfg.cluster_name}
13 ${lib.optionalString cfg.single_node "discovery.type: single-node"}
14 ${lib.optionalString (cfg.single_node && es7) "gateway.auto_import_dangling_indices: true"}
16 http.port: ${toString cfg.port}
17 transport.port: ${toString cfg.tcp_port}
22 configDir = cfg.dataDir + "/config";
24 elasticsearchYml = pkgs.writeTextFile {
25 name = "elasticsearch.yml";
29 loggingConfigFilename = "log4j2.properties";
30 loggingConfigFile = pkgs.writeTextFile {
31 name = loggingConfigFilename;
35 esPlugins = pkgs.buildEnv {
36 name = "elasticsearch-plugins";
38 postBuild = "${pkgs.coreutils}/bin/mkdir -p $out/plugins";
46 options.services.elasticsearch = {
48 description = "Whether to enable elasticsearch.";
53 package = mkPackageOption pkgs "elasticsearch" { };
55 listenAddress = mkOption {
56 description = "Elasticsearch listen address.";
57 default = "127.0.0.1";
62 description = "Elasticsearch port to listen for HTTP traffic.";
68 description = "Elasticsearch port for the node to node communication.";
73 cluster_name = mkOption {
74 description = "Elasticsearch name that identifies your cluster for auto-discovery.";
75 default = "elasticsearch";
79 single_node = mkOption {
80 description = "Start a single-node cluster";
85 extraConf = mkOption {
86 description = "Extra configuration for elasticsearch.";
90 node.name: "elasticsearch"
97 description = "Elasticsearch logging configuration.";
99 logger.action.name = org.elasticsearch.action
100 logger.action.level = info
102 appender.console.type = Console
103 appender.console.name = console
104 appender.console.layout.type = PatternLayout
105 appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
107 rootLogger.level = info
108 rootLogger.appenderRef.console.ref = console
115 default = "/var/lib/elasticsearch";
117 Data directory for elasticsearch.
121 extraCmdLineOptions = mkOption {
122 description = "Extra command line options for the elasticsearch launcher.";
124 type = types.listOf types.str;
127 extraJavaOptions = mkOption {
128 description = "Extra command line options for Java.";
130 type = types.listOf types.str;
131 example = [ "-Djava.net.preferIPv4Stack=true" ];
135 description = "Extra elasticsearch plugins";
137 type = types.listOf types.package;
138 example = lib.literalExpression "[ pkgs.elasticsearchPlugins.discovery-ec2 ]";
141 restartIfChanged = mkOption {
144 Automatically restart the service on config change.
145 This can be set to false to defer restarts on a server or cluster.
146 Please consider the security implications of inadvertently running an older version,
147 and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
154 ###### implementation
156 config = mkIf cfg.enable {
157 systemd.services.elasticsearch = {
158 description = "Elasticsearch Daemon";
159 wantedBy = [ "multi-user.target" ];
160 after = [ "network.target" ];
161 path = [ pkgs.inetutils ];
162 inherit (cfg) restartIfChanged;
164 ES_HOME = cfg.dataDir;
165 ES_JAVA_OPTS = toString cfg.extraJavaOptions;
166 ES_PATH_CONF = configDir;
169 ExecStart = "${cfg.package}/bin/elasticsearch ${toString cfg.extraCmdLineOptions}";
170 User = "elasticsearch";
171 PermissionsStartOnly = true;
172 LimitNOFILE = "1024000";
174 TimeoutStartSec = "infinity";
177 ${optionalString (!config.boot.isContainer) ''
178 # Only set vm.max_map_count if lower than ES required minimum
179 # This avoids conflict if configured via boot.kernel.sysctl
180 if [ `${pkgs.procps}/bin/sysctl -n vm.max_map_count` -lt 262144 ]; then
181 ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144
185 mkdir -m 0700 -p ${cfg.dataDir}
188 ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins
189 ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib
190 ln -sfT ${cfg.package}/modules ${cfg.dataDir}/modules
192 # elasticsearch needs to create the elasticsearch.keystore in the config directory
193 # so this directory needs to be writable.
194 mkdir -m 0700 -p ${configDir}
196 # Note that we copy config files from the nix store instead of symbolically linking them
197 # because otherwise X-Pack Security will raise the following exception:
198 # java.security.AccessControlException:
199 # access denied ("java.io.FilePermission" "/var/lib/elasticsearch/config/elasticsearch.yml" "read")
201 cp ${elasticsearchYml} ${configDir}/elasticsearch.yml
202 # Make sure the logging configuration for old elasticsearch versions is removed:
203 rm -f "${configDir}/logging.yml"
204 cp ${loggingConfigFile} ${configDir}/${loggingConfigFilename}
205 mkdir -p ${configDir}/scripts
206 cp ${cfg.package}/config/jvm.options ${configDir}/jvm.options
207 # redirect jvm logs to the data directory
208 mkdir -m 0700 -p ${cfg.dataDir}/logs
209 ${pkgs.sd}/bin/sd 'logs/gc.log' '${cfg.dataDir}/logs/gc.log' ${configDir}/jvm.options \
211 if [ "$(id -u)" = 0 ]; then chown -R elasticsearch:elasticsearch ${cfg.dataDir}; fi
214 # Make sure elasticsearch is up and running before dependents
216 while ! ${pkgs.curl}/bin/curl -sS -f http://${cfg.listenAddress}:${toString cfg.port} 2>/dev/null; do
222 environment.systemPackages = [ cfg.package ];
225 groups.elasticsearch.gid = config.ids.gids.elasticsearch;
226 users.elasticsearch = {
227 uid = config.ids.uids.elasticsearch;
228 description = "Elasticsearch daemon user";
230 group = "elasticsearch";