1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.mealie;
9 pkg = cfg.package;
10in
11{
12 options.services.mealie = {
13 enable = lib.mkEnableOption "Mealie, a recipe manager and meal planner";
14
15 package = lib.mkPackageOption pkgs "mealie" { };
16
17 listenAddress = lib.mkOption {
18 type = lib.types.str;
19 default = "0.0.0.0";
20 description = "Address on which the service should listen.";
21 };
22
23 port = lib.mkOption {
24 type = lib.types.port;
25 default = 9000;
26 description = "Port on which to serve the Mealie service.";
27 };
28
29 settings = lib.mkOption {
30 type = with lib.types; attrsOf anything;
31 default = { };
32 description = ''
33 Configuration of the Mealie service.
34
35 See [the mealie documentation](https://nightly.mealie.io/documentation/getting-started/installation/backend-config/) for available options and default values.
36 '';
37 example = {
38 ALLOW_SIGNUP = "false";
39 };
40 };
41
42 extraOptions = lib.mkOption {
43 type = lib.types.listOf lib.types.str;
44 default = [ ];
45 example = [
46 "--log-level"
47 "debug"
48 ];
49 description = ''
50 Specifies extra command line arguments to pass to mealie (Gunicorn).
51 '';
52 };
53
54 credentialsFile = lib.mkOption {
55 type = with lib.types; nullOr path;
56 default = null;
57 example = "/run/secrets/mealie-credentials.env";
58 description = ''
59 File containing credentials used in mealie such as {env}`POSTGRES_PASSWORD`
60 or sensitive LDAP options.
61
62 Expects the format of an `EnvironmentFile=`, as described by {manpage}`systemd.exec(5)`.
63 '';
64 };
65
66 database = {
67 createLocally = lib.mkOption {
68 type = lib.types.bool;
69 default = false;
70 description = ''
71 Configure local PostgreSQL database server for Mealie.
72 '';
73 };
74 };
75 };
76
77 config = lib.mkIf cfg.enable {
78 systemd.services.mealie = {
79 description = "Mealie, a self hosted recipe manager and meal planner";
80
81 after = [ "network-online.target" ] ++ lib.optional cfg.database.createLocally "postgresql.target";
82 requires = lib.optional cfg.database.createLocally "postgresql.target";
83 wants = [ "network-online.target" ];
84 wantedBy = [ "multi-user.target" ];
85
86 environment = {
87 PRODUCTION = "true";
88 API_PORT = toString cfg.port;
89 BASE_URL = "http://localhost:${toString cfg.port}";
90 DATA_DIR = "/var/lib/mealie";
91 NLTK_DATA = pkgs.nltk-data.averaged-perceptron-tagger-eng;
92 }
93 // (builtins.mapAttrs (_: val: toString val) cfg.settings);
94
95 serviceConfig = {
96 DynamicUser = true;
97 User = "mealie";
98 ExecStartPre = "${pkg}/libexec/init_db";
99 ExecStart = "${lib.getExe pkg} -b ${cfg.listenAddress}:${builtins.toString cfg.port} ${lib.escapeShellArgs cfg.extraOptions}";
100 EnvironmentFile = lib.mkIf (cfg.credentialsFile != null) cfg.credentialsFile;
101 StateDirectory = "mealie";
102 StandardOutput = "journal";
103 };
104 };
105
106 services.mealie.settings = lib.mkIf cfg.database.createLocally {
107 DB_ENGINE = "postgres";
108 POSTGRES_URL_OVERRIDE = "postgresql://mealie:@/mealie?host=/run/postgresql";
109 };
110
111 services.postgresql = lib.mkIf cfg.database.createLocally {
112 enable = true;
113 ensureDatabases = [ "mealie" ];
114 ensureUsers = [
115 {
116 name = "mealie";
117 ensureDBOwnership = true;
118 }
119 ];
120 };
121 };
122}