From 4cddd93189ec26fed40edd953d51b29b979b9b58 Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Wed, 11 Jun 2025 22:53:22 +0200
Subject: [PATCH 1/8] deploy microvm

---
 flake.nix                |  1 +
 hosts/stream/default.nix | 77 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)
 create mode 100644 hosts/stream/default.nix

diff --git a/flake.nix b/flake.nix
index ddde63b..2b085bc 100644
--- a/flake.nix
+++ b/flake.nix
@@ -71,6 +71,7 @@
             "forgejo"
             "miniflux"
             "radicale"
+            "stream"
           ];
           microvm-unstable-list = [
             "auth"
diff --git a/hosts/stream/default.nix b/hosts/stream/default.nix
new file mode 100644
index 0000000..cd0b29e
--- /dev/null
+++ b/hosts/stream/default.nix
@@ -0,0 +1,77 @@
+{ config, lib, ... }:
+let
+  mac = "02:00:00:00:00:07";
+in
+{
+  imports = [
+  ];
+  # sops.defaultSopsFile = ./secrets.yaml;
+  # sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
+  # 
+  # sops.secrets = {
+  #   "wg/0xa-proxy" = {
+  #     owner = config.users.users.systemd-network.name;
+  #   };
+  # };
+
+  microvm = {
+    hypervisor = "qemu";
+    mem = 3 * 1024;
+    vcpu = 2;
+    interfaces = [
+      {
+        type = "tap";
+        id = "uvm-stream";
+        mac = mac;
+      }
+    ];
+    shares =
+      [
+        {
+          source = "/nix/store";
+          mountPoint = "/nix/.ro-store";
+          tag = "store";
+          proto = "virtiofs";
+          socket = "store.socket";
+        }
+      ]
+      ++ map
+        (dir: {
+          source = dir;
+          mountPoint = "/${dir}";
+          tag = dir;
+          proto = "virtiofs";
+          socket = "${dir}.socket";
+        })
+        [
+          "etc"
+          "var"
+          "media"
+          "home"
+        ];
+  };
+
+  networking.useNetworkd = true;
+  networking.firewall.enable = lib.mkForce false; # firewalling done by the host
+
+  systemd.network = {
+    enable = true;
+    networks."11-host" = {
+      matchConfig.MACAddress = mac;
+      networkConfig = {
+        Address = "10.99.99.17/24";
+        DHCP = "no";
+      };
+      routes = [
+        {
+          Gateway = "10.99.99.1";
+          Destination = "0.0.0.0/0";
+          Metric = 1024;
+        }
+      ];
+    };
+  };
+
+  networking.hostName = "stream";
+  system.stateVersion = "25.05";
+}

From 1f0ca3f5d4c792023c1f13e4a81194447c399d45 Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Thu, 12 Jun 2025 21:20:29 +0000
Subject: [PATCH 2/8] some-tweaks

---
 hosts/stream/default.nix | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/hosts/stream/default.nix b/hosts/stream/default.nix
index cd0b29e..8a382f7 100644
--- a/hosts/stream/default.nix
+++ b/hosts/stream/default.nix
@@ -16,8 +16,8 @@ in
 
   microvm = {
     hypervisor = "qemu";
-    mem = 3 * 1024;
-    vcpu = 2;
+    mem = 4 * 1024;
+    vcpu = 3;
     interfaces = [
       {
         type = "tap";
@@ -32,7 +32,6 @@ in
           mountPoint = "/nix/.ro-store";
           tag = "store";
           proto = "virtiofs";
-          socket = "store.socket";
         }
       ]
       ++ map
@@ -41,12 +40,10 @@ in
           mountPoint = "/${dir}";
           tag = dir;
           proto = "virtiofs";
-          socket = "${dir}.socket";
         })
         [
           "etc"
           "var"
-          "media"
           "home"
         ];
   };

From 5dbd3988a12af6bed3ce3d284c4d9208bc9196ef Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Fri, 13 Jun 2025 00:58:20 +0200
Subject: [PATCH 3/8] setup 0xa-proxy

---
 .sops.yaml                |  7 +++++++
 hosts/stream/default.nix  | 17 +++++++++--------
 hosts/stream/secrets.yaml | 38 ++++++++++++++++++++++++++++++++++++++
 modules/wg/proxy.nix      |  8 ++++++++
 4 files changed, 62 insertions(+), 8 deletions(-)
 create mode 100644 hosts/stream/secrets.yaml

