From f8907ccd055401c8068f8ba0ef58cacf6a163581 Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Sun, 17 May 2026 13:24:29 +0000 Subject: [PATCH] manatee: Add `romm` module --- hosts/manatee/modules/certs/default.nix | 13 ++ hosts/manatee/modules/default.nix | 1 + .../modules/home-assistant/default.nix | 2 +- hosts/manatee/modules/romm/default.nix | 213 ++++++++++++++++++ secrets/manatee/romm-auth-secret-key.age | Bin 0 -> 407 bytes secrets/manatee/romm-db-password.age | Bin 0 -> 410 bytes secrets/manatee/romm-metadata-api-keys.age | 8 + secrets/secrets.nix | 3 + 8 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 hosts/manatee/modules/romm/default.nix create mode 100644 secrets/manatee/romm-auth-secret-key.age create mode 100644 secrets/manatee/romm-db-password.age create mode 100644 secrets/manatee/romm-metadata-api-keys.age diff --git a/hosts/manatee/modules/certs/default.nix b/hosts/manatee/modules/certs/default.nix index fb9705e..bb1dd18 100644 --- a/hosts/manatee/modules/certs/default.nix +++ b/hosts/manatee/modules/certs/default.nix @@ -33,6 +33,19 @@ "--http-timeout=60" ]; }; + + "romm.ppp.pm" = { + dnsProvider = "hetzner"; + environmentFile = config.age.secrets.hetzner-dns.path; + group = "nginx"; + + extraLegoFlags = [ + "--dns.resolvers=1.1.1.1:53,8.8.8.8:53" + "--dns.propagation-wait=60s" + "--dns-timeout=60" + "--http-timeout=60" + ]; + }; }; }; diff --git a/hosts/manatee/modules/default.nix b/hosts/manatee/modules/default.nix index 12d438c..9417c67 100644 --- a/hosts/manatee/modules/default.nix +++ b/hosts/manatee/modules/default.nix @@ -21,6 +21,7 @@ in immich.enable = false; navidrome.enable = true; komga.enable = true; + romm.enable = true; homepage.enable = true; }; }; diff --git a/hosts/manatee/modules/home-assistant/default.nix b/hosts/manatee/modules/home-assistant/default.nix index b5a8f49..98cade6 100644 --- a/hosts/manatee/modules/home-assistant/default.nix +++ b/hosts/manatee/modules/home-assistant/default.nix @@ -195,7 +195,7 @@ in ]; script = '' - SUBDOMAINS="ha komga" + SUBDOMAINS="ha komga romm" INTERFACE="enp3s0" CURRENT_IP=$(curl -s --fail --interface "$INTERFACE" ifconfig.me) diff --git a/hosts/manatee/modules/romm/default.nix b/hosts/manatee/modules/romm/default.nix new file mode 100644 index 0000000..24050ef --- /dev/null +++ b/hosts/manatee/modules/romm/default.nix @@ -0,0 +1,213 @@ +{ + pkgs, + lib, + config, + ... +}: +let + enabled = config.mod.romm.enable; + nginxEnabled = config.mod.nginx.enable; + + configFile = pkgs.writeText "romm-config.yml" '' + filesystem: + skip_hash_calculation: false + exclude: + roms: + single_file: + extensions: + - xml + - txt + - nfo + - dat + - jpg + - png + names: + - '._*' + - 'Thumbs.db' + - '.DS_Store' + ''; +in +{ + options = { + mod.romm = { + enable = lib.mkEnableOption "Enable romm module"; + }; + }; + + config = lib.mkIf enabled { + mod.homepage.services = [ + { + name = "RomM"; + port = 8085; + description = "ROM library manager"; + } + ]; + + systemd.tmpfiles.rules = [ + "d /var/lib/romm 0755 root root -" + "d /var/lib/romm/db 0755 root root -" + "d /var/lib/romm/redis 0755 999 1000 -" + "d /var/lib/romm/resources 0755 root root -" + "d /var/lib/romm/assets 0755 root root -" + ]; + + systemd.services.romm-net = { + description = "Create Podman network for RomM"; + after = [ "podman.service" ]; + requires = [ "podman.service" ]; + before = [ + "podman-romm.service" + "podman-romm-db.service" + "podman-romm-redis.service" + ]; + requiredBy = [ + "podman-romm.service" + "podman-romm-db.service" + "podman-romm-redis.service" + ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "/run/current-system/sw/bin/podman network create romm-net"; + ExecStop = "/run/current-system/sw/bin/podman network rm -f romm-net"; + }; + }; + + virtualisation.oci-containers = { + backend = "podman"; + + containers.romm-db = { + image = "mariadb:latest"; + + environment = { + MARIADB_DATABASE = "romm"; + MARIADB_USER = "romm"; + }; + + environmentFiles = [ + config.age.secrets.romm-db-password.path + ]; + + volumes = [ + "/var/lib/romm/db:/var/lib/mysql" + ]; + + extraOptions = [ + "--network=romm-net" + ]; + }; + + containers.romm-redis = { + image = "redis:alpine"; + + volumes = [ + "/var/lib/romm/redis:/data" + ]; + + extraOptions = [ + "--network=romm-net" + "--user=root" + ]; + }; + + containers.romm = { + image = "rommapp/romm:latest"; + + dependsOn = [ + "romm-db" + "romm-redis" + ]; + + environment = { + DB_HOST = "romm-db"; + DB_PORT = "3306"; + DB_NAME = "romm"; + DB_USER = "romm"; + REDIS_HOST = "romm-redis"; + REDIS_PORT = "6379"; + ROMM_AUTH_ENABLED = "true"; + }; + + environmentFiles = [ + config.age.secrets.romm-auth-secret-key.path + config.age.secrets.romm-db-password.path + config.age.secrets.romm-metadata-api-keys.path + ]; + + ports = [ + "127.0.0.1:8086:8080" + ]; + + volumes = [ + "${configFile}:/romm/config/config.yml:ro" + "/mnt/media/public/games:/romm/library" + "/var/lib/romm/resources:/romm/resources" + "/var/lib/romm/assets:/romm/assets" + ]; + + extraOptions = [ + "--network=romm-net" + ]; + }; + }; + + services.nginx = lib.mkIf nginxEnabled { + virtualHosts."romm-local" = { + listen = [ + { + addr = "0.0.0.0"; + port = 8085; + } + ]; + + extraConfig = '' + client_max_body_size 0; + ''; + + locations."/" = { + proxyPass = "http://127.0.0.1:8086"; + proxyWebsockets = true; + }; + }; + + virtualHosts."romm.ppp.pm" = { + forceSSL = true; + useACMEHost = "romm.ppp.pm"; + + extraConfig = '' + client_max_body_size 0; + ''; + + locations."/" = { + proxyPass = "http://127.0.0.1:8086"; + proxyWebsockets = true; + }; + }; + }; + + boot.kernel.sysctl."net.ipv4.ip_forward" = 1; + + networking.firewall.allowedTCPPorts = [ 8085 ]; + + age.secrets = { + "romm-auth-secret-key" = { + file = ../../../../secrets/manatee/romm-auth-secret-key.age; + owner = "root"; + group = "root"; + }; + + "romm-db-password" = { + file = ../../../../secrets/manatee/romm-db-password.age; + owner = "root"; + group = "root"; + }; + + "romm-metadata-api-keys" = { + file = ../../../../secrets/manatee/romm-metadata-api-keys.age; + owner = "root"; + group = "root"; + }; + }; + }; +} diff --git a/secrets/manatee/romm-auth-secret-key.age b/secrets/manatee/romm-auth-secret-key.age new file mode 100644 index 0000000000000000000000000000000000000000..ed84e394aa25c96d37391f6e229e5a6110ab0dc7 GIT binary patch literal 407 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCSH&kic{b5sa*ORuoV z_b|%Os7iG!2rseJFNx51jxhFc@y^Q+FR2VMPpZiAu1bqAEavhn4D^dg4h$)>@Gj4E zOV$p`F!wje$`1;Dw|7JS69K+-PyP*)1=(OHMP_^JJBS{pgbhlFe2T> zv&hxM-`~t4z&FbvDJj*=-;qmvkskLguKoj4m!9aARll?DW@_ld;yZdp!W&XDHSRU# z8E7%gIK4!>Vq(OS#eQdxp6@f*^TX!)eaDwqUl*G{KOw&8xZqZ;EzZt6lcV2C-&-a3(s_QDXP*BORe;ba7DLGJKrzSBT&K6%~w05(j(W!q_ix{ zEkE3(7ZsxT=tqrjyq(?2lCDJd(pLf@}2D3mKTu-GTO(%s25Ing*HxV+Fa&#gSe z!@VNh(l@j!-7g|sKP@+C^9_E z&n4Kbw9F;bIH$NYrQFCX+?DHr>5my|b-_}Kzc*Dz#P&-wEWO5SwK?vB^%eyu&*R|| zhRrNFqEQwni)L^zu01Z!s@axa9h)0t&a&XVSbo%`%+vkaJPUaLpZ3o@JkXDZPtWWX|0I<-MT>t<8 literal 0 HcmV?d00001 diff --git a/secrets/manatee/romm-metadata-api-keys.age b/secrets/manatee/romm-metadata-api-keys.age new file mode 100644 index 0000000..d5355f4 --- /dev/null +++ b/secrets/manatee/romm-metadata-api-keys.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 wkRvNA 5d22LU+2Mn6fq8SHOCwDht/ebnI2uOk6WKf+t1kwwCM +hCGnLoCy1PX5PJx2IjQnyESmtKM6wVQmyS6aHNhkb1g +-> ssh-ed25519 +oNaHQ gPUMsavbGVPOuvTtNgoDuzrT+q0I7Wbkd6QK5z4oUGc +M3HhrugFlNQkL7WxF1qrW+ocGRqOXid32AVVYLSSxPI +--- TGURCDEIuSFCfXBHxzFHA2svHES7Ubagy1uYjbWCO7g +gҙQ +oF[H:tar3Z0x @:0ӴI[\=@ePWrX,*s$c:Fl z|B# pZ4ns[%\P;R㣧$97A0.x簍?9,ýt+  fA)mV \ No newline at end of file diff --git a/secrets/secrets.nix b/secrets/secrets.nix index f75bc71..0143bef 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -39,6 +39,9 @@ in { "manatee/komga-bookmanager-credentials.age".publicKeys = [ manatee alex]; "manatee/komga-reading-stats-claude-api-key.age".publicKeys = [ manatee alex]; "manatee/komga-reading-stats-komga-api-key.age".publicKeys = [ manatee alex]; + "manatee/romm-auth-secret-key.age".publicKeys = [ manatee alex ]; + "manatee/romm-db-password.age".publicKeys = [ manatee alex ]; + "manatee/romm-metadata-api-keys.age".publicKeys = [ manatee alex ]; "backwards/root.backwards.age".publicKeys = [ backwards alex ]; "backwards/root.backwards.pub.age".publicKeys = [ backwards alex ];