add forgejo service
This commit is contained in:
parent
eb11a94d44
commit
253ec980d9
8 changed files with 951 additions and 23 deletions
|
@ -24,7 +24,7 @@ let
|
||||||
|
|
||||||
ghRoot = (gitHubDeclaration "ibizaman" "selfhostblocks" "").url;
|
ghRoot = (gitHubDeclaration "ibizaman" "selfhostblocks" "").url;
|
||||||
|
|
||||||
buildOptionsDocs = args@{ modules, includeModuleSystemOptions ? true, ... }:
|
buildOptionsDocs = args@{ modules, ... }:
|
||||||
let
|
let
|
||||||
config = {
|
config = {
|
||||||
_module.check = false;
|
_module.check = false;
|
||||||
|
@ -45,9 +45,7 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
options = if includeModuleSystemOptions
|
options = lib.filterAttrs (name: v: name == "shb") eval.options;
|
||||||
then eval.options
|
|
||||||
else builtins.removeAttrs eval.options [ "_module" ];
|
|
||||||
in buildPackages.nixosOptionsDoc ({
|
in buildPackages.nixosOptionsDoc ({
|
||||||
inherit options;
|
inherit options;
|
||||||
|
|
||||||
|
@ -66,18 +64,14 @@ let
|
||||||
_module.check = false;
|
_module.check = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
optionsDocs = buildOptionsDocs {
|
allOptionsDocs = paths: (buildOptionsDocs {
|
||||||
modules = allModules ++ [
|
modules = paths ++ allModules ++ [ scrubbedModule ];
|
||||||
scrubbedModule
|
|
||||||
];
|
|
||||||
variablelistId = "selfhostblocks-options";
|
variablelistId = "selfhostblocks-options";
|
||||||
includeModuleSystemOptions = false;
|
}).optionsJSON;
|
||||||
};
|
|
||||||
|
|
||||||
individualModuleOptionsDocs = path: (buildOptionsDocs {
|
individualModuleOptionsDocs = paths: (buildOptionsDocs {
|
||||||
modules = [ path scrubbedModule ];
|
modules = paths ++ [ scrubbedModule ];
|
||||||
variablelistId = "selfhostblocks-options";
|
variablelistId = "selfhostblocks-options";
|
||||||
includeModuleSystemOptions = false;
|
|
||||||
}).optionsJSON;
|
}).optionsJSON;
|
||||||
|
|
||||||
nmd = import nmdsrc {
|
nmd = import nmdsrc {
|
||||||
|
@ -129,37 +123,47 @@ in stdenv.mkDerivation {
|
||||||
substituteInPlace ./options.md \
|
substituteInPlace ./options.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${optionsDocs.optionsJSON}/share/doc/nixos/options.json
|
${allOptionsDocs [
|
||||||
|
(pkgs.path + "/nixos/modules/services/misc/forgejo.nix")
|
||||||
|
]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
substituteInPlace ./modules/blocks/ssl/docs/default.md \
|
substituteInPlace ./modules/blocks/ssl/docs/default.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${individualModuleOptionsDocs ../modules/blocks/ssl.nix}/share/doc/nixos/options.json
|
${individualModuleOptionsDocs [ ../modules/blocks/ssl.nix ]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
substituteInPlace ./modules/blocks/restic/docs/default.md \
|
substituteInPlace ./modules/blocks/restic/docs/default.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${individualModuleOptionsDocs ../modules/blocks/restic.nix}/share/doc/nixos/options.json
|
${individualModuleOptionsDocs [ ../modules/blocks/restic.nix ]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
substituteInPlace ./modules/services/nextcloud-server/docs/default.md \
|
substituteInPlace ./modules/services/nextcloud-server/docs/default.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${individualModuleOptionsDocs ../modules/services/nextcloud-server.nix}/share/doc/nixos/options.json
|
${individualModuleOptionsDocs [ ../modules/services/nextcloud-server.nix ]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
substituteInPlace ./modules/services/vaultwarden/docs/default.md \
|
substituteInPlace ./modules/services/vaultwarden/docs/default.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${individualModuleOptionsDocs ../modules/services/vaultwarden.nix}/share/doc/nixos/options.json
|
${individualModuleOptionsDocs [ ../modules/services/vaultwarden.nix ]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
|
substituteInPlace ./modules/services/forgejo/docs/default.md \
|
||||||
|
--replace \
|
||||||
|
'@OPTIONS_JSON@' \
|
||||||
|
${individualModuleOptionsDocs [
|
||||||
|
../modules/services/forgejo.nix
|
||||||
|
(pkgs.path + "/nixos/modules/services/misc/forgejo.nix")
|
||||||
|
]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
substituteInPlace ./modules/contracts/backup/docs/default.md \
|
substituteInPlace ./modules/contracts/backup/docs/default.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${individualModuleOptionsDocs ../modules/contracts/backup/dummyModule.nix}/share/doc/nixos/options.json
|
${individualModuleOptionsDocs [ ../modules/contracts/backup/dummyModule.nix ]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
substituteInPlace ./modules/contracts/ssl/docs/default.md \
|
substituteInPlace ./modules/contracts/ssl/docs/default.md \
|
||||||
--replace \
|
--replace \
|
||||||
'@OPTIONS_JSON@' \
|
'@OPTIONS_JSON@' \
|
||||||
${individualModuleOptionsDocs ../modules/contracts/ssl/dummyModule.nix}/share/doc/nixos/options.json
|
${individualModuleOptionsDocs [ ../modules/contracts/ssl/dummyModule.nix ]}/share/doc/nixos/options.json
|
||||||
|
|
||||||
find . -name "*.md" -print0 | \
|
find . -name "*.md" -print0 | \
|
||||||
while IFS= read -r -d ''' f; do
|
while IFS= read -r -d ''' f; do
|
||||||
|
|
|
@ -13,7 +13,8 @@ information is provided in the respective manual sections.
|
||||||
| Service | Backup | Reverse Proxy | SSO | LDAP | Monitoring | Profiling |
|
| Service | Backup | Reverse Proxy | SSO | LDAP | Monitoring | Profiling |
|
||||||
|-----------------------|--------|---------------|-----|-------|------------|-----------|
|
|-----------------------|--------|---------------|-----|-------|------------|-----------|
|
||||||
| [Nextcloud Server][1] | P (1) | Y | Y | Y | Y | P (2) |
|
| [Nextcloud Server][1] | P (1) | Y | Y | Y | Y | P (2) |
|
||||||
| [Vaultwarden][2] | N | Y | Y | Y | N | N |
|
| [Vaultwarden][2] | P (1) | Y | Y | Y | N | N |
|
||||||
|
| [Forgejo][3] | Y | Y | Y | Y | N | N |
|
||||||
|
|
||||||
Legend: **N**: no but WIP; **P**: partial; **Y**: yes
|
Legend: **N**: no but WIP; **P**: partial; **Y**: yes
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ Legend: **N**: no but WIP; **P**: partial; **Y**: yes
|
||||||
|
|
||||||
[1]: services-nextcloud.html
|
[1]: services-nextcloud.html
|
||||||
[2]: services-vaultwarden.html
|
[2]: services-vaultwarden.html
|
||||||
|
[3]: services-foregjo.html
|
||||||
|
|
||||||
```{=include=} chapters html:into-file=//services-vaultwarden.html
|
```{=include=} chapters html:into-file=//services-vaultwarden.html
|
||||||
modules/services/vaultwarden/docs/default.md
|
modules/services/vaultwarden/docs/default.md
|
||||||
|
@ -30,3 +32,7 @@ modules/services/vaultwarden/docs/default.md
|
||||||
```{=include=} chapters html:into-file=//services-nextcloud.html
|
```{=include=} chapters html:into-file=//services-nextcloud.html
|
||||||
modules/services/nextcloud-server/docs/default.md
|
modules/services/nextcloud-server/docs/default.md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```{=include=} chapters html:into-file=//services-forgejo.html
|
||||||
|
modules/services/forgejo/docs/default.md
|
||||||
|
```
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
modules/services/arr.nix
|
modules/services/arr.nix
|
||||||
modules/services/audiobookshelf.nix
|
modules/services/audiobookshelf.nix
|
||||||
modules/services/deluge.nix
|
modules/services/deluge.nix
|
||||||
|
modules/services/forgejo.nix
|
||||||
modules/services/grocy.nix
|
modules/services/grocy.nix
|
||||||
modules/services/hledger.nix
|
modules/services/hledger.nix
|
||||||
modules/services/home-assistant.nix
|
modules/services/home-assistant.nix
|
||||||
|
@ -55,7 +56,7 @@
|
||||||
modules/services/vaultwarden.nix
|
modules/services/vaultwarden.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
# Only used for documentation.
|
# The contract dummies are used to show options for contracts.
|
||||||
contractDummyModules = [
|
contractDummyModules = [
|
||||||
modules/contracts/backup/dummyModule.nix
|
modules/contracts/backup/dummyModule.nix
|
||||||
modules/contracts/ssl/dummyModule.nix
|
modules/contracts/ssl/dummyModule.nix
|
||||||
|
@ -116,6 +117,7 @@
|
||||||
// (vm_test "arr" ./test/services/arr.nix)
|
// (vm_test "arr" ./test/services/arr.nix)
|
||||||
// (vm_test "audiobookshelf" ./test/services/audiobookshelf.nix)
|
// (vm_test "audiobookshelf" ./test/services/audiobookshelf.nix)
|
||||||
// (vm_test "deluge" ./test/services/deluge.nix)
|
// (vm_test "deluge" ./test/services/deluge.nix)
|
||||||
|
// (vm_test "forgejo" ./test/services/forgejo.nix)
|
||||||
// (vm_test "grocy" ./test/services/grocy.nix)
|
// (vm_test "grocy" ./test/services/grocy.nix)
|
||||||
// (vm_test "home-assistant" ./test/services/home-assistant.nix)
|
// (vm_test "home-assistant" ./test/services/home-assistant.nix)
|
||||||
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
||||||
|
|
|
@ -42,6 +42,7 @@ let
|
||||||
|
|
||||||
autheliaRules = lib.mkOption {
|
autheliaRules = lib.mkOption {
|
||||||
type = lib.types.listOf (lib.types.attrsOf lib.types.anything);
|
type = lib.types.listOf (lib.types.attrsOf lib.types.anything);
|
||||||
|
default = [];
|
||||||
description = "Authelia rule configuration";
|
description = "Authelia rule configuration";
|
||||||
example = lib.literalExpression ''[{
|
example = lib.literalExpression ''[{
|
||||||
policy = "two_factor";
|
policy = "two_factor";
|
||||||
|
|
519
modules/services/forgejo.nix
Normal file
519
modules/services/forgejo.nix
Normal file
|
@ -0,0 +1,519 @@
|
||||||
|
{ config, options, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.shb.forgejo;
|
||||||
|
|
||||||
|
contracts = pkgs.callPackage ../contracts {};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.shb.forgejo = {
|
||||||
|
enable = lib.mkEnableOption "selfhostblocks.forgejo";
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Subdomain under which Forgejo will be served.
|
||||||
|
|
||||||
|
```
|
||||||
|
<subdomain>.<domain>[:<port>]
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
example = "forgejo";
|
||||||
|
};
|
||||||
|
|
||||||
|
domain = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Domain under which Forgejo is served.
|
||||||
|
|
||||||
|
```
|
||||||
|
<subdomain>.<domain>[:<port>]
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "domain.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
ssl = lib.mkOption {
|
||||||
|
description = "Path to SSL files";
|
||||||
|
type = lib.types.nullOr contracts.ssl.certs;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
LDAP Integration.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = lib.types.nullOr (lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
enable = lib.mkEnableOption "LDAP integration.";
|
||||||
|
|
||||||
|
provider = lib.mkOption {
|
||||||
|
type = lib.types.enum [ "LLDAP" ];
|
||||||
|
description = "LDAP provider name, used for display.";
|
||||||
|
default = "LLDAP";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Host serving the LDAP server.
|
||||||
|
'';
|
||||||
|
default = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
description = ''
|
||||||
|
Port of the service serving the LDAP server.
|
||||||
|
'';
|
||||||
|
default = 389;
|
||||||
|
};
|
||||||
|
|
||||||
|
dcdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "dc domain for ldap.";
|
||||||
|
example = "dc=mydomain,dc=com";
|
||||||
|
};
|
||||||
|
|
||||||
|
adminName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Admin user of the LDAP server.";
|
||||||
|
default = "admin";
|
||||||
|
};
|
||||||
|
|
||||||
|
adminPasswordFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
File containing the admin password of the LDAP server.
|
||||||
|
|
||||||
|
Must be readable by the forgejo system user.
|
||||||
|
'';
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
userGroup = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Group users must belong to be able to login.";
|
||||||
|
default = "forgejo_user";
|
||||||
|
};
|
||||||
|
|
||||||
|
adminGroup = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Group users must belong to be admins.";
|
||||||
|
default = "forgejo_admin";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Setup SSO integration.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
enable = lib.mkEnableOption "SSO integration.";
|
||||||
|
|
||||||
|
provider = lib.mkOption {
|
||||||
|
type = lib.types.enum [ "Authelia" ];
|
||||||
|
description = "OIDC provider name, used for display.";
|
||||||
|
default = "Authelia";
|
||||||
|
};
|
||||||
|
|
||||||
|
endpoint = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "OIDC endpoint for SSO.";
|
||||||
|
example = "https://authelia.example.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
clientID = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Client ID for the OIDC endpoint.";
|
||||||
|
default = "forgejo";
|
||||||
|
};
|
||||||
|
|
||||||
|
authorization_policy = lib.mkOption {
|
||||||
|
type = lib.types.enum [ "one_factor" "two_factor" ];
|
||||||
|
description = "Require one factor (password) or two factor (device) authentication.";
|
||||||
|
default = "one_factor";
|
||||||
|
};
|
||||||
|
|
||||||
|
secretFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
File containing the secret for the OIDC endpoint.
|
||||||
|
|
||||||
|
Must be readable by the forgejo system user.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
secretFileForAuthelia = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
File containing the secret for the OIDC endpoint, must be readable by the Authelia user.
|
||||||
|
|
||||||
|
Must be readable by the authelia system user.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
adminPasswordFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = "File containing the Forgejo admin user password.";
|
||||||
|
example = "/run/secrets/forgejo/adminPassword";
|
||||||
|
};
|
||||||
|
|
||||||
|
databasePasswordFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = "File containing the Forgejo database password.";
|
||||||
|
example = "/run/secrets/forgejo/databasePassword";
|
||||||
|
};
|
||||||
|
|
||||||
|
repositoryRoot = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
description = "Path where to store the repositories. If null, uses the default under the Forgejo StateDir.";
|
||||||
|
default = null;
|
||||||
|
example = "/srv/forgejo";
|
||||||
|
};
|
||||||
|
|
||||||
|
localActionRunner = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Enable local action runner that runs for all labels.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
backup = lib.mkOption {
|
||||||
|
type = contracts.backup;
|
||||||
|
description = ''
|
||||||
|
Backup configuration. This is an output option.
|
||||||
|
|
||||||
|
Use it to initialize a block implementing the "backup" contract.
|
||||||
|
For example, with the restic block:
|
||||||
|
|
||||||
|
```
|
||||||
|
shb.restic.instances."forgejo" = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# Options specific to Restic.
|
||||||
|
} // config.shb.forgejo.backup;
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
readOnly = true;
|
||||||
|
default = {
|
||||||
|
user = options.services.forgejo.user.value;
|
||||||
|
sourceDirectories = [
|
||||||
|
options.services.forgejo.dump.backupDir.value
|
||||||
|
] ++ lib.optionals (cfg.repositoryRoot != null) [
|
||||||
|
cfg.repositoryRoot
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mount = lib.mkOption {
|
||||||
|
type = contracts.mount;
|
||||||
|
description = ''
|
||||||
|
Mount configuration. This is an output option.
|
||||||
|
|
||||||
|
Use it to initialize a block implementing the "mount" contract.
|
||||||
|
For example, with a zfs dataset:
|
||||||
|
|
||||||
|
```
|
||||||
|
shb.zfs.datasets."forgejo" = {
|
||||||
|
poolName = "root";
|
||||||
|
} // config.shb.forgejo.mount;
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
readOnly = true;
|
||||||
|
default = { path = config.services.forgejo.stateDir; };
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Send notifications by smtp.
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
type = lib.types.nullOr (lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
from_address = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "SMTP address from which the emails originate.";
|
||||||
|
example = "authelia@mydomain.com";
|
||||||
|
};
|
||||||
|
host = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "SMTP host to send the emails to.";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
description = "SMTP port to send the emails to.";
|
||||||
|
default = 25;
|
||||||
|
};
|
||||||
|
username = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Username to connect to the SMTP host.";
|
||||||
|
};
|
||||||
|
passwordFile = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "File containing the password to connect to the SMTP host.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
debug = lib.mkOption {
|
||||||
|
description = "Enable debug logging.";
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkMerge [
|
||||||
|
(lib.mkIf cfg.enable {
|
||||||
|
services.forgejo = {
|
||||||
|
enable = true;
|
||||||
|
repositoryRoot = lib.mkIf (cfg.repositoryRoot != null) cfg.repositoryRoot;
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
DOMAIN = cfg.domain;
|
||||||
|
PROTOCOL = "http+unix";
|
||||||
|
ROOT_URL = "https://${cfg.subdomain}.${cfg.domain}/";
|
||||||
|
};
|
||||||
|
|
||||||
|
service.DISABLE_REGISTRATION = true;
|
||||||
|
|
||||||
|
log.LEVEL = if cfg.debug then "Debug" else "Info";
|
||||||
|
|
||||||
|
cron = {
|
||||||
|
ENABLE = true;
|
||||||
|
RUN_AT_START = true;
|
||||||
|
SCHEDULE = "@every 1h";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 1 lower than default, to solve conflict between shb.postgresql and nixpkgs' forgejo module.
|
||||||
|
services.postgresql.enable = lib.mkOverride 999 true;
|
||||||
|
|
||||||
|
# https://github.com/NixOS/nixpkgs/issues/258371#issuecomment-2271967113
|
||||||
|
systemd.services.forgejo.serviceConfig.Type = lib.mkForce "exec";
|
||||||
|
|
||||||
|
shb.nginx.vhosts = [{
|
||||||
|
inherit (cfg) domain subdomain ssl;
|
||||||
|
upstream = "http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}";
|
||||||
|
}];
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.enable {
|
||||||
|
services.forgejo.database = {
|
||||||
|
type = "postgres";
|
||||||
|
|
||||||
|
passwordFile = cfg.databasePasswordFile;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.enable {
|
||||||
|
services.forgejo.dump = {
|
||||||
|
enable = true;
|
||||||
|
type = "tar.gz";
|
||||||
|
interval = "hourly";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# For Forgejo setup: https://github.com/lldap/lldap/blob/main/example_configs/gitea.md
|
||||||
|
# For cli info: https://docs.gitea.com/usage/command-line
|
||||||
|
# Security protocols in: https://codeberg.org/forgejo/forgejo/src/branch/forgejo/services/auth/source/ldap/security_protocol.go#L27-L31
|
||||||
|
(lib.mkIf (cfg.enable && cfg.ldap.enable != false) {
|
||||||
|
# The delimiter in the `cut` command is a TAB!
|
||||||
|
systemd.services.forgejo.preStart = let
|
||||||
|
provider = "SHB-${cfg.ldap.provider}";
|
||||||
|
in ''
|
||||||
|
auth="${lib.getExe config.services.forgejo.package} admin auth"
|
||||||
|
|
||||||
|
echo "Trying to find existing ldap configuration for ${provider}"...
|
||||||
|
set +e -o pipefail
|
||||||
|
id="$($auth list | grep "${provider}.*LDAP" | cut -d' ' -f1)"
|
||||||
|
found=$?
|
||||||
|
set -e +o pipefail
|
||||||
|
|
||||||
|
if [[ $found = 0 ]]; then
|
||||||
|
echo Found ldap configuration at id=$id, updating it if needed.
|
||||||
|
$auth update-ldap \
|
||||||
|
--id $id \
|
||||||
|
--name ${provider} \
|
||||||
|
--host ${cfg.ldap.host} \
|
||||||
|
--port ${toString cfg.ldap.port} \
|
||||||
|
--bind-dn uid=${cfg.ldap.adminName},ou=people,${cfg.ldap.dcdomain} \
|
||||||
|
--bind-password $(tr -d '\n' < ${cfg.ldap.adminPasswordFile}) \
|
||||||
|
--security-protocol Unencrypted \
|
||||||
|
--user-search-base ou=people,${cfg.ldap.dcdomain} \
|
||||||
|
--user-filter '(&(memberof=cn=${cfg.ldap.userGroup},ou=groups,${cfg.ldap.dcdomain})(|(uid=%[1]s)(mail=%[1]s)))' \
|
||||||
|
--admin-filter '(memberof=cn=${cfg.ldap.adminGroup},ou=groups,${cfg.ldap.dcdomain})' \
|
||||||
|
--username-attribute uid \
|
||||||
|
--firstname-attribute givenName \
|
||||||
|
--surname-attribute sn \
|
||||||
|
--email-attribute mail \
|
||||||
|
--avatar-attribute jpegPhoto \
|
||||||
|
--synchronize-users
|
||||||
|
echo "Done updating LDAP configuration."
|
||||||
|
else
|
||||||
|
echo Did not find any ldap configuration, creating one with name ${provider}.
|
||||||
|
$auth add-ldap \
|
||||||
|
--name ${provider} \
|
||||||
|
--host ${cfg.ldap.host} \
|
||||||
|
--port ${toString cfg.ldap.port} \
|
||||||
|
--bind-dn uid=${cfg.ldap.adminName},ou=people,${cfg.ldap.dcdomain} \
|
||||||
|
--bind-password $(tr -d '\n' < ${cfg.ldap.adminPasswordFile}) \
|
||||||
|
--security-protocol Unencrypted \
|
||||||
|
--user-search-base ou=people,${cfg.ldap.dcdomain} \
|
||||||
|
--user-filter '(&(memberof=cn=${cfg.ldap.userGroup},ou=groups,${cfg.ldap.dcdomain})(|(uid=%[1]s)(mail=%[1]s)))' \
|
||||||
|
--admin-filter '(memberof=cn=${cfg.ldap.adminGroup},ou=groups,${cfg.ldap.dcdomain})' \
|
||||||
|
--username-attribute uid \
|
||||||
|
--firstname-attribute givenName \
|
||||||
|
--surname-attribute sn \
|
||||||
|
--email-attribute mail \
|
||||||
|
--avatar-attribute jpegPhoto \
|
||||||
|
--synchronize-users
|
||||||
|
echo "Done adding LDAP configuration."
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
|
||||||
|
# For Authelia to Forgejo integration: https://www.authelia.com/integration/openid-connect/gitea/
|
||||||
|
# For Forgejo config: https://forgejo.org/docs/latest/admin/config-cheat-sheet
|
||||||
|
# For cli info: https://docs.gitea.com/usage/command-line
|
||||||
|
(lib.mkIf (cfg.enable && cfg.sso.enable != false) {
|
||||||
|
services.forgejo.settings = {
|
||||||
|
oauth2 = {
|
||||||
|
ENABLED = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
openid = {
|
||||||
|
ENABLE_OPENID_SIGNIN = false;
|
||||||
|
ENABLE_OPENID_SIGNUP = true;
|
||||||
|
WHITELISTED_URIS = cfg.sso.endpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
service = {
|
||||||
|
# DISABLE_REGISTRATION = lib.mkForce false;
|
||||||
|
# ALLOW_ONLY_EXTERNAL_REGISTRATION = false;
|
||||||
|
SHOW_REGISTRATION_BUTTON = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# The delimiter in the `cut` command is a TAB!
|
||||||
|
systemd.services.forgejo.preStart = let
|
||||||
|
provider = "SHB-${cfg.sso.provider}";
|
||||||
|
in ''
|
||||||
|
auth="${lib.getExe config.services.forgejo.package} admin auth"
|
||||||
|
|
||||||
|
echo "Trying to find existing sso configuration for ${provider}"...
|
||||||
|
set +e -o pipefail
|
||||||
|
id="$($auth list | grep "${provider}.*OAuth2" | cut -d' ' -f1)"
|
||||||
|
found=$?
|
||||||
|
set -e +o pipefail
|
||||||
|
|
||||||
|
if [[ $found = 0 ]]; then
|
||||||
|
echo Found sso configuration at id=$id, updating it if needed.
|
||||||
|
$auth update-oauth \
|
||||||
|
--id $id \
|
||||||
|
--name ${provider} \
|
||||||
|
--provider openidConnect \
|
||||||
|
--key forgejo \
|
||||||
|
--secret $(tr -d '\n' < ${cfg.sso.secretFile}) \
|
||||||
|
--auto-discover-url ${cfg.sso.endpoint}/.well-known/openid-configuration
|
||||||
|
else
|
||||||
|
echo Did not find any sso configuration, creating one with name ${provider}.
|
||||||
|
$auth add-oauth \
|
||||||
|
--name ${provider} \
|
||||||
|
--provider openidConnect \
|
||||||
|
--key forgejo \
|
||||||
|
--secret $(tr -d '\n' < ${cfg.sso.secretFile}) \
|
||||||
|
--auto-discover-url ${cfg.sso.endpoint}/.well-known/openid-configuration
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
shb.authelia.oidcClients = lib.lists.optionals (!(isNull cfg.sso)) [
|
||||||
|
(let
|
||||||
|
provider = "SHB-${cfg.sso.provider}";
|
||||||
|
in {
|
||||||
|
client_id = cfg.sso.clientID;
|
||||||
|
client_name = "Forgejo";
|
||||||
|
client_secret.source = cfg.sso.secretFileForAuthelia;
|
||||||
|
public = false;
|
||||||
|
authorization_policy = cfg.sso.authorization_policy;
|
||||||
|
redirect_uris = [ "https://${cfg.subdomain}.${cfg.domain}/user/oauth2/${provider}/callback" ];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.enable {
|
||||||
|
systemd.services.forgejo.preStart = ''
|
||||||
|
admin="${lib.getExe config.services.forgejo.package} admin user"
|
||||||
|
$admin create --admin --email "root@localhost" --username meadmin --password "$(tr -d '\n' < ${cfg.adminPasswordFile})" || true
|
||||||
|
$admin change-password --username meadmin --password "$(tr -d '\n' < ${cfg.adminPasswordFile})" || true
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf (cfg.enable && cfg.smtp != null) {
|
||||||
|
services.forgejo.settings.mailer = {
|
||||||
|
ENABLED = true;
|
||||||
|
SMTP_ADDR = "${cfg.smtp.host}:${toString cfg.smtp.port}";
|
||||||
|
FROM = cfg.smtp.from_address;
|
||||||
|
USER = cfg.smtp.username;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.forgejo.mailerPasswordFile = cfg.smtp.passwordFile;
|
||||||
|
})
|
||||||
|
|
||||||
|
# https://wiki.nixos.org/wiki/Forgejo#Runner
|
||||||
|
(lib.mkIf cfg.enable {
|
||||||
|
services.forgejo.settings.actions = {
|
||||||
|
ENABLED = true;
|
||||||
|
DEFAULT_ACTIONS_URL = "github";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea-actions-runner = lib.mkIf cfg.localActionRunner {
|
||||||
|
package = pkgs.forgejo-actions-runner;
|
||||||
|
instances.local = {
|
||||||
|
enable = true;
|
||||||
|
name = "local";
|
||||||
|
url = let
|
||||||
|
protocol = if cfg.ssl != null then "https" else "http";
|
||||||
|
in "${protocol}://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
tokenFile = ""; # Empty variable to satisfy an assertion.
|
||||||
|
labels = [
|
||||||
|
# "ubuntu-latest:docker://node:16-bullseye"
|
||||||
|
# "ubuntu-22.04:docker://node:16-bullseye"
|
||||||
|
# "ubuntu-20.04:docker://node:16-bullseye"
|
||||||
|
# "ubuntu-18.04:docker://node:16-buster"
|
||||||
|
"native:host"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# This combined with the next statement takes care of
|
||||||
|
# automatically registering a forgejo runner.
|
||||||
|
systemd.services.forgejo.postStart = lib.mkIf cfg.localActionRunner (lib.mkBefore ''
|
||||||
|
${pkgs.bash}/bin/bash -c '(while ! ${pkgs.netcat-openbsd}/bin/nc -z -U ${config.services.forgejo.settings.server.HTTP_ADDR}; do echo "Waiting for unix ${config.services.forgejo.settings.server.HTTP_ADDR} to open..."; sleep 2; done); sleep 2'
|
||||||
|
actions="${lib.getExe config.services.forgejo.package} actions"
|
||||||
|
echo -n TOKEN= > /run/forgejo/forgejo-runner-token
|
||||||
|
$actions generate-runner-token >> /run/forgejo/forgejo-runner-token
|
||||||
|
'');
|
||||||
|
|
||||||
|
systemd.services.gitea-runner-local.serviceConfig = {
|
||||||
|
# LoadCredential = "TOKEN_FILE:/run/forgejo/forgejo-runner-token";
|
||||||
|
# EnvironmentFile = [ "$CREDENTIALS_DIRECTORY/TOKEN_FILE" ];
|
||||||
|
EnvironmentFile = [ "/run/forgejo/forgejo-runner-token" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.gitea-runner-local.wants = [ "forgejo.service" ];
|
||||||
|
systemd.services.gitea-runner-local.after = [ "forgejo.service" ];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
245
modules/services/forgejo/docs/default.md
Normal file
245
modules/services/forgejo/docs/default.md
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
# Forgejo Service {#services-forgejo}
|
||||||
|
|
||||||
|
Defined in [`/modules/services/forgejo.nix`](@REPO@/modules/services/forgejo.nix).
|
||||||
|
|
||||||
|
This NixOS module is a service that sets up a [Forgejo](https://forgejo.org/) instance.
|
||||||
|
|
||||||
|
Compared to the stock module from nixpkgs,
|
||||||
|
this one sets up, in a fully declarative manner,
|
||||||
|
LDAP and SSO integration as well as one local runner.
|
||||||
|
|
||||||
|
## Features {#services-forgejo-features}
|
||||||
|
|
||||||
|
- Declarative [LDAP](#services-forgejo-options-shb.forgejo.ldap) Configuration. [Manual](#services-forgejo-usage-ldap).
|
||||||
|
- Declarative [SSO](#services-forgejo-options-shb.forgejo.sso) Configuration. [Manual](#services-forgejo-usage-sso).
|
||||||
|
- Declarative [local runner](#services-forgejo-options-shb.forgejo.localActionRunner) Configuration.
|
||||||
|
- Access through [subdomain](#services-forgejo-options-shb.forgejo.subdomain) using reverse proxy. [Manual](#services-forgejo-usage-basic).
|
||||||
|
- Access through [HTTPS](#services-forgejo-options-shb.forgejo.ssl) using reverse proxy. [Manual](#services-forgejo-usage-basic).
|
||||||
|
- [Backup](#services-forgejo-options-shb.forgejo.sso) through the [backup block](./blocks-backup.html) with the . [Manual](#services-forgejo-usage-backup).
|
||||||
|
|
||||||
|
## Usage {#services-forgejo-usage}
|
||||||
|
|
||||||
|
### Secrets {#services-forgejo-secrets}
|
||||||
|
|
||||||
|
All the secrets should be readable by the forgejo user.
|
||||||
|
|
||||||
|
Secrets should not be stored in the nix store.
|
||||||
|
If you're using [sops-nix](https://github.com/Mic92/sops-nix)
|
||||||
|
and assuming your secrets file is located at `./secrets.yaml`,
|
||||||
|
you can define a secret with:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
sops.secrets."forgejo/adminPasswordFile" = {
|
||||||
|
sopsFile = ./secrets.yaml;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "forgejo";
|
||||||
|
group = "forgejo";
|
||||||
|
restartUnits = [ "forgejo.service" ];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can use that secret:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.forgejo.adminPasswordFile = config.sops.secrets."forgejo/adminPasswordFile".path;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forgejo through HTTP(S) {#services-forgejo-usage-basic}
|
||||||
|
|
||||||
|
This will set up a Forgejo service that runs on the NixOS target machine,
|
||||||
|
reachable at `http://forgejo.example.com`.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.forgejo = {
|
||||||
|
enable = true;
|
||||||
|
domain = "example.com";
|
||||||
|
subdomain = "forgejo";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
If the `shb.ssl` block is used (see [manual](blocks-ssl.html#usage) on how to set it up),
|
||||||
|
the instance will be reachable at `https://fogejo.example.com`.
|
||||||
|
|
||||||
|
Here is an example with self-signed certificates:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.certs = {
|
||||||
|
cas.selfsigned.myca = {
|
||||||
|
name = "My CA";
|
||||||
|
};
|
||||||
|
certs.selfsigned = {
|
||||||
|
foregejo = {
|
||||||
|
ca = config.shb.certs.cas.selfsigned.myca;
|
||||||
|
domain = "forgejo.example.com";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can tell Forgejo to use those certificates.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.forgejo = {
|
||||||
|
ssl = config.shb.certs.certs.selfsigned.forgejo;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### With LDAP Support {#services-forgejo-usage-ldap}
|
||||||
|
|
||||||
|
:::: {.note}
|
||||||
|
We will build upon the [Forgejo through HTTP(S)](#services-forgejo-usage-basic) section,
|
||||||
|
so please follow that first.
|
||||||
|
::::
|
||||||
|
|
||||||
|
We will use the LDAP block provided by Self Host Blocks
|
||||||
|
to setup a [LLDAP](https://github.com/lldap/lldap) service.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.ldap = {
|
||||||
|
enable = true;
|
||||||
|
domain = "example.com";
|
||||||
|
subdomain = "ldap";
|
||||||
|
ldapPort = 3890;
|
||||||
|
webUIListenPort = 17170;
|
||||||
|
dcdomain = "dc=example,dc=com";
|
||||||
|
ldapUserPasswordFile = <path/to/ldapUserPasswordSecret>;
|
||||||
|
jwtSecretFile = <path/to/ldapJwtSecret>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
We also need to configure the `forgejo` service
|
||||||
|
to talk to the LDAP server we just defined:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.forgejo.ldap
|
||||||
|
enable = true;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = config.shb.ldap.ldapPort;
|
||||||
|
dcdomain = config.shb.ldap.dcdomain;
|
||||||
|
adminPasswordFile = <path/to/ldapUserPasswordSecret>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `shb.forgejo.ldap.adminPasswordFile` must be the same
|
||||||
|
as the `shb.ldap.ldapUserPasswordFile`.
|
||||||
|
The other secrets can be randomly generated with
|
||||||
|
`nix run nixpkgs#openssl -- rand -hex 64`.
|
||||||
|
|
||||||
|
And that's it.
|
||||||
|
Now, go to the LDAP server at `http://ldap.example.com`,
|
||||||
|
create the `forgejo_user` and `forgejo_admin` groups,
|
||||||
|
create a user and add it to one or both groups.
|
||||||
|
When that's done, go back to the Forgejo server at
|
||||||
|
`http://forgejo.example.com` and login with that user.
|
||||||
|
|
||||||
|
### With SSO Support {#services-forgejo-usage-sso}
|
||||||
|
|
||||||
|
:::: {.note}
|
||||||
|
We will build upon the [With LDAP Support](#services-forgejo-usage-ldap) section,
|
||||||
|
so please follow that first.
|
||||||
|
::::
|
||||||
|
|
||||||
|
Here though, we must setup SSL certificates
|
||||||
|
because the SSO provider only works with the https protocol.
|
||||||
|
Let's add self-signed certificates for Authelia and LLDAP:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.certs = {
|
||||||
|
certs.selfsigned = {
|
||||||
|
auth = {
|
||||||
|
ca = config.shb.certs.cas.selfsigned.myca;
|
||||||
|
domain = "auth.example.com";
|
||||||
|
};
|
||||||
|
ldap = {
|
||||||
|
ca = config.shb.certs.cas.selfsigned.myca;
|
||||||
|
domain = "ldap.example.com";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
We then need to setup the SSO provider,
|
||||||
|
here Authelia thanks to the corresponding SHB block:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.authelia = {
|
||||||
|
enable = true;
|
||||||
|
domain = "example.com";
|
||||||
|
subdomain = "auth";
|
||||||
|
ssl = config.shb.certs.certs.selfsigned.auth;
|
||||||
|
|
||||||
|
ldapHostname = "127.0.0.1";
|
||||||
|
ldapPort = config.shb.ldap.ldapPort;
|
||||||
|
dcdomain = config.shb.ldap.dcdomain;
|
||||||
|
|
||||||
|
secrets = {
|
||||||
|
jwtSecretFile = <path/to/autheliaJwtSecret>;
|
||||||
|
ldapAdminPasswordFile = <path/to/ldapUserPasswordSecret>;
|
||||||
|
sessionSecretFile = <path/to/autheliaSessionSecret>;
|
||||||
|
storageEncryptionKeyFile = <path/to/autheliaStorageEncryptionKeySecret>;
|
||||||
|
identityProvidersOIDCHMACSecretFile = <path/to/providersOIDCHMACSecret>;
|
||||||
|
identityProvidersOIDCIssuerPrivateKeyFile = <path/to/providersOIDCIssuerSecret>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `shb.authelia.secrets.ldapAdminPasswordFile` must be the same
|
||||||
|
as the `shb.ldap.ldapUserPasswordFile` defined in the previous section.
|
||||||
|
The other secrets can be randomly generated
|
||||||
|
with `nix run nixpkgs#openssl -- rand -hex 64`.
|
||||||
|
|
||||||
|
Now, on the forgejo side, you need to add the following options:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.forgejo.sso = {
|
||||||
|
enable = true;
|
||||||
|
endpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
|
||||||
|
secretFile = <path/to/oidcForgejoSharedSecret>;
|
||||||
|
secretFileForAuthelia = <path/to/oidcForgejoSharedSecret>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Passing the `ssl` option will auto-configure nginx to force SSL connections with the given
|
||||||
|
certificate.
|
||||||
|
|
||||||
|
The `shb.foregejo.sso.secretFile` and `shb.forgejo.sso.secretFileForAuthelia` options
|
||||||
|
must have the same content. The former is a file that must be owned by the `forgejo` user while
|
||||||
|
the latter must be owned by the `authelia` user. I want to avoid needing to define the same secret
|
||||||
|
twice with a future secrets SHB block.
|
||||||
|
|
||||||
|
### Backup {#services-forgejo-usage-backup}
|
||||||
|
|
||||||
|
Backing up Forgejo using the [Restic block](blocks-restic.html) is done like so:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
shb.restic.instances."forgejo" = config.shb.forgejo.backup // {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The name `"foregjo"` in the `instances` can be anything.
|
||||||
|
The `config.shb.forgejo.backup` option provides what directories to backup.
|
||||||
|
You can define any number of Restic instances to backup Foregejo multiple times.
|
||||||
|
|
||||||
|
### Extra Settings {#services-forgejo-usage-extra-settings}
|
||||||
|
|
||||||
|
Other Forgejo settings can be accessed through the nixpkgs [stock service][].
|
||||||
|
|
||||||
|
[stock service]: https://search.nixos.org/options?channel=24.05&from=0&size=50&sort=alpha_asc&type=packages&query=services.forgejo
|
||||||
|
|
||||||
|
## Debug {#services-forgejo-debug}
|
||||||
|
|
||||||
|
In case of an issue, check the logs for systemd service `forgejo.service`.
|
||||||
|
|
||||||
|
Enable verbose logging by setting the `shb.forgejo.debug` boolean to `true`.
|
||||||
|
|
||||||
|
Access the database with `sudo -u forgejo psql`.
|
||||||
|
|
||||||
|
## Options Reference {#services-forgejo-options}
|
||||||
|
|
||||||
|
```{=include=} options
|
||||||
|
id-prefix: services-forgejo-options-
|
||||||
|
list-id: selfhostblocks-service-forgejo-options
|
||||||
|
source: @OPTIONS_JSON@
|
||||||
|
```
|
|
@ -112,6 +112,12 @@ in
|
||||||
default = "jellyfin_user";
|
default = "jellyfin_user";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
authorization_policy = lib.mkOption {
|
||||||
|
type = lib.types.enum [ "one_factor" "two_factor" ];
|
||||||
|
description = "Require one factor (password) or two factor (device) authentication.";
|
||||||
|
default = "one_factor";
|
||||||
|
};
|
||||||
|
|
||||||
secretFile = lib.mkOption {
|
secretFile = lib.mkOption {
|
||||||
type = lib.types.path;
|
type = lib.types.path;
|
||||||
description = "File containing the OIDC shared secret.";
|
description = "File containing the OIDC shared secret.";
|
||||||
|
@ -419,7 +425,7 @@ in
|
||||||
client_name = "Jellyfin";
|
client_name = "Jellyfin";
|
||||||
client_secret.source = cfg.sso.secretFile;
|
client_secret.source = cfg.sso.secretFile;
|
||||||
public = false;
|
public = false;
|
||||||
authorization_policy = "one_factor";
|
authorization_policy = cfg.sso.authorization_policy;
|
||||||
redirect_uris = [ "https://${cfg.subdomain}.${cfg.domain}/sso/OID/r/${cfg.sso.provider}" ];
|
redirect_uris = [ "https://${cfg.subdomain}.${cfg.domain}/sso/OID/r/${cfg.sso.provider}" ];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
145
test/services/forgejo.nix
Normal file
145
test/services/forgejo.nix
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
pkgs' = pkgs;
|
||||||
|
|
||||||
|
testLib = pkgs.callPackage ../common.nix {};
|
||||||
|
|
||||||
|
subdomain = "f";
|
||||||
|
domain = "example.com";
|
||||||
|
|
||||||
|
adminPassword = "AdminPassword";
|
||||||
|
|
||||||
|
commonTestScript = testLib.accessScript {
|
||||||
|
inherit subdomain domain;
|
||||||
|
hasSSL = { node, ... }: !(isNull node.config.shb.forgejo.ssl);
|
||||||
|
waitForServices = { ... }: [
|
||||||
|
"forgejo.service"
|
||||||
|
"nginx.service"
|
||||||
|
];
|
||||||
|
waitForUnixSocket = { node, ... }: [
|
||||||
|
node.config.services.forgejo.settings.server.HTTP_ADDR
|
||||||
|
];
|
||||||
|
extraScript = { node, ... }: ''
|
||||||
|
server.wait_for_unit("gitea-runner-local.service", timeout=10)
|
||||||
|
server.succeed("journalctl -o cat -u gitea-runner-local.service | grep -q 'Runner registered successfully'")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
base = testLib.base pkgs' [
|
||||||
|
../../modules/services/forgejo.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
basic = {
|
||||||
|
shb.forgejo = {
|
||||||
|
enable = true;
|
||||||
|
inherit domain subdomain;
|
||||||
|
|
||||||
|
adminPasswordFile = pkgs.writeText "adminPasswordFile" adminPassword;
|
||||||
|
databasePasswordFile = pkgs.writeText "databasePassword" "databasePassword";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Needed for gitea-runner-local to be able to ping forgejo.
|
||||||
|
networking.hosts = {
|
||||||
|
"127.0.0.1" = [ "${subdomain}.${domain}" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
https = { config, ... }: {
|
||||||
|
shb.forgejo = {
|
||||||
|
ssl = config.shb.certs.certs.selfsigned.n;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap = { config, ... }: {
|
||||||
|
shb.forgejo = {
|
||||||
|
ldap = {
|
||||||
|
enable = true;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = config.shb.ldap.ldapPort;
|
||||||
|
dcdomain = config.shb.ldap.dcdomain;
|
||||||
|
adminPasswordFile = config.shb.ldap.ldapUserPasswordFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = { config, ... }: {
|
||||||
|
shb.forgejo = {
|
||||||
|
sso = {
|
||||||
|
enable = true;
|
||||||
|
endpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
secretFile = pkgs.writeText "ssoSecretFile" "ssoSecretFile";
|
||||||
|
secretFileForAuthelia = pkgs.writeText "ssoSecretFile" "ssoSecretFile";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
basic = pkgs.testers.runNixOSTest {
|
||||||
|
name = "forgejo_basic";
|
||||||
|
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
base
|
||||||
|
basic
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
|
||||||
|
testScript = commonTestScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
https = pkgs.testers.runNixOSTest {
|
||||||
|
name = "forgejo_https";
|
||||||
|
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
base
|
||||||
|
(testLib.certs domain)
|
||||||
|
basic
|
||||||
|
https
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
|
||||||
|
testScript = commonTestScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap = pkgs.testers.runNixOSTest {
|
||||||
|
name = "forgejo_ldap";
|
||||||
|
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
base
|
||||||
|
basic
|
||||||
|
(testLib.ldap domain pkgs')
|
||||||
|
ldap
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
|
||||||
|
testScript = commonTestScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = pkgs.testers.runNixOSTest {
|
||||||
|
name = "forgejo_sso";
|
||||||
|
|
||||||
|
nodes.server = { config, pkgs, ... }: {
|
||||||
|
imports = [
|
||||||
|
base
|
||||||
|
(testLib.certs domain)
|
||||||
|
basic
|
||||||
|
https
|
||||||
|
(testLib.ldap domain pkgs')
|
||||||
|
(testLib.sso domain pkgs' config.shb.certs.certs.selfsigned.n)
|
||||||
|
sso
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
|
||||||
|
testScript = commonTestScript;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue