volumes: grafana_lib: {} services: traefik: image: "traefik:v3.6.11" container_name: "traefik" env_file: .env command: - "--log.level=INFO" - "--api.dashboard=true" - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.http.middlewares=crowdsec@file" - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true" - "--certificatesresolvers.mytlschallenge.acme.email=rewelacyjny.rower@gmail.com" - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json" - "--accesslog" - "--accesslog.filepath=/logs/access.log" - "--accesslog.fields.names.StartUTC=drop" - "--metrics.prometheus=true" - "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0" - "--entrypoints.web.address=:80" - "--serversTransport.insecureSkipVerify=true" - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge=true" - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge.entrypoint=web" - "--providers.file.filename=/etc/traefik/dynamic_conf.yml" ports: - target: 443 published: 443 mode: host - target: 8080 published: 8082 protocol: tcp mode: ingress volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - ${PWD}/traefik/letsencrypt:/letsencrypt/ - ${PWD}/traefik/logs:/logs - ${PWD}/traefik/config/dynamic_conf.yml:/etc/traefik/dynamic_conf.yml:ro labels: - "traefik.port=8080" - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`traefik.sebson.space`)" - "traefik.http.routers.api.service=api@internal" - "traefik.http.routers.api.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=seba:$$2y$$05$$nYWLfxVJthoWM3ow7h7KJuy4gcx9vNog9jTyfsgf0qbO0Cul0X0Fy" - "traefik.http.routers.api.tls.certresolver=mytlschallenge" - "traefik.http.routers.api.entrypoints=websecure" restart: always depends_on: - grafana - whoami whoami: image: "traefik/whoami" env_file: .env container_name: "whoami" ports: - 81:80 restart: always labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.sebson.space`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.tls.certresolver=mytlschallenge" - "traefik.http.middlewares.whoami-auth.basicauth.users=seba:$$2y$$05$$nYWLfxVJthoWM3ow7h7KJuy4gcx9vNog9jTyfsgf0qbO0Cul0X0Fy" - "traefik.http.routers.whoami.middlewares=whoami-auth" # ============================================ # MONITORING # ============================================ grafana: image: grafana/grafana:latest env_file: .env container_name: grafana ports: - "3001:3000" environment: GF_INSTALL_PLUGINS: "grafana-piechart-panel" GF_SERVER_PROTOCOL: "http" GF_SERVER_DOMAIN: "sebson.space" GF_SERVER_METRICS_ENABLED: "true" GF_SERVER_METRICS_INTERVAL_SECONDS: "10" GF_SERVER_ROOT_URL: https://grafana.sebson.space GF_FEATURE_TOGGLES_PUBLICDASHBOARDS: "true" GF_SECURITY_ADMIN_USER: seba GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD} INFLUXDB_URI: "http://influxdb:8086" INFLUXDB_DB: GRAFANA INFLUXDB_USER: seba INFLUXDB_USER_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD} PROMETHEUS_USER: ${PROMETHEUS_USER} PROMETHEUS_PASSWORD: ${PROMETHEUS_PASSWORD} TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID} volumes: - grafana_lib:/var/lib/grafana - ${PWD}/grafana/etc/grafana/provisioning:/etc/grafana/provisioning/ restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.grafana.rule=Host(`grafana.sebson.space`)" - "traefik.http.routers.grafana.entrypoints=websecure" - "traefik.http.routers.grafana.tls.certresolver=mytlschallenge" - "com.centurylinklabs.watchtower.enable=true" prometheus: image: quay.io/prometheus/prometheus:latest user: "1000:1000" container_name: prometheus env_file: .env volumes: - ./prometheus/:/etc/prometheus/ - ./prometheus/hosts:/etc/hosts - ./prometheus/storage/:/prometheus/storage/ networks: - default command: "--web.config.file=/etc/prometheus/web.yml --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/prometheus/storage --storage.tsdb.retention.time=30d --storage.tsdb.retention.size=20GB --web.enable-admin-api" ports: - 29090:9090 restart: always labels: - "traefik.enable=true" - "traefik.http.routers.prom.rule=Host(`prom.sebson.space`)" - "traefik.http.routers.prom.entrypoints=websecure" - "traefik.http.routers.prom.tls.certresolver=mytlschallenge" - "traefik.http.routers.prom.middlewares=auth" victoriametrics: image: victoriametrics/victoria-metrics:latest container_name: victoriametrics restart: unless-stopped command: - "-storageDataPath=/storage" - "-retentionPeriod=10y" - "-httpListenAddr=:8428" volumes: - ${PWD}/vm_data:/storage networks: - default pushgateway: container_name: prom_push_gateway image: prom/pushgateway restart: unless-stopped ports: - "0.0.0.0:9091:9091" healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:9091/-/ready"] interval: 15s timeout: 3s retries: 5 node_exporter: image: prom/node-exporter:latest container_name: node_exporter environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Prague command: - '--path.rootfs=/host' - '--collector.textfile' - '--collector.textfile.directory=/var/lib/prometheus/node-exporter/' user: "1000:1000" network_mode: host pid: host restart: unless-stopped volumes: - '/:/host:ro,rslave' - '/var/lib/prometheus/node-exporter/:/var/lib/prometheus/node-exporter' cadvisor: image: gcr.io/cadvisor/cadvisor:latest container_name: cadvisor restart: unless-stopped privileged: true devices: - /dev/kmsg ports: - 38080:8080 volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro - /dev/disk/:/dev/disk:ro side-agent: container_name: side-agent build: context: ./side-agent volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ${PWD}:/mydocker - ${PWD}/side-agent/manifest:/app/manifest - /media/evo2t/frigate/clips:/source:ro - ${PWD}/homeassistant/config/www/frigate_notification:/target restart: unless-stopped environment: - TZ=${TZ} labels: - "com.centurylinklabs.watchtower.enable=true" # ============================================ # PROXIES # ============================================ adguard-proxy: container_name: adguard-proxy env_file: .env image: marcnuri/port-forward environment: - TZ=${TZ} - REMOTE_HOST=192.168.1.151 - REMOTE_PORT=80 restart: always labels: - "traefik.enable=true" - "traefik.http.routers.adguard.rule=Host(`adguard.sebson.space`)" - "traefik.http.routers.adguard.entrypoints=websecure" - "traefik.http.routers.adguard.tls.certresolver=mytlschallenge" # ============================================ # DATABASE # ============================================ postgresql18: container_name: postgres18 image: postgres:18 command: ["postgres", "-c", "ssl=on", "-c", "ssl_cert_file=/etc/postgresql/ssl/server.crt", "-c", "ssl_key_file=/etc/postgresql/ssl/server.key"] restart: always ports: - "5432:5432" environment: POSTGRES_USER: homeassistant POSTGRES_PASSWORD: ${DB_PASS} POSTGRES_DB: homeassistant volumes: - ${PWD}/postgres18/data:/var/lib/postgresql - ${PWD}/postgresql-ssl:/etc/postgresql/ssl:ro gitea: image: gitea/gitea:1.21 container_name: gitea restart: unless-stopped environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=postgresql18:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=homeassistant - GITEA__database__PASS=${DB_PASS} - GITEA__database__SSL_MODE=disable volumes: - ./gitea:/data - /home/seba/git.repos:/import/git.repos:ro - /etc/localtime:/etc/localtime:ro ports: - "3003:3000" - "2222:22" labels: - "traefik.enable=true" - "traefik.http.routers.gitea.rule=Host(`git.sebson.space`)" - "traefik.http.routers.gitea.entrypoints=websecure" - "traefik.http.routers.gitea.tls.certresolver=mytlschallenge" - "traefik.http.services.gitea.loadbalancer.server.port=3000" depends_on: - postgresql18 postgres-exporter: image: prometheuscommunity/postgres-exporter container_name: postgres-exporter restart: unless-stopped depends_on: - postgresql18 environment: DATA_SOURCE_NAME: "postgresql://${DB_USER}:${DB_PASS}@postgresql18:5432/homeassistant?sslmode=disable" mktxp: image: ghcr.io/akpw/mktxp:latest container_name: mktxp restart: unless-stopped volumes: - ./mktxp:/home/mktxp/mktxp smartctl-exporter: image: prometheuscommunity/smartctl-exporter container_name: smartctl-exporter privileged: true user: root ports: - "9633:9633" volumes: - /dev:/dev:ro command: - "--smartctl.interval=60s" - "--log.level=error" - "--smartctl.device=/dev/disk/by-id/nvme-Apacer_AS2280P4_1TB_AFJK2451200315" - "--smartctl.device=/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_2TB_S4J4NJ0NC05791A" - "--smartctl.device=/dev/disk/by-id/ata-WDC_WD10JUCT-63CYNY0_WD-WX71AB72J9YC" - "--smartctl.device=/dev/disk/by-id/ata-WDC_WD181PURP-74B6HY0_2JJGDJ0L" restart: unless-stopped pgadmin: container_name: pgadmin image: dpage/pgadmin4:latest restart: always ports: - 9988:80 environment: PGADMIN_DEFAULT_EMAIL: sebastian.blasiak@gmail.com PGADMIN_DEFAULT_PASSWORD: ${DB_PASS} # ============================================ # HOME AUTOMATION # ============================================ homeassistant: container_name: homeassistant env_file: .env image: ghcr.io/home-assistant/home-assistant:stable privileged: true devices: - /dev/serial/by-id/usb-Nabu_Casa_ZBT-2_DCB4D90CBE78-if00:/dev/ttyACM0 - /dev/vhci:/dev/vhci volumes: - ${PWD}/homeassistant/config:/config - ${PWD}/homeassistant/resolv.conf:/etc/resolv.conf - ${PWD}/homeassistant/sysctl.d:/etc/sysctl.d - ${PWD}/homeassistant/ssh_dir:/root/.ssh - ${PWD}/homeassistant/doorbell:/doorbell - /media/seagata16t/hikvision16t/:/hikvision16t:slave - /home/seba/.ssh/id_ed25519:/config/ssh/asus_private_key/id_ed25519:ro - /home/seba/.ssh/id_ed25519:/config/ssh/ansible_private_key/id_ed25519:ro - /etc/localtime:/etc/localtime:ro - /run/dbus:/run/dbus:ro environment: - TZ=Europe/Prague - GRPC_VERBOSITY=NONE - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID} restart: unless-stopped network_mode: host security_opt: - apparmor:unconfined cap_add: - NET_ADMIN - NET_RAW depends_on: - mosquitto - esphome - frigate homeassistant-external: image: traefik/whoami container_name: homeassistant-external restart: always labels: - "traefik.enable=true" - "traefik.http.routers.ha.rule=Host(`ha.sebson.space`)" - "traefik.http.routers.ha.entrypoints=websecure" - "traefik.http.routers.ha.tls.certresolver=mytlschallenge" - "traefik.http.services.ha.loadbalancer.server.url=http://192.168.1.132:8123" - "traefik.http.middlewares.ha-headers.headers.customrequestheaders.X-Forwarded-Proto=https" - "traefik.http.routers.ha.middlewares=ha-headers" frigate: container_name: frigate privileged: true restart: unless-stopped image: ghcr.io/blakeblackshear/frigate:stable shm_size: "1gb" devices: - /dev/bus/usb:/dev/bus/usb volumes: - /etc/localtime:/etc/localtime:ro - ./frigate:/config - /media/evo2t/frigate:/media/frigate - type: tmpfs target: /tmp/cache tmpfs: size: 2000000000 ports: - "5000:5000" - "8554:8554" - "8555:8555" - "8971:8971" environment: - FRIGATE_MERCUSYS_PW=${FRIGATE_MERCUSYS_PW} - FRIGATE_MERCUSYS_USER=${FRIGATE_MERCUSYS_USER} - FRIGATE_REO_PW=${FRIGATE_REO_PW} - FRIGATE_HIK_PW=${FRIGATE_HIK_PW} - FRIGATE_DOMOFON_HIK_PW=${FRIGATE_DOMOFON_HIK_PW} - MOSQUITTO_PASSWORD=${MOSQUITTO_PASSWORD} - FRIGATE_MQTT_PW=${FRIGATE_MQTT_PW} - PLUS_API_KEY=${FRIGATE_PLUS_API_KEY} - LIBVA_DRIVER_NAME=radeonsi - LIBVA_DRIVERS_PATH=/usr/lib/x86_64-linux-gnu/dri logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: memory: 6G esphome: container_name: esphome image: ghcr.io/esphome/esphome privileged: true network_mode: host volumes: - ${PWD}/esphome:/config:rw restart: unless-stopped logging: driver: "json-file" options: max-size: "20m" max-file: "3" mosquitto: container_name: mosquitto restart: unless-stopped image: eclipse-mosquitto:2 volumes: - ${PWD}/mosquitto/config:/mosquitto/config - ${PWD}/mosquitto/log:/mosquitto/log - ${PWD}/mosquitto/data:/mosquitto/data - /etc/localtime:/etc/localtime:ro network_mode: host environment: - TZ=Europe/Prague logging: driver: "json-file" options: max-size: "10m" max-file: "3" # ============================================ # MEDIA # ============================================ jellyfin: container_name: jellyfin restart: always image: jellyfin/jellyfin:latest env_file: .env volumes: - ${PWD}/jellyfin/config:/config - ${PWD}/jellyfin/Downloads/jellyfin_tmp:/cache - ${PWD}/jellyfin/shared:/shared - /media/seagata16t:/media/seagata16t:slave - /media/wd1t:/media/wd1t - /media/evo2t:/media/evo2t - /media/asustor/asustor_volume1:/media/asustor/asustor_volume1 ports: - "8096:8096/tcp" - "8920:8920/tcp" - "7359:7359/udp" environment: - TZ=${TZ} - JELLYFIN_PUID=${PUID} - JELLYFIN_PGID=${PGID} - JELLYFIN_ADVERTISE_IP="http://192.168.1.132:8096/,https://jfin.sebson.space/" labels: - "traefik.enable=true" - "traefik.http.services.jfin.loadbalancer.server.port=8096" - "traefik.http.routers.jfin.rule=Host(`jfin.sebson.space`)" - "traefik.http.routers.jfin.entrypoints=websecure" - "traefik.http.routers.jfin.tls.certresolver=mytlschallenge" timelapse-maker: container_name: timelapse-maker build: context: ./timelapse_service volumes: - /media/seagata16t/hikvision16t/:/media/seagata16t/hikvision16t:slave - /media/seagata16t/all_timelapses/:/media/seagata16t/all_timelapses:slave - /etc/localtime:/etc/localtime:ro environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Prague restart: always # ============================================ # UTILITIES # ============================================ pingexporter: image: czerwonk/ping_exporter container_name: pingexporter environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Prague ports: - 9427:9427 volumes: - ${PWD}/pingexporter/config:/config:ro restart: unless-stopped glances: container_name: glances image: docker.io/nicolargo/glances restart: always volumes: - /var/run/docker.sock:/var/run/docker.sock:ro ports: - 61208:61208 environment: - GLANCES_OPT=-w labels: - "traefik.enable=true" - "traefik.http.routers.glances.rule=Host(`glances.sebson.space`)" - "traefik.http.routers.glances.entrypoints=websecure" - "traefik.http.routers.glances.tls.certresolver=mytlschallenge" - "traefik.http.services.glances.loadbalancer.server.port=61208" - "traefik.http.routers.glances.middlewares=auth_glances" - "traefik.http.middlewares.auth_glances.basicauth.users=seba:$$2y$$05$$nYWLfxVJthoWM3ow7h7KJuy4gcx9vNog9jTyfsgf0qbO0Cul0X0Fy" brana-frontend: build: ./brana-frontend container_name: brana-frontend restart: unless-stopped ports: - "9080:80" labels: - "traefik.enable=true" - "traefik.http.routers.brana.rule=Host(`brana.sebson.space`)" - "traefik.http.routers.brana.entrypoints=websecure" - "traefik.http.routers.brana.tls.certresolver=mytlschallenge" - "traefik.http.services.brana.loadbalancer.server.port=80" networks: - default ha-dashboard: build: ./ha-dashboard container_name: ha-dashboard restart: unless-stopped ports: - "9081:8080" environment: - DB_HOST=postgres18 - DB_PORT=5432 - DB_USER=homeassistant - DB_PASS=${DB_PASS} - HA_URL=http://${HOST_IP_HA}:8123 - HA_TOKEN=${HA_TOKEN} - SECRET_KEY=${HA_DASHBOARD_SECRET_KEY} - AUTH_DIR=/auth volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ${PWD}/backup.log:/backup.log:ro - ${PWD}/ha-dashboard/auth:/auth - ${PWD}/ha-dashboard/app.py:/app/app.py:ro - ${PWD}/ha-dashboard/templates:/app/templates:ro - ${PWD}/ha-dashboard/static:/app/static:ro - ${PWD}/homeassistant/config:/ha_config:ro - /home/seba/git.repos/myansible:/myansible:ro labels: - "traefik.enable=true" - "traefik.http.routers.ha-dashboard.rule=Host(`hadash.sebson.space`)" - "traefik.http.routers.ha-dashboard.entrypoints=websecure" - "traefik.http.routers.ha-dashboard.tls.certresolver=mytlschallenge" - "traefik.http.services.ha-dashboard.loadbalancer.server.port=8080" networks: - default depends_on: - postgresql18 bitwarden: image: vaultwarden/server container_name: bitwarden restart: always env_file: .env ports: - '9989:80' environment: ADMIN_TOKEN: ${ENCRYPTED_BITWARDEN_ADMIN_TOKEN} DATABASE_URL: postgresql://homeassistant:${DB_PASS}@192.168.1.132:5432/bitwarden YUBICO_CLIENT_ID: ${YUBICO_CLIENT_ID} YUBICO_SECRET_KEY: ${YUBICO_SECRET_KEY} YUBICO_SERVER: https://bward.sebson.space/wsapi/2.0/verify volumes: - ./bitwarden:/data labels: - "traefik.enable=true" - "traefik.http.routers.bward.rule=Host(`bward.sebson.space`)" - "traefik.http.routers.bward.entrypoints=websecure" - "traefik.http.routers.bward.tls.certresolver=mytlschallenge" - "traefik.http.services.bward.loadbalancer.server.port=80" duplicati: image: lscr.io/linuxserver/duplicati:latest container_name: duplicati env_file: .env environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Prague volumes: - /etc/localtime:/etc/localtime:ro - /home/seba/git.repos:/git.repos:ro - /home/seba/:/seba_home:ro - /home/seba/mydocker:/mydocker:ro - /media/evo2t/backups:/evo2t:rw - type: bind source: /media/seagata16t target: /backups bind: propagation: rshared - ${PWD}/duplicati/config:/config ports: - "8200:8200" healthcheck: test: ["CMD-SHELL","[ -d /backups ] && ls /backups >/dev/null 2>&1 || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 30s restart: unless-stopped openspeedtest: image: openspeedtest/latest container_name: openspeedtest restart: unless-stopped ports: - "3005:3000" - "3006:3001" labels: - "traefik.enable=true" - "traefik.http.routers.speedtest.rule=Host(`speed.sebson.space`)" - "traefik.http.routers.speedtest.entrypoints=websecure" - "traefik.http.routers.speedtest.tls.certresolver=mytlschallenge" - "traefik.http.services.speedtest.loadbalancer.server.port=3000" dozzle: container_name: dozzle image: amir20/dozzle:latest restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock ports: - 9888:8080 environment: DOZZLE_LEVEL: info networks: - default # ============================================ # NETWORKING # ============================================ unifi: image: jacobalberty/unifi:latest container_name: unifi restart: unless-stopped network_mode: host environment: - TZ=Europe/Warsaw - DB_NAME=unifi - DB_URI=mongodb://127.0.0.1:27017/unifi - STATDB_URI=mongodb://127.0.0.1:27017/unifi_stat - UNIFI_UID=1000 - UNIFI_GID=1000 volumes: - ./unifi-config:/unifi depends_on: - unifi-db unifi-db: image: mongo:7.0 container_name: unifi-db restart: unless-stopped network_mode: host volumes: - ./unifi-db:/data/db # ============================================ # PHOTO MANAGEMENT # ============================================ immich-server: container_name: immich_server image: ghcr.io/immich-app/immich-server:release volumes: - /media/seagata16t/immich:/usr/src/app/upload:slave - /etc/localtime:/etc/localtime:ro env_file: - .env ports: - "2283:2283" depends_on: - redis - database networks: - default restart: always deploy: resources: limits: memory: 6G labels: - "traefik.enable=true" - "traefik.http.services.immch.loadbalancer.server.port=2283" - "traefik.http.services.immch.loadbalancer.server.scheme=http" - "traefik.http.routers.immch.rule=Host(`immch.sebson.space`)" - "traefik.http.routers.immch.entrypoints=websecure" - "traefik.http.routers.immch.tls.certresolver=mytlschallenge" immich-machine-learning: container_name: immich_machine_learning image: ghcr.io/immich-app/immich-machine-learning:release volumes: - ./immich/model-cache:/cache env_file: - .env restart: always deploy: resources: limits: cpus: '2.0' memory: 3G redis: container_name: immich_redis image: redis:7.2-alpine restart: always database: container_name: immich_postgres image: ghcr.io/immich-app/postgres:14-vectorchord0.5.3 environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: postgres POSTGRES_DB: immich volumes: - ./immich/postgres:/var/lib/postgresql/data restart: always # ============================================ # LOGGING # ============================================ loki: image: grafana/loki:latest container_name: loki user: "0:0" volumes: - ./loki/data:/loki - ./loki/wal:/wal - ./loki/loki-config.yaml:/etc/loki/local-config.yaml ports: - "3100:3100" command: -config.file=/etc/loki/local-config.yaml restart: unless-stopped networks: - default promtail: image: grafana/promtail:latest container_name: promtail volumes: - /var/log:/var/log:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - ./promtail/promtail-config.yaml:/etc/promtail/config.yml - /var/run/docker.sock:/var/run/docker.sock:ro command: -config.file=/etc/promtail/config.yml restart: unless-stopped networks: - default depends_on: - loki # ============================================ # EXTERNAL PROXIES # ============================================ nextcloud-external: image: traefik/whoami container_name: nextcloud-external restart: always labels: - "traefik.enable=true" - "traefik.http.routers.nc-external.rule=Host(`nc.sebson.space`)" - "traefik.http.routers.nc-external.entrypoints=websecure" - "traefik.http.routers.nc-external.tls.certresolver=mytlschallenge" - "traefik.http.services.nc-external.loadbalancer.server.url=http://192.168.1.10/nextcloud-php/" - "traefik.http.routers.nc-external.middlewares=nc-prefix,nc-headers" - "traefik.http.middlewares.nc-prefix.addprefix.prefix=/nextcloud-php" - "traefik.http.middlewares.nc-headers.headers.customrequestheaders.X-Forwarded-Proto=https" - "traefik.http.middlewares.nc-headers.headers.referrerPolicy=same-origin" gotify: image: gotify/server container_name: gotify ports: - 8089:80 environment: - GOTIFY_DEFAULTUSER_PASS=${GOTIFY_PASSWORD} volumes: - "./gotify_data:/app/data" labels: - "traefik.enable=true" - "traefik.http.routers.gotify.rule=Host(`gotify.sebson.space`)" - "traefik.http.routers.gotify.entrypoints=websecure" - "traefik.http.routers.gotify.tls.certresolver=mytlschallenge" - "traefik.http.services.gotify.loadbalancer.server.port=80" # ============================================ # DOWNLOADERS # ============================================ # gluetun, qbittorrent, radarr removed — replaced by torrent-box-with-vpn stack prowlarr: image: linuxserver/prowlarr container_name: prowlarr environment: - PUID=1000 - PGID=1000 - TZ=Europe/Warsaw volumes: - ./prowlarr:/config ports: - 9696:9696 restart: always # ============================================ # SECURITY # ============================================ crowdsec: image: crowdsecurity/crowdsec:latest container_name: crowdsec environment: - COLLECTIONS=crowdsecurity/linux crowdsecurity/sshd crowdsecurity/traefik crowdsecurity/whitelist-good-actors - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID} ports: - "127.0.0.1:8878:8080" - "127.0.0.1:6060:6060" volumes: - /var/log/auth.log:/var/log/auth.log:ro - ./traefik/logs:/var/log/traefik:ro - ./crowdsec/conf:/etc/crowdsec - ./crowdsec/data:/var/lib/crowdsec/data - ./jellyfin/config/log:/var/log/jellyfin:ro - /var/run/docker.sock:/var/run/docker.sock:ro restart: unless-stopped traefik-bouncer: image: fbonalair/traefik-crowdsec-bouncer:latest container_name: traefik-bouncer environment: - CROWDSEC_BOUNCER_API_KEY=${CROWDSEC_BOUNCER_API_KEY} - CROWDSEC_AGENT_HOST=crowdsec:8080 - GIN_MODE=release depends_on: - crowdsec restart: unless-stopped # ============================================ # AI / LLM STACK # ============================================ ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped volumes: - ./ollama_data:/root/.ollama ports: - "11434:11434" environment: - TZ=${TZ} open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui restart: unless-stopped depends_on: - ollama volumes: - ./open-webui_data:/app/backend/data ports: - "3002:8080" environment: - TZ=${TZ} - OLLAMA_BASE_URL=http://ollama:11434 - VECTOR_DB=chroma - CHROMA_HTTP_HOST=chromadb - CHROMA_HTTP_PORT=8000 labels: - "traefik.enable=true" - "traefik.http.routers.open-webui.rule=Host(`oi.sebson.space`)" - "traefik.http.routers.open-webui.entrypoints=websecure" - "traefik.http.routers.open-webui.tls.certresolver=mytlschallenge" - "traefik.http.services.open-webui.loadbalancer.server.port=8080" chromadb: image: chromadb/chroma:latest container_name: chromadb restart: unless-stopped volumes: - ./chromadb/data:/chroma/chroma ports: - "8000:8000" environment: - TZ=${TZ} - IS_PERSISTENT=TRUE log-ingester: build: context: ./log-ingester container_name: log-ingester restart: unless-stopped depends_on: - chromadb - ollama volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./frigate:/data/frigate:ro - ./homeassistant/config:/data/ha:ro - ./log-ingester/state:/data/state ports: - "8765:8765" environment: - TZ=${TZ} - CHROMA_HOST=chromadb - CHROMA_PORT=8000 - OLLAMA_URL=http://ollama:11434 - FRIGATE_DB=/data/frigate/frigate.db - HA_LOG=/data/ha/home-assistant.log - STATE_FILE=/data/state/state.json - INGEST_INTERVAL=300 - PG_HOST=postgres18 - PG_PORT=5432 - PG_DB=homeassistant - PG_USER=${DB_USER} - PG_PASS=${DB_PASS} # ============================================ # HOME ASSISTANT VOICE PIPELINE # (disabled — configure when RPi4 satellite is ready) # ============================================ # piper + wyoming-openwakeword: uncomment when setting up voice satellite # ============================================ # TRANSMISSION VPN (legacy, kept for compatibility) # ============================================ transmission-vpn: image: haugene/transmission-openvpn:latest container_name: transmission-vpn restart: unless-stopped cap_add: - NET_ADMIN volumes: - ./transmission-vpn/transmission-home:/config - ./transmission-vpn/completed:/data/completed - ./transmission-vpn/incomplete:/data/incomplete - ./transmission-vpn/watch:/data/watch environment: - TZ=${TZ} - OPENVPN_PROVIDER=${OPENVPN_PROVIDER} - OPENVPN_USERNAME=${NORD_VPN_USERNAME_ID} - OPENVPN_PASSWORD=${NORD_VPN_PASSWORD} - TRANSMISSION_RATIO_LIMIT_ENABLED=${TRANSMISSION_RATIO_LIMIT_ENABLED} - TRANSMISSION_RATIO_LIMIT=${TRANSMISSION_RATIO_LIMIT} - TRANSMISSION_SPEED_LIMIT_DOWN_ENABLED=${TRANSMISSION_SPEED_LIMIT_DOWN_ENABLED} - TRANSMISSION_SPEED_LIMIT_DOWN=${TRANSMISSION_SPEED_LIMIT_DOWN} - TRANSMISSION_SPEED_LIMIT_UP_ENABLED=${TRANSMISSION_SPEED_LIMIT_UP_ENABLED} - TRANSMISSION_SPEED_LIMIT_UP=${TRANSMISSION_SPEED_LIMIT_UP} - WEBPROXY_ENABLED=false - LOCAL_NETWORK=192.168.1.0/24 ports: - "9092:9091" sysctls: - net.ipv6.conf.all.disable_ipv6=0 devices: - /dev/net/tun uptime-kuma: image: louislam/uptime-kuma container_name: uptime-kuma restart: unless-stopped volumes: - ${PWD}/uptime-kuma/data:/app/data labels: - "traefik.enable=true" - "traefik.http.routers.uptime-kuma.rule=Host(`kuma.sebson.space`)" - "traefik.http.routers.uptime-kuma.entrypoints=websecure" - "traefik.http.routers.uptime-kuma.tls.certresolver=mytlschallenge" - "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"