Rename modules directory system to nixos

This commit is contained in:
SebastianStork 2026-02-26 21:11:45 +01:00
parent 653a6f310b
commit 1c1b9221fc
Signed by: SebastianStork
SSH key fingerprint: SHA256:tRrGdjYOwgHxpSc/wTOZQZEjxcb15P0tyXRsbAfd+2Q
48 changed files with 1 additions and 1 deletions

View file

@ -0,0 +1,57 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.actualbudget;
inherit (config.services.actual.settings) dataDir;
in
{
options.custom.web-services.actualbudget = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 5006;
};
doBackups = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
users = {
users.actual = {
isSystemUser = true;
group = config.users.groups.actual.name;
};
groups.actual = { };
};
systemd.services.actual.serviceConfig = {
DynamicUser = lib.mkForce false;
PrivateTmp = true;
RemoveIPC = true;
};
services.actual = {
enable = true;
settings = {
hostname = "localhost";
inherit (cfg) port;
};
};
custom = {
services = {
caddy.virtualHosts.${cfg.domain}.port = cfg.port;
restic.backups.actual = lib.mkIf cfg.doBackups {
conflictingService = "actual.service";
paths = [ dataDir ];
};
};
persistence.directories = [ dataDir ];
};
};
}

View file

@ -0,0 +1,53 @@
{
config,
self,
lib,
...
}:
let
cfg = config.custom.web-services.filebrowser;
dataDir = "/var/lib/filebrowser";
in
{
options.custom.web-services.filebrowser = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 44093;
};
doBackups = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
assertions = lib.singleton {
assertion = self.lib.isPrivateDomain cfg.domain;
message = self.lib.mkUnprotectedMessage "Filebrowser";
};
services.filebrowser = {
enable = true;
settings = {
inherit (cfg) port;
noauth = true;
};
};
custom = {
services = {
caddy.virtualHosts.${cfg.domain}.port = cfg.port;
restic.backups.filebrowser = lib.mkIf cfg.doBackups {
conflictingService = "filebrowser.service";
paths = [ dataDir ];
};
};
persistence.directories = [ dataDir ];
};
};
}

View file

@ -0,0 +1,88 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.forgejo;
in
{
options.custom.web-services.forgejo = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 3003;
};
doBackups = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
users = {
users.git = {
isSystemUser = true;
useDefaultShell = true;
group = config.users.groups.git.name;
home = config.services.forgejo.stateDir;
};
groups.git = { };
};
services.forgejo = {
enable = true;
user = "git";
group = "git";
settings = {
server = {
DOMAIN = cfg.domain;
ROOT_URL = "https://${cfg.domain}/";
HTTP_PORT = cfg.port;
LANDING_PAGE = "/SebastianStork";
};
service.DISABLE_REGISTRATION = true;
session.PROVIDER = "db";
mirror.DEFAULT_INTERVAL = "1h";
other = {
SHOW_FOOTER_VERSION = false;
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
SHOW_FOOTER_POWERED_BY = false;
};
cron.ENABLED = true;
"cron.git_gc_repos".ENABLED = true;
repository.ENABLE_PUSH_CREATE_USER = true;
# https://forgejo.org/docs/latest/admin/recommendations
database.SQLITE_JOURNAL_MODE = "WAL";
cache = {
ADAPTER = "twoqueue";
HOST = lib.strings.toJSON {
size = 100;
recent_ratio = 0.25;
ghost_ratio = 0.5;
};
};
"repository.signing".DEFAULT_TRUST_MODEL = "committer";
security.LOGIN_REMEMBER_DAYS = 365;
};
};
# Create user: `forgejo-user create --admin --username NAME --email EMAIL --password PASSWORD`
environment.shellAliases.forgejo-user = "sudo --user=${config.services.forgejo.user} ${lib.getExe config.services.forgejo.package} admin user --config /var/lib/forgejo/custom/conf/app.ini";
custom = {
services = {
caddy.virtualHosts.${cfg.domain}.port = cfg.port;
restic.backups.forgejo = lib.mkIf cfg.doBackups {
conflictingService = "forgejo.service";
paths = [ config.services.forgejo.stateDir ];
};
};
persistence.directories = [ config.services.forgejo.stateDir ];
};
};
}

View file

