# Started from https://nixos.wiki/wiki/Podman { config, pkgs, ... }: { # Additional configuration imports = [ ./containers/gitea.nix ./containers/grafana.nix ./containers/jobhunt.nix ./containers/nextcloud.nix ./containers/prometheus.nix ./containers/pocket-id.nix ./containers/public-homepage.nix ./containers/searxng.nix ./containers/shared-postgres.nix ./containers/synapse.nix ]; # Enable common container config files in /etc/containers virtualisation.containers.enable = true; virtualisation = { podman = { enable = true; # Create a `docker` alias for podman, to use it as a drop-in replacement dockerCompat = true; # Required for containers under podman-compose to be able to talk to each other. defaultNetwork.settings.dns_enabled = true; extraPackages = [ pkgs.zfs ]; }; }; # Useful other development tools environment.systemPackages = with pkgs; [ dive # look into docker image layers podman-tui # status of containers in the terminal docker-compose # start group of containers for dev #podman-compose # start group of containers for dev ]; users.groups = { git = { }; timetagger = { }; }; users.users = { gitea = { uid = 2001; isSystemUser = true; description = "System User for Gitea"; extraGroups = [ "git" ]; group = "git"; }; timetagger = { uid = 2002; isSystemUser = true; description = "System User for TimeTagger"; group = "timetagger"; }; }; virtualisation.oci-containers.backend = "podman"; virtualisation.oci-containers.containers = let inherit (import ./containers/lib.nix config) hostRuleHavenisms localHostRuleHavenisms havenisms; in { traefik = { image = "traefik"; autoStart = true; cmd = [ ]; extraOptions = [ # Proxying Traefik itself "-l=traefik.enable=true" "-l=traefik.http.routers.traefik.rule=${localHostRuleHavenisms "proxy"}" "-l=traefik.http.services.traefik.loadbalancer.server.port=8080" "-l=homepage.group=Infra" "-l=homepage.name=Traefik" "-l=homepage.icon=traefik.svg" "-l=homepage.href=https://proxy.${havenisms}" "-l=homepage.description=Reverse proxy" "-l=homepage.widget.type=traefik" "-l=homepage.widget.url=http://traefik:8080" ]; ports = [ "443:443" "80:80" ]; environmentFiles = [ ]; volumes = [ "/var/run/podman/podman.sock:/var/run/docker.sock:ro" "/tank/config/traefik:/etc/traefik" ]; }; jellyfin = { image = "lscr.io/linuxserver/jellyfin"; autoStart = true; extraOptions = [ "--device=/dev/dri:/dev/dri" "-l=traefik.enable=true" "-l=traefik.http.routers.jellyfin.rule=${hostRuleHavenisms "jellyfin"}" "-l=traefik.http.services.jellyfin.loadbalancer.server.port=8096" "-l=homepage.group=Apps" "-l=homepage.name=Jellyfin" "-l=homepage.icon=jellyfin.svg" "-l=homepage.href=https://jellyfin.${havenisms}" "-l=homepage.description=Media player" "-l=homepage.widget.type=jellyfin" "-l=homepage.widget.key={{HOMEPAGE_FILE_JELLYFIN_KEY}}" "-l=homepage.widget.url=http://jellyfin:8096" "-l=homepage.widget.enableBlocks=true" ]; volumes = [ "/tank/media/collection:/data" "/tank/config/jellyfin:/config" ]; # environment = { # TZ = vars.timeZone; # PUID = "994"; # UMASK = "002"; # GUID = "993"; # }; }; deluge = { image = "linuxserver/deluge:latest"; autoStart = true; dependsOn = [ "gluetun" ]; extraOptions = [ "--network=container:gluetun" "-l=homepage.group=Arr" "-l=homepage.name=Deluge" "-l=homepage.icon=deluge.svg" "-l=homepage.href=https://deluge.${havenisms}" "-l=homepage.description=Torrent client" "-l=homepage.widget.type=deluge" "-l=homepage.widget.password={{HOMEPAGE_FILE_DELUGE_PASSWORD}}" "-l=homepage.widget.url=http://gluetun:8112" ]; volumes = [ "/tank/media:/data" "/tank/config/deluge:/config" ]; }; qbittorrent = { image = "linuxserver/qbittorrent:latest"; autoStart = true; dependsOn = [ "gluetun" ]; extraOptions = [ "--network=container:gluetun" "-l=homepage.group=Arr" "-l=homepage.name=qBitTorrent" "-l=homepage.icon=qbittorrent.svg" "-l=homepage.href=https://torrents.${havenisms}" "-l=homepage.description=Torrent client" "-l=homepage.widget.type=qbittorrent" "-l=homepage.widget.url=http://torrents.${havenisms}" ]; volumes = [ "/tank/media/Downloads:/downloads" "/tank/config/qbittorrent:/config" ]; environment = { PUID = "911"; PGID = "911"; UMASK = "002"; }; }; gluetun = { image = "qmcgaw/gluetun:latest"; autoStart = true; extraOptions = [ # add network admin capability. "--cap-add=NET_ADMIN" "--device=/dev/net/tun:/dev/net/tun" "-l=traefik.enable=true" "-l=traefik.http.routers.torrents.rule=${localHostRuleHavenisms "torrents"}" "-l=traefik.http.routers.torrents.service=torrents" "-l=traefik.http.services.torrents.loadbalancer.server.port=8080" "-l=homepage.group=Infra" "-l=homepage.name=GlueTun" "-l=homepage.icon=gluetun.svg" "-l=homepage.href=https://torrents.${havenisms}" "-l=homepage.description=VPN killswitch" "-l=homepage.widget.type=gluetun" "-l=homepage.widget.url=http://gluetun:8000" ]; ports = [ "127.0.0.1:8083:8000" ]; environmentFiles = [ "/tank/config/gluetun/vpn.env" ]; environment = { VPN_SERVICE_PROVIDER = "protonvpn"; UMASK = "002"; }; }; prowlarr = { image = "lscr.io/linuxserver/prowlarr"; autoStart = true; extraOptions = [ "-l=traefik.enable=true" "-l=traefik.http.routers.prowlarr.rule=${localHostRuleHavenisms "prowlarr"}" "-l=traefik.http.services.prowlarr.loadbalancer.server.port=9696" "-l=homepage.group=Arr" "-l=homepage.name=Prowlarr" "-l=homepage.icon=prowlarr.svg" "-l=homepage.href=https://prowlarr.${havenisms}" "-l=homepage.description=Torrent indexer" ]; volumes = [ "/tank/config/prowlarr:/config" ]; environment = { UMASK = "002"; }; }; # Currently broken and doesn't work. :( # flaresolverr = { # image = "ghcr.io/flaresolverr/flaresolverr:latest"; # autoStart = true; # extraOptions = [ # "-l=homepage.group=Infra" # "-l=homepage.name=FlareSolverr" # "-l=homepage.icon=flaresolverr.svg" # "-l=homepage.href=https://flaresolverr.${domain}" # "-l=homepage.description=Cloudflare bypass" # ]; # volumes = [ # "/tank/config/flaresolverr:/config" # ]; # environment = { # UMASK = "002"; # }; # }; radarr = { image = "lscr.io/linuxserver/radarr"; autoStart = true; extraOptions = [ "-l=traefik.enable=true" "-l=traefik.http.routers.radarr.rule=${localHostRuleHavenisms "radarr"}" "-l=traefik.http.services.radarr.loadbalancer.server.port=7878" "-l=homepage.group=Arr" "-l=homepage.name=Radarr" "-l=homepage.icon=radarr.svg" "-l=homepage.href=https://radarr.${havenisms}" "-l=homepage.description=Movie acquisition" "-l=homepage.widget.type=radarr" "-l=homepage.widget.url=http://radarr:7878" "-l=homepage.widget.key={{HOMEPAGE_FILE_RADARR_KEY}}" ]; volumes = [ "/tank/media:/data" "/tank/config/radarr:/config" ]; environment = { UMASK = "002"; }; }; sonarr = { image = "lscr.io/linuxserver/sonarr"; autoStart = true; extraOptions = [ "-l=traefik.enable=true" "-l=traefik.http.routers.sonarr.rule=${localHostRuleHavenisms "sonarr"}" "-l=traefik.http.services.sonarr.loadbalancer.server.port=8989" "-l=homepage.group=Arr" "-l=homepage.name=Sonarr" "-l=homepage.icon=sonarr.svg" "-l=homepage.href=https://sonarr.${havenisms}" "-l=homepage.description=Show acquisition" "-l=homepage.widget.type=sonarr" "-l=homepage.widget.url=http://sonarr:8989" "-l=homepage.widget.key={{HOMEPAGE_FILE_SONARR_KEY}}" ]; volumes = [ "/tank/media:/data" "/tank/config/sonarr:/config" ]; environment = { UMASK = "002"; }; }; readarr = { # The Linuxserver version of this image doesn't have a latest tag. Odd. image = "lscr.io/linuxserver/readarr:develop"; autoStart = true; extraOptions = [ "-l=traefik.enable=true" "-l=traefik.http.routers.readarr.rule=${localHostRuleHavenisms "readarr"}" "-l=traefik.http.services.readarr.loadbalancer.server.port=8787" "-l=homepage.group=Arr" "-l=homepage.name=Readarr" "-l=homepage.icon=readarr.svg" "-l=homepage.href=https://readarr.${havenisms}" "-l=homepage.description=E-book acquisition" "-l=homepage.widget.type=readarr" "-l=homepage.widget.url=http://readarr.havenisms.com:8787" "-l=homepage.widget.key={{HOMEPAGE_FILE_READARR_KEY}}" ]; volumes = [ "/tank/media:/data" "/tank/config/readarr:/config" ]; environment = { UMASK = "002"; }; }; homepage = { image = "ghcr.io/gethomepage/homepage:latest"; autoStart = true; extraOptions = [ "-l=traefik.enable=true" "-l=traefik.http.routers.homepage.rule=${localHostRuleHavenisms "start"}" "-l=traefik.http.services.homepage.loadbalancer.server.port=3000" ]; volumes = [ "/tank/config/homepage:/app/config" "/tank/secrets/deluge.pass:/app/config/secrets/deluge.pass" "/tank/secrets/jellyfin.key:/app/config/secrets/jellyfin.key" "/tank/secrets/radarr.key:/app/config/secrets/radarr.key" "/tank/secrets/sonarr.key:/app/config/secrets/sonarr.key" "/var/run/podman/podman.sock:/var/run/docker.sock:ro" ]; environment = { HOMEPAGE_FILE_JELLYFIN_KEY = "/app/config/secrets/jellyfin.key"; HOMEPAGE_FILE_RADARR_KEY = "/app/config/secrets/radarr.key"; HOMEPAGE_FILE_SONARR_KEY = "/app/config/secrets/sonarr.key"; HOMEPAGE_FILE_READARR_KEY = "/app/config/secrets/readarr.key"; HOMEPAGE_FILE_DELUGE_PASSWORD = "/app/config/secrets/deluge.pass"; }; }; scrutiny = { image = "ghcr.io/analogj/scrutiny:master-omnibus"; autoStart = true; extraOptions = [ "-l=traefik.enable=true" "-l=traefik.http.routers.scrutiny.rule=${localHostRuleHavenisms "scrutiny"}" "-l=traefik.http.services.scrutiny.loadbalancer.server.port=8080" "-l=homepage.group=Infra" "-l=homepage.name=Scrutiny" "-l=homepage.icon=scrutiny-light.png" "-l=homepage.href=https://scrutiny.${havenisms}" "-l=homepage.description=S.M.A.R.T. monitoring" "-l=homepage.widget.type=scrutiny" "-l=homepage.widget.url=http://scrutiny:8080" "--cap-add=SYS_RAWIO" "--device=/dev/sda:/dev/sda" "--device=/dev/sdb:/dev/sdb" "--device=/dev/sdc:/dev/sdc" "--device=/dev/sdd:/dev/sdd" ]; volumes = [ "/run/udev:/run/udev:ro" "/tank/config/scrutiny/config:/opt/scrutiny/config" "/tank/config/scrutiny/influxdb:/opt/scrutiny/influxdb" ]; }; valkey = { image = "docker.io/valkey/valkey:7-alpine"; autoStart = true; volumes = [ "/tank/config/valkey:/usr/local/etc/valkey" ]; }; }; }