services: # PairDrop - P2P file sharing pairdrop: image: lscr.io/linuxserver/pairdrop:latest container_name: ${UTIL_COMPOSE_PROJECT_NAME}_pairdrop restart: unless-stopped volumes: - ./rtc_config.json:/rtc_config.json:ro environment: PUID: 1000 PGID: 1000 TZ: ${TIMEZONE:-Europe/Berlin} RATE_LIMIT: true WS_FALLBACK: true WS_SERVER: true RTC_CONFIG: /rtc_config.json DEBUG_MODE: true networks: - compose_network labels: - 'traefik.enable=${UTIL_TRAEFIK_ENABLED}' # HTTP to HTTPS redirect - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-redirect-web-secure.redirectscheme.scheme=https' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-redirect-web-secure' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web.rule=Host(`${UTIL_DROP_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web.entrypoints=web' # HTTPS router - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure.rule=Host(`${UTIL_DROP_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure.entrypoints=web-secure' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure-compress.compress=true' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure-compress,security-headers@file' # Service - 'traefik.http.services.${UTIL_COMPOSE_PROJECT_NAME}-pairdrop-web-secure.loadbalancer.server.port=3000' - 'traefik.docker.network=${NETWORK_NAME}' # Watchtower - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' # Joplin Server - Note-taking and sync joplin: image: ${UTIL_JOPLIN_IMAGE:-joplin/server:latest} container_name: ${UTIL_COMPOSE_PROJECT_NAME}_joplin restart: unless-stopped volumes: - joplin_data:/data environment: TZ: ${TIMEZONE:-Europe/Berlin} APP_PORT: ${UTIL_JOPLIN_APP_PORT:-22300} APP_BASE_URL: https://${UTIL_JOPLIN_TRAEFIK_HOST} DB_CLIENT: pg POSTGRES_HOST: ${CORE_DB_HOST} POSTGRES_PORT: ${CORE_DB_PORT} POSTGRES_DATABASE: ${UTIL_JOPLIN_DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} MAILER_ENABLED: 1 MAILER_HOST: net_mailpit MAILER_PORT: 1025 MAILER_SECURE: 0 MAILER_NOREPLY_NAME: Joplin Server MAILER_NOREPLY_EMAIL: ${EMAIL_FROM} networks: - compose_network depends_on: - postgres labels: - 'traefik.enable=${UTIL_TRAEFIK_ENABLED}' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-joplin-redirect-web-secure.redirectscheme.scheme=https' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-joplin-redirect-web-secure' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web.rule=Host(`${UTIL_JOPLIN_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web.entrypoints=web' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure.rule=Host(`${UTIL_JOPLIN_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure.entrypoints=web-secure' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure-compress.compress=true' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure-compress' - 'traefik.http.services.${UTIL_COMPOSE_PROJECT_NAME}-joplin-web-secure.loadbalancer.server.port=22300' - 'traefik.docker.network=${NETWORK_NAME}' - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' # Linkwarden - Bookmark manager linkwarden: image: ${UTIL_LINKS_DOCKER_IMAGE} container_name: ${UTIL_COMPOSE_PROJECT_NAME}_linkwarden restart: unless-stopped networks: - compose_network environment: TZ: ${TIMEZONE:-Europe/Amsterdam} DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${CORE_DB_HOST}:${CORE_DB_PORT}/${UTIL_LINKS_DB_NAME} NEXTAUTH_SECRET: ${LINKS_NEXTAUTH_SECRET} NEXTAUTH_URL: https://${UTIL_LINKS_TRAEFIK_HOST} MEILI_ADDR: http://linkwarden_meilisearch:7700 MEILI_MASTER_KEY: ${LINKS_MEILI_MASTER_KEY} BASE_URL: https://${UTIL_LINKS_TRAEFIK_HOST} NEXT_PUBLIC_EMAIL_PROVIDER: true EMAIL_FROM: ${EMAIL_FROM} EMAIL_SERVER: smtp://net_mailpit:1025 volumes: - linkwarden_data:/data/data depends_on: - linkwarden_meilisearch labels: - 'traefik.enable=${UTIL_TRAEFIK_ENABLED}' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-redirect-web-secure.redirectscheme.scheme=https' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-redirect-web-secure' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web.rule=Host(`${UTIL_LINKS_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web.entrypoints=web' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure.rule=Host(`${UTIL_LINKS_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure.entrypoints=web-secure' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure-compress.compress=true' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure-compress' - 'traefik.http.services.${UTIL_COMPOSE_PROJECT_NAME}-linkwarden-web-secure.loadbalancer.server.port=3000' - 'traefik.docker.network=${NETWORK_NAME}' - 'com.centurylinklabs.watchtower.enable=true' # Linkwarden Meilisearch linkwarden_meilisearch: image: ${UTIL_LINKS_MEILI_IMAGE} container_name: ${UTIL_COMPOSE_PROJECT_NAME}_linkwarden_meilisearch restart: unless-stopped networks: - compose_network environment: MEILI_MASTER_KEY: ${LINKS_MEILI_MASTER_KEY} MEILI_NO_ANALYTICS: ${UTIL_LINKS_MEILI_NO_ANALYTICS:-true} volumes: - linkwarden_meili_data:/meili_data # Mattermost - Team collaboration mattermost: image: ${UTIL_MATTERMOST_IMAGE:-mattermost/mattermost-team-edition:latest} container_name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost restart: unless-stopped security_opt: - no-new-privileges:true pids_limit: 200 read_only: false tmpfs: - /tmp volumes: - mattermost_config:/mattermost/config:rw - mattermost_data:/mattermost/data:rw - mattermost_logs:/mattermost/logs:rw - mattermost_plugins:/mattermost/plugins:rw - mattermost_client_plugins:/mattermost/client/plugins:rw - mattermost_bleve:/mattermost/bleve-indexes:rw environment: TZ: ${TIMEZONE:-Europe/Berlin} MM_SQLSETTINGS_DRIVERNAME: postgres MM_SQLSETTINGS_DATASOURCE: postgres://${DB_USER}:${DB_PASSWORD}@${CORE_DB_HOST}:${CORE_DB_PORT}/${UTIL_MATTERMOST_DB_NAME}?sslmode=disable&connect_timeout=10 MM_BLEVESETTINGS_INDEXDIR: /mattermost/bleve-indexes MM_SERVICESETTINGS_SITEURL: https://${UTIL_MATTERMOST_TRAEFIK_HOST} MM_SERVICESETTINGS_ENABLELOCALMODE: "true" # Email settings MM_EMAILSETTINGS_ENABLESMTPAUTH: "false" MM_EMAILSETTINGS_SMTPSERVER: net_mailpit MM_EMAILSETTINGS_SMTPPORT: 1025 MM_EMAILSETTINGS_CONNECTIONSECURITY: "" MM_EMAILSETTINGS_FEEDBACKNAME: Mattermost MM_EMAILSETTINGS_FEEDBACKEMAIL: ${EMAIL_FROM} MM_EMAILSETTINGS_REPLYTOADDRESS: ${EMAIL_FROM} networks: - compose_network labels: - 'traefik.enable=${UTIL_TRAEFIK_ENABLED}' # HTTP to HTTPS redirect - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-redirect-web-secure.redirectscheme.scheme=https' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-mattermost-redirect-web-secure' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web.rule=Host(`${UTIL_MATTERMOST_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web.entrypoints=web' # HTTPS router - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure.rule=Host(`${UTIL_MATTERMOST_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure.entrypoints=web-secure' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure-compress.compress=true' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure-compress,security-headers@file' # Service - 'traefik.http.services.${UTIL_COMPOSE_PROJECT_NAME}-mattermost-web-secure.loadbalancer.server.port=8065' - 'traefik.docker.network=${NETWORK_NAME}' # Watchtower - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' # Vaultwarden - Password manager vaultwarden: image: ${UTIL_VAULT_IMAGE:-vaultwarden/server:latest} container_name: ${UTIL_COMPOSE_PROJECT_NAME}_vaultwarden restart: unless-stopped volumes: - vaultwarden_data:/data environment: TZ: ${TIMEZONE:-Europe/Berlin} DOMAIN: https://${UTIL_VAULT_TRAEFIK_HOST} WEBSOCKET_ENABLED: ${UTIL_VAULT_WEBSOCKET_ENABLED:-true} SIGNUPS_ALLOWED: ${UTIL_VAULT_SIGNUPS_ALLOWED:-false} INVITATIONS_ALLOWED: ${UTIL_VAULT_INVITATIONS_ALLOWED:-true} SHOW_PASSWORD_HINT: ${UTIL_VAULT_SHOW_PASSWORD_HINT:-false} SMTP_HOST: net_mailpit SMTP_FROM: ${EMAIL_FROM} SMTP_FROM_NAME: Vaultwarden SMTP_SECURITY: off SMTP_PORT: 1025 networks: - compose_network labels: - 'traefik.enable=${UTIL_TRAEFIK_ENABLED}' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-redirect-web-secure.redirectscheme.scheme=https' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-redirect-web-secure' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web.rule=Host(`${UTIL_VAULT_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web.entrypoints=web' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure.rule=Host(`${UTIL_VAULT_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure.entrypoints=web-secure' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure-compress.compress=true' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure-compress' - 'traefik.http.services.${UTIL_COMPOSE_PROJECT_NAME}-vaultwarden-web-secure.loadbalancer.server.port=80' - 'traefik.docker.network=${NETWORK_NAME}' - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' # Tandoor - Recipe manager tandoor: image: ${UTIL_TANDOOR_IMAGE:-vabene1111/recipes:latest} container_name: ${UTIL_COMPOSE_PROJECT_NAME}_tandoor restart: unless-stopped environment: # Django settings SECRET_KEY: ${TANDOOR_SECRET_KEY} ALLOWED_HOSTS: ${UTIL_TANDOOR_TRAEFIK_HOST} TIMEZONE: ${TIMEZONE:-Europe/Berlin} # Database configuration DB_ENGINE: django.db.backends.postgresql POSTGRES_HOST: ${CORE_DB_HOST} POSTGRES_PORT: ${CORE_DB_PORT} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${UTIL_TANDOOR_DB_NAME} # Application settings ENABLE_SIGNUP: ${UTIL_TANDOOR_ENABLE_SIGNUP:-0} REVERSE_PROXY_AUTH: ${UTIL_TANDOOR_REVERSE_PROXY_AUTH:-0} # Email configuration (IONOS SMTP) EMAIL_HOST: net_mailpit EMAIL_PORT: 1025 EMAIL_USE_TLS: 0 EMAIL_USE_SSL: 0 DEFAULT_FROM_EMAIL: ${EMAIL_FROM} # Gunicorn settings GUNICORN_MEDIA: ${UTIL_TANDOOR_GUNICORN_MEDIA:-0} # Optional features COMMENT_PREF_DEFAULT: ${UTIL_TANDOOR_COMMENT_PREF_DEFAULT:-1} SHOPPING_MIN_AUTOSYNC_INTERVAL: ${UTIL_TANDOOR_SHOPPING_MIN_AUTOSYNC_INTERVAL:-5} volumes: - tandoor_staticfiles:/opt/recipes/staticfiles - tandoor_mediafiles:/opt/recipes/mediafiles depends_on: - postgres networks: - compose_network labels: - 'traefik.enable=${UTIL_TRAEFIK_ENABLED}' # HTTP to HTTPS redirect - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-redirect-web-secure.redirectscheme.scheme=https' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-tandoor-redirect-web-secure' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web.rule=Host(`${UTIL_TANDOOR_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web.entrypoints=web' # HTTPS router - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure.rule=Host(`${UTIL_TANDOOR_TRAEFIK_HOST}`)' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure.entrypoints=web-secure' - 'traefik.http.middlewares.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure-compress.compress=true' - 'traefik.http.routers.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure.middlewares=${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure-compress,security-headers@file' # Service - 'traefik.http.services.${UTIL_COMPOSE_PROJECT_NAME}-tandoor-web-secure.loadbalancer.server.port=80' - 'traefik.docker.network=${NETWORK_NAME}' # Watchtower - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' volumes: joplin_data: name: ${UTIL_COMPOSE_PROJECT_NAME}_joplin_data linkwarden_data: name: ${UTIL_COMPOSE_PROJECT_NAME}_linkwarden_data linkwarden_meili_data: name: ${UTIL_COMPOSE_PROJECT_NAME}_linkwarden_meili_data mattermost_config: name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost_config mattermost_data: name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost_data mattermost_logs: name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost_logs mattermost_plugins: name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost_plugins mattermost_client_plugins: name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost_client_plugins mattermost_bleve: name: ${UTIL_COMPOSE_PROJECT_NAME}_mattermost_bleve vaultwarden_data: name: ${UTIL_COMPOSE_PROJECT_NAME}_vaultwarden_data tandoor_staticfiles: name: ${UTIL_COMPOSE_PROJECT_NAME}_tandoor_staticfiles tandoor_mediafiles: name: ${UTIL_COMPOSE_PROJECT_NAME}_tandoor_mediafiles networks: compose_network: name: ${NETWORK_NAME} external: true