diff --git a/.env.example b/.env.example index 0179c0e..5137894 100644 --- a/.env.example +++ b/.env.example @@ -9,20 +9,16 @@ TIMEZONE=America/Los_Angeles # ----- Host ----- LOCAL_IPV4=192.168.50.0 # of your device -EXTERNAL_IPV4=123.156.178.190 -SERVER_NAME=your-server # most likely, set this to be the same as your local ipv4, unless you use tailscale or any sort of mDNS on your machine. homepage relies on this for hyperlinks, but not api calls. -WEB_NAME=your-server.com -TAILNET_NAME=tasty-food.ts.net +EXTERNAL_IPV4=255.255.255.0 +SERVER_NAME=localhost # most likely, set this to be the same as your local ipv4, unless you use tailscale or any sort of mDNS on your machine. homepage relies on this for hyperlinks, but not api calls. +WEB_NAME=127.0.0.1 +TAILNET_NAME=favorite-food.ts.net WEB_PROTOCOL=http # ----- Storage ----- -DISK1=/mnt/media -DISK2=/mnt/11tb_ext -DISK3=/mnt/shaimpy - -# ----- Gluetun (VPN) ----- -GLUETUN_KEY= -VPN_PRIVATE_KEY= +DISK1=/mnt/disk1 +DISK2=/mnt/disk2 +DISK3=/mnt/disk3 # ----- Service Ports ----- PLEX_PORT=32400 @@ -39,7 +35,7 @@ LIDARR_PORT=8686 QBITTORRENT_PORT=2161 TDARR_PORT=8265 TDARR_NODE_PORT=8266 -ODYSSEUS_PORT=7001 +OPENWEBUI_PORT=7001 PORTAINER_PORT=9443 SCRUTINY_PORT=4545 SCRUTINY_ADMIN_PORT=4646 @@ -47,51 +43,38 @@ PIHOLE_PORT=6060 KARAKEEP_PORT=4621 KARAKEEP_CHROME_PORT=9222 MEILI_PORT=7700 -LLAMA_PORT=8079 +BAZARR_PORT=8787 +VLLM_PORT=5081 +SPOTIZERR_PORT=7171 +SPOTIZERR_REDIS_PORT=6379 TDARR_NODE_ID=ShaanNode -# ----- API Keys (for homepage widgets & service integrations) ----- -PLEX_KEY= -PROWLARR_KEY= -RADARR_KEY= -SONARR_KEY= -LIDARR_KEY= -TAUTULLI_KEY= -SEERR_KEY= -QBITTORRENT_KEY= -TAILSCALE_KEY= -TAILSCALE_DEVICE_KEY= -CLOUDFLARED_KEY= +# ----- Docker Images ----- +# get with command: +# docker compose ps -q | xargs docker inspect --format '{{.Image}}' | sort -u | xargs docker inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{else}}{{.Id}} (local build){{end}}' -# ----- Cloudflare (for homepage widget) ----- -CLOUDFLARED_ACCOUNT_ID= -CLOUDFLARED_TUNNEL_ID= -CLOUDFLARED_API_KEY= - -# ----- Portainer (for homepage widget) ----- -PORTAINER_API_KEY= - -# ----- Pi-hole ----- -PIHOLE_WEBPASSWORD= - -# ----- Glances ----- -GLANCES_USERNAME= -GLANCES_PASSWORD= - -# ----- Karakeep ----- -# KARAKEEP - -DATA_DIR=/karakeep-data -MEILI_ADDR=http://127.0.0.1:${MEILI_PORT} -MEILI_MASTER_KEY= -NEXTAUTH_URL=http://localhost:3001 -NEXTAUTH_SECRET= - -OPENAI_API_KEY=ollama -OPENAI_BASE_URL=http://${LOCAL_IPV4}:${LLAMA_PORT}/v1 -INFERENCE_TEXT_MODEL=Qwen3.6 -INFERENCE_IMAGE_MODEL=Qwen3.6 -EMBEDDING_TEXT_MODEL=Qwen3-Embedding -EMBEDDING_DIMENSIONS=2048 -EMBEDDING_CONTEXT_LENGTH=4096 -EMBEDDING_ENABLE_AUTO_INDEXING=true +TAUTULLI_IMAGE=ghcr.io/tautulli/tautulli:latest +GLUETUN_IMAGE=qmcgaw/gluetun@sha256:e3272b29a4bc177b389fbdcb54cf9716ccbfc30f04d8b7a35b0a5be9cdb58461 +QBITTORRENT_IMAGE=lscr.io/linuxserver/qbittorrent@sha256:b6ab43fe86039e5bdd3cc0b59b946414fcff0c8183e93636e6cb438fdac45028 +PROWLARR_IMAGE=lscr.io/linuxserver/prowlarr@sha256:1295cff29d10b486c0d8324d1559a552140a5932bf8b3d87e398654414f63f92 +SONARR_IMAGE=lscr.io/linuxserver/sonarr@sha256:373159ba768e23a3a1c497d9f2b936addf8fd5b1fdce7dd6a14080ac928bfda0 +RADARR_IMAGE=lscr.io/linuxserver/radarr@sha256:a45b5ab0f850f39edb4cc9c95bbd967b52ddc3d4574a4dfb45561177db6c88f4 +LIDARR_IMAGE=lscr.io/linuxserver/lidarr@sha256:bfec0ec2dc351fa5928379d785b08be395886f109393b9040ed7973bd1008060 +BAZARR_IMAGE=lscr.io/linuxserver/bazarr@sha256:819327cb5da94a4187bd0512a8f6f8632541404e52cf5977a96e8865d983b07b +TDARR_IMAGE=haveagitgat/tdarr@sha256:45742f00e51a58553844c8b13d97e7ae9b2ee9a056bd8e5993d9a8282a45a23f +TDARR_NODE_IMAGE=haveagitgat/tdarr_node@sha256:7542459ac5ed5cd299600530e9625b9d590629d5dc391c0016773f5d6aa3fe75 +SEERR_IMAGE=ghcr.io/seerr-team/seerr:latest +SEARXNG_IMAGE=searxng/searxng:latest +OPENWEBUI_IMAGE=ghcr.io/open-webui/open-webui@sha256:f67aea542a85e82cfab8c1de0719487b1566bffbb53c2b5448223611a16889dc +KARAKEEP_IMAGE=ghcr.io/karakeep-app/karakeep@sha256:5467873df817ab3aa837f2b06bd7f2b0974132ba1ae5bce0b7e2fd134abc269b +CLOUDFLARED_IMAGE=cloudflare/cloudflared:latest +PORTUPDATER_IMAGE=curlimages/curl:8.21.0 +CADDY_IMAGE=caddy:latest +AUTOHEAL_IMAGE=willfarrell/autoheal:latest +MYSPEED_IMAGE=germannewsmaker/myspeed:latest +HOMEPAGE_IMAGE=ghcr.io/gethomepage/homepage:latest +SCRUTINY_IMAGE=ghcr.io/analogj/scrutiny@sha256:9d0e6d146529d9d1407e1d0a9f685d0b6b840cac070e87e0ab62034d9b80c2b7 +PIHOLE_IMAGE=pihole/pihole@sha256:f7d1be836e3bc608b56d82fc9904f5a831cdfbc0dc9c6d58f94e4c985c70038b +PORTAINER_IMAGE=portainer/portainer-ce:lts +SPOTIZERR_IMAGE=spotizerrphoenix/spotizerr:latest +REDIS_IMAGE=redis:alpine diff --git a/.gitignore b/.gitignore index 5d8d27a..4e80662 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,12 @@ karakeep-data SECURITY.md init-database.* etc* -!odysseus/.* +openwebui/ +searxng/ +vllm/ +bazarr/ +docker-data/ +spotizerr/ # Only track homepage structural yaml files, ignore app cache homepage/* @@ -38,111 +43,3 @@ homepage/* !homepage/*.css !homepage/*.js !homepage/images/ - - -# from odysseus .gitignore - -# Python -__pycache__/ -*.pyc -*.pyo -*.egg-info/ -dist/ -build/ -!static/js/editor/build/ -venv/ -.venv/ -*.egg - -# Environment -.env -.env.bak.* -!.env.example -# Local uv lockfile (optional, per-platform — see "Faster installs with uv" in README) -requirements.lock - -# SOPS workflow — encrypted `secrets.env` is intentionally committable, -# but every variant (plaintext, manual decrypt copy, editor backup) -# must stay out of git. Mirrored in .dockerignore so the same artifacts -# also cannot enter image build layers. -secrets.env.* -!secrets.env.example - -# Data — all user data stays local -data/ -!services/hwfit/data/ -!services/hwfit/data/hf_models.json -logs/ -*.log -*.db -*.sqlite -*.sqlite3 - -# Node -node_modules/ -services/node_modules/ -services/data/ - -# IDE / Editor -.aider* -.claude/ -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# Test capture artifacts (browser session dumps may contain personal content) -.playwright-mcp/ - -# OS -.DS_Store -Thumbs.db - -# Build artifacts -*.cache -cache/ -output.txt.txt - -# Media (uploaded/generated) -*.jpg -*.jpeg -*.png -*.gif -*.bmp -*.webp -*.tiff -*.pdf - -# …except shipped static assets -!static/icons/*.png - -# …except shipped demo assets in docs/ that the README links to. -!docs/*.jpg -!docs/*.jpeg -!docs/*.png -!docs/*.gif -!docs/*.webp -# …and curated docs/ subfolder assets (e.g. accessibility before/after shots). -!docs/**/*.png -!docs/**/*.jpg -!docs/**/*.gif -!docs/**/*.webp - -# Reports and temp files -reports/ -tasks/ -scripts/compound/*.json -research_data/ -**/search_analytics.json - -# Internal dev/review notes — not for public repo -dev-docs/ -# Windows-port working docs (local only, not for public repo) -docs/windows-port/ - -# Local config -compound.config.json -*.error.log -_scratch/ -/odysseus/ diff --git a/caddy/Caddyfile b/caddy/Caddyfile old mode 100644 new mode 100755 diff --git a/compose.yml b/compose.yml old mode 100644 new mode 100755 index 8306025..55fe5ac --- a/compose.yml +++ b/compose.yml @@ -1,10 +1,8 @@ -# ============================================================================= -# Torrent Stack - Docker Compose -# ============================================================================= +name: torrent-stack networks: - caddy_net: - external: true + #caddy_net: + # external: true tdarr-net: driver: bridge default: @@ -14,8 +12,8 @@ volumes: #caddy_config: #caddy_data: # external: true - myspeed: - external: true + #myspeed: + # external: true portainer_data: name: portainer_data @@ -27,721 +25,7 @@ volumes: # → devices → restart # ============================================================================= -services: - # --------------------------------------------------------------------------- - # VPN & Download - # --------------------------------------------------------------------------- - - gluetun: - image: qmcgaw/gluetun:latest - container_name: gluetun - env_file: - - .env - - ./env/.gluetun.env - cap_add: - - NET_ADMIN - ports: - - 8888:8000/tcp - - ${QBITTORRENT_PORT}:${QBITTORRENT_PORT} - - ${PROWLARR_PORT}:${PROWLARR_PORT} - - ${SONARR_PORT}:${SONARR_PORT} - - ${RADARR_PORT}:${RADARR_PORT} - - ${LIDARR_PORT}:${LIDARR_PORT} - volumes: - - ./gluetun-data:/tmp/gluetun:rw - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - VPN_SERVICE_PROVIDER=protonvpn - - VPN_TYPE=wireguard - - HTTP_CONTROL_SERVER=ON - - WIREGUARD_MTU=1280 - - VPN_PORT_FORWARDING=on - - VPN_PORT_FORWARDING_PROVIDER=protonvpn - - SERVER_COUNTRIES=Netherlands - - NETWORK_LOCAL_ADDRESSES=192.168.50.0/24,172.16.0.0/12 - - FIREWALL_OUTBOUND_SUBNETS=192.168.50.0/24 - - TZ=${TIMEZONE} - - DNS_UPSTREAM_RESOLVER_TYPE=doh - healthcheck: - test: ["CMD-SHELL", "wget --spider -q http://1.1.1.1 || exit 1"] - interval: 30s - timeout: 15s - retries: 3 - start_period: 1m - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - extra_hosts: - - "host.docker.internal:host-gateway" - devices: - - /dev/net/tun:/dev/net/tun - restart: always - - qbittorrent: - image: lscr.io/linuxserver/qbittorrent:latest - container_name: qbittorrent - network_mode: "container:gluetun" - depends_on: - gluetun: - condition: service_healthy - volumes: - - ./qbittorrent:/config - - ${DISK1}:${DISK1} - - ${DISK2}:${DISK2} - - ./gluetun-data:/tmp/gluetun - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - TZ=${TIMEZONE} - - WEBUI_PORT=${QBITTORRENT_PORT} - labels: - - "autoheal=true" - healthcheck: - test: - [ - "CMD-SHELL", - "curl -sf http://localhost:${QBITTORRENT_PORT}/api/v2/app/version || exit 1", - ] - interval: 1m - timeout: 10s - retries: 3 - start_period: 30s - security_opt: - - no-new-privileges:true - mem_limit: 512m - cpus: 2.0 - restart: unless-stopped - - port-updater: - image: curlimages/curl:latest - container_name: port-updater - network_mode: "container:gluetun" - depends_on: - gluetun: - condition: service_healthy - volumes: - - ./gluetun-data:/tmp/gluetun:ro - entrypoint: ["/bin/sh", "-c"] - command: - - | - trap 'exit 0' SIGTERM; - while true; do - while [ ! -s /tmp/gluetun/forwarded_port ]; do - echo "Waiting for Gluetun to provide a port..." - sleep 5 - done - - read -r PORT_VAL < /tmp/gluetun/forwarded_port; - CLEAN_PORT=$$(echo "$$PORT_VAL" | tr -d '\r\n '); - - if [ -n "$$CLEAN_PORT" ]; then - echo "Updating qBit to port: $$CLEAN_PORT"; - sleep 10; - curl -s -X POST -d "json={\"listen_port\":$$CLEAN_PORT}" http://localhost:${QBITTORRENT_PORT}/api/v2/app/setPreferences; - sleep 3600 & wait $$!; - else - sleep 10 - fi - done - labels: - - "autoheal=true" - healthcheck: - test: ["CMD-SHELL", "curl -sf https://1.1.1.1 || exit 1"] - interval: 1m - timeout: 10s - retries: 3 - start_period: 30s - security_opt: - - no-new-privileges:true - read_only: true - tmpfs: - - /tmp - mem_limit: 64m - cpus: 0.25 - restart: unless-stopped - - # --------------------------------------------------------------------------- - # *arr Stack - # --------------------------------------------------------------------------- - - prowlarr: - image: lscr.io/linuxserver/prowlarr:latest - container_name: prowlarr - network_mode: "container:gluetun" - depends_on: - gluetun: - condition: service_healthy - volumes: - - ./prowlarr:/config - - ./notify.sh:/notify.sh:ro - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - TZ=${TIMEZONE} - labels: - - "autoheal=true" - healthcheck: - test: - [ - "CMD-SHELL", - "curl -sf http://localhost:${PROWLARR_PORT}/ping || exit 1", - ] - interval: 1m - timeout: 10s - retries: 3 - start_period: 30s - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - sonarr: - image: lscr.io/linuxserver/sonarr:latest - container_name: sonarr - network_mode: "container:gluetun" - depends_on: - gluetun: - condition: service_healthy - volumes: - - /var/lib/sonarr:/config - - ${DISK1}:${DISK1} - - ${DISK2}:${DISK2} - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - TZ=${TIMEZONE} - labels: - - "autoheal=true" - healthcheck: - test: - ["CMD-SHELL", "curl -sf http://localhost:${SONARR_PORT}/ping || exit 1"] - interval: 1m - timeout: 10s - retries: 3 - start_period: 60s - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - radarr: - image: lscr.io/linuxserver/radarr:latest - container_name: radarr - network_mode: "container:gluetun" - depends_on: - gluetun: - condition: service_healthy - volumes: - - /var/lib/radarr:/config - - ${DISK1}:${DISK1} - - ${DISK2}:${DISK2} - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - TZ=${TIMEZONE} - labels: - - "autoheal=true" - healthcheck: - test: - ["CMD-SHELL", "curl -sf http://localhost:${RADARR_PORT}/ping || exit 1"] - interval: 1m - timeout: 10s - retries: 3 - start_period: 30s - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - lidarr: - image: lscr.io/linuxserver/lidarr:latest - container_name: lidarr - network_mode: "container:gluetun" - depends_on: - gluetun: - condition: service_healthy - volumes: - - ./lidarr:/music - - /var/lib/lidarr:/config - - ${DISK1}:${DISK1} - - ${DISK2}:${DISK2} - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - TZ=${TIMEZONE} - labels: - - "autoheal=true" - healthcheck: - test: - ["CMD-SHELL", "curl -sf http://localhost:${LIDARR_PORT}/ping || exit 1"] - interval: 1m - timeout: 10s - retries: 3 - start_period: 30s - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - # --------------------------------------------------------------------------- - # Media - # --------------------------------------------------------------------------- - - tautulli: - image: ghcr.io/tautulli/tautulli - container_name: tautulli - networks: - - caddy_net - ports: - - ${TAUTULLI_PORT}:${TAUTULLI_PORT} - volumes: - - ./tautulli:/config - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - tdarr: - image: haveagitgat/tdarr:latest - container_name: tdarr - networks: - - tdarr-net - ports: - - ${TDARR_PORT}:${TDARR_PORT} - - ${TDARR_NODE_PORT}:${TDARR_NODE_PORT} - volumes: - - ./tdarr/server:/app/server - - ./tdarr/configs:/app/configs - - ./tdarr/temp:/temp - - ${DISK1}:${DISK1} - - ${DISK2}:${DISK2} - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - UMASK_SET=002 - - serverIP=0.0.0.0 - security_opt: - - no-new-privileges:true - mem_limit: 512m - cpus: 2.0 - restart: unless-stopped - - tdarr-node: - image: haveagitgat/tdarr_node:latest - container_name: tdarr-node - networks: - - tdarr-net - volumes: - - ./tdarr/configs:/app/configs - - ./tdarr/logs:/app/logs - - ./tdarr/temp:/temp - - ${DISK1}:${DISK1} - - ${DISK2}:${DISK2} - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - - nodeID=${TDARR_NODE_ID} - - nodeIP=0.0.0.0 - - serverIP=tdarr - - serverPort=${TDARR_NODE_PORT} - security_opt: - - no-new-privileges:true - mem_limit: 2g - cpus: 4.0 - devices: - - /dev/dri:/dev/dri - restart: unless-stopped - - seerr: - image: ghcr.io/seerr-team/seerr:latest - container_name: seerr - networks: - - caddy_net - ports: - - ${SEERR_PORT}:${SEERR_PORT} - volumes: - - ./seerr:/app/config - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - LOG_LEVEL=info - - TZ=${TIMEZONE} - - PUID=${HOST_PUID:-1000} - - PGID=${HOST_PGID:-1000} - labels: - - "autoheal=true" - init: true - working_dir: "/app" - healthcheck: - test: - [ - "CMD-SHELL", - "wget -qO- http://127.0.0.1:${SEERR_PORT}/api/v1/status || exit 1", - ] - interval: 1m - timeout: 10s - retries: 3 - start_period: 60s - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - # Anubis anti-bot proxy for Seerr (uncomment to enable): - #seerr-anubis: - # image: ghcr.io/techarohq/anubis:latest - # container_name: seerr-anubis - # networks: - # - caddy_net - # environment: - # - BIND=:55055 - # - TARGET=http://seerr:${SEERR_PORT} - # security_opt: - # - no-new-privileges:true - # mem_limit: 128m - # cpus: 0.5 - # restart: unless-stopped - - # --------------------------------------------------------------------------- - # Monitoring - # --------------------------------------------------------------------------- - - homepage: - image: ghcr.io/gethomepage/homepage:latest - container_name: homepage - env_file: - - .env - - ./env/.homepage.env - networks: - - caddy_net - ports: - - ${HOMEPAGE_PORT}:${HOMEPAGE_PORT} - volumes: - - ./homepage:/app/config - - ./homepage/images:/app/public/images - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./gluetun-data:/tmp/gluetun:ro - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - "HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev,${LOCAL_IPV4}:${HOMEPAGE_PORT},${SERVER_NAME}:${HOMEPAGE_PORT},${SERVER_NAME}.${TAILNET_NAME}:${HOMEPAGE_PORT}" - - "HOMEPAGE_VAR_DISK1=${DISK1}" - - "HOMEPAGE_VAR_DISK2=${DISK2}" - - "HOMEPAGE_VAR_DISK3=${DISK3}" - - "HOMEPAGE_VAR_WEB_PROTOCOL=${WEB_PROTOCOL}" - - "HOMEPAGE_VAR_LOCAL_IPV4=${LOCAL_IPV4}" - - "HOMEPAGE_VAR_SERVER_NAME=${SERVER_NAME}" - - "HOMEPAGE_VAR_PLEX_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PLEX_PORT}" - - "HOMEPAGE_VAR_QBITTORRENT_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${QBITTORRENT_PORT}" - - "HOMEPAGE_VAR_PROWLARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PROWLARR_PORT}" - - "HOMEPAGE_VAR_SONARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SONARR_PORT}" - - "HOMEPAGE_VAR_RADARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${RADARR_PORT}" - - "HOMEPAGE_VAR_LIDARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${LIDARR_PORT}" - - "HOMEPAGE_VAR_TAUTULLI_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TAUTULLI_PORT}" - - "HOMEPAGE_VAR_TDARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TDARR_PORT}" - - "HOMEPAGE_VAR_HOMEPAGE_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${HOMEPAGE_PORT}" - - "HOMEPAGE_VAR_GLANCES_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${GLANCES_PORT}" - - "HOMEPAGE_VAR_SEERR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SEERR_PORT}" - - "HOMEPAGE_VAR_MYSPEED_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${MYSPEED_PORT}" - - "HOMEPAGE_VAR_ODYSSEUS_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${ODYSSEUS_PORT}" - - "HOMEPAGE_VAR_PIHOLE_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PIHOLE_PORT}" - - "HOMEPAGE_VAR_PORTAINER_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PORTAINER_PORT}" - - "HOMEPAGE_VAR_SCRUTINY_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SCRUTINY_PORT}" - - "HOMEPAGE_VAR_KARAKEEP_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${KARAKEEP_PORT}" - - "HOMEPAGE_VAR_PLEX_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PLEX_PORT}" - - "HOMEPAGE_VAR_QBITTORRENT_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${QBITTORRENT_PORT}" - - "HOMEPAGE_VAR_PROWLARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PROWLARR_PORT}" - - "HOMEPAGE_VAR_SONARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SONARR_PORT}" - - "HOMEPAGE_VAR_RADARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${RADARR_PORT}" - - "HOMEPAGE_VAR_LIDARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${LIDARR_PORT}" - - "HOMEPAGE_VAR_TAUTULLI_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TAUTULLI_PORT}" - - "HOMEPAGE_VAR_TDARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TDARR_PORT}" - - "HOMEPAGE_VAR_HOMEPAGE_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${HOMEPAGE_PORT}" - - "HOMEPAGE_VAR_GLANCES_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${GLANCES_PORT}" - - "HOMEPAGE_VAR_SEERR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SEERR_PORT}" - - "HOMEPAGE_VAR_MYSPEED_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${MYSPEED_PORT}" - - "HOMEPAGE_VAR_ODYSSEUS_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${ODYSSEUS_PORT}" - - "HOMEPAGE_VAR_PIHOLE_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PIHOLE_PORT}" - - "HOMEPAGE_VAR_PORTAINER_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PORTAINER_PORT}" - - "HOMEPAGE_VAR_SCRUTINY_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SCRUTINY_PORT}" - - "HOMEPAGE_VAR_KARAKEEP_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${KARAKEEP_PORT}" - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - extra_hosts: - - "host.docker.internal:host-gateway" - restart: unless-stopped - - # glances: - # image: nicolargo/glances:latest-full - # container_name: glances - # network_mode: host - # volumes: - # - /etc/os-release:/etc/os-release:ro - # - /:/host:ro - # #- /etc/localtime:/etc/localtime:ro - # #- /etc/timezone:/etc/timezone:ro - # environment: - # - "GLANCES_OPT=-w --password ${GLANCES_PASSWORD}" - # - PUID=${HOST_PUID:-1000} - # - PGID=${HOST_PGID:-1000} - # - TZ=${TIMEZONE} - # healthcheck: - # test: - # ["CMD", "curl", "-f", "http://localhost:${GLANCES_PORT}/api/4/status"] - # interval: 1m - # timeout: 10s - # retries: 3 - # start_period: 60s - # security_opt: - # - no-new-privileges:true - # mem_limit: 256m - # cpus: 1.0 - # devices: - # - /dev/dri:/dev/dri - # restart: unless-stopped - # # Uncomment to protect Glances WebUI by a login/password (add --password to GLANCES_OPT) - # secrets: - # - source: glances_password - # target: /root/.config/glances/.pwd - # secrets: - # glances_password: - # file: ./secrets/glances_password - - autoheal: - image: willfarrell/autoheal:latest - container_name: autoheal - volumes: - - /var/run/docker.sock:/var/run/docker.sock - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - AUTOHEAL_CONTAINER_LABEL=all - - AUTOHEAL_INTERVAL=30 - - AUTOHEAL_START_PERIOD=60 - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - read_only: true - mem_limit: 64m - cpus: 0.25 - restart: unless-stopped - - myspeed: - image: germannewsmaker/myspeed - container_name: myspeed - ports: - - ${MYSPEED_PORT}:${MYSPEED_PORT}/tcp - volumes: - - myspeed:/myspeed/data - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - scrutiny: - image: ghcr.io/analogj/scrutiny:nightly-omnibus - container_name: scrutiny - cap_add: - - SYS_RAWIO - ports: - - ${SCRUTINY_PORT}:8080 - - ${SCRUTINY_ADMIN_PORT}:8086 - volumes: - - /run/udev:/run/udev:ro - - ./scrutiny/config:/opt/scrutiny/config - - ./scrutiny/influxdb:/opt/scrutiny/influxdb - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - mem_limit: 512m - cpus: 1.0 - devices: - - /dev/nvme0n1 - - /dev/sda - restart: unless-stopped - - # --------------------------------------------------------------------------- - # Infrastructure - # --------------------------------------------------------------------------- - - pihole: - image: pihole/pihole:latest - container_name: pihole - cap_add: - - NET_ADMIN # Allows managing network interfaces & sockets - - NET_BIND_SERVICE # Allows non-root users to bind to ports < 1024 (port 53 & 123) - - SYS_TIME # Resolves the NTP system time warning - network_mode: host - ports: - - 53:53/tcp - - 53:53/udp - - 67:67/udp - - ${PIHOLE_PORT}:${PIHOLE_PORT}/tcp - volumes: - - ./etc-pihole:/etc/pihole - - ./etc-dnsmasq.d:/etc/dnsmasq.d - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - - FTLCONF_misc_etc_dnsmasq_d=true - # security_opt: - # - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - cloudflared: - image: cloudflare/cloudflared:latest - container_name: cloudflared - env_file: - - ./env/.cloudflared.env - command: tunnel --no-autoupdate run # --token ${CLOUDFLARED_KEY} - security_opt: - - no-new-privileges:true - read_only: true - mem_limit: 128m - cpus: 0.5 - restart: always - - portainer: - image: portainer/portainer-ce:lts - container_name: portainer - ports: - - ${PORTAINER_PORT}:${PORTAINER_PORT} - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - portainer_data:/data - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - mem_limit: 256m - cpus: 1.0 - restart: unless-stopped - - caddy: - image: caddy:latest - container_name: caddy - networks: - - caddy_net - ports: - - 80:80 - - 443:443 - volumes: - - ./caddy/Caddyfile:/etc/caddy/Caddyfile - - ./caddy/site:/srv - - ./caddy/caddy_data:/data - - ./caddy/caddy_config:/config - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - TZ=${TIMEZONE} - security_opt: - - no-new-privileges:true - mem_limit: 128m - cpus: 0.5 - restart: unless-stopped - - # --------------------------------------------------------------------------- - # Karakeep - # --------------------------------------------------------------------------- - - karakeep: - image: ghcr.io/karakeep-app/karakeep:${KARAKEEP_VERSION:-release} - container_name: karakeep - env_file: - - ./env/.karakeep.env - ports: - - ${KARAKEEP_PORT}:3000 # must be 3000 as per the dev - volumes: - - ./karakeep-data:/data - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - MEILI_ADDR=http://meilisearch:${MEILI_PORT} - - BROWSER_WEB_URL=http://chrome:${KARAKEEP_CHROME_PORT} - - DATA_DIR=/data - security_opt: - - no-new-privileges:true - mem_limit: 512m - cpus: 2.0 - restart: unless-stopped - - chrome: - image: gcr.io/zenika-hub/alpine-chrome:124 - container_name: karakeep-chromebrowser - command: - - --no-sandbox - - --disable-gpu - - --disable-dev-shm-usage - - --remote-debugging-address=0.0.0.0 - - --remote-debugging-port=${KARAKEEP_CHROME_PORT} - - --hide-scrollbars - - --disable-blink-features=AutomationControlled - - --window-size=1440,900 - security_opt: - - no-new-privileges:true - mem_limit: 512m - cpus: 1.0 - restart: unless-stopped - - meilisearch: - image: getmeili/meilisearch:v1.41.0 - container_name: karakeep-meilisearch - env_file: - - .env - volumes: - - ./meilisearch:/meili_data - #- /etc/localtime:/etc/localtime:ro - #- /etc/timezone:/etc/timezone:ro - environment: - - MEILI_NO_ANALYTICS=true - security_opt: - - no-new-privileges:true - mem_limit: 512m - cpus: 1.0 - restart: unless-stopped +include: + - media.yml + - infra.yml + - web.yml diff --git a/homepage/bookmarks.yaml b/homepage/bookmarks.yaml old mode 100644 new mode 100755 index 4d6984a..a12fcfa --- a/homepage/bookmarks.yaml +++ b/homepage/bookmarks.yaml @@ -3,80 +3,85 @@ # https://gethomepage.dev/configs/bookmarks - "User": - - "Plex": - - icon: si-plex-#EBAF00 - href: "{{HOMEPAGE_VAR_PLEX_HOST}}" - - "Seerr": - - icon: sh-seerr - href: "{{HOMEPAGE_VAR_SEERR_HOST}}" - - "Odysseus": - - icon: http://shaan-server:7001/static/icons/icon-192.png - href: https://shaan-server.cc - - "Karakeep": - - icon: sh-karakeep-light - href: "{{HOMEPAGE_VAR_KARAKEEP_HOST}}" + - "Plex": + - icon: si-plex-#EBAF00 + href: "{{HOMEPAGE_VAR_PLEX_HOST}}" + - "Seerr": + - icon: sh-seerr + href: "{{HOMEPAGE_VAR_SEERR_HOST}}" + - "Open WebUI": + - icon: sh-open-webui + href: https://shaan-server.cc + - "Hermes Agent": + - icon: http://shaan-server:9119/favicon.ico # "{{HOMEPAGE_VAR_HERMES_HOST}}"/favicon.ico + href: http://shaan-server:9119 # "{{HOMEPAGE_VAR_HERMES_HOST}}" + - "Karakeep": + - icon: sh-karakeep-light + href: "{{HOMEPAGE_VAR_KARAKEEP_HOST}}" + - "SearXNG": + - icon: sh-searxng + href: http://shaan-server:5080 # "{{HOMEPAGE_VAR_SEARXNG_HOST}}" - "Admin": - - "Sonarr": - - icon: sh-sonarr - href: "{{HOMEPAGE_VAR_SONARR_HOST}}" - - "Radarr": - - icon: sh-radarr - href: "{{HOMEPAGE_VAR_RADARR_HOST}}" - - "Lidarr": - - icon: sh-lidarr - href: "{{HOMEPAGE_VAR_LIDARR_HOST}}" - - "Prowlarr": - - icon: sh-prowlarr - href: "{{HOMEPAGE_VAR_PROWLARR_HOST}}" - - "Tautulli": - - icon: sh-tautulli - href: "{{HOMEPAGE_VAR_TAUTULLI_HOST}}" - - "Tdarr": - - icon: sh-tdarr - href: "{{HOMEPAGE_VAR_TDARR_HOST}}" - - "qBittorrent": - - icon: sh-qbittorrent - href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" - - "Speedtest": - - icon: sh-speedtest-light - href: "{{HOMEPAGE_VAR_MYSPEED_HOST}}" - - "Scrutiny": - - icon: sh-scrutiny-light - href: "{{HOMEPAGE_VAR_SCRUTINY_HOST}}" - - "Router Gateway": - - icon: "http://192.168.50.1/images/favicon.png" - href: http://192.168.50.1 - - "Tailscale": - - icon: sh-tailscale-light - href: https://login.tailscale.com - - "Portainer": - - icon: sh-portainer-light - href: "{{HOMEPAGE_VAR_PORTAINER_HOST}}" - - "Pi-Hole": - - icon: sh-pi-hole - href: "{{HOMEPAGE_VAR_PIHOLE_HOST}}/admin" - - "Cloudflare": - - icon: sh-cloudflare - href: https://dash.cloudflare.com - - Monitorix: - - icon: "{{HOMEPAGE_VAR_WEB_PROTOCOL}}://{{HOMEPAGE_VAR_LOCAL_IPV4}}:4000/monitorix/monitorixico.png" - href: http://{{HOMEPAGE_VAR_SERVER_NAME}}:4000/monitorix + - "Sonarr": + - icon: sh-sonarr + href: "{{HOMEPAGE_VAR_SONARR_HOST}}" + - "Radarr": + - icon: sh-radarr + href: "{{HOMEPAGE_VAR_RADARR_HOST}}" + - "Lidarr": + - icon: sh-lidarr + href: "{{HOMEPAGE_VAR_LIDARR_HOST}}" + - "Prowlarr": + - icon: sh-prowlarr + href: "{{HOMEPAGE_VAR_PROWLARR_HOST}}" + - "Tautulli": + - icon: sh-tautulli + href: "{{HOMEPAGE_VAR_TAUTULLI_HOST}}" + - "Tdarr": + - icon: sh-tdarr + href: "{{HOMEPAGE_VAR_TDARR_HOST}}" + - "qBittorrent": + - icon: sh-qbittorrent + href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" + - "Scrutiny": + - icon: sh-scrutiny-light + href: "{{HOMEPAGE_VAR_SCRUTINY_HOST}}" + - "Router Gateway": + - icon: "http://192.168.50.1/images/favicon.png" + href: http://192.168.50.1 + - "Tailscale": + - icon: sh-tailscale-light + href: https://login.tailscale.com + - "Portainer": + - icon: sh-portainer-light + href: "{{HOMEPAGE_VAR_PORTAINER_HOST}}" + - "Pi-Hole": + - icon: sh-pi-hole + href: "{{HOMEPAGE_VAR_PIHOLE_HOST}}/admin" + - "Cloudflare": + - icon: sh-cloudflare + href: https://dash.cloudflare.com - Bookmarks: - - "Youtube": - - icon: sh-youtube - href: https://www.youtube.com - - "Gmail": - - icon: sh-gmail - href: https://mail.google.com -# - github/dhaan7/torrent-stack: -# - icon: sh-github-light -# href: https://github.com/dhaan7/torrent-stack -# description: link to this GitHub repository -# - Termix: -# - icon: "{{HOMEPAGE_VAR_TERMIX_ADDRESS}}/favicon.ico" -# href: "{{HOMEPAGE_VAR_TERMIX_HOST}}" -# description: Terminal emulator in your web browser -# -# + - "Youtube": + - icon: sh-youtube + href: https://www.youtube.com + - "Gmail": + - icon: sh-gmail + href: https://mail.google.com + - "dhaan7/torrent-stack": + - icon: sh-github-light + href: https://github.com/dhaan7/torrent-stack + - "Twitter": + - icon: sh-twitter + href: https://x.com/ + - "Roblox": + - icon: sh-roblox + href: https://roblox.com + - "Reddit": + - icon: sh-reddit + href: https://reddit.com + - "Discord": + - icon: sh-discord + href: https://discord.com/channels/@me diff --git a/homepage/custom.css b/homepage/custom.css old mode 100644 new mode 100755 diff --git a/homepage/custom.js b/homepage/custom.js old mode 100644 new mode 100755 diff --git a/homepage/disabled-custom.css b/homepage/disabled-custom.css old mode 100644 new mode 100755 diff --git a/homepage/docker.yaml b/homepage/docker.yaml old mode 100644 new mode 100755 diff --git a/homepage/kubernetes.yaml b/homepage/kubernetes.yaml old mode 100644 new mode 100755 diff --git a/homepage/proxmox.yaml b/homepage/proxmox.yaml old mode 100644 new mode 100755 diff --git a/homepage/services.yaml b/homepage/services.yaml old mode 100644 new mode 100755 index e838e85..949c30f --- a/homepage/services.yaml +++ b/homepage/services.yaml @@ -1,423 +1,429 @@ ---- # For configuration options and examples, please see: # https://gethomepage.dev/configs/services/ - "Top": - - "Cloudflared Tunnel": - icon: sh-cloudflare - href: "https://dash.cloudflare.com/" - server: my-docker - container: cloudflared - description: - widget: - type: cloudflared - accountid: "{{HOMEPAGE_VAR_CLOUDFLARED_ACCOUNT_ID}}" - tunnelid: "{{HOMEPAGE_VAR_CLOUDFLARED_TUNNEL_ID}}" - key: "{{HOMEPAGE_VAR_CLOUDFLARED_API_KEY}}" - - "VPN Address >": - icon: sh-gluetun - href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" - server: my-docker - container: gluetun - widget: - type: customapi - url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" - mappings: + - "Cloudflared Tunnel": + icon: sh-cloudflare + href: "https://dash.cloudflare.com/" + server: my-docker + container: cloudflared + description: + widget: + type: cloudflared + accountid: "{{HOMEPAGE_VAR_CLOUDFLARED_ACCOUNT_ID}}" + tunnelid: "{{HOMEPAGE_VAR_CLOUDFLARED_TUNNEL_ID}}" + key: "{{HOMEPAGE_VAR_CLOUDFLARED_API_KEY}}" + - "VPN Address >": + icon: sh-gluetun + href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" + server: my-docker + container: gluetun + widget: + type: customapi + url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" + mappings: - field: server_state.last_external_address_v4 label: "Address" format: string - - "Tailscale >": - icon: sh-tailscale-light - href: https://login.tailscale.com - siteMonitor: https://tailscale.com - widget: - type: tailscale - deviceid: "{{HOMEPAGE_VAR_TAILSCALE_DEVICE_KEY}}" - key: "{{HOMEPAGE_VAR_TAILSCALE_KEY}}" - fields: [address] - - "Speedtest Results >": - icon: sh-speedtest-light - href: "{{HOMEPAGE_VAR_MYSPEED_HOST}}" - server: my-docker - container: myspeed - widget: - type: myspeed - url: "{{HOMEPAGE_VAR_MYSPEED_ADDRESS}}" - fields: [download, upload] + - "Tailscale >": + icon: sh-tailscale-light + href: https://login.tailscale.com + siteMonitor: https://tailscale.com + widget: + type: tailscale + deviceid: "{{HOMEPAGE_VAR_TAILSCALE_DEVICE_KEY}}" + key: "{{HOMEPAGE_VAR_TAILSCALE_KEY}}" + fields: [address] - "Media": - - "Media_1": - - "Odysseus": - icon: "{{HOMEPAGE_VAR_ODYSSEUS_HOST}}/static/icons/icon-192.png" - href: "{{HOMEPAGE_VAR_ODYSSEUS_HOST}}" - siteMonitor: "{{HOMEPAGE_VAR_ODYSSEUS_HOST}}" - description: Local AI Models - - "Port Updater": - icon: sh-docker - description: Shell - server: my-docker - container: port-updater - - "Monitorix": - icon: "{{HOMEPAGE_VAR_WEB_PROTOCOL}}://{{HOMEPAGE_VAR_LOCAL_IPV4}}:4000/monitorix/monitorixico.png" - href: http://{{HOMEPAGE_VAR_SERVER_NAME}}:4000/monitorix - description: System - - "Media_2": - - "Plex >": - icon: sh-plex - #icon: sh-plex-dark - href: "{{HOMEPAGE_VAR_PLEX_HOST}}" - description: Watch - siteMonitor: "{{HOMEPAGE_VAR_PLEX_ADDRESS}}" - widget: - type: plex - url: "{{HOMEPAGE_VAR_PLEX_ADDRESS}}" - key: "{{HOMEPAGE_VAR_PLEX_KEY}}" - fields: [albums, movies, tv] - - "Tautulli >": - icon: sh-tautulli - href: "{{HOMEPAGE_VAR_TAUTULLI_HOST}}" - description: Monitor - server: my-docker - container: tautulli - widget: - type: tautulli - url: "{{HOMEPAGE_VAR_TAUTULLI_ADDRESS}}" - key: "{{HOMEPAGE_VAR_TAUTULLI_KEY}}" - enableUser: false - expandOneStreamToTwoRows: false - - "Sonarr >": - icon: sh-sonarr - href: "{{HOMEPAGE_VAR_SONARR_HOST}}" - description: Shows - server: my-docker - container: sonarr - widget: - type: sonarr - url: "{{HOMEPAGE_VAR_SONARR_ADDRESS}}" - key: "{{HOMEPAGE_VAR_SONARR_KEY}}" - enableQueue: false # shows a long list of queued items. looks ugly unless you reorder the page yourself - fields: [wanted, queued] - highlight: - queued: - numeric: - - level: warn - when: gt - value: 0 - - Upcoming TV Episodes: - icon: sh-sonarr - server: my-docker - container: sonarr - widget: - type: calendar - firstDayInWeek: sunday # optional - defaults to monday - view: agenda # optional - possible values monthly, agenda - maxEvents: 2 # optional - defaults to 10 - showTime: true # optional - show time for event happening today - defaults to false - timezone: America/Los_Angeles - integrations: # optional - - type: sonarr - service_name: "Sonarr >" - baseUrl: "{{HOMEPAGE_VAR_SONARR_HOST}}" - unmonitored: true - - "Radarr >": - icon: sh-radarr - href: "{{HOMEPAGE_VAR_RADARR_HOST}}" - description: Movies - server: my-docker - container: radarr - widget: - type: radarr - url: "{{HOMEPAGE_VAR_RADARR_ADDRESS}}" - key: "{{HOMEPAGE_VAR_RADARR_KEY}}" - fields: [wanted, queued] - highlight: - queued: - numeric: - - level: warn - when: gt - value: 0 - - Upcoming Movies: - icon: sh-radarr - server: my-docker - container: radarr - widget: - type: calendar - firstDayInWeek: sunday # optional - defaults to monday - view: agenda # optional - possible values monthly, agenda - maxEvents: 2 # optional - defaults to 10 - showTime: true # optional - show time for event happening today - defaults to false - timezone: America/Los_Angeles - integrations: # optional - - type: radarr - service_name: "Radarr >" - baseUrl: "{{HOMEPAGE_VAR_RADARR_HOST}}" - unmonitored: true - - "Lidarr >": - icon: sh-lidarr - href: "{{HOMEPAGE_VAR_LIDARR_HOST}}" - description: Music - server: my-docker - container: lidarr - widget: - type: lidarr - url: "{{HOMEPAGE_VAR_LIDARR_ADDRESS}}" - key: "{{HOMEPAGE_VAR_LIDARR_KEY}}" - fields: [wanted, queued] - highlight: - queued: - numeric: - - level: warn - when: gt - value: 0 - - "Seerr >": - icon: sh-overseerr - href: "{{HOMEPAGE_VAR_SEERR_HOST}}" - description: Request - server: my-docker - container: seerr - widget: - type: seerr - url: "{{HOMEPAGE_VAR_SEERR_ADDRESS}}" - key: "{{HOMEPAGE_VAR_SEERR_KEY}}" - fields: [completed, pending] - highlight: - pending: - numeric: - - level: warn - when: gt - value: 0 - - "Tdarr Node (Intel Arc Pro B70)": - icon: sh-tdarr - server: my-docker - container: tdarr-node - - "Tdarr Node (Intel Graphics UHD 710)": - icon: sh-tdarr - server: my-docker - container: tdarr-node - - "Media_Bottom": - - "Tdarr >": - icon: sh-tdarr - href: "{{HOMEPAGE_VAR_TDARR_HOST}}" - description: Transcode - server: my-docker - container: tdarr - widget: - type: tdarr - url: "{{HOMEPAGE_VAR_TDARR_ADDRESS}}" - key: "{{HOMEPAGE_VAR_TDARR_KEY}}" - highlight: - queue: - numeric: - - level: warn - when: gt - value: 0 - errored: - numeric: - - level: danger - when: gt - value: 0 + - "Media_1": + - "Open WebUI": + icon: sh-open-webui + href: "{{HOMEPAGE_VAR_OPENWEBUI_HOST}}" + siteMonitor: "{{HOMEPAGE_VAR_OPENWEBUI_ADDRESS}}" + description: Chatbot + - "Port Updater": + icon: sh-docker + description: Shell + server: my-docker + container: port-updater + - "VLLM Status": + icon: sh-vllm + server: my-docker + href: "{{HOMEPAGE_VAR_WEB_PROTOCOL}}://{{HOMEPAGE_VAR_SERVER_NAME}}:9119" + container: vllm + description: LLM Serving + - "Media_2": + - "Plex >": + icon: sh-plex + #icon: sh-plex-dark + href: "{{HOMEPAGE_VAR_PLEX_HOST}}" + description: Watch + siteMonitor: "{{HOMEPAGE_VAR_PLEX_ADDRESS}}" + widget: + type: plex + url: "{{HOMEPAGE_VAR_PLEX_ADDRESS}}" + key: "{{HOMEPAGE_VAR_PLEX_KEY}}" + fields: [albums, movies, tv] + - "Tautulli >": + icon: sh-tautulli + href: "{{HOMEPAGE_VAR_TAUTULLI_HOST}}" + description: Monitor + server: my-docker + container: tautulli + widget: + type: tautulli + url: "{{HOMEPAGE_VAR_TAUTULLI_ADDRESS}}" + key: "{{HOMEPAGE_VAR_TAUTULLI_KEY}}" + enableUser: false + expandOneStreamToTwoRows: false + - "Sonarr >": + icon: sh-sonarr + href: "{{HOMEPAGE_VAR_SONARR_HOST}}" + description: Shows + server: my-docker + container: sonarr + widget: + type: sonarr + url: "{{HOMEPAGE_VAR_SONARR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_SONARR_KEY}}" + enableQueue: false # shows a long list of queued items. looks ugly unless you reorder the page yourself + fields: [wanted, queued] + highlight: + queued: + numeric: + - level: warn + when: gt + value: 0 + - Upcoming TV Episodes: + icon: sh-sonarr + server: my-docker + container: sonarr + widget: + type: calendar + firstDayInWeek: sunday # optional - defaults to monday + view: agenda # optional - possible values monthly, agenda + maxEvents: 2 # optional - defaults to 10 + showTime: true # optional - show time for event happening today - defaults to false + timezone: America/Los_Angeles + integrations: # optional + - type: sonarr + service_name: "Sonarr >" + baseUrl: "{{HOMEPAGE_VAR_SONARR_HOST}}" + unmonitored: true + - "Radarr >": + icon: sh-radarr + href: "{{HOMEPAGE_VAR_RADARR_HOST}}" + description: Movies + server: my-docker + container: radarr + widget: + type: radarr + url: "{{HOMEPAGE_VAR_RADARR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_RADARR_KEY}}" + fields: [wanted, queued] + highlight: + queued: + numeric: + - level: warn + when: gt + value: 0 + - Upcoming Movies: + icon: sh-radarr + server: my-docker + container: radarr + widget: + type: calendar + firstDayInWeek: sunday # optional - defaults to monday + view: agenda # optional - possible values monthly, agenda + maxEvents: 2 # optional - defaults to 10 + showTime: true # optional - show time for event happening today - defaults to false + timezone: America/Los_Angeles + integrations: # optional + - type: radarr + service_name: "Radarr >" + baseUrl: "{{HOMEPAGE_VAR_RADARR_HOST}}" + unmonitored: true + - "Lidarr >": + icon: sh-lidarr + href: "{{HOMEPAGE_VAR_LIDARR_HOST}}" + description: Music + server: my-docker + container: lidarr + widget: + type: lidarr + url: "{{HOMEPAGE_VAR_LIDARR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_LIDARR_KEY}}" + fields: [wanted, queued] + highlight: + queued: + numeric: + - level: warn + when: gt + value: 0 + - "Seerr >": + icon: sh-overseerr + href: "{{HOMEPAGE_VAR_SEERR_HOST}}" + description: Request + server: my-docker + container: seerr + widget: + type: seerr + url: "{{HOMEPAGE_VAR_SEERR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_SEERR_KEY}}" + fields: [completed, pending] + highlight: + pending: + numeric: + - level: warn + when: gt + value: 0 + - "Bazarr >": + icon: sh-bazarr + href: "{{HOMEPAGE_VAR_BAZARR_HOST}}" + description: Subtitles + server: my-docker + container: bazarr + widget: + type: bazarr + url: "{{HOMEPAGE_VAR_BAZARR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_BAZARR_KEY}}" + # fields: [wanted, queued] + highlight: + queued: + numeric: + - level: warn + when: gt + value: 0 + - "Spotizerr": + icon: sh-spotify + href: http://shaan-server:7171 + server: my-docker + container: spotizerr + - "Media_Bottom": + - "Tdarr >": + icon: sh-tdarr + href: "{{HOMEPAGE_VAR_TDARR_HOST}}" + description: Transcode + server: my-docker + container: tdarr-node + widget: + type: tdarr + url: "{{HOMEPAGE_VAR_TDARR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_TDARR_KEY}}" + highlight: + queue: + numeric: + - level: warn + when: gt + value: 0 + errored: + numeric: + - level: danger + when: gt + value: 0 - "Network": - - "Network_1": - - "Portainer": - icon: sh-portainer-light - href: https://shaan-server:9443 - description: Containers - server: my-docker - container: portainer - widget: - type: portainer - url: https://shaan-server:9443 - env: 3 - key: "{{HOMEPAGE_VAR_PORTAINER_KEY}}" - - "Pi-Hole Adblocker": - icon: sh-pi-hole - href: "http://192.168.50.2:6060/admin/login" - description: DNS - server: my-docker - container: pihole - widget: - type: pihole - url: http://shaan-server:6060 - version: 6 # required if running v6 or higher, defaults to 5 - key: "{{HOMEPAGE_VAR_PIHOLE_PASSWORD}}" - - "Network_2": - - "Scrutiny": - icon: sh-scrutiny - href: http://192.168.50.2:4545 #"{{HOMEPAGE_VAR_SCRUTINY_ADDRESS}}"" - description: S.M.A.R.T. - server: my-docker - container: scrutiny - widget: - type: scrutiny - url: http://192.168.50.2:4545 #"{{HOMEPAGE_VAR_SCRUTINY_ADDRESS}}" - - "Karakeep": - icon: sh-karakeep-light - href: http://192.168.50.2:4545 #"{{HOMEPAGE_VAR_SCRUTINY_ADDRESS}}"" - description: Bookmarks - server: my-docker - container: karakeep - widget: - type: karakeep - url: http://shaan-server:4621 - key: ak2_bfee1806ec533a9557bd_940feeb8fbe798d465ab6f90a3562c43 - - "Network_qbit": - - "Prowlarr >": - icon: sh-prowlarr - href: "{{HOMEPAGE_VAR_PROWLARR_HOST}}" - description: Indexers - server: my-docker - container: prowlarr - widget: - type: prowlarr - url: "{{HOMEPAGE_VAR_PROWLARR_ADDRESS}}" - key: "{{HOMEPAGE_VAR_PROWLARR_KEY}}" - #fields: ["numberOfGrabs"] - highlight: - "numberOfGrabs": - numeric: - - level: warn - when: lte - value: 0 - "numberOfQueries": - numeric: - - level: warn - when: lte - value: 0 - "numberOfFailGrabs": - numeric: - - level: warn - when: gt - value: 0 - "numberOfFailQueries": - numeric: - - level: warn - when: gt - value: 0 + - "Network_1": + - "Portainer": + icon: sh-portainer-light + href: https://shaan-server:9443 + description: Containers + server: my-docker + container: portainer + widget: + type: portainer + url: https://portainer:9443 + env: 3 + key: "{{HOMEPAGE_VAR_PORTAINER_KEY}}" + - "Pi-Hole Adblocker": + icon: sh-pi-hole + href: "{{HOMEPAGE_VAR_PIHOLE_ADDRESS}}/admin/login" + description: DNS + server: my-docker + container: pihole + widget: + type: pihole + url: "{{HOMEPAGE_VAR_PIHOLE_ADDRESS}}" + version: 6 # required if running v6 or higher, defaults to 5 + key: "{{HOMEPAGE_VAR_PIHOLE_PASSWORD}}" + - "Network_2": + - "Scrutiny": + icon: sh-scrutiny + href: "{{HOMEPAGE_VAR_SCRUTINY_HOST}}" + description: S.M.A.R.T. + server: my-docker + container: scrutiny + widget: + type: scrutiny + url: "{{HOMEPAGE_VAR_SCRUTINY_ADDRESS}}" + - "Karakeep": + icon: sh-karakeep-light + href: "{{HOMEPAGE_VAR_KARAKEEP_HOST}}" + description: Bookmarks + server: my-docker + container: karakeep + widget: + type: karakeep + url: "{{HOMEPAGE_VAR_KARAKEEP_ADDRESS}}" + key: ak2_bfee1806ec533a9557bd_940feeb8fbe798d465ab6f90a3562c43 + - "Network_qbit": + - "Prowlarr >": + icon: sh-prowlarr + href: "{{HOMEPAGE_VAR_PROWLARR_HOST}}" + description: Indexers + server: my-docker + container: prowlarr + widget: + type: prowlarr + url: "{{HOMEPAGE_VAR_PROWLARR_ADDRESS}}" + key: "{{HOMEPAGE_VAR_PROWLARR_KEY}}" + #fields: ["numberOfGrabs"] + highlight: + "numberOfGrabs": + numeric: + - level: warn + when: lte + value: 0 + "numberOfQueries": + numeric: + - level: warn + when: lte + value: 0 + "numberOfFailGrabs": + numeric: + - level: warn + when: gt + value: 0 + "numberOfFailQueries": + numeric: + - level: warn + when: gt + value: 0 - - "qBittorrent Active >": - icon: sh-qbittorrent - href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" - server: my-docker - container: qbittorrent - #description: - widget: - type: customapi - url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/torrents/info?filter=seeding" - mappings: - #- field: - - field: _count - label: "Active" - format: integer - scale: 1 - highlight: - "Active": - numeric: - - level: danger - when: lte - value: 20 + - "qBittorrent Active >": + icon: sh-qbittorrent + href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" + server: my-docker + container: qbittorrent + #description: + widget: + type: customapi + url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/torrents/info?filter=seeding" + mappings: + #- field: + - field: _count + label: "Active" + format: integer + scale: 1 + highlight: + "Active": + numeric: + - level: danger + when: lte + value: 20 - - "qBittorrent Status >": - icon: sh-qbittorrent - href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" - server: my-docker - container: qbittorrent - widget: - type: customapi - url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" - mappings: - - field: server_state.connection_status - label: "status" - format: string - - field: server_state.dht_nodes - label: "DHT" - format: integer - scale: 1 - - field: server_state.last_external_address_v4 - label: "Address" - format: string - highlight: - "status": - string: - - level: danger - when: equals - value: connected - negate: true - "DHT": - #valueOnly: true - numeric: - - level: danger - when: lte - value: 0 - - level: warn - when: lte - value: 200 + - "qBittorrent Status >": + icon: sh-qbittorrent + href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" + server: my-docker + container: qbittorrent + widget: + type: customapi + url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" + mappings: + - field: server_state.connection_status + label: "status" + format: string + - field: server_state.dht_nodes + label: "DHT" + format: integer + scale: 1 + - field: server_state.last_external_address_v4 + label: "Address" + format: string + highlight: + "status": + string: + - level: danger + when: equals + value: connected + negate: true + "DHT": + #valueOnly: true + numeric: + - level: danger + when: lte + value: 0 + - level: warn + when: lte + value: 200 - - "qBittorrent Stats >": - icon: sh-qbittorrent - href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" - server: my-docker - container: qbittorrent - widget: - type: customapi - url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" - mappings: - - field: server_state.alltime_dl - label: "T. Down" - format: bytes - scale: 0.862 - - field: server_state.alltime_ul - label: "T. Up" - format: bytes - scale: 0.862 - - field: server_state.global_ratio - label: "Ratio" - format: percent - scale: 100 - #suffix: "%" - highlight: - "Ratio": - numeric: - - level: warn - when: lt - value: 100 - - level: danger - when: lte - value: 60 + - "qBittorrent Stats >": + icon: sh-qbittorrent + href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" + server: my-docker + container: qbittorrent + widget: + type: customapi + url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" + mappings: + - field: server_state.alltime_dl + label: "T. Down" + format: bytes + scale: 0.862 + - field: server_state.alltime_ul + label: "T. Up" + format: bytes + scale: 0.862 + - field: server_state.global_ratio + label: "Ratio" + format: percent + scale: 100 + #suffix: "%" + highlight: + "Ratio": + numeric: + - level: warn + when: lt + value: 100 + - level: danger + when: lte + value: 60 - - "qBittorrent Session >": - icon: sh-qbittorrent - href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" - server: my-docker - container: qbittorrent - widget: - type: customapi - url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" - key: "{{HOMEPAGE_VAR_QBITTORRENT_KEY}}" - mappings: - - field: server_state.dl_info_speed - label: Down - format: bitrate - scale: 0.862 - - field: server_state.dl_info_data - label: T. Down - format: bytes - scale: 0.862 - - field: server_state.up_info_speed - label: Up - format: bitrate - scale: 0.862 - - field: server_state.up_info_data - label: T. Up - format: bytes - scale: 0.862 - highlight: - "Down": - numeric: - - level: good - when: gt - value: 0 - "Up": - numeric: - - level: good - when: gt - value: 0 + - "qBittorrent Session >": + icon: sh-qbittorrent + href: "{{HOMEPAGE_VAR_QBITTORRENT_HOST}}" + server: my-docker + container: qbittorrent + widget: + type: customapi + url: "{{HOMEPAGE_VAR_QBITTORRENT_ADDRESS}}/api/v2/sync/maindata" + key: "{{HOMEPAGE_VAR_QBITTORRENT_KEY}}" + mappings: + - field: server_state.dl_info_speed + label: Down + format: bitrate + scale: 0.862 + - field: server_state.dl_info_data + label: T. Down + format: bytes + scale: 0.862 + - field: server_state.up_info_speed + label: Up + format: bitrate + scale: 0.862 + - field: server_state.up_info_data + label: T. Up + format: bytes + scale: 0.862 + highlight: + "Down": + numeric: + - level: good + when: gt + value: 0 + "Up": + numeric: + - level: good + when: gt + value: 0 diff --git a/homepage/settings.yaml b/homepage/settings.yaml old mode 100644 new mode 100755 index 475c735..90ccaa0 --- a/homepage/settings.yaml +++ b/homepage/settings.yaml @@ -6,7 +6,7 @@ instanceName: torrent-stack # Aesthetics background: - image: /images/wallhaven-pk997m.jpg + image: ./images/wallhaven-pk997m.jpg #blur: sm # Options: sm, md, lg, xl #saturate: 10 #brightness: 10 @@ -44,20 +44,20 @@ layout: tab: Apps iconsOnly: false header: true - disableCollapse: true + initiallyCollapsed: false style: row columns: 3 "Admin": tab: Apps iconsOnly: false header: true - disableCollapse: true + initiallyCollapsed: false style: row columns: 3 "Bookmarks": tab: Apps header: true - initiallyCollapsed: true + initiallyCollapsed: false style: row columns: 3 "Top": diff --git a/homepage/widgets.yaml b/homepage/widgets.yaml old mode 100644 new mode 100755 diff --git a/infra.yml b/infra.yml new file mode 100644 index 0000000..b872f8f --- /dev/null +++ b/infra.yml @@ -0,0 +1,157 @@ +# ============================================================================= + +# Torrent Stack (infra) - DNS, management & monitoring +# +# Split from compose.yml on 2026-09-11 - verbatim service blocks. +# Shared top-level networks:/volumes: are repeated in each subfile so it also +# works standalone (docker compose -f infra.yml up -d). Identical copies merge +# cleanly under compose.yml's `include:` with no change to the live config. +# Keep ./ paths, container names and /mnt data as-is. +# ============================================================================= + +networks: + #caddy_net: + # external: true + tdarr-net: + driver: bridge + default: + name: portainer_network + +volumes: + #caddy_config: + #caddy_data: + # external: true + #myspeed: + # external: true + portainer_data: + name: portainer_data + +services: + # --------------------------------------------------------------------------- + # Monitoring + # --------------------------------------------------------------------------- + + # glances: + # image: ${GLANCES_IMAGE} + # container_name: glances + # network_mode: host + # volumes: + # - /etc/os-release:/etc/os-release:ro + # - /:/host:ro + # #- /etc/localtime:/etc/localtime:ro + # #- /etc/timezone:/etc/timezone:ro + # environment: + # - "GLANCES_OPT=-w --password ${GLANCES_PASSWORD}" + # - PUID=${HOST_PUID:-1000} + # - PGID=${HOST_PGID:-1000} + # - TZ=${TIMEZONE} + # healthcheck: + # test: + # ["CMD", "curl", "-f", "http://localhost:${GLANCES_PORT}/api/4/status"] + # interval: 1m + # timeout: 10s + # retries: 3 + # start_period: 60s + # security_opt: + # - no-new-privileges:true + # mem_limit: 256m + # cpus: 1.0 + # devices: + # - /dev/dri:/dev/dri + # restart: unless-stopped + # # Uncomment to protect Glances WebUI by a login/password (add --password to GLANCES_OPT) + # secrets: + # - source: glances_password + # target: /root/.config/glances/.pwd + # secrets: + # glances_password: + # file: ./secrets/glances_password + + autoheal: + image: ${AUTOHEAL_IMAGE} + container_name: autoheal + volumes: + - /var/run/docker.sock:/var/run/docker.sock + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - AUTOHEAL_CONTAINER_LABEL=all + - AUTOHEAL_INTERVAL=30 + - AUTOHEAL_START_PERIOD=60 + - TZ=${TIMEZONE} + security_opt: + - no-new-privileges:true + read_only: true + mem_limit: 64m + cpus: 0.25 + restart: unless-stopped + + scrutiny: + image: ${SCRUTINY_IMAGE} + container_name: scrutiny + cap_add: + - SYS_RAWIO + ports: + - ${SCRUTINY_PORT}:8080 + - ${SCRUTINY_ADMIN_PORT}:8086 + volumes: + - /run/udev:/run/udev:ro + - ./scrutiny/config:/opt/scrutiny/config + - ./scrutiny/influxdb:/opt/scrutiny/influxdb + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - TZ=${TIMEZONE} + security_opt: + - no-new-privileges:true + mem_limit: 128m + cpus: 0.25 + devices: + - /dev/nvme0n1 + - /dev/sda + restart: unless-stopped + + # --------------------------------------------------------------------------- + # Infrastructure + # --------------------------------------------------------------------------- + + pihole: + image: ${PIHOLE_IMAGE} + container_name: pihole + cap_add: + - NET_ADMIN # Allows managing network interfaces & sockets + - NET_BIND_SERVICE # Allows non-root users to bind to ports < 1024 (port 53 & 123) + - SYS_TIME # Resolves the NTP system time warning + network_mode: host + volumes: + - ./etc-pihole:/etc/pihole + - ./etc-dnsmasq.d:/etc/dnsmasq.d + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - TZ=${TIMEZONE} + - FTLCONF_misc_etc_dnsmasq_d=true + - FTLCONF_webserver_port=${PIHOLE_PORT:-80} + # security_opt: + # - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + portainer: + image: ${PORTAINER_IMAGE} + container_name: portainer + ports: + - ${PORTAINER_PORT}:${PORTAINER_PORT} + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - portainer_data:/data + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - TZ=${TIMEZONE} + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped diff --git a/media.yml b/media.yml new file mode 100644 index 0000000..cce24f9 --- /dev/null +++ b/media.yml @@ -0,0 +1,517 @@ +# ============================================================================= + +# Torrent Stack (media) - VPN, *arr stack & media tooling +# +# Split from compose.yml on 2026-09-11 - verbatim service blocks. +# Shared top-level networks:/volumes: are repeated in each subfile so it also +# works standalone (docker compose -f media.yml up -d). Identical copies merge +# cleanly under compose.yml's `include:` with no change to the live config. +# Keep ./ paths, container names and /mnt data as-is. +# ============================================================================= + +networks: + #caddy_net: + # external: true + tdarr-net: + driver: bridge + default: + name: portainer_network + +volumes: + #caddy_config: + #caddy_data: + # external: true + #myspeed: + # external: true + portainer_data: + name: portainer_data + redis-data: + driver: local + +services: + # --------------------------------------------------------------------------- + # VPN & Download + # --------------------------------------------------------------------------- + + gluetun: + image: ${GLUETUN_IMAGE} + container_name: gluetun + env_file: + - .env + - ./env/.gluetun.env + cap_add: + - NET_ADMIN + ports: + - 8877:8000/tcp + - ${QBITTORRENT_PORT}:${QBITTORRENT_PORT} + - ${PROWLARR_PORT}:${PROWLARR_PORT} + - ${SONARR_PORT}:${SONARR_PORT} + - ${RADARR_PORT}:${RADARR_PORT} + - ${LIDARR_PORT}:${LIDARR_PORT} + - ${BAZARR_PORT}:${BAZARR_PORT} + volumes: + - ./gluetun-data:/tmp/gluetun:rw + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - VPN_SERVICE_PROVIDER=protonvpn + - VPN_TYPE=wireguard + - HTTP_CONTROL_SERVER=ON + - WIREGUARD_MTU=1280 + - VPN_PORT_FORWARDING=on + - VPN_PORT_FORWARDING_PROVIDER=protonvpn + - SERVER_COUNTRIES=Netherlands + - NETWORK_LOCAL_ADDRESSES=192.168.50.0/24,172.16.0.0/12 + - FIREWALL_OUTBOUND_SUBNETS=192.168.50.0/24 + - HEALTH_SERVER_ADDRESS=0.0.0.0:8877 + - HEALTH_TARGET_ADDRESSES=${EXTERNAL_IPV4}:${PLEX_PFWD_PORT} + - TZ=${TIMEZONE} + - DNS_UPSTREAM_RESOLVER_TYPE=doh + healthcheck: + test: + [ + "CMD-SHELL", + "wget -qO- '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m30s + timeout: 15s + retries: 3 + start_period: 45s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + devices: + - /dev/net/tun:/dev/net/tun + restart: no + + qbittorrent: + image: ${QBITTORRENT_IMAGE} + container_name: qbittorrent + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./qbittorrent:/config + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + - ./gluetun-data:/tmp/gluetun + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + - WEBUI_PORT=${QBITTORRENT_PORT} + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + security_opt: + - no-new-privileges:true + mem_limit: 512m + cpus: 1.0 + restart: unless-stopped + + port-updater: + image: curlimages/curl:8.21.0 + container_name: port-updater + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./gluetun-data:/tmp/gluetun:ro + entrypoint: ["/bin/sh", "-c"] + command: + - | + trap 'exit 0' SIGTERM; + while true; do + while [ ! -s /tmp/gluetun/forwarded_port ]; do + echo "Waiting for Gluetun to provide a port..." + sleep 5 + done + + read -r PORT_VAL < /tmp/gluetun/forwarded_port; + CLEAN_PORT=$$(echo "$$PORT_VAL" | tr -d '\r\n '); + + if [ -n "$$CLEAN_PORT" ]; then + echo "Updating qBit to port: $$CLEAN_PORT"; + sleep 10; + curl -s -X POST -d "json={\"listen_port\":$$CLEAN_PORT}" http://localhost:${QBITTORRENT_PORT}/api/v2/app/setPreferences; + sleep 3600 & wait $$!; + else + sleep 10 + fi + done + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + security_opt: + - no-new-privileges:true + read_only: true + tmpfs: + - /tmp + mem_limit: 64m + cpus: 0.25 + restart: unless-stopped + + # --------------------------------------------------------------------------- + # *arr Stack + # --------------------------------------------------------------------------- + + prowlarr: + image: ${PROWLARR_IMAGE} + container_name: prowlarr + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./prowlarr:/config + - ./notify.sh:/notify.sh:ro + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + sonarr: + image: ${SONARR_IMAGE} + container_name: sonarr + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./sonarr:/config + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 60s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + radarr: + image: ${RADARR_IMAGE} + container_name: radarr + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./radarr:/config + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + lidarr: + image: ${LIDARR_IMAGE} + container_name: lidarr + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./lidarr:/music + - ./lidarr:/config + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + bazarr: + image: ${BAZARR_IMAGE} + container_name: bazarr + network_mode: "container:gluetun" + depends_on: + gluetun: + condition: service_healthy + volumes: + - ./bazarr:/config + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + labels: + - "autoheal=true" + healthcheck: + test: + [ + "CMD-SHELL", + "curl -sf '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + # --------------------------------------------------------------------------- + # Media + # --------------------------------------------------------------------------- + + tautulli: + image: ${TAUTULLI_IMAGE} + container_name: tautulli + #networks: + # - caddy_net + ports: + - ${TAUTULLI_PORT}:${TAUTULLI_PORT} + volumes: + - ./tautulli:/config + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - TZ=${TIMEZONE} + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + tdarr: + image: ${TDARR_IMAGE} + container_name: tdarr + networks: + - tdarr-net + ports: + - ${TDARR_PORT}:${TDARR_PORT} + - ${TDARR_NODE_PORT}:${TDARR_NODE_PORT} + volumes: + - ./tdarr/server:/app/server + - ./tdarr/configs:/app/configs + - ./tdarr/temp:/temp + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - TZ=${TIMEZONE} + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - UMASK_SET=002 + - serverIP=0.0.0.0 + security_opt: + - no-new-privileges:true + mem_limit: 512m + cpus: 2.0 + restart: unless-stopped + + tdarr-node: + image: ${TDARR_NODE_IMAGE} + container_name: tdarr-node + networks: + - tdarr-net + volumes: + - ./tdarr/configs:/app/configs + - ./tdarr/logs:/app/logs + - ./tdarr/temp:/temp + - ${DISK1}:${DISK1} + - ${DISK2}:${DISK2} + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - TZ=${TIMEZONE} + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + - nodeID=${TDARR_NODE_ID} + - nodeIP=0.0.0.0 + - serverIP=tdarr + - serverPort=${TDARR_NODE_PORT} + security_opt: + - no-new-privileges:true + mem_limit: 4g + cpus: 4.0 + devices: + - /dev/dri:/dev/dri + restart: unless-stopped + + seerr: + image: ${SEERR_IMAGE} + container_name: seerr + # networks: + # - caddy_net + ports: + - ${SEERR_PORT}:${SEERR_PORT} + volumes: + - ./seerr:/app/config + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - LOG_LEVEL=info + - TZ=${TIMEZONE} + - PUID=${HOST_PUID:-1000} + - PGID=${HOST_PGID:-1000} + labels: + - "autoheal=true" + init: true + working_dir: "/app" + healthcheck: + test: + [ + "CMD-SHELL", + "wget -qO- '${WEB_PROTOCOL}://${EXTERNAL_IPV4}:${PLEX_PFWD_PORT}/identity' | grep -q 'MediaContainer' || exit 1", + ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 60s + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1.0 + restart: unless-stopped + + spotizerr: + image: spotizerrphoenix/spotizerr + user: "1000:1000" # Spotizerr user:group ids + volumes: + # Ensure these directories and the .cache file exist and are writable by the container user + - ./spotizerr:/app/data # data directory, contains config, creds, watch, history + - ${DISK1}/media/Music/spotizerr:/app/downloads # downloads directory, contains downloaded files + - ./spotizerr/logs:/app/logs # logs directory, contains logs + - ./spotizerr/.cache:/app/.cache # cache file + ports: + # Port to expose the app on + - 7171:7171 + container_name: spotizerr + restart: unless-stopped + env_file: + # Ensure you have a .env file in the root of the project, with the correct values + - ./.env + depends_on: + - redis + + redis: + image: redis:alpine + container_name: spotizerr-redis + restart: unless-stopped + env_file: + - .env + volumes: + - redis-data:/data + command: sh -c 'redis-server --requirepass "$REDIS_PASSWORD" --appendonly yes' + + # Anubis anti-bot proxy for Seerr (uncomment to enable): + #seerr-anubis: + # image: ghcr.io/techarohq/anubis:latest + # container_name: seerr-anubis + # networks: + # - caddy_net + # environment: + # - BIND=:55055 + # - TARGET=http://seerr:${SEERR_PORT} + # security_opt: + # - no-new-privileges:true + # mem_limit: 128m + # cpus: 0.5 + # restart: unless-stopped diff --git a/startup.sh b/startup.sh index 3ab4b21..c2cca25 100755 --- a/startup.sh +++ b/startup.sh @@ -2,12 +2,5 @@ sleep 15 cd /home/shaan/torrent-stack || exit -docker compose up -d gluetun & sleep 90 -docker compose up -d - -sleep 5 - -cd /home/shaan/torrent-stack/odysseus || exit -git pull . dev -docker compose pull -docker compose up -d +docker compose config ||> /tmp/startup.log && exit 1 +docker compose up -d 2>&1 | tee /tmp/startup.log diff --git a/web.yml b/web.yml new file mode 100644 index 0000000..17f994e --- /dev/null +++ b/web.yml @@ -0,0 +1,287 @@ +# ============================================================================= + +# Torrent Stack (web) - dashboard, edge & AI services +# +# Split from compose.yml on 2026-09-11 - verbatim service blocks. +# Shared top-level networks:/volumes: are repeated in each subfile so it also +# works standalone (docker compose -f web.yml up -d). Identical copies merge +# cleanly under compose.yml's `include:` with no change to the live config. +# Keep ./ paths, container names and /mnt data as-is. +# ============================================================================= + +networks: + #caddy_net: + # external: true + tdarr-net: + driver: bridge + default: + name: portainer_network + +volumes: + #caddy_config: + #caddy_data: + # external: true + #myspeed: + # external: true + portainer_data: + name: portainer_data + +services: + # --------------------------------------------------------------------------- + + # Dashboard + # --------------------------------------------------------------------------- + + homepage: + image: ${HOMEPAGE_IMAGE} + container_name: homepage + env_file: + - .env + - ./env/.homepage.env + #networks: + # - caddy_net + ports: + - ${HOMEPAGE_PORT}:${HOMEPAGE_PORT} + volumes: + - ./homepage:/app/config + - ./homepage/images:/app/public/images + - /var/run/docker.sock:/var/run/docker.sock:ro + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - "HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev,${LOCAL_IPV4}:${HOMEPAGE_PORT},${SERVER_NAME}:${HOMEPAGE_PORT},${SERVER_NAME}.${TAILNET_NAME}:${HOMEPAGE_PORT},host.docker.internal:{HOMEPAGE_PORT}" + - "HOMEPAGE_VAR_DISK1=${DISK1}" + - "HOMEPAGE_VAR_DISK2=${DISK2}" + - "HOMEPAGE_VAR_DISK3=${DISK3}" + - "HOMEPAGE_VAR_WEB_PROTOCOL=${WEB_PROTOCOL}" + - "HOMEPAGE_VAR_LOCAL_IPV4=${LOCAL_IPV4}" + - "HOMEPAGE_VAR_SERVER_NAME=${SERVER_NAME}" + - "HOMEPAGE_VAR_PLEX_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PLEX_PORT}" + - "HOMEPAGE_VAR_QBITTORRENT_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${QBITTORRENT_PORT}" + - "HOMEPAGE_VAR_PROWLARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PROWLARR_PORT}" + - "HOMEPAGE_VAR_SONARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SONARR_PORT}" + - "HOMEPAGE_VAR_RADARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${RADARR_PORT}" + - "HOMEPAGE_VAR_LIDARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${LIDARR_PORT}" + - "HOMEPAGE_VAR_BAZARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${BAZARR_PORT}" + - "HOMEPAGE_VAR_TAUTULLI_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TAUTULLI_PORT}" + - "HOMEPAGE_VAR_TDARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TDARR_PORT}" + - "HOMEPAGE_VAR_HOMEPAGE_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${HOMEPAGE_PORT}" + - "HOMEPAGE_VAR_GLANCES_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${GLANCES_PORT}" + - "HOMEPAGE_VAR_SEERR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SEERR_PORT}" + - "HOMEPAGE_VAR_OPENWEBUI_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${OPENWEBUI_PORT}" + - "HOMEPAGE_VAR_PIHOLE_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PIHOLE_PORT}" + - "HOMEPAGE_VAR_PORTAINER_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PORTAINER_PORT}" + - "HOMEPAGE_VAR_SCRUTINY_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SCRUTINY_PORT}" + - "HOMEPAGE_VAR_KARAKEEP_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${KARAKEEP_PORT}" + - "HOMEPAGE_VAR_VLLM_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${VLLM_PORT}" + - "HOMEPAGE_VAR_PLEX_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PLEX_PORT}" + - "HOMEPAGE_VAR_QBITTORRENT_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${QBITTORRENT_PORT}" + - "HOMEPAGE_VAR_PROWLARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PROWLARR_PORT}" + - "HOMEPAGE_VAR_SONARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SONARR_PORT}" + - "HOMEPAGE_VAR_RADARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${RADARR_PORT}" + - "HOMEPAGE_VAR_LIDARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${LIDARR_PORT}" + - "HOMEPAGE_VAR_BAZARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${BAZARR_PORT}" + - "HOMEPAGE_VAR_TAUTULLI_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TAUTULLI_PORT}" + - "HOMEPAGE_VAR_TDARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TDARR_PORT}" + - "HOMEPAGE_VAR_HOMEPAGE_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${HOMEPAGE_PORT}" + - "HOMEPAGE_VAR_GLANCES_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${GLANCES_PORT}" + - "HOMEPAGE_VAR_SEERR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SEERR_PORT}" + - "HOMEPAGE_VAR_OPENWEBUI_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${OPENWEBUI_PORT}" + - "HOMEPAGE_VAR_PIHOLE_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PIHOLE_PORT}" + - "HOMEPAGE_VAR_PORTAINER_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PORTAINER_PORT}" + - "HOMEPAGE_VAR_SCRUTINY_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SCRUTINY_PORT}" + - "HOMEPAGE_VAR_KARAKEEP_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${KARAKEEP_PORT}" + - "HOMEPAGE_VAR_VLLM_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${VLLM_PORT}" + - TZ=${TIMEZONE} + security_opt: + - no-new-privileges:true + mem_limit: 256m + cpus: 1 + # extra_hosts: + # - "host.docker.internal:${LOCAL_IPV4}" + restart: unless-stopped + # --------------------------------------------------------------------------- + + # Edge + # --------------------------------------------------------------------------- + + cloudflared: + image: cloudflare/cloudflared:latest + container_name: cloudflared + env_file: + - ./env/.cloudflared.env + command: tunnel --no-autoupdate run # --token ${CLOUDFLARED_KEY} + security_opt: + - no-new-privileges:true + read_only: true + mem_limit: 128m + cpus: 0.5 + restart: always + + caddy: + image: ${CADDY_IMAGE} + container_name: caddy + #networks: + # - caddy_net + ports: + - 82:80 + - 444:443 + volumes: + - ./caddy/Caddyfile:/etc/caddy/Caddyfile + - ./caddy/site:/srv + - ./caddy/caddy_data:/data + - ./caddy/caddy_config:/config + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - TZ=${TIMEZONE} + security_opt: + - no-new-privileges:true + mem_limit: 128m + cpus: 0.5 + restart: unless-stopped + + # --------------------------------------------------------------------------- + + # Web & AI + # --------------------------------------------------------------------------- + + openwebui: + image: ghcr.io/open-webui/open-webui:main-slim + container_name: openwebui + ports: + - "7001:8080" + volumes: + - ./openwebui:/app/backend/data + mem_limit: 1g + cpus: 1.0 + + searxng: + image: ${SEARXNG_IMAGE} + container_name: searxng + ports: + - "5080:8080" + volumes: + - ./searxng:/etc/searxng + environment: + - SEARXNG_SECRET=abcd + restart: unless-stopped + + vllm: + image: vllm/vllm-openai-xpu@sha256:f01e24f6c7ff01f1e0662234255a1372297d1dbd89d003cf13c8fad3eab1ba4f + container_name: vllm + network_mode: host + ipc: host + privileged: true + devices: + - "/dev/dri:/dev/dri" + volumes: + - ~/llm/huggingface:/root/.cache/huggingface + - ~/llm/:/llm/ + - ./vllm/xpu-patches:/patches/:ro + environment: + - "HUGGING_FACE_HUB_TOKEN=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" + - "SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS=1" + - "ZES_ENABLE_SYSMAN=1" + - "ONEAPI_DEVICE_SELECTOR=level_zero:0" + - "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1" + - "VLLM_XPU_ENABLE_XPU_GRAPH=1" + - "VLLM_ALLOW_LONG_MAX_MODEL_LEN=1" + - "VLLM_WORKER-MULTIPROC_METHOD=spawn" + - "VLLM_TARGET_DEVICE=xpu" + - "ZE_FLAT_DEVICE_HIERARCHY=COMPOSITE" + - "ZE_AFFINITY_MASK=0" + - "B70_MTP_BF16_DRAFT=1" + - "B70_DRAFT_LMHEAD_INT4=1" + - "B70_DRAFT_MTP_INT4=1" + - "PYTORCH_ALLOC_CONF=expandable_segments:True" + entrypoint: ["/bin/bash", "-lc"] + command: + - | + set -e + python /patches/patch_mtp_nightly.py + python /patches/patch_mtp_boundary.py + python /patches/patch_gdn_mixed_split_v5.py + python /patches/patch_draft_lmhead_int4.py + python /patches/patch_draft_mtp_int4.py + exec vllm serve /llm/Qwen3.8-27B-GPTQINT4-G128-MTP-BF16 \ + --quantization gptq \ + --dtype float16 \ + --max-model-len 131072 \ + --gpu-memory-utilization 0.88 \ + --kv-cache-dtype fp8 \ + --port 5081 \ + --max-num-seqs 64 \ + --block-size 64 \ + --max-num-batched-tokens 8192 \ + --served-model-name 'Qwen3.8' \ + --language-model-only \ + --speculative-config '{"method":"mtp","num_speculative_tokens":4}' \ + --reasoning-parser qwen3 \ + --tool-call-parser qwen3_coder \ + --default-chat-template-kwargs '{"enable_thinking": false, "reasoning_effort": "medium", "reasoning_preserve": "true"}' \ + --enable-auto-tool-choice \ + --disable-sliding-window \ + --enable-prefix-caching \ + --enable-chunked-prefill + restart: on-failure:5 + + # --------------------------------------------------------------------------- + # Karakeep + # --------------------------------------------------------------------------- + + karakeep: + image: ghcr.io/karakeep-app/karakeep:${KARAKEEP_VERSION:-release} + container_name: karakeep + env_file: + - ./env/.karakeep.env + ports: + - ${KARAKEEP_PORT}:3000 # must be 3000 as per the dev + volumes: + - ./karakeep-data:/data + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - MEILI_ADDR=http://meilisearch:${MEILI_PORT} + - BROWSER_WEB_URL=http://chrome:${KARAKEEP_CHROME_PORT} + - DATA_DIR=/data + security_opt: + - no-new-privileges:true + mem_limit: 512m + cpus: 1.0 + restart: unless-stopped + + chrome: + image: zenika/alpine-chrome:124 + container_name: karakeep-chromebrowser + command: + - --no-sandbox + - --disable-gpu + - --disable-dev-shm-usage + - --remote-debugging-address=0.0.0.0 + - --remote-debugging-port=${KARAKEEP_CHROME_PORT} + - --hide-scrollbars + - --disable-blink-features=AutomationControlled + - --window-size=1440,900 + security_opt: + - no-new-privileges:true + mem_limit: 1g + cpus: 1.0 + restart: unless-stopped + + meilisearch: + image: getmeili/meilisearch:v1.41.0 + container_name: karakeep-meilisearch + env_file: + - .env + volumes: + - ./meilisearch:/meili_data + #- /etc/localtime:/etc/localtime:ro + #- /etc/timezone:/etc/timezone:ro + environment: + - MEILI_NO_ANALYTICS=true + security_opt: + - no-new-privileges:true + mem_limit: 512m + cpus: 1.0 + restart: no