services: # --- Infrastructure services --- traefik: image: traefik:v2.9 restart: always ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock - ./traefik/acme:/acme command: - --api.dashboard=true - --providers.docker=true - --providers.docker.defaultRule=Host(`app.${DOMAIN}`) && PathPrefix(`/{{ index .Labels "com.docker.compose.service" }}/`) - --entrypoints.web.address=:80 # Применяем middleware auth автоматически ко всем сервисам через entrypoint - --entrypoints.web.http.middlewares=auth@docker,error-401@docker - --entrypoints.websecure.address=:443 - --entrypoints.websecure.http.tls=true - --entrypoints.websecure.http.tls.certresolver=le - --certificatesresolvers.le.acme.email=admin@mail.${DOMAIN} - --certificatesresolvers.le.acme.storage=/acme/acme.json # - --certificatesresolvers.le.acme.tlschallenge=true - --certificatesresolvers.le.acme.httpchallenge=true - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web labels: - "traefik.enable=true" - "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)" - "traefik.http.routers.traefik.entrypoints=web" - "traefik.http.routers.traefik.service=api@internal" # Forward auth middleware - "traefik.http.middlewares.auth.forwardauth.address=http://sah/api/forward/check" - "traefik.http.middlewares.auth.forwardauth.trustForwardHeader=true" - "traefik.http.middlewares.auth.forwardauth.authResponseHeaders=Authorization,Cookie" # Error handler для перехвата 401 ошибок от сервисов - "traefik.http.middlewares.error-401.errors.status=401-401" - "traefik.http.middlewares.error-401.errors.service=sah" - "traefik.http.middlewares.error-401.errors.query=/api/forward/handle-401" # Middleware для stripprefix - "traefik.http.middlewares.global-stripprefix.replacepathregex.regex=^/([^/]+)/(.*)" - "traefik.http.middlewares.global-stripprefix.replacepathregex.replacement=/$$2" - traefik.http.middlewares.global-stripprefix2.replacepathregex.regex=^/([^/]+)/[^/]+/(.*) - traefik.http.middlewares.global-stripprefix2.replacepathregex.replacement=/$$2 sah: image: ${REG}/cc/sah:latest volumes: - ./sah/data:/data environment: - COOKIE_DOMAIN=${DOMAIN} - SAH_DOMAIN=sah.${DOMAIN} labels: - "traefik.http.routers.sah.rule=Host(`sah.${DOMAIN}`)" - "traefik.http.services.sah.loadbalancer.server.port=80" portainer: image: portainer/portainer-ce:latest environment: - PORTAINER_HTTP_ENABLED=true volumes: - /var/run/docker.sock:/var/run/docker.sock labels: - "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)" - "traefik.http.services.portainer.loadbalancer.server.port=9000" watchtower: image: containrrr/watchtower volumes: - /var/run/docker.sock:/var/run/docker.sock - /root/.docker/config.json:/config.json environment: - WATCHTOWER_CLEANUP=true - WATCHTOWER_DEBUG=true - WATCHTOWER_LABEL_ENABLE=true - WATCHTOWER_POLL_INTERVAL=30 - WATCHTOWER_SSL_VERIFY=false labels: - traefik.enable=false portagent: image: portainer/agent:2.19.1 restart: always ports: - 9001:9001 volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes labels: - traefik.enable=false api: image: tecnativa/tcp-proxy restart: unless-stopped tty: true environment: - LISTEN=:80 :443 - TALK=traefik:80 traefik:443 - TIMEOUT_TUNNEL=360s labels: - traefik.http.routers.api.middlewares=global-stripprefix - traefik.http.services.api.loadbalancer.server.port=80 # --- Database services --- mongo: image: mongo:4.0.9 ports: - "27017:27017/tcp" restart: "always" volumes: - ./db/mongo:/data/db - ./dump/mongo:/dump labels: - traefik.enable=false mongoadmin: image: mongo-express:1.0-20-alpine3.19 environment: - ME_CONFIG_MONGODB_ENABLE_ADMIN=true - ME_CONFIG_MONGODB_URL=mongodb://mongo:27017/ - ME_CONFIG_BASICAUTH=false # Отключает базовую аутентификацию labels: - traefik.http.routers.mongoadmin.rule=Host(`mongoadmin.${DOMAIN}`) - traefik.http.services.mongoadmin.loadbalancer.server.port=8081 # --- Application services --- app: image: ${REG}/cc/front3:latest restart: "always" labels: - "traefik.http.routers.app.rule=Host(`app.${DOMAIN}`) && PathPrefix(`/`)" - "traefik.http.services.app.loadbalancer.server.port=80" ma: image: ${REG}/cc/cc_ma environment: - "DB_BIG=big" - "DB_HOST=mongo" - "MA_PREFIX=p1" - "DB_NAME=master" - "MA_NO_SYNC=master" - "DB=" - "PROCESSES=4" - "MA_SEARCH_LIMIT=500" restart: "always" labels: - com.centurylinklabs.watchtower.enable=true # - traefik.http.routers.ma.middlewares=global-stripprefix # --- Plugins services --- metabase: image: metabase/metabase:latest restart: always environment: - MB_JETTY_PORT=3000 - MB_DB_TYPE=h2 # Используем встроенную H2 БД (не для продакшена!) - MB_DB_FILE=/metabase-data/metabase.db - MB_SITE_NAME=SMSynergy Analytics volumes: - ./metabase:/metabase-data # Сохраняем данные между перезапусками labels: - "traefik.http.routers.metabase.rule=Host(`metabase.${DOMAIN}`)" - "traefik.http.services.metabase.loadbalancer.server.port=3000" n8n: image: n8nio/n8n:1.121.2 container_name: n8n restart: unless-stopped environment: - N8N_PORT=5678 - N8N_SECURE_COOKIE=false - DB_TYPE=sqlite - DB_SQLITE_POOL_SIZE=64 - N8N_RUNNERS_ENABLED=true - N8N_GIT_NODE_DISABLE_BARE_REPOS=true - N8N_BLOCK_ENV_ACCESS_IN_NODE=false - N8N_DIAGNOSTICS_ENABLED=false - N8N_PERSONALIZATION_ENABLED=false labels: - "traefik.http.routers.n8n.rule=Host(`n8n.${DOMAIN}`)" - "traefik.http.services.n8n.loadbalancer.server.port=5678" jupyter: image: jupyter/datascience-notebook:latest command: > start-notebook.sh --NotebookApp.token='' --NotebookApp.password='' --ServerApp.disable_check_xsrf=True volumes: - ./jupyter_data:/home/jovyan/work labels: - "traefik.http.routers.jupyter.rule=Host(`jupyter.${DOMAIN}`)" - "traefik.http.services.jupyter.loadbalancer.server.port=8888"