Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions infra/home-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Bootstrap a home network machine as a Nomad/Consul client node that joins the
VPS cluster over a Tailscale (Headscale) mesh VPN. Runs AdGuard Home for
network-wide DNS, a media stack (Jellyfin, Jellyseerr, Sonarr, Radarr,
Prowlarr, qBittorrent) with VPN-routed downloads, and Samba shares including
Time Machine.
network-wide DNS, a media stack (Jellyfin, Jellyseerr, Bazarr, Sonarr,
Radarr, Prowlarr, qBittorrent) with VPN-routed downloads, and Samba shares
including Time Machine.

## Architecture

Expand All @@ -19,8 +19,8 @@ LAN devices -> AdGuard DNS rewrite -> Home Node directly (no auth) |
+-----------------------------------------------------+ |
| |
+---------------------+---- host networking ----------+ |
| Sonarr (8989) Radarr (7878) Jellyfin (8096) | |
| Jellyseerr (5055) | |
| Bazarr (6767) Sonarr (8989) Radarr (7878) | |
| Jellyfin (8096) Jellyseerr (5055) | |
+---------------------+------------------------------+ |
| |
/mnt/media (6TB HDD) |
Expand Down Expand Up @@ -151,6 +151,7 @@ export NOMAD_ADDR=http://127.0.0.1:4646
export NOMAD_TOKEN=<your Nomad token>

nomad job run infra/nomad/jobs/media/downloads.nomad.hcl
nomad job run infra/nomad/jobs/media/bazarr.nomad.hcl
nomad job run infra/nomad/jobs/media/sonarr.nomad.hcl
nomad job run infra/nomad/jobs/media/radarr.nomad.hcl
nomad job run infra/nomad/jobs/media/jellyfin.nomad.hcl
Expand Down Expand Up @@ -195,7 +196,16 @@ Open `http://<home-ip>:7878`.
- Settings > Media Management > Root Folders > Add `/media/Films`
- Settings > Download Clients > Add qBittorrent (host: `<home-ip>`, port: `8080`)

### 3.5 Jellyfin
### 3.5 Bazarr

Open `http://<home-ip>:6767`.

- Complete the setup wizard
- Add Sonarr using `http://127.0.0.1:8989`
- Add Radarr using `http://127.0.0.1:7878`
- Keep media paths aligned with the shared `/media` mount

### 3.6 Jellyfin

Open `http://<home-ip>:8096`.

Expand All @@ -205,7 +215,7 @@ Open `http://<home-ip>:8096`.
- Add library: Anime > `/media/Anime`
- Add library: Music > `/media/Music` (optional)

### 3.6 Jellyseerr
### 3.7 Jellyseerr

Open `http://<home-ip>:5055`.

Expand All @@ -214,7 +224,7 @@ Open `http://<home-ip>:5055`.
- Add Sonarr using `http://<home-ip>:8989`
- Add Radarr using `http://<home-ip>:7878`

### 3.7 Time Machine
### 3.8 Time Machine

On your Mac:

Expand Down Expand Up @@ -289,6 +299,7 @@ sudo chown 1000:1000 /srv/nomad/sonarr/sonarr.db /srv/nomad/radarr/radarr.db
| ------------ | ------------------------------------------ | -------------------------------------- |
| Jellyfin | `http://jellyfin.jorisjonkers.dev:8096` | `https://jellyfin.jorisjonkers.dev` |
| Jellyseerr | `http://jellyseerr.jorisjonkers.dev:5055` | `https://jellyseerr.jorisjonkers.dev` |
| Bazarr | `http://bazarr.jorisjonkers.dev:6767` | `https://bazarr.jorisjonkers.dev` |
| Sonarr | `http://sonarr.jorisjonkers.dev:8989` | `https://sonarr.jorisjonkers.dev` |
| Radarr | `http://radarr.jorisjonkers.dev:7878` | `https://radarr.jorisjonkers.dev` |
| Prowlarr | `http://prowlarr.jorisjonkers.dev:9696` | `https://prowlarr.jorisjonkers.dev` |
Expand All @@ -312,6 +323,7 @@ nomad node status # home node "ready"

# Media stack
nomad job status downloads # gluetun + qbittorrent + prowlarr
nomad job status bazarr
nomad job status sonarr
nomad job status radarr
nomad job status jellyfin
Expand All @@ -324,6 +336,7 @@ nomad alloc exec -task qbittorrent "$ALLOC" curl -s ifconfig.me
# DNS rewrites (from a LAN device using AdGuard DNS)
dig @<home-ip> jellyfin.jorisjonkers.dev # -> home LAN IP
dig @<home-ip> jellyseerr.jorisjonkers.dev # -> home LAN IP
dig @<home-ip> bazarr.jorisjonkers.dev # -> home LAN IP