diff --git a/.sops.yaml b/.sops.yaml
index dd882ca..649c351 100644
--- a/.sops.yaml
+++ b/.sops.yaml
@@ -11,6 +11,7 @@ keys:
   - &immich age1afyntwvj672lcq2e4dpxmw3syplzurnnd8q8j3265843jeedpveqkp465z
   - &miniflux age15ja22wd9tt60vn32sk59pp6c7vtjsn8y3rypn8qfnvxthug8sp0q6f72uh
   - &radicale age1j6z39kmnxkqa7jdcjsydy5cryjce7fttf225fh3pldyvq06ax3fq58mk8c
+  - &stream age148r2q3cy9sjem37rvgtcc4qjx8usxkdg77pqexa56gmcexn58aaslh3cnj
 creation_rules:
   - path_regex: hosts/toaster/[^/]+\.yaml$
     key_groups:
@@ -66,3 +67,9 @@ creation_rules:
         - *admin_oxa
         age:
         - *conduwuit
+  - path_regex: hosts/stream/[^/]+\.yaml$
+    key_groups:
+      - pgp:
+        - *admin_oxa
+        age:
+        - *stream
diff --git a/hosts/stream/default.nix b/hosts/stream/default.nix
index 8a382f7..68be56f 100644
--- a/hosts/stream/default.nix
+++ b/hosts/stream/default.nix
@@ -5,14 +5,15 @@ in
 {
   imports = [
   ];
-  # sops.defaultSopsFile = ./secrets.yaml;
-  # sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
-  # 
-  # sops.secrets = {
-  #   "wg/0xa-proxy" = {
-  #     owner = config.users.users.systemd-network.name;
-  #   };
-  # };
+
+  sops.defaultSopsFile = ./secrets.yaml;
+  sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
+
+  sops.secrets = {
+    "wg/0xa-proxy" = {
+      owner = config.users.users.systemd-network.name;
+    };
+  };
 
   microvm = {
     hypervisor = "qemu";
diff --git a/hosts/stream/secrets.yaml b/hosts/stream/secrets.yaml
new file mode 100644
index 0000000..a75b120
--- /dev/null
+++ b/hosts/stream/secrets.yaml
@@ -0,0 +1,38 @@
+wg:
+    0xa-proxy: ENC[AES256_GCM,data:uZfFc4elxCAVZvdIHJ7lgoPs9qKkD9ZvLhcYbexDcqn0alaMzIr++CY52FI=,iv:CREMt6GrLHs4Jwj/55awDFHh9hQlJPEi4ZQ7ZLMPvRA=,tag:iJAGdqzQbyezmDj+tzjdNQ==,type:str]
+sops:
+    age:
+        - recipient: age148r2q3cy9sjem37rvgtcc4qjx8usxkdg77pqexa56gmcexn58aaslh3cnj
+          enc: |
+            -----BEGIN AGE ENCRYPTED FILE-----
+            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsSko5L1BCOTR1QmZabGw3
+            QS9kbDZyWEJvV09MNkNqbTNncjZrOXl6WFZrCmxQelVzbjdvUUl4aVl3UVFVL0Q5
+            S0VDNkdvcDZnZytCdjBrZUZYTFlEZncKLS0tIG1NWnlnRGovcWxDL2JYMTc2bEY5
+            K29Dd0t6b3FMZjU2cXFBbEw3RktkQlkKCh+jXv65KfAsSR4/0+UWwU5tCphrEEgE
+            WDbIdUZ8j5xHHQwJ58cU7uQ+BSy0yZlwwr8vPoaKdXQzMgyrQfq3gg==
+            -----END AGE ENCRYPTED FILE-----
+    lastmodified: "2025-06-12T22:54:11Z"
+    mac: ENC[AES256_GCM,data:15EU9VupWfvR8CrfKrX3nhpD60hYB2LY3vuAPvdqzKLliqSqolNj956fOFicfSHvmW/s+7x+M+5FROnOzSbToTZotFtvALQihHH999veGZMx8Q8oIyljT1PBw/SU9djXPI1KjG/zzYOAwu7y/Ffm0QKhMRziH7CQLn30KR0o2w0=,iv:ghdyTvcpgnBi2L9s4UrzwWwt9TeU0WkGquZ64+w9IN8=,tag:4m4hYFgejlEaQROB/OEi6g==,type:str]
+    pgp:
+        - created_at: "2025-06-12T22:51:49Z"
+          enc: |-
+            -----BEGIN PGP MESSAGE-----
+
+            hQIMA7zUOKwzpAE7AQ/8ClHQoCuiC0AH28bDit4qjNh/TnYq3IbAdyITOqUYPRc6
+            th8MCDY0CfxvzDTLYxTlHH4MNDOiWWTMg/shC8xV3MrAIpEQV79ivYMay04aWpCH
+            HqlhjBynCwAnJRanc9Ch5zW1wCjpgMp+kMDX8JhhUL0Rmt2fd2nSp4R2bb+/HRvn
+            vAaDq3TTLkLr1OHcTNKFFbXafGLKMahxkQGRMgD1DIPCLW+nUxerUnlxHo4yjj3B
+            WKXBVKeWowgBHvelHqUVf6yeSmWZyFDP/jFxFEi75A+BYmwxlQcRDn0L0NKUlMa/
+            uF3jtW3XBMS/sLX7aRscBFeEq9XPce9urJK4KPFNVFI3X1WbD6O/Z87Y+MHa2n0s
+            DuxIwrffpw8p4qSVBAJLbSW1vR/suGh/0Cr31mzo4FJT92A93wc8JdLdpHUfTXL/
+            bEbt6M7OSqvIt5/mor7Ad6/HRkEl+sZJnHqeU/qKfAIKKfz5UVG/ZCZDZlVGTmpp
+            lV9Dn8QjA1ut4lMvACJBocnrlH4T6150ULL0r3gHuVy5YhnGR+LWFdgaCJ4v3f1J
+            A59eAyQENNMoSGZU/YZx95kFPc1O/GIkmiMpXZxBISN3F70QP30ieqbP1qnZRfMg
+            GldVAFhfaHct4lujlgRfOkmwcNG3gTIru4wAqg+wzriI9jm9vEoF0MDJs2cwNYTS
+            XgE32jq6Li59TMUQH9iB4l0cM42QbQ8BcSn6o/NhmF6HHq9W5yuD6EIs4KNfdHv6
+            ikgqQuGGO9v7qDMd0piyqeLRGMANepxrR5uMsbFmMnah9RUq9CjRbMADLa+8DeU=
+            =fEVm
+            -----END PGP MESSAGE-----
+          fp: DD0998E6CDF294537FC604F991FA5E5BF9AA901C
+    unencrypted_suffix: _unencrypted
+    version: 3.10.2
diff --git a/modules/wg/proxy.nix b/modules/wg/proxy.nix
index 3b92b8d..7427829 100644
--- a/modules/wg/proxy.nix
+++ b/modules/wg/proxy.nix
@@ -71,6 +71,14 @@
           publicKey = "dj5/CnTAFe5ELnZ5oWonYc+5VdzDyooTYGb/bqcxf3Y=";
           privateKeyFile = config.sops.secrets."wg/0xa-proxy".path;
         };
+        "stream" = {
+          address = [
+            "10.89.88.17/24"
+            "fd31:185d:722f::17/48"
+          ];
+          publicKey = "RDxbOvd/1FSWqIp5v1++wPBcG1hScAT4mhIlMZdvxU4=";
+          privateKeyFile = config.sops.secrets."wg/0xa-proxy".path;
+        };
       };
     }
   ];

