diff --git a/nix/home-old.nix b/nix/home-old.nix deleted file mode 100644 index 65e2cc6..0000000 --- a/nix/home-old.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ config, pkgs, ... }: - -{ - home.username = "luca"; - home.homeDirectory = "/home/luca"; - - programs = { - git = import ./git.nix; - alacritty = { - enable = true; - settings.window.opacity = 0.6; - }; - zsh = { - enable = true; - enableCompletion = true; - autosuggestion.enable = true; - }; - }; - - services.picom = { - enable = true; - vSync = true; - }; - - xsession.windowManager.i3 = { - enable = true; - config = { - modifier = "Mod4"; - defaultWorkspace = "workspace number 1"; - terminal = "alacritty"; - }; - }; - - home.stateVersion = "24.11"; - - programs.home-manager.enable = true; - -} diff --git a/nix/homelab/config.toml b/nix/homelab/config.toml index 5f26a4e..ed2959b 100644 --- a/nix/homelab/config.toml +++ b/nix/homelab/config.toml @@ -11,6 +11,7 @@ routes = [ kind = "TCP", name = "gitea-ssh", namespace = "git", + entrypoint = "ssh", service = "gitea-ssh", port = 22, private = false @@ -24,7 +25,7 @@ routes = [ { name = "sonarr", namespace = "media", - port = 8787, + port = 8989, private = true }, { @@ -47,6 +48,7 @@ routes = [ name = "minecraft-router", hostname = "minecraft", namespace = "minecraft", + entrypoint = "minecraft", service = "minecraft-router-mc-router", port = 25565, private = false @@ -67,7 +69,7 @@ routes = [ name = "qbittorrent", hostname = "qbit", namespace = "media", - port = 8090, + port = 8080, private = true }, { diff --git a/nix/homelab/helm/helmfile.yaml b/nix/homelab/helm/helmfile.yaml index 7369286..ef52842 100644 --- a/nix/homelab/helm/helmfile.yaml +++ b/nix/homelab/helm/helmfile.yaml @@ -56,6 +56,14 @@ releases: values: - values/pihole.yaml + # Media + - name: jellyfin + namespace: media + chart: jellyfin/jellyfin + version: 2.7.0 + values: + - values/media/jellyfin.yaml + # Minecraft - name: minecraft-router namespace: minecraft diff --git a/nix/homelab/helm/values/media/jellyfin.yaml b/nix/homelab/helm/values/media/jellyfin.yaml new file mode 100644 index 0000000..550dbc0 --- /dev/null +++ b/nix/homelab/helm/values/media/jellyfin.yaml @@ -0,0 +1,21 @@ +persistence: + media: + enabled: false + +resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 1 + memory: 2Gi + +volumeMounts: + - name: data + mountPath: /mnt/data + +volumes: + - name: data + nfs: + server: 192.168.27.2 + path: /data diff --git a/nix/homelab/helm/values/pihole.yaml b/nix/homelab/helm/values/pihole.yaml index 383fb5d..f8bc59a 100644 --- a/nix/homelab/helm/values/pihole.yaml +++ b/nix/homelab/helm/values/pihole.yaml @@ -8,6 +8,12 @@ serviceWeb: https: enabled: false +serviceDns: + type: LoadBalancer + mixedService: true + annotations: + metallb.universe.tf/loadBalancerIPs: "192.168.18.32" + resources: requests: cpu: 100m diff --git a/nix/homelab/kustomize/kustomization.yaml b/nix/homelab/kustomize/kustomization.yaml index 83e6c2f..20be2d1 100644 --- a/nix/homelab/kustomize/kustomization.yaml +++ b/nix/homelab/kustomize/kustomization.yaml @@ -8,4 +8,9 @@ resources: - ./traefik/chains.yaml - ./cert-manager/config.yaml - ./routes.yaml + - ./media/sonarr.yaml + - ./media/prowlarr.yaml + - ./media/radarr.yaml + - ./media/qbittorrent.yaml + - ./media/flaresolverr.yaml diff --git a/nix/homelab/kustomize/media/flaresolverr.yaml b/nix/homelab/kustomize/media/flaresolverr.yaml new file mode 100644 index 0000000..5f5b9d4 --- /dev/null +++ b/nix/homelab/kustomize/media/flaresolverr.yaml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: flaresolverr-config + namespace: media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flaresolverr + namespace: media + labels: + app: flaresolverr +spec: + replicas: 1 + selector: + matchLabels: + app: flaresolverr + template: + metadata: + labels: + app: flaresolverr + spec: + containers: + - name: flaresolverr + image: ghcr.io/flaresolverr/flaresolverr + ports: + - containerPort: 8191 + name: http + env: + - name: TZ + value: America/Vancouver + volumeMounts: + - name: config + mountPath: /config + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1 + memory: 4Gi + livenessProbe: + httpGet: + path: /health + port: 8191 + initialDelaySeconds: 30 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /health + port: 8191 + initialDelaySeconds: 5 + volumes: + - name: config + persistentVolumeClaim: + claimName: flaresolverr-config +--- +apiVersion: v1 +kind: Service +metadata: + name: flaresolverr + namespace: media +spec: + selector: + app: flaresolverr + ports: + - port: 8191 + targetPort: 8191 + name: http diff --git a/nix/homelab/kustomize/media/prowlarr.yaml b/nix/homelab/kustomize/media/prowlarr.yaml new file mode 100644 index 0000000..aa29e8c --- /dev/null +++ b/nix/homelab/kustomize/media/prowlarr.yaml @@ -0,0 +1,84 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: prowlarr-config + namespace: media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prowlarr + namespace: media + labels: + app: prowlarr +spec: + replicas: 1 + selector: + matchLabels: + app: prowlarr + template: + metadata: + labels: + app: prowlarr + spec: + containers: + - name: prowlarr + image: lscr.io/linuxserver/prowlarr + ports: + - containerPort: 9696 + name: http + env: + - name: PUID + value: "1000" + - name: PGID + value: "1000" + - name: TZ + value: "America/Vancouver" + volumeMounts: + - name: config + mountPath: /config + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1 + memory: 1Gi + livenessProbe: + httpGet: + path: /ping + port: 9696 + initialDelaySeconds: 30 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /ping + port: 9696 + initialDelaySeconds: 10 + periodSeconds: 10 + volumes: + - name: config + persistentVolumeClaim: + claimName: prowlarr-config +--- +apiVersion: v1 +kind: Service +metadata: + name: prowlarr + namespace: media + labels: + app: prowlarr +spec: + selector: + app: prowlarr + ports: + - port: 9696 + targetPort: 9696 + protocol: TCP + name: http diff --git a/nix/homelab/kustomize/media/qbittorrent.yaml b/nix/homelab/kustomize/media/qbittorrent.yaml new file mode 100644 index 0000000..f1efc72 --- /dev/null +++ b/nix/homelab/kustomize/media/qbittorrent.yaml @@ -0,0 +1,141 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: qbittorrent-config + namespace: media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: qbittorrent + namespace: media + labels: + app: qbittorrent + annotations: + kubectl.kubernetes.io/default-container: qbittorrent +spec: + replicas: 1 + selector: + matchLabels: + app: qbittorrent + template: + metadata: + labels: + app: qbittorrent + spec: + containers: + - name: gluetun + image: qmcgaw/gluetun + securityContext: + capabilities: + add: + - NET_ADMIN + env: + - name: VPN_SERVICE_PROVIDER + value: "custom" + - name: VPN_TYPE + value: "wireguard" + - name: TZ + value: "America/Vancouver" + - name: FIREWALL + value: "on" + - name: FIREWALL_OUTBOUND_SUBNETS + value: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" + - name: DNS_KEEP_NAMESERVER + value: "on" + - name: LOG_LEVEL + value: "info" + volumeMounts: + - name: wireguard-config + mountPath: /gluetun/wireguard/wg0.conf + subPath: wg0.conf + readOnly: true + - name: tun + mountPath: /dev/net/tun + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + livenessProbe: + httpGet: + path: /v1/vpn/status + port: 8000 + initialDelaySeconds: 30 + periodSeconds: 60 + timeoutSeconds: 10 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /v1/vpn/status + port: 8000 + initialDelaySeconds: 10 + periodSeconds: 60 + timeoutSeconds: 5 + + - name: qbittorrent + image: lscr.io/linuxserver/qbittorrent + ports: + - containerPort: 8080 + name: http + env: + - name: PUID + value: "1000" + - name: PGID + value: "1000" + - name: TZ + value: "America/Vancouver" + - name: WEBUI_PORT + value: "8080" + volumeMounts: + - name: config + mountPath: /config + - name: data + mountPath: /mnt/data + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 2 + memory: 2Gi + + volumes: + - name: config + persistentVolumeClaim: + claimName: qbittorrent-config + - name: data + nfs: + server: 192.168.27.2 + path: /data + - name: wireguard-config + secret: + secretName: wireguard-config + - name: tun + hostPath: + path: /dev/net/tun + type: CharDevice +--- +apiVersion: v1 +kind: Service +metadata: + name: qbittorrent + namespace: media + labels: + app: qbittorrent +spec: + selector: + app: qbittorrent + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http diff --git a/nix/homelab/kustomize/media/radarr.yaml b/nix/homelab/kustomize/media/radarr.yaml new file mode 100644 index 0000000..5f45afe --- /dev/null +++ b/nix/homelab/kustomize/media/radarr.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: radarr-config + namespace: media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: radarr + namespace: media + labels: + app: radarr +spec: + replicas: 1 + selector: + matchLabels: + app: radarr + template: + metadata: + labels: + app: radarr + spec: + containers: + - name: radarr + image: lscr.io/linuxserver/radarr + ports: + - containerPort: 7878 + name: http + env: + - name: PUID + value: "1000" + - name: PGID + value: "1000" + - name: TZ + value: "America/Vancouver" + volumeMounts: + - name: config + mountPath: /config + - name: data + mountPath: /mnt/data + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1 + memory: 1Gi + livenessProbe: + httpGet: + path: /ping + port: 7878 + initialDelaySeconds: 30 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /ping + port: 7878 + initialDelaySeconds: 10 + periodSeconds: 10 + volumes: + - name: config + persistentVolumeClaim: + claimName: radarr-config + - name: data + nfs: + server: 192.168.27.2 + path: /data +--- +apiVersion: v1 +kind: Service +metadata: + name: radarr + namespace: media + labels: + app: radarr +spec: + selector: + app: radarr + ports: + - port: 7878 + targetPort: 7878 + protocol: TCP + name: http diff --git a/nix/homelab/kustomize/media/sonarr.yaml b/nix/homelab/kustomize/media/sonarr.yaml index 70c3734..c2524ee 100644 --- a/nix/homelab/kustomize/media/sonarr.yaml +++ b/nix/homelab/kustomize/media/sonarr.yaml @@ -35,6 +35,9 @@ spec: containers: - name: sonarr image: lscr.io/linuxserver/sonarr + securityContext: + runAsUser: 0 + runAsGroup: 0 ports: - containerPort: 8989 name: http diff --git a/nix/homelab/kustomize/routes.yaml b/nix/homelab/kustomize/routes.yaml index 4f80444..1f073dc 100644 --- a/nix/homelab/kustomize/routes.yaml +++ b/nix/homelab/kustomize/routes.yaml @@ -21,7 +21,7 @@ metadata: namespace: git spec: entryPoints: - - gitea-ssh + - ssh routes: - match: HostSNI(`*`) services: @@ -64,7 +64,7 @@ spec: rules: - backendRefs: - name: sonarr - port: 8787 + port: 8989 filters: - type: ExtensionRef extensionRef: @@ -123,7 +123,7 @@ metadata: namespace: minecraft spec: entryPoints: - - minecraft-router + - minecraft routes: - match: HostSNI(`*`) services: @@ -188,7 +188,7 @@ spec: rules: - backendRefs: - name: qbittorrent - port: 8090 + port: 8080 filters: - type: ExtensionRef extensionRef: diff --git a/nix/homelab/src/commands/generate_routes.rs b/nix/homelab/src/commands/generate_routes.rs index 0f0e7c6..edcdf4a 100644 --- a/nix/homelab/src/commands/generate_routes.rs +++ b/nix/homelab/src/commands/generate_routes.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::{Config, HelperError}; -#[derive(Serialize, Deserialize, Default)] +#[derive(Serialize, Deserialize, Default, Debug, Clone)] pub struct Route { #[serde(default)] kind: RouteKind, @@ -23,7 +23,7 @@ impl Route { } } -#[derive(Serialize, Deserialize, Default)] +#[derive(Serialize, Deserialize, Default, Debug, Clone)] enum RouteKind { #[default] HTTP, @@ -31,17 +31,16 @@ enum RouteKind { } pub fn generate_routes(config: &Config) -> Result<(), HelperError> { - let routes = config - .routes - .iter() - .enumerate() - .fold(String::new(), |mut acc, (i, r)| { + let routes = config.routes.iter().enumerate().try_fold( + String::new(), + |mut acc, (i, r)| -> Result<_, HelperError> { if i > 0 { acc.push_str("\n---\n"); } - acc.push_str(&generate_route(r)); - acc - }); + acc.push_str(&generate_route(r)?); + Ok(acc) + }, + )?; let chains = generate_chains(&config.routes); std::fs::write("kustomize/routes.yaml", &routes)?; std::fs::write("kustomize/traefik/chains.yaml", &chains)?; @@ -50,11 +49,11 @@ pub fn generate_routes(config: &Config) -> Result<(), HelperError> { Ok(()) } -fn generate_route(route: &Route) -> String { - match route.kind { +fn generate_route(route: &Route) -> Result { + Ok(match route.kind { RouteKind::HTTP => generate_http_route(route), - RouteKind::TCP => generate_tcp_route(route), - } + RouteKind::TCP => generate_tcp_route(route)?, + }) } fn generate_chains(routes: &[Route]) -> String { @@ -133,7 +132,7 @@ spec: .to_string() } -fn generate_tcp_route(route: &Route) -> String { +fn generate_tcp_route(route: &Route) -> Result { let mut middlewares_section = String::new(); if route.private { middlewares_section = format!( @@ -143,7 +142,7 @@ fn generate_tcp_route(route: &Route) -> String { ); } - format!( + Ok(format!( r#"apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: @@ -159,11 +158,14 @@ spec: port: {}"#, route.name, route.namespace, - route.entrypoint, + route + .entrypoint + .as_ref() + .ok_or(HelperError::TCPEntryPoint(route.name.clone()))?, middlewares_section, route.service.as_ref().unwrap_or_else(|| &route.name), route.port ) .trim_end() - .to_string() + .to_string()) } diff --git a/nix/homelab/src/main.rs b/nix/homelab/src/main.rs index 3c515a9..20d29c1 100644 --- a/nix/homelab/src/main.rs +++ b/nix/homelab/src/main.rs @@ -25,6 +25,8 @@ pub enum HelperError { ReadFile(#[from] std::io::Error), #[error("error parsing config toml")] TomlError(#[from] toml::de::Error), + #[error("entrypoint required for tcproute: {0:?}")] + TCPEntryPoint(String), } #[derive(Serialize, Deserialize)]