Merge pull request 'zitadel' (#2) from zitadel into master

Reviewed-on: #2
This commit is contained in:
Jurn Wubben 2025-07-24 21:45:31 +00:00
commit f7fc9b1e6a
11 changed files with 283 additions and 131 deletions

0
.locksverify Normal file
View file

View file

@ -1,40 +1,46 @@
{config, ...}: let {
config,
lib,
...
}: let
inherit (lib) mkIf;
inherit (config.niksos) server;
serviceUser = x: config.systemd.services.${x}.serviceConfig.User; serviceUser = x: config.systemd.services.${x}.serviceConfig.User;
abstrServiceUser = x: config.services.${x}.user;
abstrServiceGroup = x: config.services.${x}.group;
in { in {
age.secrets = { age.secrets = {
transferSh = {
file = ./transfer-sh.age;
owner = "jsw";
};
dcbot = {
file = ./dcbot.age;
owner =
if config.niksos.server
then serviceUser "dcbot" # "dcbot" doesn't exist on e.g laptop.
else "root";
};
bread-dcbot = {
file = ./bread-dcbot.age;
owner =
if config.niksos.server
then serviceUser "bread-dcbot" # "dcbot" doesn't exist on e.g laptop.
else "root";
};
password.file = ./password.age; password.file = ./password.age;
matrix-registration = {
file = ./matrix-registration.age; # NOTE: server things
owner = dcbot = mkIf server {
if config.niksos.server file = ./dcbot.age;
then config.services.matrix-continuwuity.user owner = serviceUser "dcbot"; #
else "root";
}; };
cloudflare-acme.file = ./cloudflare-acme.age; bread-dcbot = mkIf server {
mail-admin = { file = ./bread-dcbot.age;
# owner = #FIXME: revert when stopped using docker for stalwart. owner = "bread-dcbot";
# if config.niksos.server };
# then serviceUser "stalwart-mail" matrix-registration = mkIf server {
# else "root"; file = ./matrix-registration.age;
owner = abstrServiceUser "matrix-continuwuity";
};
mail-admin = mkIf server {
# owner = serviceUser "stalwart-mail"; #FIXME: revert when stopped using docker for stalwart.
file = ./mail-admin.age; file = ./mail-admin.age;
}; };
zitadel-key = mkIf server {
file = ./zitadel-key.age;
owner = abstrServiceUser "zitadel";
};
forgejo-mailpass = mkIf server {
file = ./forgejo-mailpass.age;
owner = abstrServiceUser "forgejo";
};
immich-oidc = mkIf server {
file = ./immich-oidc.age;
owner = abstrServiceUser "immich";
};
}; };
} }

View file

@ -0,0 +1,15 @@
age-encryption.org/v1
-> ssh-ed25519 GQzYWA j5yj1cq9FbYSW767zObF4RbJ7Jhx0818BryvWGWwnSw
LelnyL/SIat9BKl4hsz0n6rl8xPgchk+nQmfb1xkXkU
-> ssh-ed25519 MfR7VA sVGSrPd10dOdnDNROMGW1gLuczlVwMLpymgx6+cCJRE
8vf0ubRiRUWfc6Mgt0bNq99SgrY4pYJ0f4BHVRn+lYU
-> ssh-ed25519 +cvRTg VK4bHTmw+Oz7JLdP0zEbfKTjNUBtVxcbHX4zyZrQxx4
1BjqL4TuNJO8VH9c2MT24ZlGz8ifniUZaK4AkK4VjM4
-> ssh-ed25519 WCPLrA lD5KmpPXdvmTGMXMhye/ivnkbb0+XRCpUA4i6JBsK2w
0LKCxV8vSewkNOLJa+xEZp4w+qIRAVezv37g6hExpb0
-> ssh-ed25519 7/ziYw Yq6qqosp/yOekCO7NBpNTJQVv8NciaSLiDFNuLaOjyA
8Joor9/H+ExdOQBavTMH13SI9MZgBKQQA2HPxKAF9uU
-> ssh-ed25519 VQy60Q /+R2djdRbYoWq1GzMFSj+gwXGf085axPJHOa0tIeFTs
dBVQQ7yucfpbmeR82Fp6MR1/IiQun3bqNVCm9qegL2g
--- fHjHEH5JtSZnKnJFC/KDQELHDwVsExA5aeuKN7DvL1M
ªóAHñæ¥?Û '‰ah·Ç·¹<C2B7>âÂPñ>"/Þy†ûR¯<52>Æ„!I ¾G4äÙº^iXÄ}a:

15
secrets/immich-oidc.age Normal file
View file

@ -0,0 +1,15 @@
age-encryption.org/v1
-> ssh-ed25519 GQzYWA MbczMCSPu7pJru1rmOsFuloCYLKlh7koC5drXcKlwiw
ZghUrcs7YT3ciwqOkrPDEzlZe3qN9ypBw3xRGYWNPaY
-> ssh-ed25519 MfR7VA KB6RE2QZ//Z6xoyQC502dJeg79rYXFJJdOwV+c6tOWo
e1zIz2nsV9JbBaadTnONrPLI5Ztyv9vf4Ewzd9uSHnU
-> ssh-ed25519 +cvRTg GntHLoUwpIrxm3FcVw+Bavaq6kLaZpVdTRLoMMVfpAY
abE1ZkhS39vylBg8bZ5K3vgnXr70Vbk1bLCKsCFlUvU
-> ssh-ed25519 WCPLrA +/GlB5CbM/1FwI5JE63DJVUChADjJfD3jJY3Y2KmXEU
pPqBhV49/wg/hWffFm2XFRGC9p1nQ57tj1YK7pPkQ3U
-> ssh-ed25519 7/ziYw lxlJVNMIqfoMPj6VGTt2V4PxFi+6WRMfOYcv1hpEMkM
kd8CI7RECJA5uPJu33D61OEnqWwZuNQ6VmYLqXew6gc
-> ssh-ed25519 VQy60Q YSgYVPPN7QutKhbv6/1vmoRnh14KXs0g2k9qxKuvQ2U
FL3fImxWoBeHrCLd+jp/a1oRd/Acgi6sV/g40dCRrTA
--- TipdjwDPkRxiV/R1FUYCm/tcD6M+XEaZhQjrzwMxiuA
証E%キZDケ<44>Ts<54>,リ5ノ<>LタO<EFBE80>ソzエァア<>クT<>Θ <0B>煖_蕘熙H演始ロナ*ヤxQ7$釉淸v`W<04>瀲t%<25>6 <0C>5

View file

@ -18,6 +18,8 @@ in {
"dcbot.age".publicKeys = keys; "dcbot.age".publicKeys = keys;
"bread-dcbot.age".publicKeys = keys; "bread-dcbot.age".publicKeys = keys;
"matrix-registration.age".publicKeys = keys; "matrix-registration.age".publicKeys = keys;
"cloudflare-acme.age".publicKeys = keys;
"mail-admin.age".publicKeys = keys; "mail-admin.age".publicKeys = keys;
"zitadel-key.age".publicKeys = keys;
"forgejo-mailpass.age".publicKeys = keys;
"immich-oidc.age".publicKeys = keys;
} }

15
secrets/zitadel-key.age Normal file
View file

@ -0,0 +1,15 @@
age-encryption.org/v1
-> ssh-ed25519 GQzYWA YUoGdx518q+GhqnOVeuHxWE4//2KgVTXJCu4ULUkly8
XIxa/FaGC5XBcrsvhZq5rOgX5vNDfFvcDCsamN7vHJ8
-> ssh-ed25519 MfR7VA 9btD5WmqZdQ54uJYVNwU3Z5DBIlACbYfqGe1wPZwd30
QecwT2R+BkQrGmorYcMuXHyy/TG7JjBdH2fp3W9zCBU
-> ssh-ed25519 +cvRTg UZnkgS+9oRLgEI/vdLFIAPbUG4V5iAuB4Z74D/quXzE
vxWJZI/SZKH1j8bnI4xC8+TIIANqMOkIDej+BWzDJwE
-> ssh-ed25519 WCPLrA OVnublQtCOFFo7+vcKGmCY3B3FkvLvQ6GaU7xMx8uQY
PuMamZqF3vCqgmpcTGQinIdbjOOpHtrmKfOXlL924Rk
-> ssh-ed25519 7/ziYw nYxpO5kaGDOyGUEFxryEhT0XqWf0Oc1RgprYaPjC33c
UseYaBeWvetviCf1FHncVNko86ji+GX9AdyDic2A1Og
-> ssh-ed25519 VQy60Q ok1oP3f7nWBd/6DyJFDnsv/Lb2/bwHY0cvmHI386IFM
t5rIZBUz5jav6tUo01ASMzYtHoW4+cKBZ2lzmxSI7IA
--- NZ9UXYlEIcw3VPFqDswXhSecW1zqcCeKivJoHC1zKA8
“JçëªÐqUÐ0¿]D_ÿ—Õ<>Óáz ´ž×¶S!-.t‰="†„ç·¿¸eÂ<KÈáéïö[

View file

@ -8,8 +8,8 @@
./index ./index
./mail.nix ./mail.nix
./matrix.nix ./matrix.nix
./seafile.nix
./temp.nix ./temp.nix
./zitadel.nix
]; ];
options.niksos.server = lib.mkEnableOption "server servcies (such as caddy)."; #TODO: per service option. options.niksos.server = lib.mkEnableOption "server servcies (such as caddy)."; #TODO: per service option.
} }

View file

@ -26,11 +26,32 @@ in {
ROOT_URL = "https://${DOMAIN}/"; ROOT_URL = "https://${DOMAIN}/";
HTTP_PORT = 9004; HTTP_PORT = 9004;
}; };
service.DISABLE_REGISTRATION = true; service = {
ENABLE_INTERNAL_SIGNIN = false;
# DISABLE_REGISTRATION = true;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
};
oauth2_client = {
ENABLE_AUTO_REGISTRATION = true;
};
"ui.meta" = {
AUTHOR = "JSW Git";
DESCRIPTION = "Personal GIT-Forgejo instance.";
};
actions = { actions = {
ENABLED = true; ENABLED = true;
DEFAULT_ACTIONS_URL = "github"; DEFAULT_ACTIONS_URL = "github";
}; };
mailer = {
ENABLED = true;
SUBJECT_PREFIX = "JSWGit";
PROTOCOL = "smtps";
SMTP_ADDR = "mail.jsw.tf"; #FIXME: replace with config... to stalwart setting once using stalwart nixos module.
SMTP_PORT = 465;
FROM = "git@jsw.tf";
USER = "git";
PASSWD_URI = "file:${config.age.secrets.forgejo-mailpass.path}";
};
}; };
}; };
}; };

View file

@ -1,61 +1,102 @@
{ {
config, config,
lib, lib,
pkgs,
... ...
}: let }: let
inherit (lib) mkIf mkForce mkDefault;
cfg = config.niksos.server; cfg = config.niksos.server;
oidcSubstitute = "*@#OPENIDCLIENTSECRET#@*";
config-dir = "/run/immich-conf";
url = "photos.jsw.tf";
httpsUrl = "https://" + url;
in { in {
services.immich = { config =
enable = cfg; mkIf cfg
{
users.users.${config.services.immich.user}.extraGroups = ["video" "render"];
services.caddy.virtualHosts.${url}.extraConfig = ''
reverse_proxy localhost:9002
'';
port = 9002; services.immich = mkIf cfg {
machine-learning.enable = false; enable = true;
settings = { port = 9002;
server.externalDomain = "https://photos.jsw.tf"; machine-learning.enable = false;
ffmpeg = {
crf = 23; accelerationDevices = mkDefault null;
threads = 0;
preset = "ultrafast"; #NOTE: immich doesn't support variables in their config file, so we have to subsitute ourselfs..
targetVideoCodec = "h264"; environment.IMMICH_CONFIG_FILE = mkForce "${config-dir}/immich.json";
acceptedVideoCodecs = [ settings = {
"h264" server.externalDomain = httpsUrl;
oauth = {
enabled = true;
autoLaunch = true;
autoRegister = true;
buttonText = "Login with JSWAuth";
clientId = "329735769805619570";
clientSecret = oidcSubstitute;
issuerUrl = "https://${config.services.zitadel.settings.ExternalDomain}/.well-known/openid-configuration";
mobileRedirectUri = "${httpsUrl}/api/oauth/mobile-redirect";
mobileOverrideEnabled = true;
};
passwordLogin.enabled = false;
ffmpeg = {
crf = 23;
threads = 0;
preset = "ultrafast";
targetVideoCodec = "h264";
acceptedVideoCodecs = [
"h264"
];
targetAudioCodec = "aac";
acceptedAudioCodecs = [
"aac"
"mp3"
"libopus"
"pcm_s16le"
];
acceptedContainers = [
"mov"
"ogg"
"webm"
];
targetResolution = "720";
maxBitrate = "0";
bframes = -1;
refs = 0;
gopSize = 0;
temporalAQ = false;
cqMode = "auto";
twoPass = false;
preferredHwDevice = lib.mkDefault "auto";
transcode = "all";
tonemap = "hable";
accel = lib.mkDefault "vaapi";
accelDecode = true;
};
};
};
systemd = {
services.immich-server = {
preStart = let
refConfig = (pkgs.formats.json {}).generate "immich.json" config.services.immich.settings;
newConfig = "${config-dir}/immich.json";
replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
in ''
umask 077
cp -f '${refConfig}' '${newConfig}'
chmod u+w '${newConfig}'
${replaceSecretBin} '${oidcSubstitute}' '${config.age.secrets.immich-oidc.path}' '${newConfig}'
'';
};
tmpfiles.rules = [
"d ${config-dir} 0700 immich immich"
]; ];
targetAudioCodec = "aac";
acceptedAudioCodecs = [
"aac"
"mp3"
"libopus"
"pcm_s16le"
];
acceptedContainers = [
"mov"
"ogg"
"webm"
];
targetResolution = "720";
maxBitrate = "0";
bframes = -1;
refs = 0;
gopSize = 0;
temporalAQ = false;
cqMode = "auto";
twoPass = false;
preferredHwDevice = lib.mkDefault "auto";
transcode = "all";
tonemap = "hable";
accel = lib.mkDefault "vaapi";
accelDecode = true;
}; };
}; };
accelerationDevices = lib.mkDefault null;
};
users.users.immich = lib.mkIf cfg {extraGroups = ["video" "render"];}; #NOTE: was first groups = lib.mkIf.. but then users.immich gets set even when server is disabled.
services.caddy.virtualHosts."photos.jsw.tf" = {
extraConfig = ''
reverse_proxy localhost:9002
'';
};
} }

View file

@ -1,49 +0,0 @@
{
config,
inputs,
pkgs,
...
}: {
services.seafile = {
enable = config.niksos.server;
seahubPackage = inputs.nixpkgs-stable.legacyPackages.${pkgs.system}.seahub;
adminEmail = "jurnwubben@gmail.com";
initialAdminPassword = "ChangeMeTheFuckNow!";
gc.enable = true;
ccnetSettings.General.SERVICE_URL = "https://files.jsw.tf";
seahubExtraConf = ''
ALLOWED_HOSTS = ['.files.jsw.tf']
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'Strict'
CSRF_TRUSTED_ORIGINS = ['https://files.jsw.tf', 'https://www.files.jsw.tf']
SITE_NAME = "JSW Cloud"
SITE_TITLE = "JSW Cloud"
'';
seafileSettings = {
quota.default = 30;
history.keep_days = 40;
library_trash.expire_days = 14;
fileserver = {
host = "unix:/run/seafile/server.sock";
web_token_expire_time = 14400; # 4 hours
max_download_dir_size = 100000; # 100gb max download size.
};
};
};
services.caddy.virtualHosts."files.jsw.tf" = {
# serverAliases = ["www.share.jsw.tf"];
extraConfig = ''
handle_path /seafhttp/* {
reverse_proxy * unix//run/seafile/server.sock
}
handle_path /* {
reverse_proxy * unix//run/seahub/gunicorn.sock
}
'';
};
}

86
system/server/zitadel.nix Normal file
View file

@ -0,0 +1,86 @@
{
config,
lib,
...
}: let
ExternalDomain = "z.jsw.tf";
Port = 9000;
in {
config =
lib.mkIf config.niksos.server
{
services.caddy.virtualHosts.${ExternalDomain}.extraConfig = ''
reverse_proxy localhost:${builtins.toString Port}
'';
# services.zitadel = {
# enable = true;
# masterKeyFile = config.age.secrets.zitadel-key.path;
# settings = {
# inherit Port ExternalDomain;
# ExternalPort = 443;
# };
# extraSettingsPaths = [config.age.secrets.zitadel.path];
# };
systemd.services.zitadel = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
services = {
zitadel = {
enable = true;
masterKeyFile = config.age.secrets.zitadel-key.path;
settings = {
inherit Port ExternalDomain;
ExternalPort = 443;
Database.postgres = {
Host = "/var/run/postgresql/";
Port = 5432;
Database = "zitadel";
User = {
Username = "zitadel";
SSL.Mode = "disable";
};
Admin = {
Username = "zitadel";
SSL.Mode = "disable";
ExistingDatabase = "zitadel";
};
};
ExternalSecure = true;
};
steps.FirstInstance = {
InstanceName = "jsw";
Org = {
Name = "jsw";
Human = {
UserName = "jsw@jsw.tf";
FirstName = "Jurn";
LastName = "Wubben";
Email.Verified = true;
Password = "Changeme1!";
PasswordChangeRequired = true;
};
};
LoginPolicy.AllowRegister = false;
};
openFirewall = true;
};
postgresql = {
enable = true;
enableJIT = true;
ensureDatabases = ["zitadel"];
ensureUsers = [
{
name = "zitadel";
ensureDBOwnership = true;
ensureClauses.login = true;
ensureClauses.superuser = true;
}
];
};
};
};
}