@ -0,0 +1,54 @@
{
config,
self,
lib,
...
}:
let
cfg = config.custom.web-services.freshrss;
inherit (config.services.freshrss) dataDir;
in
{
options.custom.web-services.freshrss = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 22055;
};
doBackups = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
assertions = lib.singleton {
assertion = self.lib.isPrivateDomain cfg.domain;
message = self.lib.mkUnprotectedMessage "FreshRSS";
};
services.freshrss = {
enable = true;
baseUrl = "https://${cfg.domain}";
webserver = "caddy";
virtualHost = ":${toString cfg.port}";
defaultUser = "seb";
authType = "none";
};
custom = {
services = {
caddy.virtualHosts.${cfg.domain}.port = cfg.port;
restic.backups.freshrss = lib.mkIf cfg.doBackups {
conflictingService = "freshrss-updater.service";
paths = [ dataDir ];
};
};
persistence.directories = [ dataDir ];
};
};
}

View file

@ -0,0 +1,212 @@
{
config,
lib,
allHosts,
...
}:
let
cfg = config.custom.web-services.gatus;
dataDir = "/var/lib/gatus";
in
{
options.custom.web-services.gatus = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 8080;
};
ntfyUrl = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://${config.custom.web-services.ntfy.domain}";
};
generateDefaultEndpoints = lib.mkEnableOption "";
endpoints = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
enable = lib.mkEnableOption "" // {
default = true;
};
name = lib.mkOption {
type = lib.types.nonEmptyStr;
default = name;
};
group = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
protocol = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https";
};
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
path = lib.mkOption {
type = lib.types.str;
default = "";
};
interval = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "30s";
};
extraConditions = lib.mkOption {
type = lib.types.listOf lib.types.nonEmptyStr;
default = [ ];
};
enableAlerts = lib.mkEnableOption "" // {
default = true;
};
};
}
)
);
default = { };
};
};
config = lib.mkIf cfg.enable {
sops = {
secrets."healthchecks/ping-key" = { };
templates."gatus.env" = {
content = "HEALTHCHECKS_PING_KEY=${config.sops.placeholder."healthchecks/ping-key"}";
owner = config.users.users.gatus.name;
restartUnits = [ "gatus.service" ];
};
};
users = {
users.gatus = {
isSystemUser = true;
group = config.users.groups.gatus.name;
};
groups.gatus = { };
};
systemd.services.gatus.serviceConfig = {
DynamicUser = lib.mkForce false;
ProtectSystem = "strict";
ProtectHome = "read-only";
PrivateTmp = true;
RemoveIPC = true;
};
services.gatus = {
enable = true;
environmentFile = config.sops.templates."gatus.env".path;
settings = {
web = {
address = "localhost";
inherit (cfg) port;
};
storage = {
type = "sqlite";
path = "${dataDir}/data.db";
};
connectivity.checker.target = "1.1.1.1:53"; # Cloudflare DNS
alerting.ntfy = {
topic = "uptime";
url = cfg.ntfyUrl;
click = "https://${cfg.domain}";
default-alert = {
enable = true;
failure-threshold = 8;
success-threshold = 4;
send-on-resolved = true;
};
overrides = lib.singleton {
group = config.networking.hostName;
topic = "splitleaf";
url = "https://ntfy.sh";
default-alert = {
failure-threshold = 4;
success-threshold = 2;
};
};
};
ui.default-sort-by = "group";
maintenance = {
start = "03:00";
duration = "1h";
timezone = "Europe/Berlin";
};
endpoints =
let
mkEndpoint = endpoint: {
inherit (endpoint) name group interval;
url = "${endpoint.protocol}://${endpoint.domain}${endpoint.path}";
alerts = lib.mkIf endpoint.enableAlerts [ { type = "ntfy"; } ];
ssh = lib.mkIf (endpoint.protocol == "ssh") {
username = "";
password = "";
};
conditions = lib.concatLists [
endpoint.extraConditions
(lib.optional (lib.elem endpoint.protocol [
"http"
"https"
]) "[STATUS] == 200")
(lib.optional (lib.elem endpoint.protocol [
"tcp"
"ssh"
"icmp"
]) "[CONNECTED] == true")
];
};
in
cfg.endpoints |> lib.attrValues |> lib.filter (endpoint: endpoint.enable) |> lib.map mkEndpoint;
};
};
systemd.services.gatus.environment.GATUS_DELAY_START_SECONDS = "5";
custom = {
web-services.gatus.endpoints =
let
defaultEndpoints =
allHosts
|> lib.mapAttrs (
_: host:
host.config.custom.services.caddy.virtualHosts |> lib.attrValues |> lib.map (vHost: vHost.domain)
)
|> lib.concatMapAttrs (
hostName: domains:
domains
|> lib.filter (domain: domain != cfg.domain)
|> lib.map (
domain:
lib.nameValuePair domain {
inherit domain;
group = hostName;
}
)
|> lib.listToAttrs
);
in
lib.mkIf cfg.generateDefaultEndpoints (
defaultEndpoints
// {
"healthchecks.io" = {
group = "external";
domain = "hc-ping.com";
path = "/\${HEALTHCHECKS_PING_KEY}/${config.networking.hostName}-gatus-uptime?create=1";
interval = "2h";
};
}
);
services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
persistence.directories = [ dataDir ];
};
};
}