From cb198685f36adb0778849a82d893c4d82a5e7350 Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Fri, 13 Jun 2025 01:51:21 +0200
Subject: [PATCH 4/8] deploy navidrome

---
 hosts/stream/default.nix   |  2 ++
 hosts/stream/navidrome.nix | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 hosts/stream/navidrome.nix

diff --git a/hosts/stream/default.nix b/hosts/stream/default.nix
index 68be56f..fea530f 100644
--- a/hosts/stream/default.nix
+++ b/hosts/stream/default.nix
@@ -4,6 +4,7 @@ let
 in
 {
   imports = [
+    ./navidrome.nix
   ];
 
   sops.defaultSopsFile = ./secrets.yaml;
@@ -46,6 +47,7 @@ in
           "etc"
           "var"
           "home"
+          "music"
         ];
   };
 
diff --git a/hosts/stream/navidrome.nix b/hosts/stream/navidrome.nix
new file mode 100644
index 0000000..5cfc246
--- /dev/null
+++ b/hosts/stream/navidrome.nix
@@ -0,0 +1,16 @@
+{ ... }:
+{
+  services.navidrome = {
+    enable = true;
+    settings = {
+      Address = "10.89.88.17";
+      BaseUrl = "/";
+      EnableExternalServices = false;
+      MusicFolder = "/music";
+      Port = 4533;
+      ScanSchedule = "@every 11m";
+      TranscodingCacheSize = "11GiB";
+      ReverseProxyWhitelist = "10.89.88.1/24";
+    };
+  };
+}

