services: # Traefik - Reverse proxy and load balancer traefik: image: ${NET_PROXY_DOCKER_IMAGE} container_name: ${NET_COMPOSE_PROJECT_NAME}_traefik restart: unless-stopped command: # API & Dashboard - "--api.dashboard=true" - "--api.insecure=false" # Ping endpoint for healthcheck - "--ping=true" # Experimental plugins - "--experimental.plugins.sablier.modulename=github.com/acouvreur/sablier" - "--experimental.plugins.sablier.version=v1.8.0" # Logging - "--log.level=${NET_PROXY_LOG_LEVEL:-INFO}" - "--accesslog=true" # Global - "--global.sendAnonymousUsage=false" - "--global.checkNewVersion=true" # Docker Provider - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=${NETWORK_NAME}" # File Provider for dynamic configuration - "--providers.file.directory=/etc/traefik/dynamic" - "--providers.file.watch=true" # Entrypoints - "--entrypoints.web.address=:${NET_PROXY_PORT_HTTP:-80}" - "--entrypoints.web-secure.address=:${NET_PROXY_PORT_HTTPS:-443}" # Global HTTP to HTTPS redirect - "--entrypoints.web.http.redirections.entryPoint.to=web-secure" - "--entrypoints.web.http.redirections.entryPoint.scheme=https" - "--entrypoints.web.http.redirections.entryPoint.permanent=true" # Security Headers (applied globally) - "--entrypoints.web-secure.http.middlewares=security-headers@file" # Let's Encrypt - "--certificatesresolvers.resolver.acme.tlschallenge=true" - "--certificatesresolvers.resolver.acme.email=${ADMIN_EMAIL}" - "--certificatesresolvers.resolver.acme.storage=/letsencrypt/acme.json" healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 30s timeout: 5s retries: 3 start_period: 10s environment: AUTH_USERS: ${AUTH_USERS} networks: - compose_network - coolify ports: - "${NET_PROXY_PORT_HTTP:-80}:80" - "${NET_PROXY_PORT_HTTPS:-443}:443" volumes: - letsencrypt_data:/letsencrypt - /var/run/docker.sock:/var/run/docker.sock:ro - ./dynamic:/etc/traefik/dynamic:ro labels: - "traefik.enable=true" # HTTP to HTTPS redirect - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-traefik-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-traefik-redirect-web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.rule=Host(`${NET_PROXY_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.entrypoints=web" # HTTPS router with auth - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.rule=Host(`${NET_PROXY_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.entrypoints=web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.service=api@internal" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file" - "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.loadbalancer.server.port=8080" - "traefik.docker.network=${NETWORK_NAME}" # Netdata - Real-time monitoring netdata: build: context: . dockerfile: Dockerfile image: ${NET_NETDATA_IMAGE:-netdata/netdata:latest} container_name: ${NET_COMPOSE_PROJECT_NAME}_netdata restart: unless-stopped hostname: ${NET_NETDATA_HOSTNAME:-netdata.pivoine.art} cap_add: - SYS_PTRACE - SYS_ADMIN security_opt: - apparmor:unconfined volumes: - netdata_config:/etc/netdata - netdata_lib:/var/lib/netdata - netdata_cache:/var/cache/netdata - ./go.d/postgres.conf:/etc/netdata/go.d/postgres.conf:ro - ./go.d/filecheck.conf:/etc/netdata/go.d/filecheck.conf:ro - ./health_alarm_notify.conf:/etc/netdata/health_alarm_notify.conf:ro - ./msmtprc:/etc/netdata/msmtprc:ro - /mnt/hidrive/users/valknar/Backup:/mnt/hidrive/users/valknar/Backup:ro - /etc/passwd:/host/etc/passwd:ro - /etc/group:/host/etc/group:ro - /etc/localtime:/etc/localtime:ro - /proc:/host/proc:ro - /sys:/host/sys:ro - /etc/os-release:/host/etc/os-release:ro - /var/log:/host/var/log:ro - /var/run/docker.sock:/var/run/docker.sock:ro environment: - NETDATA_CLAIM_TOKEN=${NETDATA_CLAIM_TOKEN:-} - NETDATA_CLAIM_URL=${NETDATA_CLAIM_URL:-} - NETDATA_CLAIM_ROOMS=${NETDATA_CLAIM_ROOMS:-} - MATTERMOST_WEBHOOK_URL=${MATTERMOST_WEBHOOK_URL:-} networks: - compose_network labels: - "traefik.enable=${NET_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-netdata-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-netdata-redirect-web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.rule=Host(`${NET_NETDATA_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.rule=Host(`${NET_NETDATA_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-netdata-compress.compress=true" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-netdata-compress,${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file" # Service - "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-netdata.loadbalancer.server.port=19999" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Watchtower - Automatic container updates watchtower: image: containrrr/watchtower:latest container_name: ${NET_COMPOSE_PROJECT_NAME}_watchtower restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock environment: # Docker API version negotiation DOCKER_API_VERSION: "1.44" # Check for updates every 5 minutes (300 seconds) WATCHTOWER_POLL_INTERVAL: ${WATCHTOWER_POLL_INTERVAL:-300} # Only update containers with the watchtower label WATCHTOWER_LABEL_ENABLE: ${WATCHTOWER_LABEL_ENABLE:-true} # Clean up old images after update WATCHTOWER_CLEANUP: ${WATCHTOWER_CLEANUP:-true} # Include stopped containers WATCHTOWER_INCLUDE_STOPPED: ${WATCHTOWER_INCLUDE_STOPPED:-false} # Include restarting containers WATCHTOWER_INCLUDE_RESTARTING: ${WATCHTOWER_INCLUDE_RESTARTING:-true} # Run once and exit (set to false for continuous monitoring) WATCHTOWER_RUN_ONCE: ${WATCHTOWER_RUN_ONCE:-false} # Notifications via Shoutrrr WATCHTOWER_NOTIFICATIONS: ${WATCHTOWER_NOTIFICATIONS:-} WATCHTOWER_NOTIFICATION_URL: ${WATCHTOWER_NOTIFICATION_URL:-} # Log level (trace, debug, info, warn, error, fatal, panic) WATCHTOWER_LOG_LEVEL: ${WATCHTOWER_LOG_LEVEL:-info} # Rolling restart (update one container at a time) WATCHTOWER_ROLLING_RESTART: ${WATCHTOWER_ROLLING_RESTART:-false} labels: # Allow watchtower to update itself - com.centurylinklabs.watchtower.enable=true # Umami - Web analytics umami: image: ${NET_TRACK_DOCKER_IMAGE} container_name: ${NET_COMPOSE_PROJECT_NAME}_umami restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Amsterdam} # Database Configuration DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${CORE_DB_HOST}:${CORE_DB_PORT}/${NET_TRACK_DB_NAME} DATABASE_TYPE: postgresql # Application Secret APP_SECRET: ${TRACK_APP_SECRET} # Redis Cache Integration REDIS_URL: redis://${CORE_REDIS_HOST}:${CORE_REDIS_PORT} CACHE_ENABLED: true networks: - compose_network healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"] interval: 30s timeout: 10s retries: 5 start_period: 40s labels: # Traefik Configuration - "traefik.enable=${NET_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-umami-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-umami-redirect-web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.rule=Host(`${NET_TRACK_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.entrypoints=web" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.rule=Host(`${NET_TRACK_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.entrypoints=web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.middlewares=security-headers@file" - "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.loadbalancer.server.port=3000" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Mailpit - SMTP server with web UI mailpit: image: ${NET_MAILPIT_IMAGE:-axllent/mailpit:latest} container_name: ${NET_COMPOSE_PROJECT_NAME}_mailpit restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} # SMTP relay configuration for IONOS MP_SMTP_AUTH_ACCEPT_ANY: 1 MP_SMTP_AUTH_ALLOW_INSECURE: 1 MP_MAX_MESSAGES: 5000 # SMTP relay to IONOS - relay all emails preserving recipients MP_SMTP_RELAY_ALL: "true" MP_SMTP_RELAY_HOST: ${EMAIL_SMTP_HOST} MP_SMTP_RELAY_PORT: ${EMAIL_SMTP_PORT} MP_SMTP_RELAY_USERNAME: ${EMAIL_SMTP_USER} MP_SMTP_RELAY_PASSWORD: ${EMAIL_SMTP_PASSWORD} MP_SMTP_RELAY_AUTH: plain MP_SMTP_RELAY_TLS: "true" volumes: - mailpit_data:/data networks: - compose_network labels: - "traefik.enable=${NET_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.entrypoints=web" # HTTPS router with auth - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.entrypoints=web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file" # Service - "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.loadbalancer.server.port=8025" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Authelia - SSO and authentication portal authelia: image: ${NET_AUTHELIA_IMAGE:-authelia/authelia:latest} container_name: ${NET_COMPOSE_PROJECT_NAME}_authelia restart: unless-stopped command: --config /etc/authelia/configuration.yml environment: TZ: ${TIMEZONE:-Europe/Berlin} AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET: ${AUTHELIA_JWT_SECRET} AUTHELIA_SESSION_SECRET: ${AUTHELIA_SESSION_SECRET} AUTHELIA_STORAGE_ENCRYPTION_KEY: ${AUTHELIA_STORAGE_ENCRYPTION_KEY} AUTHELIA_STORAGE_POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - authelia_config:/config - ./authelia:/etc/authelia:ro networks: - compose_network labels: - "traefik.enable=${NET_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.entrypoints=web-secure" - "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.middlewares=security-headers@file" # Service - "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.loadbalancer.server.port=9091" - "traefik.docker.network=${NETWORK_NAME}" # ForwardAuth middleware for other services - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.address=http://net_authelia:9091/api/authz/forward-auth" - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.trustForwardHeader=true" - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email" - "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeadersRegex=^Remote-" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" tailscale: image: tailscale/tailscale:latest hostname: vps cap_add: - NET_ADMIN - SYS_MODULE volumes: - tailscale-state:/var/lib/tailscale - /dev/net/tun:/dev/net/tun environment: - TS_AUTHKEY=${TAILSCALE_AUTHKEY} - TS_STATE_DIR=/var/lib/tailscale restart: unless-stopped volumes: letsencrypt_data: name: ${NET_COMPOSE_PROJECT_NAME}_letsencrypt_data netdata_config: name: ${NET_COMPOSE_PROJECT_NAME}_netdata_config netdata_lib: name: ${NET_COMPOSE_PROJECT_NAME}_netdata_lib netdata_cache: name: ${NET_COMPOSE_PROJECT_NAME}_netdata_cache mailpit_data: name: ${NET_COMPOSE_PROJECT_NAME}_mailpit_data authelia_config: name: ${NET_COMPOSE_PROJECT_NAME}_authelia_config tailscale-state: name: ${NET_COMPOSE_PROJECT_NAME}_tailscale_state networks: compose_network: name: ${NETWORK_NAME} external: true coolify: name: coolify external: true