View file

@ -0,0 +1,180 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.custom.web-services.grafana;
in
{
options.custom.web-services.grafana = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 3000;
};
datasources = {
prometheus = {
enable = lib.mkEnableOption "" // {
default = config.custom.web-services.victoriametrics.enable;
};
url = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://${config.custom.web-services.victoriametrics.domain}";
};
};
victoriametrics = {
enable = lib.mkEnableOption "" // {
default = config.custom.web-services.victoriametrics.enable;
};
url = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://${config.custom.web-services.victoriametrics.domain}";
};
};
victorialogs = {
enable = lib.mkEnableOption "" // {
default = config.custom.web-services.victorialogs.enable;
};
url = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://${config.custom.web-services.victorialogs.domain}";
};
};
};
dashboards = {
nodeExporter.enable = lib.mkEnableOption "" // {
default = true;
};
victoriametrics.enable = lib.mkEnableOption "" // {
default = config.custom.web-services.victoriametrics.enable;
};
victorialogs.enable = lib.mkEnableOption "" // {
default = config.custom.web-services.victorialogs.enable;
};
};
};
config = lib.mkIf cfg.enable {
sops.secrets."grafana/admin-password" = {
owner = config.users.users.grafana.name;
restartUnits = [ "grafana.service" ];
};
services.grafana = {
enable = true;
settings = {
server = {
inherit (cfg) domain;
http_port = cfg.port;
enforce_domain = true;
enable_gzip = true;
};
security.admin_password = "$__file{${config.sops.secrets."grafana/admin-password".path}}";
users.default_theme = "system";
analytics.reporting_enabled = false;
};
provision = {
enable = true;
dashboards.settings = {
providers = lib.singleton {
name = "Dashboards";
options.path = "/etc/grafana-dashboards";
};
};
datasources.settings = {
prune = true;
datasources = [
(lib.mkIf cfg.datasources.prometheus.enable {
name = "Prometheus";
type = "prometheus";
inherit (cfg.datasources.prometheus) url;
isDefault = true;
jsonData = {
prometheusType = "Prometheus";
prometheusVersion = "2.50.0";
};
})
(lib.mkIf cfg.datasources.victoriametrics.enable {
name = "VictoriaMetrics";
type = "victoriametrics-metrics-datasource";
inherit (cfg.datasources.victoriametrics) url;
isDefault = false;
})
(lib.mkIf cfg.datasources.victorialogs.enable {
name = "VictoriaLogs";
type = "victoriametrics-logs-datasource";
inherit (cfg.datasources.victorialogs) url;
isDefault = false;
})
];
};
};
declarativePlugins =
let
plugins = pkgs.grafanaPlugins;
in
[
(lib.optional cfg.datasources.victoriametrics.enable plugins.victoriametrics-metrics-datasource)
(lib.optional cfg.datasources.victorialogs.enable plugins.victoriametrics-logs-datasource)
]
|> lib.concatLists;
};
environment.etc = {
# https://grafana.com/grafana/dashboards/1860-node-exporter-full/
"grafana-dashboards/node-exporter-full.json" = {
enable = cfg.dashboards.nodeExporter.enable;
source = pkgs.fetchurl {
name = "node-exporter-full.json";
url = "https://grafana.com/api/dashboards/1860/revisions/41/download";
hash = "sha256-EywgxEayjwNIGDvSmA/S56Ld49qrTSbIYFpeEXBJlTs=";
};
};
# https://grafana.com/grafana/dashboards/10229-victoriametrics-single-node/
"grafana-dashboards/victoriametrics-single-node-patched.json" = {
enable = cfg.dashboards.victoriametrics.enable;
source =
pkgs.fetchurl {
name = "victoriametrics-single-node.json";
url = "https://grafana.com/api/dashboards/10229/revisions/41/download";
hash = "sha256-mwtah8A2w81WZjf5bUXoTJfS1R9UX+tua2PiDrBKJCQ=";
}
|> (
src:
pkgs.runCommand "victoriametrics-single-node-patched.json" { buildInputs = [ pkgs.gnused ]; } ''
sed 's/victoriametrics-logs-//g' ${src} > $out
''
);
};
# https://grafana.com/grafana/dashboards/22084-victorialogs-single-node/
"grafana-dashboards/victorialogs-single-node-patched.json" = {
enable = cfg.dashboards.victorialogs.enable;
source =
pkgs.fetchurl {
name = "victorialogs-single-node.json";
url = "https://grafana.com/api/dashboards/22084/revisions/8/download";
hash = "sha256-/a3Rbp/6oyiLBnQtGupyFZW+fIHQfkyKRRTyfofxVTM=";
}
|> (
src:
pkgs.runCommand "victorialogs-single-node-patched.json" { buildInputs = [ pkgs.gnused ]; } ''
sed 's/victoria-logs-//g' ${src} > $out
''
);
};
};
custom.services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
};
}