# Samba
smbclient -L //<home-ip>/ -N # lists media + timemachine
Expand Down Expand Up @@ -355,6 +368,7 @@ infra/home-node/

infra/nomad/jobs/media/
downloads.nomad.hcl gluetun VPN + qBittorrent + Prowlarr
bazarr.nomad.hcl Subtitle management
sonarr.nomad.hcl TV show management
radarr.nomad.hcl Movie management
jellyfin.nomad.hcl Media server
Expand Down
2 changes: 2 additions & 0 deletions infra/home-node/adguard/AdGuardHome.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ dns:
answer: __HOME_LAN_IP__
- domain: jellyseerr.jorisjonkers.dev
answer: __HOME_LAN_IP__
- domain: bazarr.jorisjonkers.dev
answer: __HOME_LAN_IP__
- domain: sonarr.jorisjonkers.dev
answer: __HOME_LAN_IP__
- domain: radarr.jorisjonkers.dev
Expand Down
5 changes: 5 additions & 0 deletions infra/home-node/configs/nomad-client.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ client {
read_only = false
}

host_volume "bazarr_config" {
path = "/srv/nomad/bazarr"
read_only = false
}

host_volume "sonarr_config" {
path = "/srv/nomad/sonarr"
read_only = false
Expand Down
5 changes: 3 additions & 2 deletions infra/home-node/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,15 @@ install_command() {
run mkdir -p /etc/consul.d /etc/nomad.d
run mkdir -p /opt/consul /opt/nomad
run mkdir -p /srv/nomad/lightrag /srv/nomad/alloy
run mkdir -p /srv/nomad/qbittorrent /srv/nomad/prowlarr /srv/nomad/sonarr /srv/nomad/radarr /srv/nomad/jellyfin /srv/nomad/jellyseerr
run mkdir -p /srv/nomad/qbittorrent /srv/nomad/prowlarr /srv/nomad/bazarr /srv/nomad/sonarr /srv/nomad/radarr /srv/nomad/jellyfin /srv/nomad/jellyseerr
run mkdir -p /mnt/media

run chown -R consul:consul /opt/consul
run chown -R nomad:nomad /opt/nomad

# Volume ownership matching container UIDs (linuxserver.io convention: UID 1000)
run chown -R 1000:1000 /srv/nomad/lightrag
run chown -R 1000:1000 /srv/nomad/qbittorrent /srv/nomad/prowlarr /srv/nomad/sonarr /srv/nomad/radarr /srv/nomad/jellyfin /srv/nomad/jellyseerr
run chown -R 1000:1000 /srv/nomad/qbittorrent /srv/nomad/prowlarr /srv/nomad/bazarr /srv/nomad/sonarr /srv/nomad/radarr /srv/nomad/jellyfin /srv/nomad/jellyseerr

# Ensure tun module is available for gluetun VPN
run modprobe tun || true
Expand Down Expand Up @@ -265,6 +265,7 @@ EOF
run ufw allow proto tcp from 192.168.0.0/16 to any port 445 comment 'samba'
run ufw allow proto tcp from 192.168.0.0/16 to any port 8096 comment 'jellyfin'
run ufw allow proto tcp from 192.168.0.0/16 to any port 5055 comment 'jellyseerr'
run ufw allow proto tcp from 192.168.0.0/16 to any port 6767 comment 'bazarr'
run ufw allow proto tcp from "${nomad_bridge_subnet}" to any port 8989 comment 'sonarr from nomad bridge'
run ufw allow proto tcp from "${nomad_bridge_subnet}" to any port 7878 comment 'radarr from nomad bridge'
run ufw --force enable
Expand Down
2 changes: 1 addition & 1 deletion infra/nomad/jobs/apps/auth-api.nomad.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ job "auth-api" {
AUTH_ISSUER = "https://auth.${var.domain}"
SESSION_COOKIE_DOMAIN = "${var.domain}"
SESSION_COOKIE_SECURE = "true"
AUTH_CORS_ALLOWED_ORIGINS = "https://${var.domain},https://auth.${var.domain},https://assistant.${var.domain},https://vault.${var.domain},https://n8n.${var.domain},https://grafana.${var.domain},https://nomad.${var.domain},https://rabbitmq.${var.domain},https://stalwart.${var.domain},https://traefik.${var.domain},https://status.${var.domain},https://jellyfin.${var.domain},https://sonarr.${var.domain},https://radarr.${var.domain},https://prowlarr.${var.domain},https://qbittorrent.${var.domain},https://adguard.${var.domain},https://headscale.${var.domain}"
AUTH_CORS_ALLOWED_ORIGINS = "https://${var.domain},https://auth.${var.domain},https://assistant.${var.domain},https://vault.${var.domain},https://n8n.${var.domain},https://grafana.${var.domain},https://nomad.${var.domain},https://rabbitmq.${var.domain},https://stalwart.${var.domain},https://traefik.${var.domain},https://status.${var.domain},https://jellyfin.${var.domain},https://jellyseerr.${var.domain},https://bazarr.${var.domain},https://sonarr.${var.domain},https://radarr.${var.domain},https://prowlarr.${var.domain},https://qbittorrent.${var.domain},https://adguard.${var.domain},https://headscale.${var.domain}"
DEPLOYMENT_ENVIRONMENT = "production"
SERVICE_VERSION = var.image_tag
OTEL_SERVICE_NAME = "auth-api"
Expand Down
91 changes: 91 additions & 0 deletions infra/nomad/jobs/media/bazarr.nomad.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
variable "domain" {
type = string
default = "jorisjonkers.dev"
}

job "bazarr" {
datacenters = ["dc1"]
type = "service"

update {
max_parallel = 1
min_healthy_time = "10s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = true
}

group "bazarr" {
constraint {
attribute = "${meta.node_type}"
value = "home"
}

network {
mode = "host"
port "http" { static = 6767 }
}

volume "media_data" {
type = "host"
source = "media_data"
read_only = false
}

volume "bazarr_config" {
type = "host"
source = "bazarr_config"
read_only = false
}

service {
name = "bazarr"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.bazarr.rule=Host(`bazarr.${var.domain}`)",
"traefik.http.routers.bazarr.entrypoints=websecure",
"traefik.http.routers.bazarr.tls=true",
"traefik.http.routers.bazarr.middlewares=forward-auth@file,media-security-headers@file",
]

check {
type = "http"
path = "/"
interval = "15s"
timeout = "5s"
}
}

task "bazarr" {
driver = "docker"

env {
PUID = "1000"
PGID = "1000"
TZ = "Europe/Amsterdam"
}

config {
image = "linuxserver/bazarr:1.5.6"
network_mode = "host"
}

volume_mount {
volume = "media_data"
destination = "/media"
}

volume_mount {
volume = "bazarr_config"
destination = "/config"
}

resources {
cpu = 1000
memory = 768
memory_max = 1536
}
}
}
}
7 changes: 5 additions & 2 deletions infra/scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# infra Observability, platform, mail, core jobs (no Traefik)
# edge Traefik only
# apps auth-api, assistant-api, auth-ui, assistant-ui, app-ui
# media downloads (gluetun+qBittorrent+Prowlarr), Sonarr, Radarr, Jellyfin, Jellyseerr
# media downloads (gluetun+qBittorrent+Prowlarr), Bazarr, Sonarr, Radarr, Jellyfin, Jellyseerr
# all Everything (default)
set -euo pipefail

Expand Down Expand Up @@ -40,7 +40,7 @@ Phases:
infra Observability, platform, mail, core jobs
edge Traefik only
apps auth-api, assistant-api, auth-ui, assistant-ui, app-ui
media downloads (gluetun+qBittorrent+Prowlarr), Sonarr, Radarr, Jellyfin, Jellyseerr
media downloads (gluetun+qBittorrent+Prowlarr), Bazarr, Sonarr, Radarr, Jellyfin, Jellyseerr
all Everything (default)

Options:
Expand Down Expand Up @@ -242,6 +242,7 @@ deploy_apps() {

deploy_media() {
submit_job "${JOBS_DIR}/media/downloads.nomad.hcl"
submit_job "${JOBS_DIR}/media/bazarr.nomad.hcl"
submit_job "${JOBS_DIR}/media/sonarr.nomad.hcl"
submit_job "${JOBS_DIR}/media/radarr.nomad.hcl"
submit_job "${JOBS_DIR}/media/jellyfin.nomad.hcl"
Expand Down Expand Up @@ -286,6 +287,7 @@ if [[ "${WAIT}" == true && "${MODE}" == "apply" ]]; then
;;
media)
wait_for_job_ready downloads 300
wait_for_job_ready bazarr 180
wait_for_job_ready sonarr 180
wait_for_job_ready radarr 180
wait_for_job_ready jellyfin 240
Expand All @@ -307,6 +309,7 @@ if [[ "${WAIT}" == true && "${MODE}" == "apply" ]]; then
wait_for_job_ready assistant-ui 240
wait_for_job_ready app-ui 240
wait_for_job_ready traefik 180
wait_for_job_ready bazarr 180
wait_for_job_ready sonarr 180
wait_for_job_ready radarr 180
wait_for_job_ready jellyfin 240
Expand Down
Loading