REWRITE
This commit is contained in:
+17
-22
@@ -42,6 +42,18 @@ in
|
|||||||
options.homey.backup = {
|
options.homey.backup = {
|
||||||
enable = lib.mkEnableOption "Restic backup jobs";
|
enable = lib.mkEnableOption "Restic backup jobs";
|
||||||
|
|
||||||
|
extraPaths = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [];
|
||||||
|
description = "Paths to include in the restic backup. Each service module contributes its own entries.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraExcludePaths = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [];
|
||||||
|
description = "Paths to exclude from the restic backup. Each service module contributes its own entries.";
|
||||||
|
};
|
||||||
|
|
||||||
repository = lib.mkOption {
|
repository = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
example = "sftp:user@nas.local:/backups/homey";
|
example = "sftp:user@nas.local:/backups/homey";
|
||||||
@@ -127,32 +139,15 @@ in
|
|||||||
# Runtime env file written by homey-backup-pre.service (which runs first)
|
# Runtime env file written by homey-backup-pre.service (which runs first)
|
||||||
environmentFile = "/run/restic-homey-secrets.env";
|
environmentFile = "/run/restic-homey-secrets.env";
|
||||||
|
|
||||||
paths = [
|
# Paths are contributed by individual service modules via homey.backup.extraPaths.
|
||||||
"${dataDir}/openldap"
|
paths = config.homey.backup.extraPaths;
|
||||||
"${dataDir}/authelia"
|
|
||||||
"${dataDir}/gitea"
|
|
||||||
"${dataDir}/nextcloud"
|
|
||||||
# media and transmission config included when those services are enabled:
|
|
||||||
"${dataDir}/jellyfin"
|
|
||||||
"${dataDir}/transmission"
|
|
||||||
# Deliberately excluded: media/* (large, can be re-downloaded)
|
|
||||||
# Monitoring — uptime-kuma has monitors/history, ntfy has user accounts
|
|
||||||
"${dataDir}/uptime-kuma"
|
|
||||||
"${dataDir}/ntfy"
|
|
||||||
# Eurovision Vote — SQLite DB with votes and rankings
|
|
||||||
"/var/lib/eurovote"
|
|
||||||
"${dataDir}/paperless"
|
|
||||||
"${dataDir}/mealie"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Exclude Nextcloud's raw DB directory in favour of the pg_dump file
|
|
||||||
exclude = [
|
exclude = [
|
||||||
"${dataDir}/nextcloud/db"
|
# restic's own local cache is never worth backing up
|
||||||
"${dataDir}/restic-cache"
|
"${dataDir}/restic-cache"
|
||||||
|
# media is large and can be re-downloaded; services exclude their own consume dirs
|
||||||
"${dataDir}/media"
|
"${dataDir}/media"
|
||||||
# consume dir holds unprocessed drop files; usually empty after ingestion
|
] ++ config.homey.backup.extraExcludePaths;
|
||||||
"${dataDir}/paperless/consume"
|
|
||||||
];
|
|
||||||
|
|
||||||
timerConfig = {
|
timerConfig = {
|
||||||
OnCalendar = cfg.schedule;
|
OnCalendar = cfg.schedule;
|
||||||
|
|||||||
+52
-222
@@ -65,6 +65,38 @@ in
|
|||||||
default = "admin@zakobar.com";
|
default = "admin@zakobar.com";
|
||||||
description = "Email for Let's Encrypt ACME registration.";
|
description = "Email for Let's Encrypt ACME registration.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtualHosts = lib.mkOption {
|
||||||
|
type = lib.types.listOf (lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Subdomain under homeyConfig.domain (e.g. \"mealie\" → mealie.zakobar.com).";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
description = "Host port to reverse-proxy to.";
|
||||||
|
};
|
||||||
|
auth = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Prepend Authelia forward_auth to this vhost.";
|
||||||
|
};
|
||||||
|
extraConfig = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
description = "Replaces the auto-generated 'reverse_proxy localhost:<port>' for HTTPS. Empty = use default.";
|
||||||
|
};
|
||||||
|
extraHttpConfig = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
description = "Replaces the auto-generated cfProxy for the HTTP loopback vhost. Empty = use default.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
default = [];
|
||||||
|
description = "Virtual hosts to generate. Each service module contributes its own entries.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
@@ -89,229 +121,27 @@ in
|
|||||||
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Each virtual host.
|
# Each virtual host is generated from homey.caddy.virtualHosts entries.
|
||||||
|
# Each service module contributes its own entries to that list.
|
||||||
#
|
#
|
||||||
# Each service gets two vhost entries:
|
# Each entry produces two Caddy vhosts:
|
||||||
# - "host" (no scheme) → Caddy handles HTTPS + auto cert (for LAN access)
|
# - "subdomain.domain" → HTTPS (LAN access + Let's Encrypt cert)
|
||||||
# - "http://host" → plain HTTP for cloudflared on loopback (no redirect)
|
# - "http://subdomain.domain" → plain HTTP for cloudflared loopback
|
||||||
#
|
virtualHosts = lib.listToAttrs (
|
||||||
# Caddy auto-redirects HTTP→HTTPS only when no explicit http:// vhost exists.
|
lib.concatMap (vh:
|
||||||
# By defining http:// explicitly we suppress that redirect so cloudflared
|
let
|
||||||
# (which talks plain HTTP on port 80) gets a direct response.
|
d = "${vh.subdomain}.${domain}";
|
||||||
virtualHosts = {
|
authSnip = lib.optionalString vh.auth autheliaForwardAuth;
|
||||||
|
httpsBody = if vh.extraConfig != "" then vh.extraConfig
|
||||||
# ------------------------------------------------------------------
|
else "reverse_proxy localhost:${toString vh.port}\n";
|
||||||
# Authelia — public, no auth gate (it IS the auth gate)
|
httpBody = if vh.extraHttpConfig != "" then vh.extraHttpConfig
|
||||||
# ------------------------------------------------------------------
|
else cfProxy vh.port;
|
||||||
"auth.${domain}" = {
|
in [
|
||||||
extraConfig = ''
|
{ name = d; value.extraConfig = "${authSnip}${httpsBody}"; }
|
||||||
reverse_proxy localhost:9091
|
{ name = "http://${d}"; value.extraConfig = "${authSnip}${httpBody}"; }
|
||||||
'';
|
]
|
||||||
};
|
) cfg.virtualHosts
|
||||||
"http://auth.${domain}" = {
|
);
|
||||||
extraConfig = cfProxy 9091;
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Gitea — no forward_auth; git HTTP clients can't handle SSO redirects.
|
|
||||||
# Access control is handled by Gitea itself (LDAP auth + private repos).
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"git.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:3000
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://git.${domain}" = {
|
|
||||||
extraConfig = cfProxy 3000;
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Nextcloud — public auth (Nextcloud manages its own users + LDAP)
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"nextcloud.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
# Redirect CardDAV/CalDAV discovery
|
|
||||||
redir /.well-known/carddav /remote.php/dav/ 301
|
|
||||||
redir /.well-known/caldav /remote.php/dav/ 301
|
|
||||||
|
|
||||||
# Large uploads (5 GB)
|
|
||||||
request_body {
|
|
||||||
max_size 5GB
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_proxy localhost:8080 {
|
|
||||||
header_up X-Forwarded-For {remote_host}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://nextcloud.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
redir /.well-known/carddav /remote.php/dav/ 301
|
|
||||||
redir /.well-known/caldav /remote.php/dav/ 301
|
|
||||||
request_body {
|
|
||||||
max_size 5GB
|
|
||||||
}
|
|
||||||
reverse_proxy localhost:8080 {
|
|
||||||
header_up X-Forwarded-Proto https
|
|
||||||
header_up X-Forwarded-For {remote_host}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# phpLDAPadmin — two_factor, admins only (enforced by authelia policy)
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"ldapadmin.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:8081
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://ldapadmin.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
${cfProxy 8081}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Jellyfin — no forward_auth; Jellyfin has its own login UI and
|
|
||||||
# native app clients can't handle SSO redirects.
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"jellyfin.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:8096
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://jellyfin.${domain}" = {
|
|
||||||
extraConfig = cfProxy 8096;
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Transmission — two_factor, admins only (enforced by authelia policy)
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"torrent.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:9092
|
|
||||||
'';
|
|
||||||
# NOTE: transmission is bound to 9092 to avoid clash with authelia on 9091.
|
|
||||||
};
|
|
||||||
"http://torrent.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
${cfProxy 9092}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Uptime Kuma — two_factor, admins only (enforced by authelia policy)
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"uptime.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:3001
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://uptime.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
${cfProxy 3001}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Ntfy — no forward_auth; ntfy has its own token/password auth so the
|
|
||||||
# mobile app can connect without Authelia SSO complications.
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"ntfy.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:2586
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://ntfy.${domain}" = {
|
|
||||||
extraConfig = cfProxy 2586;
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Eurovision Vote — one_factor for all authenticated users.
|
|
||||||
# /admin/* is restricted to group:admins by Authelia access_control.
|
|
||||||
# Caddy passes Remote-User → X-Remote-User so Django auto-logs in
|
|
||||||
# the SSO-authenticated user via RemoteUserMiddleware.
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"eurovision-vote.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:8007 {
|
|
||||||
header_up X-Remote-User {http.request.header.Remote-User}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://eurovision-vote.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:8007 {
|
|
||||||
header_up X-Forwarded-Proto https
|
|
||||||
header_up X-Remote-User {http.request.header.Remote-User}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Paperless — one_factor for all authenticated users (authelia policy).
|
|
||||||
# Authelia sets Remote-User; Caddy copies it to the upstream request;
|
|
||||||
# Paperless trusts HTTP_REMOTE_USER for automatic login (no separate
|
|
||||||
# Paperless login page shown).
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"paperless.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:8083
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://paperless.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
${cfProxy 8083}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Mealie — no forward_auth; LDAP handles auth via Mealie's login page.
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"mealie.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:9093
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://mealie.${domain}" = {
|
|
||||||
extraConfig = cfProxy 9093;
|
|
||||||
};
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Grafana — two_factor, admins only (enforced by authelia policy).
|
|
||||||
# After Authelia verifies the user, Caddy maps the Remote-User header
|
|
||||||
# to X-WEBAUTH-USER so Grafana's proxy auth auto-signs the user in.
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
"grafana.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:3002 {
|
|
||||||
header_up X-WEBAUTH-USER {http.request.header.Remote-User}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"http://grafana.${domain}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
${autheliaForwardAuth}
|
|
||||||
reverse_proxy localhost:3002 {
|
|
||||||
header_up X-Forwarded-Proto https
|
|
||||||
header_up X-WEBAUTH-USER {http.request.header.Remote-User}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
+25
-1
@@ -38,7 +38,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.monitoring = {
|
options.homey.monitoring = {
|
||||||
enable = lib.mkEnableOption "Prometheus + Grafana monitoring stack";
|
enable = lib.mkEnableOption "Prometheus + Grafana monitoring stack" // { default = true; };
|
||||||
|
|
||||||
prometheusPort = lib.mkOption {
|
prometheusPort = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
@@ -205,6 +205,30 @@ in
|
|||||||
mode = "0444";
|
mode = "0444";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — forward_auth; Caddy maps Remote-User → X-WEBAUTH-USER
|
||||||
|
# so Grafana's proxy auth auto-signs the user in
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "grafana";
|
||||||
|
port = cfg.grafanaPort;
|
||||||
|
auth = true;
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy localhost:${toString cfg.grafanaPort} {
|
||||||
|
header_up X-WEBAUTH-USER {http.request.header.Remote-User}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
extraHttpConfig = ''
|
||||||
|
reverse_proxy localhost:${toString cfg.grafanaPort} {
|
||||||
|
header_up X-Forwarded-Proto https
|
||||||
|
header_up X-WEBAUTH-USER {http.request.header.Remote-User}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
}];
|
||||||
|
|
||||||
|
# Grafana and Prometheus use system state dirs (/var/lib/grafana,
|
||||||
|
# /var/lib/prometheus2) — no extraDirs or backup entries needed.
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor for Grafana
|
# Uptime Kuma monitor for Grafana
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.authelia = {
|
options.homey.authelia = {
|
||||||
enable = lib.mkEnableOption "Authelia SSO gateway";
|
enable = lib.mkEnableOption "Authelia SSO gateway" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -241,6 +241,28 @@ in
|
|||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-openldap.service" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-openldap.service" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — no forward_auth (Authelia IS the auth gateway)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "auth";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = false;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "authelia"; }
|
||||||
|
{ path = "authelia/config"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/authelia" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor for this service
|
# Uptime Kuma monitor for this service
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.eurovote = {
|
options.homey.eurovote = {
|
||||||
enable = lib.mkEnableOption "Eurovision Vote app";
|
enable = lib.mkEnableOption "Eurovision Vote app" // { default = true; };
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
@@ -48,6 +48,34 @@ in
|
|||||||
logoutRedirectUrl = "https://auth.${domain}/logout";
|
logoutRedirectUrl = "https://auth.${domain}/logout";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — forward_auth; X-Remote-User passed to Django's
|
||||||
|
# RemoteUserMiddleware for automatic SSO login
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "eurovision-vote";
|
||||||
|
port = 8007;
|
||||||
|
auth = true;
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy localhost:8007 {
|
||||||
|
header_up X-Remote-User {http.request.header.Remote-User}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
extraHttpConfig = ''
|
||||||
|
reverse_proxy localhost:8007 {
|
||||||
|
header_up X-Forwarded-Proto https
|
||||||
|
header_up X-Remote-User {http.request.header.Remote-User}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
}];
|
||||||
|
|
||||||
|
# Eurovision Vote uses DynamicUser + /var/lib/eurovote — no extraDirs needed.
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup — /var/lib/eurovote holds the SQLite DB with votes
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "/var/lib/eurovote" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor
|
# Uptime Kuma monitor
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.giteaRunner = {
|
options.homey.giteaRunner = {
|
||||||
enable = lib.mkEnableOption "Gitea Actions runner";
|
enable = lib.mkEnableOption "Gitea Actions runner" // { default = true; };
|
||||||
|
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.gitea = {
|
options.homey.gitea = {
|
||||||
enable = lib.mkEnableOption "Gitea Git server";
|
enable = lib.mkEnableOption "Gitea Git server" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -188,6 +188,28 @@ in
|
|||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — no forward_auth; git clients can't handle SSO redirects
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "git";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = false;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories (UID 1000 = Gitea's internal user)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "gitea"; user = "1000"; group = "1000"; }
|
||||||
|
{ path = "gitea/data"; user = "1000"; group = "1000"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/gitea" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor for this service
|
# Uptime Kuma monitor for this service
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.jellyfin = {
|
options.homey.jellyfin = {
|
||||||
enable = lib.mkEnableOption "Jellyfin media server";
|
enable = lib.mkEnableOption "Jellyfin media server" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -51,5 +51,27 @@ in
|
|||||||
after = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
after = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — no forward_auth; Jellyfin has its own login UI
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "jellyfin";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = false;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "jellyfin"; }
|
||||||
|
{ path = "jellyfin/config"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/jellyfin" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.mealie = {
|
options.homey.mealie = {
|
||||||
enable = lib.mkEnableOption "Mealie recipe manager";
|
enable = lib.mkEnableOption "Mealie recipe manager" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -96,6 +96,28 @@ in
|
|||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — no forward_auth; Mealie uses LDAP login page
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "mealie";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = false;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "mealie"; }
|
||||||
|
{ path = "mealie/data"; mode = "0755"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/mealie" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor
|
# Uptime Kuma monitor
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.nextcloud = {
|
options.homey.nextcloud = {
|
||||||
enable = lib.mkEnableOption "Nextcloud file server";
|
enable = lib.mkEnableOption "Nextcloud file server" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -166,6 +166,54 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — no forward_auth; Nextcloud manages its own auth
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "nextcloud";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = false;
|
||||||
|
extraConfig = ''
|
||||||
|
redir /.well-known/carddav /remote.php/dav/ 301
|
||||||
|
redir /.well-known/caldav /remote.php/dav/ 301
|
||||||
|
request_body {
|
||||||
|
max_size 5GB
|
||||||
|
}
|
||||||
|
reverse_proxy localhost:${toString cfg.port} {
|
||||||
|
header_up X-Forwarded-For {remote_host}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
extraHttpConfig = ''
|
||||||
|
redir /.well-known/carddav /remote.php/dav/ 301
|
||||||
|
redir /.well-known/caldav /remote.php/dav/ 301
|
||||||
|
request_body {
|
||||||
|
max_size 5GB
|
||||||
|
}
|
||||||
|
reverse_proxy localhost:${toString cfg.port} {
|
||||||
|
header_up X-Forwarded-Proto https
|
||||||
|
header_up X-Forwarded-For {remote_host}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# UID 33 = www-data in the Nextcloud container
|
||||||
|
# UID 999 = postgres — must own the db dir (creates files directly in it)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "nextcloud"; }
|
||||||
|
{ path = "nextcloud/html"; user = "33"; group = "33"; }
|
||||||
|
{ path = "nextcloud/db"; mode = "0700"; user = "999"; group = "999"; }
|
||||||
|
{ path = "nextcloud/db-dump"; mode = "0700"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup — exclude raw DB dir (pg_dump file in db-dump/ is used instead)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/nextcloud" ];
|
||||||
|
homey.backup.extraExcludePaths = [ "${dataDir}/nextcloud/db" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor for this service
|
# Uptime Kuma monitor for this service
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
+25
-25
@@ -62,7 +62,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.ntfy = {
|
options.homey.ntfy = {
|
||||||
enable = lib.mkEnableOption "Ntfy push notification server";
|
enable = lib.mkEnableOption "Ntfy push notification server" // { default = true; };
|
||||||
|
|
||||||
port = lib.mkOption {
|
port = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
@@ -105,36 +105,14 @@ in
|
|||||||
mode = "0444";
|
mode = "0444";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create ntfy data directories on the external HD before ntfy starts.
|
|
||||||
# Runs as a separate root service (outside ntfy-sh's restricted namespace)
|
|
||||||
# so it can access /mnt/data without hitting ReadWritePaths restrictions.
|
|
||||||
systemd.services.ntfy-sh-mkdir = {
|
|
||||||
description = "Create Ntfy data directories on external HD";
|
|
||||||
wantedBy = [ "ntfy-sh.service" ];
|
|
||||||
before = [ "ntfy-sh.service" ];
|
|
||||||
after = [ "mnt-data.mount" ];
|
|
||||||
requires = [ "mnt-data.mount" ];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecStart = pkgs.writeShellScript "ntfy-mkdir" ''
|
|
||||||
set -euo pipefail
|
|
||||||
mkdir -p ${dataDir}/ntfy/attachments
|
|
||||||
chown -R ntfy-sh:ntfy-sh ${dataDir}/ntfy
|
|
||||||
chmod 0750 ${dataDir}/ntfy ${dataDir}/ntfy/attachments
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Ensure ntfy-sh starts after the HD is mounted and dirs are ready.
|
# Ensure ntfy-sh starts after the HD is mounted and dirs are ready.
|
||||||
# Widen ReadWritePaths so ntfy-sh can write to the external HD.
|
# Widen ReadWritePaths so ntfy-sh can write to the external HD.
|
||||||
# Inject the VAPID private key at runtime: ExecStartPre copies the
|
# Inject the VAPID private key at runtime: ExecStartPre copies the
|
||||||
# build-time base config to /run/ntfy-sh/server.yml and appends the key,
|
# build-time base config to /run/ntfy-sh/server.yml and appends the key,
|
||||||
# then we override ExecStart to use that runtime config file.
|
# then we override ExecStart to use that runtime config file.
|
||||||
systemd.services.ntfy-sh = {
|
systemd.services.ntfy-sh = {
|
||||||
after = lib.mkAfter [ "mnt-data.mount" "ntfy-sh-mkdir.service" ];
|
after = lib.mkAfter [ "mnt-data.mount" "systemd-tmpfiles-setup.service" ];
|
||||||
requires = lib.mkAfter [ "mnt-data.mount" "ntfy-sh-mkdir.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ReadWritePaths = lib.mkAfter [ "${dataDir}/ntfy" ];
|
ReadWritePaths = lib.mkAfter [ "${dataDir}/ntfy" ];
|
||||||
RuntimeDirectory = "ntfy-sh"; # creates /run/ntfy-sh, owned by ntfy-sh user
|
RuntimeDirectory = "ntfy-sh"; # creates /run/ntfy-sh, owned by ntfy-sh user
|
||||||
@@ -198,6 +176,28 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — no forward_auth; ntfy uses its own token auth
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "ntfy";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = false;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories (owned by the ntfy-sh system user)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "ntfy"; user = "ntfy-sh"; group = "ntfy-sh"; }
|
||||||
|
{ path = "ntfy/attachments"; user = "ntfy-sh"; group = "ntfy-sh"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/ntfy" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor for this service
|
# Uptime Kuma monitor for this service
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.openldap = {
|
options.homey.openldap = {
|
||||||
enable = lib.mkEnableOption "OpenLDAP identity provider";
|
enable = lib.mkEnableOption "OpenLDAP identity provider" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -114,6 +114,20 @@ in
|
|||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "openldap"; }
|
||||||
|
{ path = "openldap/etc-ldap-slapd.d"; }
|
||||||
|
{ path = "openldap/var-lib-ldap"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/openldap" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Firewall — openldap port is NOT opened externally
|
# Firewall — openldap port is NOT opened externally
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.paperless = {
|
options.homey.paperless = {
|
||||||
enable = lib.mkEnableOption "Paperless-ngx document management";
|
enable = lib.mkEnableOption "Paperless-ngx document management" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -124,6 +124,32 @@ in
|
|||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-paperless-redis.service" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-paperless-redis.service" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — forward_auth; Remote-User passed to Paperless for SSO
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "paperless";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = true;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories (UID 1000 = USERMAP_UID in container)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "paperless"; }
|
||||||
|
{ path = "paperless/data"; user = "1000"; group = "1000"; }
|
||||||
|
{ path = "paperless/media"; user = "1000"; group = "1000"; }
|
||||||
|
{ path = "paperless/consume"; user = "1000"; group = "1000"; }
|
||||||
|
{ path = "paperless/export"; user = "1000"; group = "1000"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup — exclude consume dir (unprocessed drops, usually empty)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/paperless" ];
|
||||||
|
homey.backup.extraExcludePaths = [ "${dataDir}/paperless/consume" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor
|
# Uptime Kuma monitor
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.phpldapadmin = {
|
options.homey.phpldapadmin = {
|
||||||
enable = lib.mkEnableOption "phpLDAPadmin web interface";
|
enable = lib.mkEnableOption "phpLDAPadmin web interface" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -50,6 +50,17 @@ in
|
|||||||
wants = lib.mkAfter [ "podman-openldap.service" "podman-homey-network.service" ];
|
wants = lib.mkAfter [ "podman-openldap.service" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — forward_auth + reverse_proxy
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "ldapadmin";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = true;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# phpLDAPadmin is stateless (no persistent volumes) — no storage or backup entries needed.
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma monitor for this service
|
# Uptime Kuma monitor for this service
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.homey.transmission = {
|
options.homey.transmission = {
|
||||||
enable = lib.mkEnableOption "Transmission torrent client";
|
enable = lib.mkEnableOption "Transmission torrent client" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -60,5 +60,27 @@ in
|
|||||||
after = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
after = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — forward_auth, admins only
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "torrent";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = true;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "transmission"; }
|
||||||
|
{ path = "transmission/config"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/transmission" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
options.homey.uptimeKuma = {
|
options.homey.uptimeKuma = {
|
||||||
enable = lib.mkEnableOption "Uptime Kuma uptime monitoring";
|
enable = lib.mkEnableOption "Uptime Kuma uptime monitoring" // { default = true; };
|
||||||
|
|
||||||
image = lib.mkOption {
|
image = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -285,6 +285,27 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Caddy virtual host — forward_auth, admins only
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.caddy.virtualHosts = [{
|
||||||
|
subdomain = "uptime";
|
||||||
|
port = cfg.port;
|
||||||
|
auth = true;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Storage directories
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.storage.extraDirs = [
|
||||||
|
{ path = "uptime-kuma"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Backup
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
homey.backup.extraPaths = [ "${dataDir}/uptime-kuma" ];
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Uptime Kuma self-monitor
|
# Uptime Kuma self-monitor
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
+30
-40
@@ -63,6 +63,22 @@ in
|
|||||||
default = "ext4";
|
default = "ext4";
|
||||||
description = "Filesystem type of the external drive.";
|
description = "Filesystem type of the external drive.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extraDirs = lib.mkOption {
|
||||||
|
type = lib.types.listOf (lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
path = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Path relative to mountPoint (e.g. \"gitea/data\").";
|
||||||
|
};
|
||||||
|
mode = lib.mkOption { type = lib.types.str; default = "0750"; };
|
||||||
|
user = lib.mkOption { type = lib.types.str; default = "root"; };
|
||||||
|
group = lib.mkOption { type = lib.types.str; default = "root"; };
|
||||||
|
};
|
||||||
|
});
|
||||||
|
default = [];
|
||||||
|
description = "Per-service directories to create under mountPoint. Each service module contributes its own entries.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg.device != "") {
|
config = lib.mkIf (cfg.device != "") {
|
||||||
@@ -79,46 +95,20 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Ensure the mount point directory exists
|
# Mount point root + shared infrastructure dirs (restic cache, shared media).
|
||||||
|
# Per-service dirs are contributed via homey.storage.extraDirs by each
|
||||||
|
# service module, so adding a new service only requires editing that module.
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d ${cfg.mountPoint} 0755 root root -"
|
"d ${cfg.mountPoint} 0755 root root -"
|
||||||
|
# Shared media directories used by both Jellyfin and Transmission.
|
||||||
# Service subdirectories — created on boot so containers can start
|
"d ${cfg.mountPoint}/media 0755 root root -"
|
||||||
# even before any data is restored into them.
|
"d ${cfg.mountPoint}/media/movies 0755 root root -"
|
||||||
"d ${cfg.mountPoint}/openldap 0750 root root -"
|
"d ${cfg.mountPoint}/media/tvshows 0755 root root -"
|
||||||
"d ${cfg.mountPoint}/openldap/etc-ldap-slapd.d 0750 root root -"
|
"d ${cfg.mountPoint}/media/general 0755 root root -"
|
||||||
"d ${cfg.mountPoint}/openldap/var-lib-ldap 0750 root root -"
|
"d ${cfg.mountPoint}/media/complete 0755 root root -"
|
||||||
"d ${cfg.mountPoint}/authelia 0750 root root -"
|
"d ${cfg.mountPoint}/restic-cache 0700 root root -"
|
||||||
"d ${cfg.mountPoint}/authelia/config 0750 root root -"
|
] ++ (map
|
||||||
"d ${cfg.mountPoint}/gitea 0750 1000 1000 -"
|
(d: "d ${cfg.mountPoint}/${d.path} ${d.mode} ${d.user} ${d.group} -")
|
||||||
"d ${cfg.mountPoint}/gitea/data 0750 1000 1000 -"
|
config.homey.storage.extraDirs);
|
||||||
"d ${cfg.mountPoint}/nextcloud 0750 root root -"
|
|
||||||
# www-data in the Nextcloud container is UID 33; it needs rx on the
|
|
||||||
# directory and rw on all files it creates inside.
|
|
||||||
"d ${cfg.mountPoint}/nextcloud/html 0750 33 33 -"
|
|
||||||
# Postgres (uid 999) must own this directory — it creates files directly in it
|
|
||||||
"d ${cfg.mountPoint}/nextcloud/db 0700 999 999 -"
|
|
||||||
"d ${cfg.mountPoint}/jellyfin 0750 root root -"
|
|
||||||
"d ${cfg.mountPoint}/jellyfin/config 0750 root root -"
|
|
||||||
"d ${cfg.mountPoint}/media 0755 root root -"
|
|
||||||
"d ${cfg.mountPoint}/media/movies 0755 root root -"
|
|
||||||
"d ${cfg.mountPoint}/media/tvshows 0755 root root -"
|
|
||||||
"d ${cfg.mountPoint}/media/general 0755 root root -"
|
|
||||||
"d ${cfg.mountPoint}/media/complete 0755 root root -"
|
|
||||||
"d ${cfg.mountPoint}/transmission 0750 root root -"
|
|
||||||
"d ${cfg.mountPoint}/transmission/config 0750 root root -"
|
|
||||||
"d ${cfg.mountPoint}/uptime-kuma 0750 root root -"
|
|
||||||
"d ${cfg.mountPoint}/ntfy 0750 ntfy-sh ntfy-sh -"
|
|
||||||
"d ${cfg.mountPoint}/ntfy/attachments 0750 ntfy-sh ntfy-sh -"
|
|
||||||
"d ${cfg.mountPoint}/paperless 0750 root root -"
|
|
||||||
# Paperless runs as UID 1000 (configured via USERMAP_UID)
|
|
||||||
"d ${cfg.mountPoint}/paperless/data 0750 1000 1000 -"
|
|
||||||
"d ${cfg.mountPoint}/paperless/media 0750 1000 1000 -"
|
|
||||||
"d ${cfg.mountPoint}/paperless/consume 0750 1000 1000 -"
|
|
||||||
"d ${cfg.mountPoint}/paperless/export 0750 1000 1000 -"
|
|
||||||
"d ${cfg.mountPoint}/mealie 0750 root root -"
|
|
||||||
"d ${cfg.mountPoint}/mealie/data 0755 root root -"
|
|
||||||
"d ${cfg.mountPoint}/restic-cache 0700 root root -"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user