View file

@ -0,0 +1,22 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.custom.web-services.it-tools;
in
{
options.custom.web-services.it-tools = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
};
config = lib.mkIf cfg.enable {
custom.services.caddy.virtualHosts.${cfg.domain}.files = "${pkgs.it-tools}/lib";
};
}

View file

@ -0,0 +1,62 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.karakeep;
in
{
options.custom.web-services.karakeep = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 18195;
};
};
config = lib.mkIf cfg.enable {
sops = {
secrets."karakeep/openai-api-key" = { };
templates."karakeep.env" = {
content = "OPENAI_API_KEY=${config.sops.placeholder."karakeep/openai-api-key"}";
owner = config.users.users.karakeep.name;
restartUnits = [ "karakeep-web.service" ];
};
};
services.karakeep = {
enable = true;
environmentFile = config.sops.templates."karakeep.env".path;
extraEnvironment = {
PORT = toString cfg.port;
DISABLE_NEW_RELEASE_CHECK = "true";
OCR_LANGS = "eng,deu";
};
};
users = {
users.meilisearch = {
isSystemUser = true;
group = config.users.groups.meilisearch.name;
};
groups.meilisearch = { };
};
systemd.services.meilisearch.serviceConfig = {
DynamicUser = lib.mkForce false;
User = config.users.users.meilisearch.name;
Group = config.users.groups.meilisearch.name;
ReadWritePaths = lib.mkForce [ ];
};
custom = {
services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
persistence.directories = [
"/var/lib/karakeep"
"/var/lib/meilisearch"
];
};
};
}

View file

@ -0,0 +1,27 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.networking-toolbox;
in
{
options.custom.web-services.networking-toolbox = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 4479;
};
};
config = lib.mkIf cfg.enable {
virtualisation.oci-containers.containers.networking-toolbox = {
image = "lissy93/networking-toolbox";
ports = [ "127.0.0.1:${toString cfg.port}:3000" ];
pull = "newer";
};
custom.services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
};
}

View file

@ -0,0 +1,31 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.ntfy;
in
{
options.custom.web-services.ntfy = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 2586;
};
};
config = lib.mkIf cfg.enable {
services.ntfy-sh = {
enable = true;
settings = lib.mkForce {
base-url = "https://${cfg.domain}";
listen-http = "localhost:${toString cfg.port}";
behind-proxy = true;
web-root = "disable";
};
};
custom.services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
};
}

View file

