mydocker/docker-compose.yaml

991 lines
30 KiB
YAML

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
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