From d8791f27bbbc2176566b20c1af3339fca20f7c10 Mon Sep 17 00:00:00 2001 From: Quinn Unger Date: Fri, 28 Aug 2026 19:42:42 +0100 Subject: [PATCH] setup oidc --- hosts/tsumugi/arr/shelfarr.nix | 175 ++++++++++++++++++--------------- secrets/secrets.yaml | 5 +- 2 files changed, 99 insertions(+), 81 deletions(-) diff --git a/hosts/tsumugi/arr/shelfarr.nix b/hosts/tsumugi/arr/shelfarr.nix index 9bf8f3e..8434883 100644 --- a/hosts/tsumugi/arr/shelfarr.nix +++ b/hosts/tsumugi/arr/shelfarr.nix @@ -8,12 +8,13 @@ let cfg = config.virtualisation.oci-containers.containers; version = "2026.08.24.1"; + ip = "100.109.197.202"; libationBooksPath = "/mnt/media/data/appdata/libation/books"; shelfarrState = "/var/lib/shelfarr"; libationState = "/var/lib/shelfarr-libation"; in { - sops.secrets.oci = { }; + sops.secrets."tsumugi/shelfarrEnv" = { }; systemd = { services.shelfarr.after = [ "mnt-media.mount" ]; tmpfiles.rules = [ @@ -22,84 +23,100 @@ in "d ${libationState}/control 0700 root root -" ]; }; - virtualisation.oci-containers.containers = { - shelfarr = - let - tokenFolder = "/run/shelfarr-libation"; - in - { - autoStart = true; - serviceName = "shelfarr"; - hostname = "shelfarr"; - image = "ghcr.io/pedro-revez-silva/shelfarr:${version}"; - environment = { - SOLID_QUEUE_IN_PUMA = "1"; - SHELFARR_LIBATION_URL = "http://shelfarr-libation:8080"; - SHELFARR_LIBATION_TOKEN_FILE = "${tokenFolder}/token"; - SHELFARR_LIBATION_IMPORT_ROOT = "/imports/libation"; - # Keep these identical to the companion so both services can use the - # read-only token and completed-backup volumes. - PUID = "1000"; - PGID = "1000"; - CHOWN_ON_START = "auto"; - TZ = "Europe/Dublin"; - # Optional: Change internal port (default: 80) - # HTTP_PORT=8080; - # Optional: Set your own key instead of auto-generating - # RAILS_MASTER_KEY=your-64-char-hex-key; - }; - volumes = [ - # Database and app storage (required - contains auto-generated secret key) - "${shelfarrState}/data:/rails/storage" - # Audiobooks output folder (where Shelfarr places completed audiobooks) - "/mnt/media/data/media/audiobooks:/audiobooks" - # Ebooks output folder (where Shelfarr places completed ebooks) - "/mnt/media/data/media/ebooks:/ebooks" - # Download client completed folder (where downloads land before processing) - "/mnt/media/data/appdata/shelfarr/downloads:/downloads" - # Completed Audible backups from the optional Libation companion - "${libationBooksPath}:${cfg.shelfarr.environment.SHELFARR_LIBATION_IMPORT_ROOT}:ro" - # Read-only bridge credential generated by the companion - "${libationState}/control:${tokenFolder}:ro" - ]; - ports = [ "127.0.0.1:5056:80" ]; - }; - shelfarr-libation = - let - tokenFolder = "/control"; - in - { - autoStart = true; - serviceName = "shelfarr-libation"; - hostname = "shelfarr-libation"; - dependsOn = [ "shelfarr" ]; - image = "ghcr.io/pedro-revez-silva/shelfarr-libation:${version}"; - environment = rec { - inherit (cfg.shelfarr.environment) - PUID - PGID - CHOWN_ON_START - TZ - ; - LIBATION_FILES_DIR = "/config"; - LIBATION_BOOKS_DIR = "/data"; - LIBATION_IN_PROGRESS_DIR = "${LIBATION_FILES_DIR}/in-progress"; - COMPANION_STATE_DIR = "${LIBATION_FILES_DIR}/shelfarr-companion"; - COMPANION_TOKEN_FILE = "${tokenFolder}/token"; - COMPANION_MAX_ACTIVE_JOBS = "500"; - COMPANION_MAX_TERMINAL_JOBS = "5000"; - COMPANION_TERMINAL_JOB_RETENTION_DAYS = "30"; - ASPNETCORE_URLS = "http://0.0.0.0:8080"; - }; - volumes = [ - # Private account tokens, device keys, Libation database, and job state - "${libationState}/config:${cfg.shelfarr-libation.environment.LIBATION_FILES_DIR}" - # Completed backups shared with Shelfarr - "${libationBooksPath}:${cfg.shelfarr-libation.environment.LIBATION_BOOKS_DIR}" - # Narrow credential handoff: Shelfarr cannot see the private state volume - "${libationState}/control:${tokenFolder}" - ]; - ports = [ "127.0.0.1:5057:8080" ]; + virtualisation = { + containers.enable = true; + podman = { + enable = true; + dockerCompat = true; + defaultNetwork.settings.dns_enabled = true; + }; + oci-containers = { + backend = "podman"; + containers = { + shelfarr = + let + tokenFolder = "/run/shelfarr-libation"; + in + { + autoStart = true; + serviceName = "shelfarr"; + hostname = "shelfarr"; + image = "ghcr.io/pedro-revez-silva/shelfarr:${version}"; + environment = { + SOLID_QUEUE_IN_PUMA = "1"; + SHELFARR_LIBATION_URL = "http://shelfarr-libation:8080"; + SHELFARR_LIBATION_TOKEN_FILE = "${tokenFolder}/token"; + SHELFARR_LIBATION_IMPORT_ROOT = "/imports/libation"; + # Keep these identical to the companion so both services can use the + # read-only token and completed-backup volumes. + PUID = "1000"; + PGID = "1000"; + CHOWN_ON_START = "auto"; + TZ = "Europe/Dublin"; + # Optional: Change internal port (default: 80) + HTTP_PORT = "5056"; + # Optional: Set your own key instead of auto-generating + # RAILS_MASTER_KEY=your-64-char-hex-key; + SHELFARR_SETTING_OIDC_ENABLED = "true"; + SHELFARR_SETTING_OIDC_AUTO_REDIRECT = "false"; + SHELFARR_SETTING_OIDC_ISSUER = "https://auth.moppu.dev"; + SHELFARR_SETTING_OIDC_AUTO_CREATE_USERS = "true"; + }; + environmentFiles = [ config.sops.secrets."tsumugi/shelfarrEnv".path ]; + volumes = [ + # Database and app storage (required - contains auto-generated secret key) + "${shelfarrState}/data:/rails/storage" + # Audiobooks output folder (where Shelfarr places completed audiobooks) + "/mnt/media/data/media/audiobooks:/audiobooks" + # Ebooks output folder (where Shelfarr places completed ebooks) + "/mnt/media/data/media/ebooks:/ebooks" + # Download client completed folder (where downloads land before processing) + "/mnt/media/data/appdata/shelfarr/downloads:/downloads" + # Completed Audible backups from the optional Libation companion + "${libationBooksPath}:${cfg.shelfarr.environment.SHELFARR_LIBATION_IMPORT_ROOT}:ro" + # Read-only bridge credential generated by the companion + "${libationState}/control:${tokenFolder}:ro" + ]; + ports = [ "${ip}:5056:5056" ]; + }; + shelfarr-libation = + let + tokenFolder = "/control"; + in + { + autoStart = true; + serviceName = "shelfarr-libation"; + hostname = "shelfarr-libation"; + dependsOn = [ "shelfarr" ]; + image = "ghcr.io/pedro-revez-silva/shelfarr-libation:${version}"; + environment = rec { + inherit (cfg.shelfarr.environment) + PUID + PGID + CHOWN_ON_START + TZ + ; + LIBATION_FILES_DIR = "/config"; + LIBATION_BOOKS_DIR = "/data"; + LIBATION_IN_PROGRESS_DIR = "${LIBATION_FILES_DIR}/in-progress"; + COMPANION_STATE_DIR = "${LIBATION_FILES_DIR}/shelfarr-companion"; + COMPANION_TOKEN_FILE = "${tokenFolder}/token"; + COMPANION_MAX_ACTIVE_JOBS = "500"; + COMPANION_MAX_TERMINAL_JOBS = "5000"; + COMPANION_TERMINAL_JOB_RETENTION_DAYS = "30"; + ASPNETCORE_URLS = "http://0.0.0.0:8080"; + }; + volumes = [ + # Private account tokens, device keys, Libation database, and job state + "${libationState}/config:${cfg.shelfarr-libation.environment.LIBATION_FILES_DIR}" + # Completed backups shared with Shelfarr + "${libationBooksPath}:${cfg.shelfarr-libation.environment.LIBATION_BOOKS_DIR}" + # Narrow credential handoff: Shelfarr cannot see the private state volume + "${libationState}/control:${tokenFolder}" + ]; + ports = [ "127.0.0.1:5057:8080" ]; + }; }; + }; }; } diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index 4b6e3e7..2fcb94e 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -11,6 +11,7 @@ tsumugi: transmission: ENC[AES256_GCM,data:lUOP1FgucJ/Qi2nCx3SlZ5X36akHdHKa9ZA1H0JuBrqbyxAogRQJayLd606QNk8QE5Cecrg+el9/njKawWfB,iv:qpHSlLVKskSwW33iOwvINNnEidbQGqxBNjDdzNF7Y7Y=,tag:f7+mPCIvGqBA3t8EfATAew==,type:str] autobrrSecret: ENC[AES256_GCM,data:F3WlaDlhlzFL6ix/stAZIg==,iv:j4EaVIRc6LhqwIGbCEzEFGzKqOd/cfvSI/DgFoAlzDk=,tag:JmpWL0CNydnuluO7x9SRwg==,type:str] autobrrEnv: ENC[AES256_GCM,data:FEYeU8Q1bH/VJBECkk9+Xa7VEHd5QyOywbgFN/1rJSGo97mjnlm6T2z+jfzBZUfAWw93+w39SARKgrU84ENJE/fP0USwd+t4EiduupNkRaMbL7EJxFKtSi1dICHh8nLf9qIUTAIQfE9XbNP1o9LQ2IdFj91z7b27akDc1orStJcfgdvOMWd8Wg==,iv:TR7rRAvTgSdQwczfxjW/QsUcH4SmfYuju0ZWhrI0HD4=,tag:cZwT7bWKYYapkGMwmVLYAQ==,type:str] + shelfarrEnv: ENC[AES256_GCM,data:UwNtYMZ27y2Pp7Kp658FMEk6POzoeaUBD/l/pwcXtjeDmXB6ryqdPvHD4s4OKPYR562tJcH+XoSfZF4i3amcN44QurtyqjOoI87ZU4gBqnBOE7wAOdCQLJAExHrTDOEX5GCwah661cNCm4iO18HD4s/RhzrUErnXQoW0qyrQcqxnr+WwlxSC01VZd6T+av06OM08H0RaCjs=,iv:Kt0tdDQKvRqf6eUlgVkQ/8wNdnFVMJiPzBOph4YFfQM=,tag:XCfCUTKS6UV2V0xhXEBO5g==,type:str] nutPass: ENC[AES256_GCM,data:jCJ9IEdtRVPy1NfcHUIwqnQ3rsc=,iv:Zafd/x8TOyWwKHAcGK41hZeWu/krb1ErzUo1ei2JqcA=,tag:WZfDmzVIsJ6hQ9Z+UfCvjg==,type:str] radarrMainApiKey: ENC[AES256_GCM,data:KX6ISlzv0DDdAOGUGAgHOoLGrv0Z0mo9KTz7W0BprlY=,iv:bb5CgT874g+5ExlSjCFnMFcp34LSkzGvmh6JdZ85pKs=,tag:9BR2O9SDPjsZ22xm6ADxRw==,type:str] radarrAnimeApiKey: ENC[AES256_GCM,data:Dn9LmPjgmGYlIoi0nV760R8v5nbu0iVtEO5rhgkpDGA=,iv:17YeBObcUP+AmAB2DHHRvgRZNfe2TdQ6+IsWV7qYqS8=,tag:1KLlrXSHM5CKZKP02KFSrw==,type:str] @@ -79,7 +80,7 @@ sops: JFaroA1RPAmhCC0nSl4seBSIuRl8QrPjfcBJy4mFycll5Mp/0/WwLA== -----END AGE ENCRYPTED FILE----- recipient: age1cpqgsevvfgk0nnmxacsdcwsrkefd0xcx7wkdlyaqj8vgvfvnm4rq4npjv6 - lastmodified: "2026-08-28T16:50:37Z" - mac: ENC[AES256_GCM,data:eMhgA5nyUNsKrKSIMBbeoHLWoWQ5GxViI7OsbU6QRJqjvSN45vOFLTMtefNP3MZz77dolzNDuGGR7OH+4ouzm5diu2Cwxd+GW3HxnujDu56G1cnQucRWzPfnRiZ23HhGFvfkIEL5ZqbBrt31n6s8v7GNzbRegnJjb9DcAT1JFlk=,iv:cIZ0cd+2eO/+cW6Rog+NE24cmd10o1QR2XvsD6OsPlA=,tag:SJaCJsLOrgr+7bPbPczj3g==,type:str] + lastmodified: "2026-08-28T18:24:36Z" + mac: ENC[AES256_GCM,data:mPvqDOAaQJAcLWj1VwovGHGATYuJpjePY2XslRYKPhZCHC5SGiZYRFjM+7ihDsiEaznY1iYtUt/Thy7976utTahIGW5Febx44/JZI4sdbQE9vmGzC/lu/5JVZOJtZQSBf2ey3yvOh+AhINArq3xlms9yCxBC+oyvcp2qu2XsVQ0=,iv:sdAZV4nLjc++AjIkkg2WFy4LADM0RGmW/reMxRFGQ+s=,tag:vcXrtSdCuV6YwSegR5//+w==,type:str] unencrypted_suffix: _unencrypted version: 3.13.3 -- 2.51.2