@ -0,0 +1,90 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.custom.web-services.outline;
in
{
options.custom.web-services.outline = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 32886;
};
doBackups = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
sops.secrets."outline/gitlab-auth-secret" = {
owner = config.users.users.outline.name;
restartUnits = [ "outline.service" ];
};
services.outline = {
enable = true;
publicUrl = "https://${cfg.domain}";
inherit (cfg) port;
forceHttps = false;
storage.storageType = "local";
# See https://docs.getoutline.com/s/hosting/doc/rate-limiter-HSqErsUgXH
rateLimiter = {
enable = true;
requests = 1000;
};
# See https://docs.getoutline.com/s/hosting/doc/gitlab-GjNVvyv7vW
oidcAuthentication =
let
baseURL = "https://code.fbi.h-da.de/oauth";
in
{
clientId = "3153f617736d608c0c10ddc4dd83f16c6a1f1b92d7f09a0493a924d389244295";
clientSecretFile = config.sops.secrets."outline/gitlab-auth-secret".path;
authUrl = "${baseURL}/authorize";
tokenUrl = "${baseURL}/token";
userinfoUrl = "${baseURL}/userinfo";
usernameClaim = "username";
displayName = "GitLab";
scopes = [
"openid"
"email"
];
};
};
systemd.services.outline.enableStrictShellChecks = false;
custom =
let
dataDir = "/var/lib/outline";
inherit (config.services.outline) user;
in
{
services = {
caddy.virtualHosts.${cfg.domain}.port = cfg.port;
restic.backups.outline = lib.mkIf cfg.doBackups {
conflictingService = "outline.service";
paths = [ dataDir ];
extraConfig.backupPrepareCommand = ''
${lib.getExe pkgs.sudo} --user=${user} ${lib.getExe' config.services.postgresql.package "pg_dump"} outline --format=custom --file=${dataDir}/db.dump
'';
restoreCommand.postRestore = "sudo --user=${user} pg_restore --clean --if-exists --dbname outline ${dataDir}/db.dump";
};
};
persistence.directories = [
dataDir
config.services.postgresql.dataDir
];
};
};
}

View file

@ -0,0 +1,32 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.custom.web-services.personal-blog;
dataDir = "/var/lib/personal-blog";
in
{
options.custom.web-services.personal-blog = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
};
config = lib.mkIf cfg.enable {
systemd.services.generate-blog = {
serviceConfig.Type = "oneshot";
wantedBy = [ "multi-user.target" ];
startAt = "*:0/5"; # Every 5 minutes
path = [ pkgs.nix ];
script = "nix build github:SebastianStork/blog --out-link ${dataDir} --refresh";
};
custom.services.caddy.virtualHosts.${cfg.domain}.files = dataDir;
};
}

View file

@ -0,0 +1,42 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.privatebin;
in
{
options.custom.web-services.privatebin = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 61009;
};
branding.name = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "PrivateBin";
};
};
config = lib.mkIf cfg.enable {
services = {
privatebin = {
enable = true;
enableNginx = true;
virtualHost = "privatebin";
settings.main = {
basepath = "https://${cfg.domain}";
inherit (cfg.branding) name;
};
};
nginx.virtualHosts.privatebin.listen = lib.singleton {
addr = "localhost";
inherit (cfg) port;
};
};
custom.services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
};
}

View file

@ -0,0 +1,114 @@
{
config,
inputs,
pkgs,
lib,
...
}:
let
cfg = config.custom.web-services.radicale;
dataDir = config.services.radicale.settings.storage.filesystem_folder;
initScript =
let
gitignore = pkgs.writeText "radicale-collection-gitignore" ''
.Radicale.cache
.Radicale.lock
.Radicale.tmp-*
'';
in
pkgs.writeShellApplication {
name = "radicale-git-init";
runtimeInputs = [ pkgs.git ];
text = ''
cd ${dataDir}
if [[ ! -e .git ]]; then
git init --initial-branch main
fi
git config user.name "Radicale"
git config user.email "radicale@${config.networking.hostName}"
cat ${gitignore} > .gitignore
git add .gitignore
if ! git diff --cached --quiet; then
git commit --message "Update .gitignore"
fi
'';
};
hookScript = pkgs.writeShellApplication {
name = "radicale-git-hook";
runtimeInputs = [
pkgs.git
pkgs.gawk
(pkgs.python3.withPackages (python-pkgs: [
python-pkgs.python-dateutil
python-pkgs.vobject
]))
];
text = ''
username="$1"
create_birthday_calendar="${inputs.radicale-birthday-calendar}/create_birthday_calendar.py"
git status --porcelain | awk '{print $2}' | python3 $create_birthday_calendar
git add -A
if ! git diff --cached --quiet; then
git commit --message "Changes by $username"
fi
'';
};
in
{
options.custom.web-services.radicale = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 5232;
};
doBackups = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
sops.secrets."radicale/htpasswd" = {
owner = config.users.users.radicale.name;
restartUnits = [ "radicale.service" ];
};
services.radicale = {
enable = true;
settings = {
server.hosts = "localhost:${toString cfg.port}";
auth = {
type = "htpasswd";
htpasswd_filename = config.sops.secrets."radicale/htpasswd".path;
htpasswd_encryption = "bcrypt";
};
storage.filesystem_folder = "/var/lib/radicale/collections";
storage.hook = "${lib.getExe hookScript} %(user)s";
};
};
systemd.services.radicale.serviceConfig.ExecStartPre = lib.getExe initScript;
custom = {
services = {
caddy.virtualHosts.${cfg.domain}.port = cfg.port;
restic.backups.radicale = lib.mkIf cfg.doBackups {
conflictingService = "radicale.service";
paths = [ dataDir ];
};
};
persistence.directories = [ dataDir ];
};
};
}

