--- secrets: gitea_runner_token: file: secrets/gitea_runner_token.txt authentik_secret_key: file: secrets/authentik_secret_key email_host: file: secrets/email_host email_username: file: secrets/email_username email_password: file: secrets/email_password postgres_general_username: file: secrets/postgres_general_username postgres_general_password: file: secrets/postgres_general_password mariadb_root_password: file: secrets/mariadb_root_password yamtrack_secret: file: secrets/yamtrack_secret yamtrack_trakt_api_client_id: file: secrets/yamtrack_trakt_api_client_id yamtrack_trakt_api_client_secret: file: secrets/yamtrack_trakt_api_client_secret steam_api_key: file: secrets/steam_api_key igdb_api_client_id: file: secrets/igdb_api_client_id igdb_api_client_secret: file: secrets/igdb_api_client_secret hardcover_api_token: file: secrets/hardcover_api_token configs: caddyfile: content: | notes-old.${DOMAIN_LOCAL} { handle { root * /srv/notes file_server } } mimi.${DOMAIN} { handle { root * /etc/caddy/sites-enabled file_server { index mimikong.html } } } files.${DOMAIN_LOCAL} { reverse_proxy 192.168.0.106:3923 } photos.${DOMAIN} { reverse_proxy 192.168.0.166:2283 } ai-chat.${DOMAIN_LOCAL} { reverse_proxy 192.168.0.203:8080 } http://ca.${DOMAIN_LOCAL} { root * /data/caddy/pki/authorities/local/ file_server browse } dnsmasq: content: | log-facility=- log-queries no-resolv server=8.8.4.4 server=8.8.8.8 # This ensures local lookups from /etc/hosts or host-record are logged log-async # for self-hosted services via caddy address=/.${DOMAIN_LOCAL}/192.168.0.106 # each host needs a host record # otherwise its hostname will be redirected to the above IP address host-record=nas.${DOMAIN_LOCAL},192.168.0.106 host-record=nixos.${DOMAIN_LOCAL},192.168.0.203 host-record=oldguy.${DOMAIN_LOCAL},192.168.0.168 ptr-record=106.0.168.192.in-addr.arpa,nas.${DOMAIN_LOCAL} host-record=suma.${DOMAIN_LOCAL},192.168.0.159 host-record=suma-proxy3.${DOMAIN_LOCAL},192.168.0.176 host-record=suma-proxy4.${DOMAIN_LOCAL},192.168.0.123 host-record=suma-proxy5.${DOMAIN_LOCAL},192.168.0.166 host-record=suma-proxy6.${DOMAIN_LOCAL},192.168.0.204 host-record=suma-proxy7.${DOMAIN_LOCAL},192.168.0.152 host-record=suma-proxy8.${DOMAIN_LOCAL},192.168.0.196 include: - services/bazarr.yml - services/jellyfin.yml - services/komga.yml - services/radarr.yml - services/miniflux.yml - services/jelu.yml - services/sonarr.yml - services/postgres.yml - services/nextcloud.yml - services/sabnzbd.yml - services/openldap.yml - services/prowlarr.yml - services/netbootxyz.yml - services/registry.yml - services/portainer.yml - services/drone/drone.yml - services/enshrouded.yml - services/7dtdserver.yml - services/gluetun.yml - services/handbrake-server.yml - services/redlib.yml - services/calibre-web.yml - services/calibre-web-automated.yml - services/kavita.yml services: caddy: image: lucaslorentz/caddy-docker-proxy:2.10-alpine container_name: caddy ports: - "${TIMETRACKER_EXTERNAL_PORT}:${TIMETRACKER_INTERNAL_PORT}" - "${DENDRON_NOTES_EXTERNAL_PORT}:${DENDRON_NOTES_INTERNAL_PORT}" - 80:80 - 443:443 environment: - CADDY_INGRESS_NETWORKS=docker-compose-templates_public - CADDY_DOCKER_CADDYFILE_PATH=/Caddyfile configs: - source: caddyfile target: /Caddyfile volumes: - "${DOCKER_STORAGE_PATH}/caddy/etc:/etc/caddy" - "${DOCKER_STORAGE_PATH}/caddy/data:/data" - "${DOCKER_STORAGE_PATH}/caddy/config:/config" - "/var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock" - "/www/notes:/srv/notes" - /var/run/docker.sock:/var/run/docker.sock networks: public: ipv4_address: 192.168.240.2 restart: unless-stopped # cap_drop: # - ALL # cap_add: # - NET_BIND_SERVICE timetracker: image: ${REGISTRY_URL}/timetracker container_name: timetracker environment: - TZ=${TZ} - "CSRF_TRUSTED_ORIGINS=https://tracker.kucharczyk.xyz" - PUID=${PUID} - PGID=${PGID} - DATA_DIR=/home/timetracker/app/data volumes: - "${DOCKER_STORAGE_PATH}/timetracker/data:/home/timetracker/app/data" - "${DOCKER_STORAGE_PATH}/timetracker/backups:/home/timetracker/app/games/fixtures/backups" depends_on: - caddy networks: public: ipv4_address: 192.168.240.3 labels: caddy: tracker.${DOMAIN} caddy.reverse_proxy: "{{ upstreams 8000 }}" restart: unless-stopped trilium: image: triliumnext/notes:v0.95.0 container_name: trilium restart: always environment: - TRILIUM_DATA_DIR=/home/node/trilium-data volumes: - ${DOCKER_STORAGE_PATH}/trilium:/home/node/trilium-data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro labels: caddy: trilium.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams $TRILIUM_INTERNAL_PORT }}" ports: - "${TRILIUM_EXTERNAL_PORT}:${TRILIUM_INTERNAL_PORT}" networks: public: ipv4_address: 192.168.240.4 ntfy: image: binwiederhier/ntfy:v2.16.0 container_name: ntfy command: - serve user: ${PUID}:${PGID} environment: - TZ=${TZ} - NTFY_LOG_LEVEL=debug volumes: - "${DOCKER_STORAGE_PATH}/ntfy/cache:/var/cache/ntfy" - "${DOCKER_STORAGE_PATH}/ntfy/config:/etc/ntfy" ports: - "${NTFY_EXTERNAL_PORT}:${NTFY_INTERNAL_PORT}" networks: public: ipv4_address: 192.168.240.5 labels: caddy: "notify.${DOMAIN}, http://notify.${DOMAIN}" caddy.reverse_proxy: "{{ upstreams $NTFY_INTERNAL_PORT }}" caddy.@httpget.protocol: http caddy.@httpget.method: get caddy.@httpget.path_regexp: "^/([-_a-z0-9]{0,64}$|docs/|static/)" caddy.redir: "@httpget https://{host}{uri}" restart: unless-stopped audiobookshelf: image: ghcr.io/advplyr/audiobookshelf:2.34.0 container_name: audiobookshelf environment: - AUDIOBOOKSHELF_UID=${PUID} - AUDIOBOOKSHELF_GID=${PGID} - TZ=${TZ} volumes: - "${DOCKER_STORAGE_PATH}/audiobookshelf/audiobooks:/audiobooks" - "${DOCKER_STORAGE_PATH}/audiobookshelf/podcasts:/podcasts" - "${DOCKER_STORAGE_PATH}/audiobookshelf/config:/config" - "${DOCKER_STORAGE_PATH}/audiobookshelf/metadata:/metadata" labels: caddy: audiobooks.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 80 }}" networks: public: ipv4_address: 192.168.240.6 restart: unless-stopped beets: image: lscr.io/linuxserver/beets:2.11.0 container_name: beets user: 1000:100 environment: - TZ=${TZ} volumes: - "${DOCKER_STORAGE_PATH}/beets:/config" - "${STORAGE_PATH}/media/music2:/music" - "${STORAGE_PATH}/download/music:/downloads" ports: - 8337:8337 networks: public: ipv4_address: 192.168.240.7 restart: unless-stopped mealie: container_name: mealie image: hkotel/mealie:v3.5.0 depends_on: - authentik-server environment: PUID: ${PUID} PGID: ${PGID} TZ: ${TZ} OIDC_AUTH_ENABLED: true OIDC_PROVIDER_NAME: Authentik OIDC_CONFIGURATION_URL: https://authentik.kucharczyk.xyz/application/o/mealie/.well-known/openid-configuration OIDC_CLIENT_ID: asDhzvutfxxpgwaaz0Jjr6SNpEtZo8GKjjs1WzUU OIDC_CLIENT_SECRET: iIgP3aaF1t0sTd8JPwXrCYmd3Ycc5hhfQROdHN7ByDU81gFJiNbRQ1OrTU7e9yzuPAyqLShRQ2Ve7ov03maHpQtyZzZ2FBdb0OHCkoS4brVuV8uZ4cnVPCzwLEO9bk9U OIDC_SIGNUP_ENABLED: false OIDC_USER_GROUP: mealie-users OIDC_ADMIN_GROUP: mealie-admins OIDC_AUTO_REDIRECT: true # Optional: The login page will be bypassed and you will be sent directly to your Identity Provider. OIDC_REMEMBER_ME: true # Option ALLOW_PASSWORD_LOGIN: false env_file: - mealie.env volumes: - "${DOCKER_STORAGE_PATH}/mealie/data/:/app/data" networks: public: ipv4_address: 192.168.240.8 labels: caddy: recipes.${DOMAIN} caddy.reverse_proxy: "{{ upstreams 9000 }}" restart: unless-stopped webhook: image: ${REGISTRY_URL}/webhook container_name: webhook build: https://git.${DOMAIN}/containers/webhook.git#main user: ${PUID}:${PGID} environment: - TZ=${TZ} volumes: - "${DOCKER_STORAGE_PATH}/webhook/config:/config" - "${DOCKER_STORAGE_PATH}/webhook/scripts:/var/webhook" ports: - "${WEBHOOK_EXTERNAL_PORT}:${WEBHOOK_INTERNAL_PORT}" networks: public: ipv4_address: 192.168.240.10 restart: unless-stopped valheim: image: ghcr.io/lloesche/valheim-server container_name: valheim volumes: - ${DOCKER_STORAGE_PATH}/valheim/config:/config - ${DOCKER_STORAGE_PATH}/valheim/data:/opt/valheim env_file: - valheim.env ports: - ${VALHEIM_EXTERNAL_PORT}:${VALHEIM_INTERNAL_PORT} cap_add: - SYS_NICE networks: public: ipv4_address: 192.168.240.11 restart: unless-stopped stash: image: stashapp/stash:v0.31.1 container_name: stash ports: - "${STASH_EXTERNAL_PORT}:${STASH_INTERNAL_PORT}" logging: driver: "json-file" options: max-file: "10" max-size: "2m" environment: - STASH_STASH=/data/ - STASH_GENERATED=/generated/ - STASH_METADATA=/metadata/ - STASH_CACHE=/cache/ - STASH_PORT=${STASH_INTERNAL_PORT} volumes: - /etc/localtime:/etc/localtime:ro ## Adjust below paths (the left part) to your liking. ## E.g. you can change ./config:/root/.stash to ./stash:/root/.stash ## Keep configs, scrapers, and plugins here. - "${DOCKER_STORAGE_PATH}/stash/config:/root/.stash" ## Point this at your collection. - "${STORAGE_PATH}/xxx:/data/" ## This is where your stash's metadata lives - "${DOCKER_STORAGE_PATH}/stash/metadata:/metadata" ## Any other cache content. - "${DOCKER_STORAGE_PATH}/stash/cache:/cache" ## Where to store generated content (screenshots,previews,transcodes,sprites) - "${DOCKER_STORAGE_PATH}/stash/generated:/generated" ## Where to store binary blob data (scene covers, images) - "${DOCKER_STORAGE_PATH}/stash/blobs:/blobs" networks: public: ipv4_address: 192.168.240.13 restart: unless-stopped navidrome: image: deluan/navidrome:0.61.2 container_name: navidrome user: "${PUID}:${PGID}" volumes: - "${DOCKER_STORAGE_PATH}/navidrome:/data" - "${STORAGE_PATH}/media/music2:/music" networks: public: ipv4_address: 192.168.240.14 labels: caddy: music.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 4533 }}" caddy.@protected.not.path: "/share/* /rest/*" caddy.forward_auth_0: "@protected authentik-server:9000" caddy.forward_auth_0.uri: "/outpost.goauthentik.io/auth/caddy" caddy.forward_auth_0.copy_headers: "X-Authentik-Username" environment: ND_LASTFM_APIKEY: 29e22ee836a0cb51cfaacb72d605e30d ND_LASTFM_SECRET: 10aa58294eeffa142685e78a0cd78ad6 ND_DEEZER_ENABLED: true ND_DEVACTIVITYPANEL: true ND_ENABLESHARING: true ND_SEARCH_FULLSTRING: true ND_LOGLEVEL: debug ND_PREFERSORTTAGS: true ND_ENABLEM3UEXTERNALALBUMART: true ND_ENABLEWEBPENCODING: true ND_UICOVERARTSIZE: 600 ND_EXTAUTH_TRUSTEDSOURCES: 192.168.240.2/32 ND_EXTAUTH_USERHEADER: X-Authentik-Username ND_EXTAUTH_LOGOUTURL: https://authentik.kucharczyk.xyz/if/flow/default-invalidation-flow/ restart: unless-stopped maloja: image: krateng/maloja container_name: maloja ports: - "${MALOJA_EXTERNAL_PORT}:${MALOJA_INTERNAL_PORT}" env_file: - maloja.env user: "${PUID}:${PGID}" volumes: - "${DOCKER_STORAGE_PATH}/maloja:/data" networks: public: ipv4_address: 192.168.240.15 restart: unless-stopped redis: container_name: redis image: docker.io/library/redis:7 networks: public: ipv4_address: 192.168.240.30 restart: unless-stopped volumes: - "${DOCKER_STORAGE_PATH}/redis:/data" paperless-ngx: container_name: paperless-ngx image: ghcr.io/paperless-ngx/paperless-ngx:2.20.14 restart: unless-stopped depends_on: - redis - gotenberg - tika ports: - "${PAPERLESS_EXTERNAL_PORT}:${PAPERLESS_INTERNAL_PORT}" labels: caddy: paperless.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams $PAPERLESS_INTERNAL_PORT }}" networks: public: ipv4_address: 192.168.240.16 healthcheck: test: [ "CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000" ] interval: 30s timeout: 10s retries: 5 volumes: - "${DOCKER_STORAGE_PATH}/paperless-ngx/data:/usr/src/paperless/data" - "${DOCKER_STORAGE_PATH}/paperless-ngx/media:/usr/src/paperless/media" - "${DOCKER_STORAGE_PATH}/paperless-ngx/export:/usr/src/paperless/export" - "${DOCKER_STORAGE_PATH}/paperless-ngx/consume:/usr/src/paperless/consume" env_file: paperless-ngx.env environment: PAPERLESS_REDIS: redis://redis:6379 PAPERLESS_TIKA_ENABLED: 1 PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 PAPERLESS_TIKA_ENDPOINT: http://tika:9998 PAPERLESS_URL: "https://paperless.${DOMAIN_LOCAL}" PAPERLESS_APPS: allauth.socialaccount.providers.openid_connect PAPERLESS_SOCIALACCOUNT_PROVIDERS: > { "openid_connect": { "OAUTH_PKCE_ENABLED": true, "APPS": [ { "provider_id": "authentik", "name": "authentik", "client_id": "h73QXG52ujoT2XuF6nIf7KaDk2swVbeMM6mHGDrj", "secret": "gQb5sAyoEeNDzT9MMELYN8dgIbXXyVVdFyudrHckanILu21baf3A1V9lzc29AH11YHsXK9ZJuNy6aaWWWWEVysImJ6MWRCTORfg3Fjhst1zDp9brr4QKpjzFUHMjaolK", "settings": { "server_url": "https://authentik.kucharczyk.xyz/application/o/paperless-ngx/.well-known/openid-configuration", "fetch_userinfo": true } } ], "SCOPE": ["openid", "profile", "email"] } } PAPERLESS_LOGOUT_REDIRECT_URL: "https://authentik.kucharczyk.xyz/application/o/paperless-ngx/end-session/" # PAPERLESS_SOCIAL_AUTO_SIGNUP: true # PAPERLESS_SOCIALACCOUNT_ALLOW_SIGNUPS: true PAPERLESS_DISABLE_REGULAR_LOGIN: true PAPERLESS_REDIRECT_LOGIN_TO_SSO: true gotenberg: image: docker.io/gotenberg/gotenberg:7.6 restart: unless-stopped networks: public: ipv4_address: 192.168.240.17 # The gotenberg chromium route is used to convert .eml files. We do not # want to allow external content like tracking pixels or even javascript. command: - "gotenberg" - "--chromium-disable-javascript=true" - "--chromium-allow-list=file:///tmp/.*" tika: image: ghcr.io/paperless-ngx/tika:latest networks: public: ipv4_address: 192.168.240.18 restart: unless-stopped homer: image: b4bz/homer:v25.11.1 container_name: homer ports: - "${HOMER_EXTERNAL_PORT}:${HOMER_INTERNAL_PORT}" labels: caddy: dashboard.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams $HOMER_INTERNAL_PORT }}" networks: public: ipv4_address: 192.168.240.19 volumes: - "${DOCKER_STORAGE_PATH}/homer:/www/assets" environment: UID: ${PUID} GID: ${PGID} restart: unless-stopped syncthing: image: lscr.io/linuxserver/syncthing:2.0.12 container_name: syncthing volumes: - "${DOCKER_STORAGE_PATH_SLOW}/syncthing:/config" - "${DOCKER_STORAGE_PATH_SLOW}/syncthing/shares:/shares" - "${STORAGE_PATH}:/storage" ports: - "${SYNCTHING_EXTERNAL_PORT1}:${SYNCTHING_INTERNAL_PORT1}" - "${SYNCTHING_EXTERNAL_PORT2}:${SYNCTHING_INTERNAL_PORT2}" - "${SYNCTHING_EXTERNAL_PORT3}:${SYNCTHING_INTERNAL_PORT3}" - "${SYNCTHING_EXTERNAL_PORT4}:${SYNCTHING_INTERNAL_PORT4}" environment: - "PUID=${PUID}" - "PGID=${PGID}" restart: unless-stopped networks: public: ipv4_address: 192.168.240.20 mediawiki: container_name: mediawiki image: mediawiki networks: public: ipv4_address: 192.168.240.21 labels: caddy: wiki.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams $MEDIAWIKI_INTERNAL_PORT }}" depends_on: - mariadb ports: - "${MEDIAWIKI_EXTERNAL_PORT}:${MEDIAWIKI_INTERNAL_PORT}" volumes: - "${DOCKER_STORAGE_PATH}/mediawiki/images:/var/www/html/images" - "${DOCKER_STORAGE_PATH}/mediawiki/extensions:/var/www/html/extensions" - "${DOCKER_STORAGE_PATH}/mediawiki/LocalSettings.php:/var/www/html/LocalSettings.php" restart: unless-stopped photoprism: container_name: photoprism image: docker.io/photoprism/photoprism networks: public: ipv4_address: 192.168.240.22 ports: - "${PHOTOPRISM_EXTERNAL_PORT}:${PHOTOPRISM_INTERNAL_PORT}" labels: caddy: photoprism.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 2342 }}" depends_on: - mariadb env_file: - photoprism.env volumes: - "${PHOTOS_STORAGE_PATH}/import:/photoprism/import" - "${PHOTOS_STORAGE_PATH}/originals:/photoprism/originals" - "${PHOTOS_STORAGE_PATH}/storage:/photoprism/storage" restart: unless-stopped mariadb: container_name: mariadb image: linuxserver/mariadb:11.4.5 networks: public: ipv4_address: 192.168.240.23 ports: - "${MARIADB_EXTERNAL_PORT}:${MARIADB_INTERNAL_PORT}" secrets: - mariadb_root_password environment: - MARIADB_AUTO_UPGRADE=true - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} - FILE__MYSQL_ROOT_PASSWORD=/run/secrets/mariadb_root_password volumes: - "${DOCKER_STORAGE_PATH}/mariadb:/config" - sockets:/run/mysqld/ restart: unless-stopped healthcheck: test: [ "CMD", "mariadb-admin", "ping", "-h", "localhost" ] interval: 5s timeout: 5s retries: 10 baserow: container_name: baserow image: baserow/baserow:latest networks: public: ipv4_address: 192.168.240.24 labels: caddy: baserow.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 80 }}" depends_on: - postgres env_file: - baserow.env volumes: - "${DOCKER_STORAGE_PATH}/baserow:/baserow/data" restart: unless-stopped gitea: container_name: gitea image: gitea/gitea:1.26.1 networks: public: ipv4_address: 192.168.240.26 depends_on: - postgres - authentik-server ports: - "${GITEA_WEBUI_EXTERNAL_PORT}:${GITEA_WEBUI_INTERNAL_PORT}" - "${GITEA_SSH_EXTERNAL_PORT}:${GITEA_SSH_INTERNAL_PORT}" labels: caddy: git.${DOMAIN} caddy.reverse_proxy: "{{ upstreams $GITEA_WEBUI_INTERNAL_PORT }}" volumes: - "${DOCKER_STORAGE_PATH}/gitea:/data" restart: unless-stopped gitearunner: container_name: gitearunner image: gitea/act_runner depends_on: - gitea volumes: - "${DOCKER_STORAGE_PATH}/gitearunner/config:/config" - "${DOCKER_STORAGE_PATH}/gitearunner/data:/data" - /var/run/docker.sock:/var/run/docker.sock networks: public: ipv4_address: 192.168.240.27 environment: - GITEA_INSTANCE_URL=https://git.${DOMAIN} - CONFIG_FILE=/config/config.yaml - GITEA_RUNNER_REGISTRATION_TOKEN_FILE=/run/secrets/gitea_runner_token - GITEA_RUNNER_LABELS="ubuntu-latest:docker://catthehacker/ubuntu:act-latest" - GITEA_RUNNER_NAME="NAS_CONTAINER" secrets: - gitea_runner_token restart: unless-stopped vaultwarden: image: vaultwarden/server:1.32.1 container_name: vaultwarden networks: public: ipv4_address: 192.168.240.29 ports: - "${VAULTWARDEN_EXTERNAL_PORT}:${VAULTWARDEN_INTERNAL_PORT}" labels: caddy: bw.${DOMAIN} caddy.reverse_proxy: "{{ upstreams 80 }}" env_file: - ./secrets/vaultwarden.env environment: - PUSH_ENABLED=true # PUSH_INSTALLATION_ID= # PUSH_INSTALLATION_KEY= - PUSH_RELAY_URI=https://api.bitwarden.eu - PUSH_IDENTITY_URI=https://identity.bitwarden.eu - ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$aWJ2cVRvYUsySkM3M01TMTJJMnZqbUF0Wm1qRWhvd1B6Sk50Q1hwck96dz0$$FKjZ36E54pX2e0AE9OaDpiH43TyAyfVwr3IvracbqEA - SMTP_HOST=${EMAIL_HOST} - SMTP_FROM=${EMAIL_FROM} - SMTP_FROM_NAME="Bitwarden (bw.kucharczyk.xyz)" - SMTP_PORT=${EMAIL_PORT} - SMTP_USERNAME=${EMAIL_FROM} - SMTP_PASSWORD=${EMAIL_PASSWORD} volumes: - ${DOCKER_STORAGE_PATH}/vaultwarden:/data restart: unless-stopped qbittorrent: image: lscr.io/linuxserver/qbittorrent:5.1.4-r1-ls437 #image: lscr.io/linuxserver/qbittorrent:5.2.0_v2.0.12-ls454 container_name: qbittorrent environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} - WEBUI_PORT=${QBITTORRENT_WEBUI_PORT} - TORRENTING_PORT=6881 - DOCKER_MODS=ghcr.io/vuetorrent/vuetorrent-lsio-mod|linuxserver/mods:universal-apprise volumes: - ${DOCKER_STORAGE_PATH}/qbittorrent/appdata:/config - "${DOWNLOADS_PATH}/sabnzbd:/downloads" - "${TORRENTS_SEED_PATH}:/seed" - ${TORRENTS_WATCH_PATH}:/watch - /etc/localtime:/etc/localtime:ro networks: public: ipv4_address: 192.168.240.55 ports: - ${QBITTORRENT_WEBUI_EXTERNAL_PORT}:${QBITTORRENT_WEBUI_INTERNAL_PORT} - 6881:6881 - 6881:6881/udp labels: caddy: qbt.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams $QBITTORRENT_WEBUI_INTERNAL_PORT }}" restart: unless-stopped # see https://github.com/FarisZR/Privacy-OCI breezewiki: container_name: breezewiki image: oci.fariszr.com/fariszr/breezewiki:latest restart: always networks: public: ipv4_address: 192.168.240.56 ports: - 8005:8000 labels: caddy: bwiki.${DOMAIN}, bwiki.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 8000 }}" environment: - bw_canonical_origin=bwiki.${DOMAIN} - bw_feature_search_suggestions=true - bw_port=8000 rss-bridge: container_name: rss-bridge image: rssbridge/rss-bridge:latest networks: public: ipv4_address: 192.168.240.57 volumes: - ./config:/config ports: - 3002:80 restart: unless-stopped karakeep: container_name: karakeep image: ghcr.io/karakeep-app/karakeep:0.31.0 restart: unless-stopped volumes: # By default, the data is stored in a docker volume called "data". # If you want to mount a custom directory, change the volume mapping to: # - /path/to/your/directory:/data - ${DOCKER_STORAGE_PATH}/karakeep:/data ports: - 3003:3000 env_file: - .env environment: LOG_LEVEL: debug MEILI_ADDR: http://meilisearch:7700 BROWSER_WEB_URL: http://chrome:9222 NEXTAUTH_SECRET: lB5mx3t9mdKclELtt+cs2pVBefB+8vD4dKuzhvUP+JzR9bL1 MEILI_MASTER_KEY: Cvu7m/RIGYQPiYcIrxacHFhbfLKfKq3wwSAWJPKVWQEauiIX NEXTAUTH_URL: https://karakeep.${DOMAIN} DISABLE_SIGNUPS: TRUE CRAWLER_VIDEO_DOWNLOAD: TRUE BROWSER_COOKIE_PATH: /data/yt-cookies.json CRAWLER_FULL_PAGE_SCREENSHOT: TRUE CRAWLER_FULL_PAGE_ARCHIVE: TRUE OPENAI_BASE_URL: http://100.84.157.12:8081/v1 OPENAI_API_KEY: "sk-llama-swap" INFERENCE_TEXT_MODEL: gemma-4-26B-A4B-it-UD-Q4_K_M INFERENCE_IMAGE_MODEL: qwen2.5-vl-7b INFERENCE_ENABLE_AUTO_TAGGING: TRUE INFERENCE_ENABLE_AUTO_SUMMARIZATION: TRUE INFERENCE_CONTEXT_LENGTH: 32000 # You almost never want to change the value of the DATA_DIR variable. # If you want to mount a custom directory, change the volume mapping above instead. DATA_DIR: /data # DON'T CHANGE THIS networks: public: ipv4_address: 192.168.240.58 labels: caddy: karakeep.${DOMAIN} caddy.reverse_proxy: "{{ upstreams 3000 }}" chrome: image: gcr.io/zenika-hub/alpine-chrome:124 restart: unless-stopped command: - --no-sandbox - --disable-gpu - --disable-dev-shm-usage - --remote-debugging-address=0.0.0.0 - --remote-debugging-port=9222 - --hide-scrollbars networks: public: ipv4_address: 192.168.240.59 ports: - 9222:9222 meilisearch: image: getmeili/meilisearch:v1.13.3 restart: unless-stopped env_file: - .env environment: MEILI_NO_ANALYTICS: "true" MEILI_MASTER_KEY: Cvu7m/RIGYQPiYcIrxacHFhbfLKfKq3wwSAWJPKVWQEauiIX volumes: - meilisearch:/meili_data networks: public: ipv4_address: 192.168.240.60 authentik-server: command: server depends_on: postgres: condition: service_healthy secrets: - authentik_secret_key - postgres_general_username - postgres_general_password environment: AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__NAME: authentik AUTHENTIK_POSTGRESQL__PASSWORD: file:///run/secrets/postgres_general_password AUTHENTIK_POSTGRESQL__USER: file:///run/secrets/postgres_general_username AUTHENTIK_SECRET_KEY: file:///run/secrets/authentik_secret_key AUTHENTIK_EMAIL__HOST: smtp.protonmail.ch AUTHENTIK_EMAIL__PORT: 587 AUTHENTIK_EMAIL__USERNAME: lukas@kucharczyk.xyz AUTHENTIK_EMAIL__PASSWORD: CQHMWAUWQG5FBJ2V AUTHENTIK_EMAIL__USE_TLS: true AUTHENTIK_EMAIL__USE_SSL: false AUTHENTIK_EMAIL__TIMEOUT: 60 AUTHENTIK_EMAIL__FROM: lukas@kucharczyk.xyz image: ghcr.io/goauthentik/server:2026.2.2 ports: - 9002:9000 - 9443:9443 networks: public: ipv4_address: 192.168.240.61 restart: unless-stopped volumes: - ${DOCKER_STORAGE_PATH}/authentik/data:/data - ${DOCKER_STORAGE_PATH}/authentik/custom-templates:/templates labels: caddy: authentik.${DOMAIN} caddy.reverse_proxy: "{{ upstreams 9000 }}" authentik-worker: command: worker depends_on: postgres: condition: service_healthy networks: public: ipv4_address: 192.168.240.62 secrets: - authentik_secret_key - email_host - email_username - email_password - postgres_general_username - postgres_general_password environment: AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__NAME: authentik AUTHENTIK_POSTGRESQL__PASSWORD: file:///run/secrets/postgres_general_password AUTHENTIK_POSTGRESQL__USER: file:///run/secrets/postgres_general_username AUTHENTIK_SECRET_KEY: file:///run/secrets/authentik_secret_key AUTHENTIK_EMAIL__HOST: file:///run/secrets/email_host AUTHENTIK_EMAIL__PORT: 587 AUTHENTIK_EMAIL__USERNAME: file:///run/secrets/email_username AUTHENTIK_EMAIL__PASSWORD: file:///run/secrets/email_password AUTHENTIK_EMAIL__USE_TLS: true AUTHENTIK_EMAIL__USE_SSL: false AUTHENTIK_EMAIL__TIMEOUT: 60 AUTHENTIK_EMAIL__FROM: file:///run/secrets/email_username image: ghcr.io/goauthentik/server:2026.2.2 restart: unless-stopped user: root volumes: - /var/run/docker.sock:/var/run/docker.sock - ${DOCKER_STORAGE_PATH}/authentik/data:/data - ${DOCKER_STORAGE_PATH}/authentik/certs:/certs - ${DOCKER_STORAGE_PATH}/authentik/custom-templates:/templates dnsmasq: restart: always image: strm/dnsmasq configs: - source: dnsmasq target: /etc/dnsmasq.conf ports: - "53:53/udp" cap_add: - NET_ADMIN ersatztv: image: jasongdove/ersatztv:latest container_name: ersatztv networks: public: ipv4_address: 192.168.240.63 ports: - 8409:8409 labels: caddy: tv.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 8409 }}" volumes: - ${DOCKER_STORAGE_PATH}/ersatztv/config:/config - ${MEDIA_PATH}:/media:ro restart: unless-stopped environment: TZ: ${TZ} immich-machine-learning: container_name: immich_machine_learning # For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag. # Example tag: ${IMMICH_VERSION:-release}-cuda image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda # extends: # uncomment this section for hardware acceleration - see https://docs.immich.app/features/ml-hardware-acceleration # file: hwaccel.ml.yml # service: cuda # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable ports: - 3003:3003 volumes: - model-cache:/cache restart: always healthcheck: disable: false deploy: resources: reservations: devices: - driver: cdi device_ids: - nvidia.com/gpu=all capabilities: - gpu slskd: image: slskd/slskd:0.24.0 container_name: slskd user: 1000:100 networks: public: ipv4_address: 192.168.240.67 labels: caddy: slskd.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 5030 }}" env_file: - secrets/slskd_secrets.env environment: - SLSKD_REMOTE_CONFIGURATION=true - SLSKD_DOWNLOADS_DIR=/downloads - SLSKD_INCOMPLETE_DIR=/app/incomplete - SLSKD_SHARED_DIR=/shares - SLSKD_SLSK_ADDRESS=server.slsknet.org - SLSKD_SLSK_PORT=2242 # from slskd_secrets.env # - SLSKD_USERNAME # - SLSKD_PASSWORD # - SLSKD_SLSK_USERNAME # - SLSKD_SLSK_PASSWORD - SLSKD_NO_HTTPS=TRUE volumes: - ${DOCKER_STORAGE_PATH}/slskd:/app - ${DOWNLOADS_PATH}/music/autoimport:/downloads - ${MUSIC_PATH}:/shares/music:ro restart: always booklore: image: booklore/booklore:v1.16.2 container_name: booklore env_file: secrets/booklore.env environment: - USER_ID=${PUID} - GROUP_ID=${PGID} - TZ=${TZ} - DATABASE_URL_FILE=jdbc:mariadb://mariadb:3306/booklore - DATABASE_USERNAME=booklore - BOOKLORE_PORT=6060 depends_on: mariadb: condition: service_healthy networks: public: ipv4_address: 192.168.240.66 ports: - "6060:6060" labels: caddy: books.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 6060 }}" caddy_config.servers.protocol.max_header_size: "32kb" volumes: - ${DOCKER_STORAGE_PATH}/booklore/data:/app/data - "${DOCKER_STORAGE_PATH_SLOW}/books-calibre:/books-calibre" - ${DOWNLOADS_PATH}/bookdrop:/bookdrop restart: unless-stopped adminer: image: adminer:latest container_name: adminer depends_on: mariadb: condition: service_healthy networks: public: ipv4_address: 192.168.240.65 ports: - 8087:8080 restart: unless-stopped yamtrack: container_name: yamtrack image: ghcr.io/fuzzygrim/yamtrack:0.25.2 restart: unless-stopped depends_on: - redis secrets: - yamtrack_secret - yamtrack_trakt_api_client_id - yamtrack_trakt_api_client_secret - steam_api_key - igdb_api_client_id - igdb_api_client_secret - hardcover_api_token environment: - TZ=${TZ} - REDIS_URL=redis://redis:6379 - URLS=https://yamtrack.${DOMAIN_LOCAL} - REGISTRATION=true - TRACK_TIME=true - PUID=${PUID} - PGID=${PGID} - SECRET_FILE=yamtrack_secret - MAL_API_FILE=yamtrack_malapi - TRAKT_API_FILE=yamtrack_trakt_api_client_id - TRAKT_API_SECRET_FILE=yamtrack_trakt_api_client_secret - STEAM_API_KEY_FILE=steam_api_key - IGDB_ID_FILE=igdb_api_client_id - IGDB_SECRET_FILE=igdb_api_client_secret - HARDCOVER_API_FILE=hardcover_api_token volumes: - ${DOCKER_STORAGE_PATH}/yamtrack:/yamtrack/db networks: public: ipv4_address: 192.168.240.69 labels: caddy: yamtrack.${DOMAIN_LOCAL} caddy.reverse_proxy: "{{ upstreams 8000 }}" networks: public: attachable: true ipam: config: # 192.168.240.1 - 192.168.240.254 - subnet: "192.168.240.0/24" volumes: timetracker-static: sockets: meilisearch: model-cache: