fix: add trusted proxy to mealie so Gunicorn trusts X-Forwarded-* headers, fix kanidm mealie groups

This commit is contained in:
oddlama 2025-05-19 22:40:59 +02:00
parent 6ed22d37af
commit f69fe83c42
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
4 changed files with 137 additions and 11 deletions

View file

@ -169,14 +169,8 @@ in
"openid"
"email"
"profile"
"groups"
];
claimMaps.groups = {
joinType = "array";
valuesByGroup = {
"mealie.access" = [ "user" ];
"mealie.admins" = [ "admin" ];
};
};
};
# Paperless

View file

@ -52,24 +52,24 @@ in
services.mealie = {
enable = true;
settings = rec {
ALLOW_SIGNUP = "false";
BASE_URL = "https://${mealieDomain}";
TZ = config.time.timeZone;
TOKEN_TIME = 87600; # 10 years session time - this is only internal so who cares
ALLOW_SIGNUP = "false";
OIDC_AUTH_ENABLED = "true";
OIDC_SIGNUP_ENABLED = "true";
OIDC_AUTO_REDIRECT = "true";
OIDC_REMEMBER_ME = "true";
OIDC_CLIENT_ID = "mealie";
OIDC_SIGNING_ALGORITHM = "ES256";
OIDC_USER_CLAIM = "preferred_username";
OIDC_PROVIDER_NAME = "Kanidm";
OIDC_CONFIGURATION_URL = "https://${globals.services.kanidm.domain}/oauth2/openid/${OIDC_CLIENT_ID}/.well-known/openid-configuration";
OIDC_USER_GROUP = "user";
OIDC_ADMIN_GROUP = "admin";
OIDC_USER_GROUP = "mealie.access@${globals.services.kanidm.domain}";
OIDC_ADMIN_GROUP = "mealie.admins@${globals.services.kanidm.domain}";
};
trustedProxies = [ nodes.ward-web-proxy.config.wireguard.proxy-home.ipv4 ];
credentialsFile = config.age.secrets.oauth2-client-secret.path;
};

View file

@ -1,4 +1,7 @@
{
disabledModules = [
"services/web-apps/mealie.nix"
];
imports = [
./acme-wildcard.nix
./backups.nix
@ -6,6 +9,7 @@
./distributed-config.nix
./ente.nix
./globals.nix
./mealie.nix
./meta.nix
./nginx-upstream-monitoring.nix
./oauth2-proxy.nix

128
modules/mealie.nix Normal file
View file

@ -0,0 +1,128 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.mealie;
pkg = cfg.package;
in
{
options.services.mealie = {
enable = lib.mkEnableOption "Mealie, a recipe manager and meal planner";
package = lib.mkPackageOption pkgs "mealie" { };
listenAddress = lib.mkOption {
type = lib.types.str;
default = "0.0.0.0";
description = "Address on which the service should listen.";
};
port = lib.mkOption {
type = lib.types.port;
default = 9000;
description = "Port on which to serve the Mealie service.";
};
settings = lib.mkOption {
type = with lib.types; attrsOf anything;
default = { };
description = ''
Configuration of the Mealie service.
See [the mealie documentation](https://nightly.mealie.io/documentation/getting-started/installation/backend-config/) for available options and default values.
'';
example = {
ALLOW_SIGNUP = "false";
};
};
extraOptions = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "--forwarded-allow-ips=10.44.0.11" ];
description = ''
Specifies extra command line arguments to pass to mealie (Gunicorn).
'';
};
credentialsFile = lib.mkOption {
type = with lib.types; nullOr path;
default = null;
example = "/run/secrets/mealie-credentials.env";
description = ''
File containing credentials used in mealie such as {env}`POSTGRES_PASSWORD`
or sensitive LDAP options.
Expects the format of an `EnvironmentFile=`, as described by {manpage}`systemd.exec(5)`.
'';
};
database = {
createLocally = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Configure local PostgreSQL database server for Mealie.
'';
};
};
trustedProxies = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "A list of trusted proxies. You must set this when you are using OIDC behind https, otherwise the generated redirect url will have the wrong url scheme.";
};
};
config = lib.mkIf cfg.enable {
systemd.services.mealie = {
description = "Mealie, a self hosted recipe manager and meal planner";
after = [ "network-online.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service";
requires = lib.optional cfg.database.createLocally "postgresql.service";
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
PRODUCTION = "true";
API_PORT = toString cfg.port;
BASE_URL = "http://localhost:${toString cfg.port}";
DATA_DIR = "/var/lib/mealie";
NLTK_DATA = pkgs.nltk-data.averaged_perceptron_tagger_eng;
} // (builtins.mapAttrs (_: toString) cfg.settings);
serviceConfig = {
DynamicUser = true;
User = "mealie";
ExecStartPre = "${pkg}/libexec/init_db";
ExecStart = "${lib.getExe pkg} -b ${cfg.listenAddress}:${builtins.toString cfg.port} ${lib.escapeShellArgs cfg.extraOptions}";
EnvironmentFile = lib.mkIf (cfg.credentialsFile != null) cfg.credentialsFile;
StateDirectory = "mealie";
StandardOutput = "journal";
};
};
services.mealie.settings = lib.mkIf cfg.database.createLocally {
DB_ENGINE = "postgres";
POSTGRES_URL_OVERRIDE = "postgresql://mealie:@/mealie?host=/run/postgresql";
};
services.mealie.extraOptions = lib.mkIf (cfg.trustedProxies != [ ]) [
"--forwarded-allow-ips=${lib.concatStringsSep "," cfg.trustedProxies}"
];
services.postgresql = lib.mkIf cfg.database.createLocally {
enable = true;
ensureDatabases = [ "mealie" ];
ensureUsers = [
{
name = "mealie";
ensureDBOwnership = true;
}
];
};
};
}