View file

@ -0,0 +1,31 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.screego;
in
{
options.custom.web-services.screego = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 5050;
};
};
config = lib.mkIf cfg.enable {
services.screego = {
enable = true;
openFirewall = true;
settings = {
SCREEGO_EXTERNAL_IP = config.custom.networking.underlay.address;
SCREEGO_SERVER_ADDRESS = "127.0.0.1:${toString cfg.port}";
SCREEGO_TURN_ADDRESS = "${config.custom.networking.underlay.address}:3478";
};
};
custom.services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
};
}

View file

@ -0,0 +1,45 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.stirling-pdf;
in
{
options.custom.web-services.stirling-pdf = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 56191;
};
branding = {
name = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "Stirling PDF";
};
description = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "Your locally hosted one-stop-shop for all your PDF needs.";
};
};
};
config = lib.mkIf cfg.enable {
services.stirling-pdf = {
enable = true;
environment = {
SERVER_ADDRESS = "127.0.0.1";
SERVER_PORT = cfg.port;
SYSTEM_ENABLEANALYTICS = "false";
LANGS = "de_DE";
UI_APPNAME = cfg.branding.name;
UI_APPNAVBARNAME = cfg.branding.name;
UI_HOMEDESCRIPTION = cfg.branding.description;
};
};
custom.services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
};
}

View file

@ -0,0 +1,44 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.victorialogs;
in
{
options.custom.web-services.victorialogs = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 9428;
};
};
config = lib.mkIf cfg.enable {
users = {
users.victorialogs = {
isSystemUser = true;
group = config.users.groups.victoriametrics.name;
};
groups.victorialogs = { };
};
systemd.services.victorialogs.serviceConfig = {
DynamicUser = lib.mkForce false;
User = config.users.users.victorialogs.name;
Group = config.users.groups.victorialogs.name;
};
services.victorialogs = {
enable = true;
listenAddress = "localhost:${toString cfg.port}";
};
custom = {
services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
persistence.directories = [ "/var/lib/${config.services.victorialogs.stateDir}" ];
};
};
}

View file

@ -0,0 +1,49 @@
{ config, lib, ... }:
let
cfg = config.custom.web-services.victoriametrics;
in
{
options.custom.web-services.victoriametrics = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "";
};
port = lib.mkOption {
type = lib.types.port;
default = 8428;
};
};
config = lib.mkIf cfg.enable {
users = {
users.victoriametrics = {
isSystemUser = true;
group = config.users.groups.victoriametrics.name;
};
groups.victoriametrics = { };
};
systemd.services.victoriametrics.serviceConfig = {
DynamicUser = lib.mkForce false;
User = config.users.users.victoriametrics.name;
Group = config.users.groups.victoriametrics.name;
};
services.victoriametrics = {
enable = true;
listenAddress = "localhost:${toString cfg.port}";
extraOptions = [
"-selfScrapeInterval=15s"
"-selfScrapeJob=victoriametrics"
"-selfScrapeInstance=${config.networking.hostName}"
];
};
custom = {
services.caddy.virtualHosts.${cfg.domain}.port = cfg.port;
persistence.directories = [ "/var/lib/${config.services.victoriametrics.stateDir}" ];
};
};
}