From d6bdcd6e43ba1a92dfb1224699a40e160507a839 Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Fri, 13 Jun 2025 02:16:58 +0200
Subject: [PATCH 5/8] reverse-proxy navidrome

---
 hosts/cloud/proxy/default.nix | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/hosts/cloud/proxy/default.nix b/hosts/cloud/proxy/default.nix
index 9994da4..c19e2dc 100644
--- a/hosts/cloud/proxy/default.nix
+++ b/hosts/cloud/proxy/default.nix
@@ -60,5 +60,37 @@ in
     '';
 
     virtualHosts."news.oxapentane.com".extraConfig = "reverse_proxy http://10.89.88.14:8080";
+
+        virtualHosts."music.oxapentane.com".extraConfig = ''
+      route {
+          reverse_proxy /outpost.goauthentik.io/* 10.89.88.11:9000 [fd31:185d:722f::11]:9000
+
+          @protected not path /share/* /rest/*
+          forward_auth @protected 10.89.88.11:9000 {
+              uri /outpost.goauthentik.io/auth/caddy
+              copy_headers X-Authentik-Username>Remote-User
+              trusted_proxies 10.89.88.11 fd31:185d:722f::11
+          }
+
+
+          @subsonic path /rest/*
+          forward_auth @subsonic 10.89.88.11:9000 {
+              uri /outpost.goauthentik.io/auth/caddy
+              copy_headers X-Authentik-Username>Remote-User
+              @error status 1xx 3xx 4xx 5xx
+              handle_response @error {
+                  respond <<SUBSONICERR
+                  <subsonic-response xmlns="http://subsonic.org/restapi" status="failed" version="1.16.1" type="proxy-auth" serverVersion="n/a" openSubsonic="true">
+                    <error code="40" message="Invalid credentials or unsupported client"></error>
+                  </subsonic-response>
+                  SUBSONICERR 200
+              }
+              trusted_proxies 10.89.88.11 fd31:185d:722f::11
+          }
+      }
+      reverse_proxy 10.89.88.17:4533 [fd31:185d:722f::17]:3533
+
+    '';
+
   };
 }

From 520fbb3fa7e17aba8efdaf02974316717f107c48 Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Fri, 13 Jun 2025 02:30:37 +0200
Subject: [PATCH 6/8] fix reverse proxy

---
 hosts/cloud/proxy/default.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hosts/cloud/proxy/default.nix b/hosts/cloud/proxy/default.nix
index c19e2dc..6cf0151 100644
--- a/hosts/cloud/proxy/default.nix
+++ b/hosts/cloud/proxy/default.nix
@@ -88,7 +88,7 @@ in
               trusted_proxies 10.89.88.11 fd31:185d:722f::11
           }
       }
-      reverse_proxy 10.89.88.17:4533 [fd31:185d:722f::17]:3533
+      reverse_proxy 10.89.88.17:4533
 
     '';
 

From 9de0990f122eb9321915711ded9f0b3c8a5acfd1 Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Fri, 13 Jun 2025 02:34:56 +0200
Subject: [PATCH 7/8] fix share

---
 hosts/stream/default.nix   | 1 -
 hosts/stream/navidrome.nix | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/hosts/stream/default.nix b/hosts/stream/default.nix
index fea530f..4543466 100644
--- a/hosts/stream/default.nix
+++ b/hosts/stream/default.nix
@@ -47,7 +47,6 @@ in
           "etc"
           "var"
           "home"
-          "music"
         ];
   };
 
diff --git a/hosts/stream/navidrome.nix b/hosts/stream/navidrome.nix
index 5cfc246..0b1cd07 100644
--- a/hosts/stream/navidrome.nix
+++ b/hosts/stream/navidrome.nix
@@ -6,7 +6,7 @@
       Address = "10.89.88.17";
       BaseUrl = "/";
       EnableExternalServices = false;
-      MusicFolder = "/music";
+      MusicFolder = "/var/lib/navidrome/music";
       Port = 4533;
       ScanSchedule = "@every 11m";
       TranscodingCacheSize = "11GiB";

From 2a44e5c81e2d46766ed095d5e94c5fafbd5d85fa Mon Sep 17 00:00:00 2001
From: Grisha Shipunov <blame@oxapentane.com>
Date: Wed, 11 Jun 2025 22:53:22 +0200
Subject: [PATCH 8/8] deploy stream (navidrome) microvm

---
 .sops.yaml                    |  7 ++++
 flake.nix                     |  1 +
 hosts/cloud/proxy/default.nix | 32 +++++++++++++++
 hosts/stream/default.nix      | 76 +++++++++++++++++++++++++++++++++++
 hosts/stream/navidrome.nix    | 16 ++++++++
 hosts/stream/secrets.yaml     | 38 ++++++++++++++++++
 modules/wg/proxy.nix          |  8 ++++
 7 files changed, 178 insertions(+)
 create mode 100644 hosts/stream/default.nix
 create mode 100644 hosts/stream/navidrome.nix
 create mode 100644 hosts/stream/secrets.yaml

diff --git a/.sops.yaml b/.sops.yaml
index dd882ca..649c351 100644
--- a/.sops.yaml
+++ b/.sops.yaml
@@ -11,6 +11,7 @@ keys:
   - &immich age1afyntwvj672lcq2e4dpxmw3syplzurnnd8q8j3265843jeedpveqkp465z
   - &miniflux age15ja22wd9tt60vn32sk59pp6c7vtjsn8y3rypn8qfnvxthug8sp0q6f72uh
   - &radicale age1j6z39kmnxkqa7jdcjsydy5cryjce7fttf225fh3pldyvq06ax3fq58mk8c
+  - &stream age148r2q3cy9sjem37rvgtcc4qjx8usxkdg77pqexa56gmcexn58aaslh3cnj
 creation_rules:
   - path_regex: hosts/toaster/[^/]+\.yaml$
     key_groups:
@@ -66,3 +67,9 @@ creation_rules:
         - *admin_oxa
         age:
         - *conduwuit
+  - path_regex: hosts/stream/[^/]+\.yaml$
+    key_groups:
+      - pgp:
+        - *admin_oxa
+        age:
+        - *stream
diff --git a/flake.nix b/flake.nix
index ddde63b..2b085bc 100644
--- a/flake.nix
+++ b/flake.nix
@@ -71,6 +71,7 @@
             "forgejo"
             "miniflux"
             "radicale"
+            "stream"
           ];
           microvm-unstable-list = [
             "auth"
diff --git a/hosts/cloud/proxy/default.nix b/hosts/cloud/proxy/default.nix
index 9994da4..6cf0151 100644
--- a/hosts/cloud/proxy/default.nix
+++ b/hosts/cloud/proxy/default.nix
@@ -60,5 +60,37 @@ in
     '';
 
     virtualHosts."news.oxapentane.com".extraConfig = "reverse_proxy http://10.89.88.14:8080";
+
+        virtualHosts."music.oxapentane.com".extraConfig = ''
+      route {
+          reverse_proxy /outpost.goauthentik.io/* 10.89.88.11:9000 [fd31:185d:722f::11]:9000
+
+          @protected not path /share/* /rest/*
+          forward_auth @protected 10.89.88.11:9000 {
+              uri /outpost.goauthentik.io/auth/caddy
+              copy_headers X-Authentik-Username>Remote-User
+              trusted_proxies 10.89.88.11 fd31:185d:722f::11
+          }
+
+
+          @subsonic path /rest/*
+          forward_auth @subsonic 10.89.88.11:9000 {
+              uri /outpost.goauthentik.io/auth/caddy
+              copy_headers X-Authentik-Username>Remote-User
+              @error status 1xx 3xx 4xx 5xx
+              handle_response @error {
+                  respond <<SUBSONICERR
+                  <subsonic-response xmlns="http://subsonic.org/restapi" status="failed" version="1.16.1" type="proxy-auth" serverVersion="n/a" openSubsonic="true">
+                    <error code="40" message="Invalid credentials or unsupported client"></error>
+                  </subsonic-response>
+                  SUBSONICERR 200
+              }
+              trusted_proxies 10.89.88.11 fd31:185d:722f::11
+          }
+      }
+      reverse_proxy 10.89.88.17:4533
+
+    '';
+
   };
 }
diff --git a/hosts/stream/default.nix b/hosts/stream/default.nix
new file mode 100644
index 0000000..4543466
--- /dev/null
+++ b/hosts/stream/default.nix
@@ -0,0 +1,76 @@
+{ config, lib, ... }:
+let
+  mac = "02:00:00:00:00:07";
+in
+{
+  imports = [
+    ./navidrome.nix
+  ];
+
+  sops.defaultSopsFile = ./secrets.yaml;
+  sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
+
+  sops.secrets = {
+    "wg/0xa-proxy" = {
+      owner = config.users.users.systemd-network.name;
+    };
+  };
+
+  microvm = {
+    hypervisor = "qemu";
+    mem = 4 * 1024;
+    vcpu = 3;
+    interfaces = [
+      {
+        type = "tap";
+        id = "uvm-stream";
+        mac = mac;
+      }
+    ];
+    shares =
+      [
+        {
+          source = "/nix/store";
+          mountPoint = "/nix/.ro-store";
+          tag = "store";
+          proto = "virtiofs";
+        }
+      ]
+      ++ map
+        (dir: {
+          source = dir;
+          mountPoint = "/${dir}";
+          tag = dir;
+          proto = "virtiofs";
+        })
+        [
+          "etc"
+          "var"
+          "home"
+        ];
+  };
+
+  networking.useNetworkd = true;
+  networking.firewall.enable = lib.mkForce false; # firewalling done by the host
+
+  systemd.network = {
+    enable = true;
+    networks."11-host" = {
+      matchConfig.MACAddress = mac;
+      networkConfig = {
+        Address = "10.99.99.17/24";
+        DHCP = "no";
+      };
+      routes = [
+        {
+          Gateway = "10.99.99.1";
+          Destination = "0.0.0.0/0";
+          Metric = 1024;
+        }
+      ];
+    };
+  };
+
+  networking.hostName = "stream";
+  system.stateVersion = "25.05";
+}
diff --git a/hosts/stream/navidrome.nix b/hosts/stream/navidrome.nix
new file mode 100644
index 0000000..0b1cd07
--- /dev/null
+++ b/hosts/stream/navidrome.nix
@@ -0,0 +1,16 @@
+{ ... }:
+{
+  services.navidrome = {
+    enable = true;
+    settings = {
+      Address = "10.89.88.17";
+      BaseUrl = "/";
+      EnableExternalServices = false;
+      MusicFolder = "/var/lib/navidrome/music";
+      Port = 4533;
+      ScanSchedule = "@every 11m";
+      TranscodingCacheSize = "11GiB";
+      ReverseProxyWhitelist = "10.89.88.1/24";
+    };
+  };
+}
diff --git a/hosts/stream/secrets.yaml b/hosts/stream/secrets.yaml
new file mode 100644
index 0000000..a75b120
--- /dev/null
+++ b/hosts/stream/secrets.yaml
@@ -0,0 +1,38 @@
+wg:
+    0xa-proxy: ENC[AES256_GCM,data:uZfFc4elxCAVZvdIHJ7lgoPs9qKkD9ZvLhcYbexDcqn0alaMzIr++CY52FI=,iv:CREMt6GrLHs4Jwj/55awDFHh9hQlJPEi4ZQ7ZLMPvRA=,tag:iJAGdqzQbyezmDj+tzjdNQ==,type:str]
+sops:
+    age:
+        - recipient: age148r2q3cy9sjem37rvgtcc4qjx8usxkdg77pqexa56gmcexn58aaslh3cnj
+          enc: |
+            -----BEGIN AGE ENCRYPTED FILE-----
+            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsSko5L1BCOTR1QmZabGw3
+            QS9kbDZyWEJvV09MNkNqbTNncjZrOXl6WFZrCmxQelVzbjdvUUl4aVl3UVFVL0Q5
+            S0VDNkdvcDZnZytCdjBrZUZYTFlEZncKLS0tIG1NWnlnRGovcWxDL2JYMTc2bEY5
+            K29Dd0t6b3FMZjU2cXFBbEw3RktkQlkKCh+jXv65KfAsSR4/0+UWwU5tCphrEEgE
+            WDbIdUZ8j5xHHQwJ58cU7uQ+BSy0yZlwwr8vPoaKdXQzMgyrQfq3gg==
+            -----END AGE ENCRYPTED FILE-----
+    lastmodified: "2025-06-12T22:54:11Z"
+    mac: ENC[AES256_GCM,data:15EU9VupWfvR8CrfKrX3nhpD60hYB2LY3vuAPvdqzKLliqSqolNj956fOFicfSHvmW/s+7x+M+5FROnOzSbToTZotFtvALQihHH999veGZMx8Q8oIyljT1PBw/SU9djXPI1KjG/zzYOAwu7y/Ffm0QKhMRziH7CQLn30KR0o2w0=,iv:ghdyTvcpgnBi2L9s4UrzwWwt9TeU0WkGquZ64+w9IN8=,tag:4m4hYFgejlEaQROB/OEi6g==,type:str]
+    pgp:
+        - created_at: "2025-06-12T22:51:49Z"
+          enc: |-
+            -----BEGIN PGP MESSAGE-----
+
+            hQIMA7zUOKwzpAE7AQ/8ClHQoCuiC0AH28bDit4qjNh/TnYq3IbAdyITOqUYPRc6
+            th8MCDY0CfxvzDTLYxTlHH4MNDOiWWTMg/shC8xV3MrAIpEQV79ivYMay04aWpCH
+            HqlhjBynCwAnJRanc9Ch5zW1wCjpgMp+kMDX8JhhUL0Rmt2fd2nSp4R2bb+/HRvn
+            vAaDq3TTLkLr1OHcTNKFFbXafGLKMahxkQGRMgD1DIPCLW+nUxerUnlxHo4yjj3B
+            WKXBVKeWowgBHvelHqUVf6yeSmWZyFDP/jFxFEi75A+BYmwxlQcRDn0L0NKUlMa/
+            uF3jtW3XBMS/sLX7aRscBFeEq9XPce9urJK4KPFNVFI3X1WbD6O/Z87Y+MHa2n0s
+            DuxIwrffpw8p4qSVBAJLbSW1vR/suGh/0Cr31mzo4FJT92A93wc8JdLdpHUfTXL/
+            bEbt6M7OSqvIt5/mor7Ad6/HRkEl+sZJnHqeU/qKfAIKKfz5UVG/ZCZDZlVGTmpp
+            lV9Dn8QjA1ut4lMvACJBocnrlH4T6150ULL0r3gHuVy5YhnGR+LWFdgaCJ4v3f1J
+            A59eAyQENNMoSGZU/YZx95kFPc1O/GIkmiMpXZxBISN3F70QP30ieqbP1qnZRfMg
+            GldVAFhfaHct4lujlgRfOkmwcNG3gTIru4wAqg+wzriI9jm9vEoF0MDJs2cwNYTS
+            XgE32jq6Li59TMUQH9iB4l0cM42QbQ8BcSn6o/NhmF6HHq9W5yuD6EIs4KNfdHv6
+            ikgqQuGGO9v7qDMd0piyqeLRGMANepxrR5uMsbFmMnah9RUq9CjRbMADLa+8DeU=
+            =fEVm
+            -----END PGP MESSAGE-----
+          fp: DD0998E6CDF294537FC604F991FA5E5BF9AA901C
+    unencrypted_suffix: _unencrypted
+    version: 3.10.2
diff --git a/modules/wg/proxy.nix b/modules/wg/proxy.nix
index 3b92b8d..7427829 100644
--- a/modules/wg/proxy.nix
+++ b/modules/wg/proxy.nix
@@ -71,6 +71,14 @@
           publicKey = "dj5/CnTAFe5ELnZ5oWonYc+5VdzDyooTYGb/bqcxf3Y=";
           privateKeyFile = config.sops.secrets."wg/0xa-proxy".path;
         };
+        "stream" = {
+          address = [
+            "10.89.88.17/24"
+            "fd31:185d:722f::17/48"
+          ];
+          publicKey = "RDxbOvd/1FSWqIp5v1++wPBcG1hScAT4mhIlMZdvxU4=";
+          privateKeyFile = config.sops.secrets."wg/0xa-proxy".path;
+        };
       };
     }
   ];