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 = lib.mdDoc "Whether to enable elasticsearch.";
54 description = lib.mdDoc "Elasticsearch package to use.";
55 default = pkgs.elasticsearch;
56 defaultText = literalExpression "pkgs.elasticsearch";
60 listenAddress = mkOption {
61 description = lib.mdDoc "Elasticsearch listen address.";
62 default = "127.0.0.1";
67 description = lib.mdDoc "Elasticsearch port to listen for HTTP traffic.";
73 description = lib.mdDoc "Elasticsearch port for the node to node communication.";
78 cluster_name = mkOption {
79 description = lib.mdDoc "Elasticsearch name that identifies your cluster for auto-discovery.";
80 default = "elasticsearch";
84 single_node = mkOption {
85 description = lib.mdDoc "Start a single-node cluster";
90 extraConf = mkOption {
91 description = lib.mdDoc "Extra configuration for elasticsearch.";
95 node.name: "elasticsearch"
102 description = lib.mdDoc "Elasticsearch logging configuration.";
104 logger.action.name = org.elasticsearch.action
105 logger.action.level = info
107 appender.console.type = Console
108 appender.console.name = console
109 appender.console.layout.type = PatternLayout
110 appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
112 rootLogger.level = info
113 rootLogger.appenderRef.console.ref = console
120 default = "/var/lib/elasticsearch";
121 description = lib.mdDoc ''
122 Data directory for elasticsearch.
126 extraCmdLineOptions = mkOption {
127 description = lib.mdDoc "Extra command line options for the elasticsearch launcher.";
129 type = types.listOf types.str;
132 extraJavaOptions = mkOption {
133 description = lib.mdDoc "Extra command line options for Java.";
135 type = types.listOf types.str;
136 example = [ "-Djava.net.preferIPv4Stack=true" ];
140 description = lib.mdDoc "Extra elasticsearch plugins";
142 type = types.listOf types.package;
143 example = lib.literalExpression "[ pkgs.elasticsearchPlugins.discovery-ec2 ]";
146 restartIfChanged = mkOption {
148 description = lib.mdDoc ''
149 Automatically restart the service on config change.
150 This can be set to false to defer restarts on a server or cluster.
151 Please consider the security implications of inadvertently running an older version,
152 and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
159 ###### implementation
161 config = mkIf cfg.enable {
162 systemd.services.elasticsearch = {
163 description = "Elasticsearch Daemon";
164 wantedBy = [ "multi-user.target" ];
165 after = [ "network.target" ];
166 path = [ pkgs.inetutils ];
167 inherit (cfg) restartIfChanged;
169 ES_HOME = cfg.dataDir;
170 ES_JAVA_OPTS = toString cfg.extraJavaOptions;
171 ES_PATH_CONF = configDir;
174 ExecStart = "${cfg.package}/bin/elasticsearch ${toString cfg.extraCmdLineOptions}";
175 User = "elasticsearch";
176 PermissionsStartOnly = true;
177 LimitNOFILE = "1024000";
179 TimeoutStartSec = "infinity";
182 ${optionalString (!config.boot.isContainer) ''
183 # Only set vm.max_map_count if lower than ES required minimum
184 # This avoids conflict if configured via boot.kernel.sysctl
185 if [ `${pkgs.procps}/bin/sysctl -n vm.max_map_count` -lt 262144 ]; then
186 ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144
190 mkdir -m 0700 -p ${cfg.dataDir}
193 ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins
194 ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib
195 ln -sfT ${cfg.package}/modules ${cfg.dataDir}/modules
197 # elasticsearch needs to create the elasticsearch.keystore in the config directory
198 # so this directory needs to be writable.
199 mkdir -m 0700 -p ${configDir}
201 # Note that we copy config files from the nix store instead of symbolically linking them
202 # because otherwise X-Pack Security will raise the following exception:
203 # java.security.AccessControlException:
204 # access denied ("java.io.FilePermission" "/var/lib/elasticsearch/config/elasticsearch.yml" "read")
206 cp ${elasticsearchYml} ${configDir}/elasticsearch.yml
207 # Make sure the logging configuration for old elasticsearch versions is removed:
208 rm -f "${configDir}/logging.yml"
209 cp ${loggingConfigFile} ${configDir}/${loggingConfigFilename}
210 mkdir -p ${configDir}/scripts
211 cp ${cfg.package}/config/jvm.options ${configDir}/jvm.options
212 # redirect jvm logs to the data directory
213 mkdir -m 0700 -p ${cfg.dataDir}/logs
214 ${pkgs.sd}/bin/sd 'logs/gc.log' '${cfg.dataDir}/logs/gc.log' ${configDir}/jvm.options \
216 if [ "$(id -u)" = 0 ]; then chown -R elasticsearch:elasticsearch ${cfg.dataDir}; fi
219 # Make sure elasticsearch is up and running before dependents
221 while ! ${pkgs.curl}/bin/curl -sS -f http://${cfg.listenAddress}:${toString cfg.port} 2>/dev/null; do
227 environment.systemPackages = [ cfg.package ];
230 groups.elasticsearch.gid = config.ids.gids.elasticsearch;
231 users.elasticsearch = {
232 uid = config.ids.uids.elasticsearch;
233 description = "Elasticsearch daemon user";
235 group = "elasticsearch";