···32323333- The default nixos package doesn't come with the [dashboard](https://docs.meilisearch.com/learn/getting_started/quick_start.html#search), since the dashboard features makes some assets downloads at compile time.
34343535-- Anonymized Analytics sent to meilisearch are disabled by default.
3535+- `no_analytics` is set to true by default.
36363737-- Default deployment is development mode. It doesn't require a secret master key. All routes are not protected and accessible.
3737+- `http_addr` is derived from {option}`services.meilisearch.listenAddress` and {option}`services.meilisearch.listenPort`. The two sub-fields are separate because this makes it easier to consume in certain other modules.
38383939-## Missing {#module-services-meilisearch-missing}
3939+- `db_path` is set to `/var/lib/meilisearch` by default. Upstream, the default value is equivalent to `/var/lib/meilisearch/data.ms`.
4040+4141+- `dump_dir` and `snapshot_dir` are set to `/var/lib/meilisearch/dumps` and `/var/lib/meilisearch/snapshots`, respectively. This is equivalent to the upstream defaults.
40424141-- the snapshot feature is not yet configurable from the module, it's just a matter of adding the relevant environment variables.
4343+- All other options inherit their upstream defaults. In particular, the default configuration uses `env = "development"`, which doesn't require a master key, in which case all routes are unprotected.
+160-90
nixos/modules/services/search/meilisearch.nix
···77let
88 cfg = config.services.meilisearch;
991010+ settingsFormat = pkgs.formats.toml { };
1111+1212+ # These secrets are used in the config file and can be set to paths.
1313+ secrets-with-path =
1414+ builtins.map
1515+ (
1616+ { environment, name }:
1717+ {
1818+ inherit name environment;
1919+ setting = cfg.settings.${name};
2020+ }
2121+ )
2222+ [
2323+ {
2424+ environment = "MEILI_SSL_CERT_PATH";
2525+ name = "ssl_cert_path";
2626+ }
2727+ {
2828+ environment = "MEILI_SSL_KEY_PATH";
2929+ name = "ssl_key_path";
3030+ }
3131+ {
3232+ environment = "MEILI_SSL_AUTH_PATH";
3333+ name = "ssl_auth_path";
3434+ }
3535+ {
3636+ environment = "MEILI_SSL_OCSP_PATH";
3737+ name = "ssl_ocsp_path";
3838+ }
3939+ ];
4040+4141+ # We also handle `master_key` separately.
4242+ # It cannot be set to a path, so we template it.
4343+ master-key-placeholder = "@MASTER_KEY@";
4444+4545+ configFile = settingsFormat.generate "config.toml" (
4646+ builtins.removeAttrs (
4747+ if cfg.masterKeyFile != null then
4848+ cfg.settings // { master_key = master-key-placeholder; }
4949+ else
5050+ builtins.removeAttrs cfg.settings [ "master_key" ]
5151+ ) (map (secret: secret.name) secrets-with-path)
5252+ );
5353+1054in
1155{
1212-1356 meta.maintainers = with lib.maintainers; [
1457 Br1ght0ne
1558 happysalada
1659 ];
1760 meta.doc = ./meilisearch.md;
18611919- ###### interface
6262+ imports = [
6363+ (lib.mkRenamedOptionModule
6464+ [ "services" "meilisearch" "environment" ]
6565+ [ "services" "meilisearch" "settings" "env" ]
6666+ )
6767+ (lib.mkRenamedOptionModule
6868+ [ "services" "meilisearch" "logLevel" ]
6969+ [ "services" "meilisearch" "settings" "log_level" ]
7070+ )
7171+ (lib.mkRenamedOptionModule
7272+ [ "services" "meilisearch" "noAnalytics" ]
7373+ [ "services" "meilisearch" "settings" "no_analytics" ]
7474+ )
7575+ (lib.mkRenamedOptionModule
7676+ [ "services" "meilisearch" "maxIndexSize" ]
7777+ [ "services" "meilisearch" "settings" "max_index_size" ]
7878+ )
7979+ (lib.mkRenamedOptionModule
8080+ [ "services" "meilisearch" "payloadSizeLimit" ]
8181+ [ "services" "meilisearch" "settings" "http_payload_size_limit" ]
8282+ )
8383+ (lib.mkRenamedOptionModule
8484+ [ "services" "meilisearch" "dumplessUpgrade" ]
8585+ [ "services" "meilisearch" "settings" "experimental_dumpless_upgrade" ]
8686+ )
8787+ (lib.mkRemovedOptionModule [ "services" "meilisearch" "masterKeyEnvironmentFile" ] ''
8888+ Use `services.meilisearch.masterKeyFile` instead. It does not require you to prefix the file with "MEILI_MASTER_KEY=".
8989+ If you were abusing this option to set other options, you can now configure them with `services.meilisearch.settings`.
9090+ '')
9191+ ];
20922193 options.services.meilisearch = {
2222- enable = lib.mkEnableOption "MeiliSearch - a RESTful search API";
9494+ enable = lib.mkEnableOption "Meilisearch - a RESTful search API";
23952496 package = lib.mkPackageOption pkgs "meilisearch" {
2597 extraDescription = ''
···28100 };
2910130102 listenAddress = lib.mkOption {
3131- description = "MeiliSearch listen address.";
3232- default = "127.0.0.1";
103103+ default = "localhost";
33104 type = lib.types.str;
105105+ description = ''
106106+ The IP address that Meilisearch will listen on.
107107+108108+ It can also be a hostname like "localhost". If it resolves to an IPv4 and IPv6 address, Meilisearch will listen on both.
109109+ '';
34110 };
3511136112 listenPort = lib.mkOption {
3737- description = "MeiliSearch port to listen on.";
38113 default = 7700;
39114 type = lib.types.port;
4040- };
4141-4242- environment = lib.mkOption {
4343- description = "Defines the running environment of MeiliSearch.";
4444- default = "development";
4545- type = lib.types.enum [
4646- "development"
4747- "production"
4848- ];
115115+ description = ''
116116+ The port that Meilisearch will listen on.
117117+ '';
49118 };
501195151- # TODO change this to LoadCredentials once possible
5252- masterKeyEnvironmentFile = lib.mkOption {
120120+ masterKeyFile = lib.mkOption {
53121 description = ''
54122 Path to file which contains the master key.
55123 By doing so, all routes will be protected and will require a key to be accessed.
56124 If no master key is provided, all routes can be accessed without requiring any key.
5757- The format is the following:
5858- MEILI_MASTER_KEY=my_secret_key
59125 '';
60126 default = null;
6161- type = with lib.types; nullOr path;
6262- };
6363-6464- noAnalytics = lib.mkOption {
6565- description = ''
6666- Deactivates analytics.
6767- Analytics allow MeiliSearch to know how many users are using MeiliSearch,
6868- which versions and which platforms are used.
6969- This process is entirely anonymous.
7070- '';
7171- default = true;
7272- type = lib.types.bool;
7373- };
7474-7575- logLevel = lib.mkOption {
7676- description = ''
7777- Defines how much detail should be present in MeiliSearch's logs.
7878- MeiliSearch currently supports four log levels, listed in order of increasing verbosity:
7979- - 'ERROR': only log unexpected events indicating MeiliSearch is not functioning as expected
8080- - 'WARN:' log all unexpected events, regardless of their severity
8181- - 'INFO:' log all events. This is the default value
8282- - 'DEBUG': log all events and including detailed information on MeiliSearch's internal processes.
8383- Useful when diagnosing issues and debugging
8484- '';
8585- default = "INFO";
8686- type = lib.types.str;
127127+ type = lib.types.nullOr lib.types.path;
87128 };
881298989- maxIndexSize = lib.mkOption {
130130+ settings = lib.mkOption {
90131 description = ''
9191- Sets the maximum size of the index.
9292- Value must be given in bytes or explicitly stating a base unit.
9393- For example, the default value can be written as 107374182400, '107.7Gb', or '107374 Mb'.
9494- Default is 100 GiB
132132+ Configuration settings for Meilisearch.
133133+ Look at the documentation for available options:
134134+ https://github.com/meilisearch/meilisearch/blob/main/config.toml
135135+ https://www.meilisearch.com/docs/learn/self_hosted/configure_meilisearch_at_launch#all-instance-options
95136 '';
9696- default = "107374182400";
9797- type = lib.types.str;
9898- };
99137100100- payloadSizeLimit = lib.mkOption {
101101- description = ''
102102- Sets the maximum size of accepted JSON payloads.
103103- Value must be given in bytes or explicitly stating a base unit.
104104- For example, the default value can be written as 107374182400, '107.7Gb', or '107374 Mb'.
105105- Default is ~ 100 MB
106106- '';
107107- default = "104857600";
108108- type = lib.types.str;
109109- };
138138+ default = { };
110139111111- # TODO: turn on by default when it stops being experimental
112112- dumplessUpgrade = lib.mkOption {
113113- default = false;
114114- example = true;
115115- description = ''
116116- Whether to enable (experimental) dumpless upgrade.
140140+ type = lib.types.submodule {
141141+ freeformType = settingsFormat.type;
117142118118- Allows upgrading from Meilisearch >=v1.12 to Meilisearch >=v1.13 without manually
119119- dumping and importing the database.
143143+ imports = builtins.map (secret: {
144144+ # give them proper types, just so they're easier to consume from this file
145145+ options.${secret.name} = lib.mkOption {
146146+ # but they should not show up in documentation as special in any way.
147147+ visible = false;
120148121121- More information at https://www.meilisearch.com/docs/learn/update_and_migration/updating#dumpless-upgrade
122122- '';
123123- type = lib.types.bool;
149149+ type = lib.types.nullOr lib.types.path;
150150+ default = null;
151151+ };
152152+ }) secrets-with-path;
153153+ };
124154 };
155155+ };
125156126126- };
157157+ config = lib.mkIf cfg.enable {
158158+ assertions = [
159159+ {
160160+ assertion = !cfg.settings ? master_key;
161161+ message = ''
162162+ Do not set `services.meilisearch.settings.master_key` in your configuration.
163163+ Use `services.meilisearch.masterKeyFile` instead.
164164+ '';
165165+ }
166166+ ];
127167128128- ###### implementation
168168+ services.meilisearch.settings = {
169169+ # we use `listenAddress` and `listenPort` to derive the `http_addr` setting.
170170+ # this is the only setting we treat like this.
171171+ # we do this because some dependent services like Misskey/Sharkey need separate host,port for no good reason.
172172+ http_addr = "${cfg.listenAddress}:${toString cfg.listenPort}";
173173+174174+ # upstream's default for `db_path` is `/var/lib/meilisearch/data.ms/`, but ours is different for no reason.
175175+ db_path = lib.mkDefault "/var/lib/meilisearch";
176176+ # these are equivalent to the upstream defaults, because we set a working directory.
177177+ # they are only set here for consistency with `db_path`.
178178+ dump_dir = lib.mkDefault "/var/lib/meilisearch/dumps";
179179+ snapshot_dir = lib.mkDefault "/var/lib/meilisearch/snapshots";
129180130130- config = lib.mkIf cfg.enable {
181181+ # this is intentionally different from upstream's default.
182182+ no_analytics = lib.mkDefault true;
183183+ };
131184132185 warnings = lib.optional (lib.versionOlder cfg.package.version "1.12") ''
133186 Meilisearch 1.11 will be removed in NixOS 25.11. As it was the last
···149202 environment.systemPackages = [ cfg.package ];
150203151204 systemd.services.meilisearch = {
152152- description = "MeiliSearch daemon";
205205+ description = "Meilisearch daemon";
153206 wantedBy = [ "multi-user.target" ];
154207 after = [ "network.target" ];
155155- environment = {
156156- MEILI_DB_PATH = "/var/lib/meilisearch";
157157- MEILI_HTTP_ADDR = "${cfg.listenAddress}:${toString cfg.listenPort}";
158158- MEILI_NO_ANALYTICS = lib.boolToString cfg.noAnalytics;
159159- MEILI_ENV = cfg.environment;
160160- MEILI_DUMP_DIR = "/var/lib/meilisearch/dumps";
161161- MEILI_LOG_LEVEL = cfg.logLevel;
162162- MEILI_MAX_INDEX_SIZE = cfg.maxIndexSize;
163163- MEILI_EXPERIMENTAL_DUMPLESS_UPGRADE = lib.boolToString cfg.dumplessUpgrade;
164164- };
208208+209209+ preStart = lib.mkMerge [
210210+ ''
211211+ install -m 700 '${configFile}' "$RUNTIME_DIRECTORY/config.toml"
212212+ ''
213213+ (lib.mkIf (cfg.masterKeyFile != null) ''
214214+ ${lib.getExe pkgs.replace-secret} '${master-key-placeholder}' "$CREDENTIALS_DIRECTORY/master_key" "$RUNTIME_DIRECTORY/config.toml"
215215+ '')
216216+ ];
217217+218218+ environment = builtins.listToAttrs (
219219+ builtins.map (secret: {
220220+ name = secret.environment;
221221+ value = lib.mkIf (secret.setting != null) "%d/${secret.name}";
222222+ }) secrets-with-path
223223+ );
224224+165225 serviceConfig = {
166166- ExecStart = "${cfg.package}/bin/meilisearch";
226226+ LoadCredential = lib.mkMerge (
227227+ [
228228+ (lib.mkIf (cfg.masterKeyFile != null) [ "master_key:${cfg.masterKeyFile}" ])
229229+ ]
230230+ ++ builtins.map (
231231+ secret: lib.mkIf (secret.setting != null) [ "${secret.name}:${secret.setting}" ]
232232+ ) secrets-with-path
233233+ );
234234+ ExecStart = "${lib.getExe cfg.package} --config-file-path \${RUNTIME_DIRECTORY}/config.toml";
167235 DynamicUser = true;
168236 StateDirectory = "meilisearch";
169169- EnvironmentFile = lib.mkIf (cfg.masterKeyEnvironmentFile != null) cfg.masterKeyEnvironmentFile;
237237+ WorkingDirectory = "%S/meilisearch";
238238+ RuntimeDirectory = "meilisearch";
239239+ RuntimeDirectoryMode = "0700";
170240 };
171241 };
172242 };
+2-2
nixos/modules/services/web-apps/sharkey.nix
···5454 description = ''
5555 Whether to automatically set up a local Meilisearch instance and configure Sharkey to use it.
56565757- You need to ensure `services.meilisearch.masterKeyEnvironmentFile` is correctly configured for a working
5757+ You need to ensure `services.meilisearch.masterKeyFile` is correctly configured for a working
5858 Meilisearch setup. You also need to configure Sharkey to use an API key obtained from Meilisearch with the
5959 `MK_CONFIG_MEILISEARCH_APIKEY` environment variable, and set `services.sharkey.settings.meilisearch.index` to
6060 the created index. See https://docs.joinsharkey.org/docs/customisation/search/meilisearch/ for how to create
···240240 (mkIf cfg.setupMeilisearch {
241241 services.meilisearch = {
242242 enable = mkDefault true;
243243- environment = mkDefault "production";
243243+ settings.env = mkDefault "production";
244244 };
245245246246 services.sharkey.settings = {