Files
system-config/system/hosts/mcp/containers.nix
2025-03-02 14:35:06 -08:00

442 lines
14 KiB
Nix

# Started from https://nixos.wiki/wiki/Podman
{ config, pkgs, ... }:
{
# Additional configuration
imports =
[
./containers/nextcloud.nix
./containers/prometheus.nix
./containers/searxng.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
domain = "havenisms.com";
hostRule = host: "Host(`${host}.${domain}`)";
localNet = "192.168.0.0/16";
localNetRule = "ClientIP(`${localNet}`)";
localHostRule = host: "${localNetRule} && ${hostRule host}";
in {
traefik = {
image = "traefik";
autoStart = true;
cmd = [];
extraOptions = [
# Proxying Traefik itself
"-l=traefik.enable=true"
"-l=traefik.http.routers.traefik.rule=${localHostRule "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.${domain}"
"-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=${hostRule "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.${domain}"
"-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";
# };
};
# Shared Postgres Database
db = {
image = "docker.io/postgres:16-alpine";
autoStart = true;
volumes = [
# TODO: move to faster storage?
"/tank/db:/var/lib/postgresql/data"
];
environment = {};
extraOptions = [
"-l=traefik.enable=false"
];
};
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.${domain}"
"-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.${domain}"
"-l=homepage.description=Torrent client"
"-l=homepage.widget.type=qbittorrent"
"-l=homepage.widget.url=http://torrents.${domain}"
];
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=${localHostRule "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.${domain}"
"-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=${localHostRule "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.${domain}"
"-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=${localHostRule "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.${domain}"
"-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=${localHostRule "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.${domain}"
"-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=${localHostRule "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.${domain}"
"-l=homepage.description=E-book acquisition"
"-l=homepage.widget.type=readarr"
"-l=homepage.widget.url=http://readarr: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=${localHostRule "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=${localHostRule "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.${domain}"
"-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"
];
};
grafana = {
image = "grafana/grafana-enterprise";
autoStart = true;
dependsOn = [
"db"
];
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.grafana.rule=${localHostRule "grafana"}"
"-l=traefik.http.services.grafana.loadbalancer.server.port=3000"
"-l=homepage.group=Infra"
"-l=homepage.name=Grafana"
"-l=homepage.icon=grafana.png"
"-l=homepage.href=https://grafana.${domain}"
"-l=homepage.description=Database visualization"
"-l=homepage.widget.type=grafana"
"-l=homepage.widget.url=http://grafana:3000"
];
volumes = [
"grafana-storage:/var/lib/grafana"
];
environment = {
GF_SERVER_ROOT_URL = "https://grafna.havenisms.com";
};
};
gitea = {
image = "gitea/gitea:latest-rootless";
autoStart = true;
dependsOn = [
"db"
];
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.gitea.rule=${localHostRule "git"}"
"-l=traefik.http.services.gitea.loadbalancer.server.port=3000"
"-l=homepage.group=Apps"
"-l=homepage.name=Gitea"
"-l=homepage.icon=gitea.png"
"-l=homepage.href=https://git.${domain}"
"-l=homepage.description=Git Server"
];
ports = [
"2222:2222"
];
volumes = [
"/tank/git:/var/lib/gitea"
"/tank/config/gitea:/etc/gitea"
];
user = toString config.users.users.gitea.uid;
environment = {
USER_UID = toString config.users.users.gitea.uid;
USER_GID = toString config.users.groups.git.gid;
GITEA__database__DB_TYPE = "postgres";
GITEA__database__HOST= "db";
GITEA__database__NAME="gitea";
GITEA__database__USER="gitea";
GITEA__database__PASSWD="gitea123";
};
};
};
}