2023-08-06 16:40:02 +00:00
|
|
|
{ config, lib, options, pkgs, ... }:
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.forgejo;
|
|
|
|
opt = options.services.forgejo;
|
|
|
|
format = pkgs.formats.ini { };
|
|
|
|
|
|
|
|
exe = lib.getExe cfg.package;
|
|
|
|
|
|
|
|
pg = config.services.postgresql;
|
|
|
|
useMysql = cfg.database.type == "mysql";
|
|
|
|
usePostgresql = cfg.database.type == "postgres";
|
|
|
|
useSqlite = cfg.database.type == "sqlite3";
|
|
|
|
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
secrets = let
|
|
|
|
mkSecret = section: values: lib.mapAttrsToList (key: value: {
|
|
|
|
env = envEscape "FORGEJO__${section}__${key}__FILE";
|
|
|
|
path = value;
|
|
|
|
}) values;
|
|
|
|
# https://codeberg.org/forgejo/forgejo/src/tag/v7.0.2/contrib/environment-to-ini/environment-to-ini.go
|
|
|
|
envEscape = string: lib.replaceStrings [ "." "-" ] [ "_0X2E_" "_0X2D_" ] (lib.strings.toUpper string);
|
|
|
|
in lib.flatten (lib.mapAttrsToList mkSecret cfg.secrets);
|
|
|
|
|
2023-08-06 16:40:02 +00:00
|
|
|
inherit (lib)
|
|
|
|
literalExpression
|
|
|
|
mkChangedOptionModule
|
|
|
|
mkDefault
|
|
|
|
mkEnableOption
|
|
|
|
mkIf
|
|
|
|
mkMerge
|
|
|
|
mkOption
|
2023-11-30 18:03:14 +00:00
|
|
|
mkPackageOption
|
2023-08-06 16:40:02 +00:00
|
|
|
mkRemovedOptionModule
|
|
|
|
mkRenamedOptionModule
|
|
|
|
optionalAttrs
|
|
|
|
optionals
|
|
|
|
optionalString
|
|
|
|
types
|
|
|
|
;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
imports = [
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "appName" ] [ "services" "forgejo" "settings" "DEFAULT" "APP_NAME" ])
|
|
|
|
(mkRemovedOptionModule [ "services" "forgejo" "extraConfig" ] "services.forgejo.extraConfig has been removed. Please use the freeform services.forgejo.settings option instead")
|
|
|
|
(mkRemovedOptionModule [ "services" "forgejo" "database" "password" ] "services.forgejo.database.password has been removed. Please use services.forgejo.database.passwordFile instead")
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "mailerPasswordFile" ] [ "services" "forgejo" "secrets" "mailer" "PASSWD" ])
|
2023-08-06 16:40:02 +00:00
|
|
|
|
|
|
|
# copied from services.gitea; remove at some point
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "cookieSecure" ] [ "services" "forgejo" "settings" "session" "COOKIE_SECURE" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "disableRegistration" ] [ "services" "forgejo" "settings" "service" "DISABLE_REGISTRATION" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "domain" ] [ "services" "forgejo" "settings" "server" "DOMAIN" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "httpAddress" ] [ "services" "forgejo" "settings" "server" "HTTP_ADDR" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "httpPort" ] [ "services" "forgejo" "settings" "server" "HTTP_PORT" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "log" "level" ] [ "services" "forgejo" "settings" "log" "LEVEL" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "log" "rootPath" ] [ "services" "forgejo" "settings" "log" "ROOT_PATH" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "rootUrl" ] [ "services" "forgejo" "settings" "server" "ROOT_URL" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "ssh" "clonePort" ] [ "services" "forgejo" "settings" "server" "SSH_PORT" ])
|
|
|
|
(mkRenamedOptionModule [ "services" "forgejo" "staticRootPath" ] [ "services" "forgejo" "settings" "server" "STATIC_ROOT_PATH" ])
|
|
|
|
(mkChangedOptionModule [ "services" "forgejo" "enableUnixSocket" ] [ "services" "forgejo" "settings" "server" "PROTOCOL" ] (
|
|
|
|
config: if config.services.forgejo.enableUnixSocket then "http+unix" else "http"
|
|
|
|
))
|
|
|
|
(mkRemovedOptionModule [ "services" "forgejo" "ssh" "enable" ] "services.forgejo.ssh.enable has been migrated into freeform setting services.forgejo.settings.server.DISABLE_SSH. Keep in mind that the setting is inverted")
|
|
|
|
];
|
|
|
|
|
|
|
|
options = {
|
|
|
|
services.forgejo = {
|
2024-04-13 12:54:15 +00:00
|
|
|
enable = mkEnableOption "Forgejo, a software forge";
|
2023-08-06 16:40:02 +00:00
|
|
|
|
2023-11-30 18:03:14 +00:00
|
|
|
package = mkPackageOption pkgs "forgejo" { };
|
2023-08-06 16:40:02 +00:00
|
|
|
|
|
|
|
useWizard = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
Whether to use the built-in installation wizard instead of
|
|
|
|
declaratively managing the {file}`app.ini` config file in nix.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
stateDir = mkOption {
|
|
|
|
default = "/var/lib/forgejo";
|
|
|
|
type = types.str;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Forgejo data directory.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
customDir = mkOption {
|
|
|
|
default = "${cfg.stateDir}/custom";
|
|
|
|
defaultText = literalExpression ''"''${config.${opt.stateDir}}/custom"'';
|
|
|
|
type = types.str;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
Base directory for custom templates and other options.
|
|
|
|
|
|
|
|
If {option}`${opt.useWizard}` is disabled (default), this directory will also
|
|
|
|
hold secrets and the resulting {file}`app.ini` config at runtime.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "forgejo";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "User account under which Forgejo runs.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
group = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "forgejo";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Group under which Forgejo runs.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
database = {
|
|
|
|
type = mkOption {
|
|
|
|
type = types.enum [ "sqlite3" "mysql" "postgres" ];
|
|
|
|
example = "mysql";
|
|
|
|
default = "sqlite3";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database engine to use.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "127.0.0.1";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database host address.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
port = mkOption {
|
|
|
|
type = types.port;
|
2024-03-17 10:54:30 +00:00
|
|
|
default = if usePostgresql then pg.settings.port else 3306;
|
2023-08-06 16:40:02 +00:00
|
|
|
defaultText = literalExpression ''
|
|
|
|
if config.${opt.database.type} != "postgresql"
|
|
|
|
then 3306
|
2024-03-17 10:54:30 +00:00
|
|
|
else 5432
|
2023-08-06 16:40:02 +00:00
|
|
|
'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database host port.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "forgejo";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database name.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "forgejo";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database user.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
passwordFile = mkOption {
|
|
|
|
type = types.nullOr types.path;
|
|
|
|
default = null;
|
|
|
|
example = "/run/keys/forgejo-dbpassword";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
A file containing the password corresponding to
|
|
|
|
{option}`${opt.database.user}`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
socket = mkOption {
|
|
|
|
type = types.nullOr types.path;
|
|
|
|
default = if (cfg.database.createDatabase && usePostgresql) then "/run/postgresql" else if (cfg.database.createDatabase && useMysql) then "/run/mysqld/mysqld.sock" else null;
|
|
|
|
defaultText = literalExpression "null";
|
|
|
|
example = "/run/mysqld/mysqld.sock";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Path to the unix socket file to use for authentication.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
path = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.stateDir}/data/forgejo.db";
|
|
|
|
defaultText = literalExpression ''"''${config.${opt.stateDir}}/data/forgejo.db"'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Path to the sqlite3 database file.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
createDatabase = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Whether to create a local database automatically.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
dump = {
|
2024-04-13 12:54:15 +00:00
|
|
|
enable = mkEnableOption "periodic dumps via the [built-in {command}`dump` command](https://forgejo.org/docs/latest/admin/command-line/#dump)";
|
2023-08-06 16:40:02 +00:00
|
|
|
|
|
|
|
interval = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "04:31";
|
|
|
|
example = "hourly";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
Run a Forgejo dump at this interval. Runs by default at 04:31 every day.
|
|
|
|
|
|
|
|
The format is described in
|
|
|
|
{manpage}`systemd.time(7)`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
backupDir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.stateDir}/dump";
|
|
|
|
defaultText = literalExpression ''"''${config.${opt.stateDir}}/dump"'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Path to the directory where the dump archives will be stored.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
type = mkOption {
|
|
|
|
type = types.enum [ "zip" "tar" "tar.sz" "tar.gz" "tar.xz" "tar.bz2" "tar.br" "tar.lz4" "tar.zst" ];
|
|
|
|
default = "zip";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Archive format used to store the dump file.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
file = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Filename to be used for the dump. If `null` a default name is chosen by forgejo.";
|
2023-08-06 16:40:02 +00:00
|
|
|
example = "forgejo-dump";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
lfs = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Enables git-lfs support.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
contentDir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.stateDir}/data/lfs";
|
|
|
|
defaultText = literalExpression ''"''${config.${opt.stateDir}}/data/lfs"'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Where to store LFS files.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
repositoryRoot = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.stateDir}/repositories";
|
|
|
|
defaultText = literalExpression ''"''${config.${opt.stateDir}}/repositories"'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Path to the git repositories.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
settings = mkOption {
|
|
|
|
default = { };
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
Free-form settings written directly to the `app.ini` configfile file.
|
|
|
|
Refer to <https://forgejo.org/docs/latest/admin/config-cheat-sheet/> for supported values.
|
|
|
|
'';
|
|
|
|
example = literalExpression ''
|
|
|
|
{
|
|
|
|
DEFAULT = {
|
|
|
|
RUN_MODE = "dev";
|
|
|
|
};
|
|
|
|
"cron.sync_external_users" = {
|
|
|
|
RUN_AT_START = true;
|
|
|
|
SCHEDULE = "@every 24h";
|
|
|
|
UPDATE_EXISTING = true;
|
|
|
|
};
|
|
|
|
mailer = {
|
|
|
|
ENABLED = true;
|
|
|
|
MAILER_TYPE = "sendmail";
|
|
|
|
FROM = "do-not-reply@example.org";
|
|
|
|
SENDMAIL_PATH = "''${pkgs.system-sendmail}/bin/sendmail";
|
|
|
|
};
|
|
|
|
other = {
|
|
|
|
SHOW_FOOTER_VERSION = false;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
type = types.submodule {
|
|
|
|
freeformType = format.type;
|
|
|
|
options = {
|
|
|
|
log = {
|
|
|
|
ROOT_PATH = mkOption {
|
|
|
|
default = "${cfg.stateDir}/log";
|
|
|
|
defaultText = literalExpression ''"''${config.${opt.stateDir}}/log"'';
|
|
|
|
type = types.str;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Root path for log files.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
LEVEL = mkOption {
|
|
|
|
default = "Info";
|
|
|
|
type = types.enum [ "Trace" "Debug" "Info" "Warn" "Error" "Critical" ];
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "General log level.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
server = {
|
|
|
|
PROTOCOL = mkOption {
|
|
|
|
type = types.enum [ "http" "https" "fcgi" "http+unix" "fcgi+unix" ];
|
|
|
|
default = "http";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''Listen protocol. `+unix` means "over unix", not "in addition to."'';
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
HTTP_ADDR = mkOption {
|
|
|
|
type = types.either types.str types.path;
|
|
|
|
default = if lib.hasSuffix "+unix" cfg.settings.server.PROTOCOL then "/run/forgejo/forgejo.sock" else "0.0.0.0";
|
|
|
|
defaultText = literalExpression ''if lib.hasSuffix "+unix" cfg.settings.server.PROTOCOL then "/run/forgejo/forgejo.sock" else "0.0.0.0"'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Listen address. Must be a path when using a unix socket.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
HTTP_PORT = mkOption {
|
|
|
|
type = types.port;
|
|
|
|
default = 3000;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Listen port. Ignored when using a unix socket.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DOMAIN = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "localhost";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Domain name of your server.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ROOT_URL = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "http://${cfg.settings.server.DOMAIN}:${toString cfg.settings.server.HTTP_PORT}/";
|
|
|
|
defaultText = literalExpression ''"http://''${config.services.forgejo.settings.server.DOMAIN}:''${toString config.services.forgejo.settings.server.HTTP_PORT}/"'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Full public URL of Forgejo server.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
STATIC_ROOT_PATH = mkOption {
|
|
|
|
type = types.either types.str types.path;
|
|
|
|
default = cfg.package.data;
|
|
|
|
defaultText = literalExpression "config.${opt.package}.data";
|
|
|
|
example = "/var/lib/forgejo/data";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Upper level of template and static files path.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DISABLE_SSH = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Disable external SSH feature.";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
SSH_PORT = mkOption {
|
|
|
|
type = types.port;
|
|
|
|
default = 22;
|
|
|
|
example = 2222;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
SSH port displayed in clone URL.
|
|
|
|
The option is required to configure a service when the external visible port
|
|
|
|
differs from the local listening port i.e. if port forwarding is used.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
session = {
|
|
|
|
COOKIE_SECURE = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-08-06 16:40:02 +00:00
|
|
|
Marks session cookies as "secure" as a hint for browsers to only send
|
|
|
|
them via HTTPS. This option is recommend, if Forgejo is being served over HTTPS.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
|
|
|
|
secrets = mkOption {
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
This is a small wrapper over systemd's `LoadCredential`.
|
|
|
|
|
|
|
|
It takes the same sections and keys as {option}`services.forgejo.settings`,
|
|
|
|
but the value of each key is a path instead of a string or bool.
|
|
|
|
|
|
|
|
The path is then loaded as credential, exported as environment variable
|
|
|
|
and then feed through
|
|
|
|
<https://codeberg.org/forgejo/forgejo/src/branch/forgejo/contrib/environment-to-ini/environment-to-ini.go>.
|
|
|
|
|
|
|
|
It does the required environment variable escaping for you.
|
|
|
|
|
|
|
|
::: {.note}
|
|
|
|
Keys specified here take priority over the ones in {option}`services.forgejo.settings`!
|
|
|
|
:::
|
|
|
|
'';
|
|
|
|
example = literalExpression ''
|
|
|
|
{
|
|
|
|
metrics = {
|
|
|
|
TOKEN = "/run/keys/forgejo-metrics-token";
|
|
|
|
};
|
|
|
|
camo = {
|
|
|
|
HMAC_KEY = "/run/keys/forgejo-camo-hmac";
|
|
|
|
};
|
|
|
|
service = {
|
|
|
|
HCAPTCHA_SECRET = "/run/keys/forgejo-hcaptcha-secret";
|
|
|
|
HCAPTCHA_SITEKEY = "/run/keys/forgejo-hcaptcha-sitekey";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
type = types.submodule {
|
|
|
|
freeformType = with types; attrsOf (attrsOf path);
|
|
|
|
options = { };
|
|
|
|
};
|
|
|
|
};
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
assertions = [
|
|
|
|
{
|
|
|
|
assertion = cfg.database.createDatabase -> useSqlite || cfg.database.user == cfg.user;
|
|
|
|
message = "services.forgejo.database.user must match services.forgejo.user if the database is to be automatically provisioned";
|
|
|
|
}
|
nixos/postgresql: drop ensurePermissions, fix ensureUsers for postgresql15
Closes #216989
First of all, a bit of context: in PostgreSQL, newly created users don't
have the CREATE privilege on the public schema of a database even with
`ALL PRIVILEGES` granted via `ensurePermissions` which is how most of
the DB users are currently set up "declaratively"[1]. This means e.g. a
freshly deployed Nextcloud service will break early because Nextcloud
itself cannot CREATE any tables in the public schema anymore.
The other issue here is that `ensurePermissions` is a mere hack. It's
effectively a mixture of SQL code (e.g. `DATABASE foo` is relying on how
a value is substituted in a query. You'd have to parse a subset of SQL
to actually know which object are permissions granted to for a user).
After analyzing the existing modules I realized that in every case with
a single exception[2] the UNIX system user is equal to the db user is
equal to the db name and I don't see a compelling reason why people
would change that in 99% of the cases. In fact, some modules would even
break if you'd change that because the declarations of the system user &
the db user are mixed up[3].
So I decided to go with something new which restricts the ways to use
`ensure*` options rather than expanding those[4]. Effectively this means
that
* The DB user _must_ be equal to the DB name.
* Permissions are granted via `ensureDBOwnerhip` for an attribute-set in
`ensureUsers`. That way, the user is actually the owner and can
perform `CREATE`.
* For such a postgres user, a database must be declared in
`ensureDatabases`.
For anything else, a custom state management should be implemented. This
can either be `initialScript`, doing it manual, outside of the module or
by implementing proper state management for postgresql[5], but the
current state of `ensure*` isn't even declarative, but a convergent tool
which is what Nix actually claims to _not_ do.
Regarding existing setups: there are effectively two options:
* Leave everything as-is (assuming that system user == db user == db
name): then the DB user will automatically become the DB owner and
everything else stays the same.
* Drop the `createDatabase = true;` declarations: nothing will change
because a removal of `ensure*` statements is ignored, so it doesn't
matter at all whether this option is kept after the first deploy (and
later on you'd usually restore from backups anyways).
The DB user isn't the owner of the DB then, but for an existing setup
this is irrelevant because CREATE on the public schema isn't revoked
from existing users (only not granted for new users).
[1] not really declarative though because removals of these statements
are simply ignored for instance: https://github.com/NixOS/nixpkgs/issues/206467
[2] `services.invidious`: I removed the `ensure*` part temporarily
because it IMHO falls into the category "manage the state on your
own" (see the commit message). See also
https://github.com/NixOS/nixpkgs/pull/265857
[3] e.g. roundcube had `"DATABASE ${cfg.database.username}" = "ALL PRIVILEGES";`
[4] As opposed to other changes that are considered a potential fix, but
also add more things like collation for DBs or passwords that are
_never_ touched again when changing those.
[5] As suggested in e.g. https://github.com/NixOS/nixpkgs/issues/206467
2023-11-08 11:50:09 +00:00
|
|
|
{ assertion = cfg.database.createDatabase && usePostgresql -> cfg.database.user == cfg.database.name;
|
|
|
|
message = ''
|
|
|
|
When creating a database via NixOS, the db user and db name must be equal!
|
|
|
|
If you already have an existing DB+user and this assertion is new, you can safely set
|
|
|
|
`services.forgejo.createDatabase` to `false` because removal of `ensureUsers`
|
|
|
|
and `ensureDatabases` doesn't have any effect.
|
|
|
|
'';
|
|
|
|
}
|
2023-08-06 16:40:02 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
services.forgejo.settings = {
|
|
|
|
DEFAULT = {
|
|
|
|
RUN_MODE = mkDefault "prod";
|
|
|
|
RUN_USER = mkDefault cfg.user;
|
|
|
|
WORK_PATH = mkDefault cfg.stateDir;
|
|
|
|
};
|
|
|
|
|
|
|
|
database = mkMerge [
|
|
|
|
{
|
|
|
|
DB_TYPE = cfg.database.type;
|
|
|
|
}
|
|
|
|
(mkIf (useMysql || usePostgresql) {
|
|
|
|
HOST = if cfg.database.socket != null then cfg.database.socket else cfg.database.host + ":" + toString cfg.database.port;
|
|
|
|
NAME = cfg.database.name;
|
|
|
|
USER = cfg.database.user;
|
|
|
|
})
|
|
|
|
(mkIf useSqlite {
|
|
|
|
PATH = cfg.database.path;
|
|
|
|
})
|
|
|
|
(mkIf usePostgresql {
|
|
|
|
SSL_MODE = "disable";
|
|
|
|
})
|
|
|
|
];
|
|
|
|
|
|
|
|
repository = {
|
|
|
|
ROOT = cfg.repositoryRoot;
|
|
|
|
};
|
|
|
|
|
|
|
|
server = mkIf cfg.lfs.enable {
|
|
|
|
LFS_START_SERVER = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
session = {
|
|
|
|
COOKIE_NAME = mkDefault "session";
|
|
|
|
};
|
|
|
|
|
|
|
|
security = {
|
|
|
|
INSTALL_LOCK = true;
|
|
|
|
};
|
|
|
|
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
lfs = mkIf cfg.lfs.enable {
|
|
|
|
PATH = cfg.lfs.contentDir;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
services.forgejo.secrets = {
|
|
|
|
security = {
|
|
|
|
SECRET_KEY = "${cfg.customDir}/conf/secret_key";
|
|
|
|
INTERNAL_TOKEN = "${cfg.customDir}/conf/internal_token";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
oauth2 = {
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
JWT_SECRET = "${cfg.customDir}/conf/oauth2_jwt_secret";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
database = mkIf (cfg.database.passwordFile != null) {
|
|
|
|
PASSWD = cfg.database.passwordFile;
|
|
|
|
};
|
|
|
|
|
|
|
|
server = mkIf cfg.lfs.enable {
|
|
|
|
LFS_JWT_SECRET = "${cfg.customDir}/conf/lfs_jwt_secret";
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
services.postgresql = optionalAttrs (usePostgresql && cfg.database.createDatabase) {
|
|
|
|
enable = mkDefault true;
|
|
|
|
|
|
|
|
ensureDatabases = [ cfg.database.name ];
|
|
|
|
ensureUsers = [
|
|
|
|
{
|
|
|
|
name = cfg.database.user;
|
nixos/postgresql: drop ensurePermissions, fix ensureUsers for postgresql15
Closes #216989
First of all, a bit of context: in PostgreSQL, newly created users don't
have the CREATE privilege on the public schema of a database even with
`ALL PRIVILEGES` granted via `ensurePermissions` which is how most of
the DB users are currently set up "declaratively"[1]. This means e.g. a
freshly deployed Nextcloud service will break early because Nextcloud
itself cannot CREATE any tables in the public schema anymore.
The other issue here is that `ensurePermissions` is a mere hack. It's
effectively a mixture of SQL code (e.g. `DATABASE foo` is relying on how
a value is substituted in a query. You'd have to parse a subset of SQL
to actually know which object are permissions granted to for a user).
After analyzing the existing modules I realized that in every case with
a single exception[2] the UNIX system user is equal to the db user is
equal to the db name and I don't see a compelling reason why people
would change that in 99% of the cases. In fact, some modules would even
break if you'd change that because the declarations of the system user &
the db user are mixed up[3].
So I decided to go with something new which restricts the ways to use
`ensure*` options rather than expanding those[4]. Effectively this means
that
* The DB user _must_ be equal to the DB name.
* Permissions are granted via `ensureDBOwnerhip` for an attribute-set in
`ensureUsers`. That way, the user is actually the owner and can
perform `CREATE`.
* For such a postgres user, a database must be declared in
`ensureDatabases`.
For anything else, a custom state management should be implemented. This
can either be `initialScript`, doing it manual, outside of the module or
by implementing proper state management for postgresql[5], but the
current state of `ensure*` isn't even declarative, but a convergent tool
which is what Nix actually claims to _not_ do.
Regarding existing setups: there are effectively two options:
* Leave everything as-is (assuming that system user == db user == db
name): then the DB user will automatically become the DB owner and
everything else stays the same.
* Drop the `createDatabase = true;` declarations: nothing will change
because a removal of `ensure*` statements is ignored, so it doesn't
matter at all whether this option is kept after the first deploy (and
later on you'd usually restore from backups anyways).
The DB user isn't the owner of the DB then, but for an existing setup
this is irrelevant because CREATE on the public schema isn't revoked
from existing users (only not granted for new users).
[1] not really declarative though because removals of these statements
are simply ignored for instance: https://github.com/NixOS/nixpkgs/issues/206467
[2] `services.invidious`: I removed the `ensure*` part temporarily
because it IMHO falls into the category "manage the state on your
own" (see the commit message). See also
https://github.com/NixOS/nixpkgs/pull/265857
[3] e.g. roundcube had `"DATABASE ${cfg.database.username}" = "ALL PRIVILEGES";`
[4] As opposed to other changes that are considered a potential fix, but
also add more things like collation for DBs or passwords that are
_never_ touched again when changing those.
[5] As suggested in e.g. https://github.com/NixOS/nixpkgs/issues/206467
2023-11-08 11:50:09 +00:00
|
|
|
ensureDBOwnership = true;
|
2023-08-06 16:40:02 +00:00
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
services.mysql = optionalAttrs (useMysql && cfg.database.createDatabase) {
|
|
|
|
enable = mkDefault true;
|
|
|
|
package = mkDefault pkgs.mariadb;
|
|
|
|
|
|
|
|
ensureDatabases = [ cfg.database.name ];
|
|
|
|
ensureUsers = [
|
|
|
|
{
|
|
|
|
name = cfg.database.user;
|
|
|
|
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.tmpfiles.rules = [
|
|
|
|
"d '${cfg.dump.backupDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.dump.backupDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.repositoryRoot}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.repositoryRoot}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.stateDir}/conf' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.customDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.customDir}/conf' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.stateDir}/data' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.stateDir}/log' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.stateDir}/.ssh' 0700 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.stateDir}/conf' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.customDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.customDir}/conf' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.stateDir}/data' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.stateDir}/log' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
|
|
|
|
# If we have a folder or symlink with Forgejo locales, remove it
|
|
|
|
# And symlink the current Forgejo locales in place
|
|
|
|
"L+ '${cfg.stateDir}/conf/locale' - - - - ${cfg.package.out}/locale"
|
|
|
|
|
|
|
|
] ++ optionals cfg.lfs.enable [
|
|
|
|
"d '${cfg.lfs.contentDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"z '${cfg.lfs.contentDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
];
|
|
|
|
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
systemd.services.forgejo-secrets = mkIf (!cfg.useWizard) {
|
|
|
|
description = "Forgejo secret bootstrap helper";
|
|
|
|
script = ''
|
|
|
|
if [ ! -s '${cfg.secrets.security.SECRET_KEY}' ]; then
|
|
|
|
${exe} generate secret SECRET_KEY > '${cfg.secrets.security.SECRET_KEY}'
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ! -s '${cfg.secrets.oauth2.JWT_SECRET}' ]; then
|
|
|
|
${exe} generate secret JWT_SECRET > '${cfg.secrets.oauth2.JWT_SECRET}'
|
|
|
|
fi
|
|
|
|
|
|
|
|
${optionalString cfg.lfs.enable ''
|
|
|
|
if [ ! -s '${cfg.secrets.server.LFS_JWT_SECRET}' ]; then
|
|
|
|
${exe} generate secret LFS_JWT_SECRET > '${cfg.secrets.server.LFS_JWT_SECRET}'
|
|
|
|
fi
|
|
|
|
''}
|
|
|
|
|
|
|
|
if [ ! -s '${cfg.secrets.security.INTERNAL_TOKEN}' ]; then
|
|
|
|
${exe} generate secret INTERNAL_TOKEN > '${cfg.secrets.security.INTERNAL_TOKEN}'
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
RemainAfterExit = true;
|
|
|
|
User = cfg.user;
|
|
|
|
Group = cfg.group;
|
|
|
|
ReadWritePaths = [ cfg.customDir ];
|
|
|
|
UMask = "0077";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-08-06 16:40:02 +00:00
|
|
|
systemd.services.forgejo = {
|
|
|
|
description = "Forgejo (Beyond coding. We forge.)";
|
|
|
|
after = [
|
|
|
|
"network.target"
|
|
|
|
] ++ optionals usePostgresql [
|
|
|
|
"postgresql.service"
|
|
|
|
] ++ optionals useMysql [
|
|
|
|
"mysql.service"
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
] ++ optionals (!cfg.useWizard) [
|
|
|
|
"forgejo-secrets.service"
|
2023-08-06 16:40:02 +00:00
|
|
|
];
|
|
|
|
requires = optionals (cfg.database.createDatabase && usePostgresql) [
|
|
|
|
"postgresql.service"
|
|
|
|
] ++ optionals (cfg.database.createDatabase && useMysql) [
|
|
|
|
"mysql.service"
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
] ++ optionals (!cfg.useWizard) [
|
|
|
|
"forgejo-secrets.service"
|
2023-08-06 16:40:02 +00:00
|
|
|
];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
path = [ cfg.package pkgs.git pkgs.gnupg ];
|
|
|
|
|
|
|
|
# In older versions the secret naming for JWT was kind of confusing.
|
|
|
|
# The file jwt_secret hold the value for LFS_JWT_SECRET and JWT_SECRET
|
|
|
|
# wasn't persistent at all.
|
|
|
|
# To fix that, there is now the file oauth2_jwt_secret containing the
|
|
|
|
# values for JWT_SECRET and the file jwt_secret gets renamed to
|
|
|
|
# lfs_jwt_secret.
|
|
|
|
# We have to consider this to stay compatible with older installations.
|
|
|
|
preStart =
|
|
|
|
''
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
${optionalString (!cfg.useWizard) ''
|
2023-08-06 16:40:02 +00:00
|
|
|
function forgejo_setup {
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
config='${cfg.customDir}/conf/app.ini'
|
|
|
|
cp -f '${format.generate "app.ini" cfg.settings}' "$config"
|
|
|
|
|
|
|
|
chmod u+w "$config"
|
|
|
|
${lib.getExe' cfg.package "environment-to-ini"} --config "$config"
|
|
|
|
chmod u-w "$config"
|
2023-08-06 16:40:02 +00:00
|
|
|
}
|
|
|
|
(umask 027; forgejo_setup)
|
|
|
|
''}
|
|
|
|
|
|
|
|
# run migrations/init the database
|
|
|
|
${exe} migrate
|
|
|
|
|
|
|
|
# update all hooks' binary paths
|
|
|
|
${exe} admin regenerate hooks
|
|
|
|
|
|
|
|
# update command option in authorized_keys
|
|
|
|
if [ -r ${cfg.stateDir}/.ssh/authorized_keys ]
|
|
|
|
then
|
|
|
|
${exe} admin regenerate keys
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "simple";
|
|
|
|
User = cfg.user;
|
|
|
|
Group = cfg.group;
|
|
|
|
WorkingDirectory = cfg.stateDir;
|
|
|
|
ExecStart = "${exe} web --pid /run/forgejo/forgejo.pid";
|
|
|
|
Restart = "always";
|
|
|
|
# Runtime directory and mode
|
|
|
|
RuntimeDirectory = "forgejo";
|
|
|
|
RuntimeDirectoryMode = "0755";
|
|
|
|
# Proc filesystem
|
|
|
|
ProcSubset = "pid";
|
|
|
|
ProtectProc = "invisible";
|
|
|
|
# Access write directories
|
|
|
|
ReadWritePaths = [ cfg.customDir cfg.dump.backupDir cfg.repositoryRoot cfg.stateDir cfg.lfs.contentDir ];
|
|
|
|
UMask = "0027";
|
|
|
|
# Capabilities
|
|
|
|
CapabilityBoundingSet = "";
|
|
|
|
# Security
|
|
|
|
NoNewPrivileges = true;
|
|
|
|
# Sandboxing
|
|
|
|
ProtectSystem = "strict";
|
|
|
|
ProtectHome = true;
|
|
|
|
PrivateTmp = true;
|
|
|
|
PrivateDevices = true;
|
|
|
|
PrivateUsers = true;
|
|
|
|
ProtectHostname = true;
|
|
|
|
ProtectClock = true;
|
|
|
|
ProtectKernelTunables = true;
|
|
|
|
ProtectKernelModules = true;
|
|
|
|
ProtectKernelLogs = true;
|
|
|
|
ProtectControlGroups = true;
|
|
|
|
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
|
|
|
|
RestrictNamespaces = true;
|
|
|
|
LockPersonality = true;
|
|
|
|
MemoryDenyWriteExecute = true;
|
|
|
|
RestrictRealtime = true;
|
|
|
|
RestrictSUIDSGID = true;
|
|
|
|
RemoveIPC = true;
|
|
|
|
PrivateMounts = true;
|
|
|
|
# System Call Filtering
|
|
|
|
SystemCallArchitectures = "native";
|
|
|
|
SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" "setrlimit" ];
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
# cfg.secrets
|
|
|
|
LoadCredential = map (e: "${e.env}:${e.path}") secrets;
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
USER = cfg.user;
|
|
|
|
HOME = cfg.stateDir;
|
|
|
|
# `GITEA_` prefix until https://codeberg.org/forgejo/forgejo/issues/497
|
|
|
|
# is resolved.
|
|
|
|
GITEA_WORK_DIR = cfg.stateDir;
|
|
|
|
GITEA_CUSTOM = cfg.customDir;
|
nixos/forgejo: refactor secrets, add `cfg.secrets`
This is not a breaking change. Existing setups continue to work as-is.
Users of `cfg.mailerPasswordFile` will get an option rename/deprecation
warning, but that's it (assuming there is no regression).
This adds `cfg.secrets`, which is a wrapper over systemd's
`LoadCredential=` leveraging Forgejo's `environment-to-ini`.
`environment-to-ini` is intended for configuring Forgejo in OCI
containers.
It requires some fairly annoying escaping of the section names to fit
into the allowed environment variable charset.
E.g. `"log.console".COLORIZE = false` becomes
`FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false`.
- `.` needs to be replaced with `_0X2E_` and
- `-` needs to be replaced with `_0X2D_`
Those are simply the hex representation of each char from an ASCII
table:
. = ASCII 46 = 46 (decimal) = 2E (hex) = 0x2E = _OX2E_
To make interacting with `environment-to-ini` less annoying, we template
and escape the sections/keys in nix:
`cfg.secrets` takes the same free-form sections/keys as `cfg.settings`.
Meaning there is now a generalized abstraction for all keys, not just
those that have been manually implemented in the past.
It goes as far as theoretically allowing one to have `DEFAULT.APP_NAME`
read from a secret file.
I don't know why one would want to do that, but it has been made
possible by this :^)
More reasonable examples are listed in the `cfg.secrets` option example.
We also continue to bootstrap a handful of secrets like
`security.SECRET_KEY`. This is done is a sort of sidecar bootstrap unit
fittingly called `forgejo-secrets.service`.
Overriding those is, just like before, not really intended and requires
the use of `lib.mkForce` and might lead to breakage. But it is, in a
way, more possible than before.
2024-05-17 21:23:20 +00:00
|
|
|
} // lib.listToAttrs (map (e: lib.nameValuePair e.env "%d/${e.env}") secrets);
|
2023-08-06 16:40:02 +00:00
|
|
|
};
|
|
|
|
|
2023-10-24 01:27:20 +00:00
|
|
|
services.openssh.settings.AcceptEnv = mkIf (!cfg.settings.START_SSH_SERVER or false) "GIT_PROTOCOL";
|
|
|
|
|
2023-08-06 16:40:02 +00:00
|
|
|
users.users = mkIf (cfg.user == "forgejo") {
|
|
|
|
forgejo = {
|
|
|
|
home = cfg.stateDir;
|
|
|
|
useDefaultShell = true;
|
|
|
|
group = cfg.group;
|
|
|
|
isSystemUser = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
users.groups = mkIf (cfg.group == "forgejo") {
|
|
|
|
forgejo = { };
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.services.forgejo-dump = mkIf cfg.dump.enable {
|
|
|
|
description = "forgejo dump";
|
|
|
|
after = [ "forgejo.service" ];
|
|
|
|
path = [ cfg.package ];
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
USER = cfg.user;
|
|
|
|
HOME = cfg.stateDir;
|
|
|
|
# `GITEA_` prefix until https://codeberg.org/forgejo/forgejo/issues/497
|
|
|
|
# is resolved.
|
|
|
|
GITEA_WORK_DIR = cfg.stateDir;
|
|
|
|
GITEA_CUSTOM = cfg.customDir;
|
|
|
|
};
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
User = cfg.user;
|
|
|
|
ExecStart = "${exe} dump --type ${cfg.dump.type}" + optionalString (cfg.dump.file != null) " --file ${cfg.dump.file}";
|
|
|
|
WorkingDirectory = cfg.dump.backupDir;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.timers.forgejo-dump = mkIf cfg.dump.enable {
|
|
|
|
description = "Forgejo dump timer";
|
|
|
|
partOf = [ "forgejo-dump.service" ];
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig.OnCalendar = cfg.dump.interval;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-11-17 14:55:24 +00:00
|
|
|
meta.doc = ./forgejo.md;
|
2023-08-06 16:40:02 +00:00
|
|
|
meta.maintainers = with lib.maintainers; [ bendlas emilylange ];
|
|
|
|
}
|