services: traefik: image: traefik:v2.11 container_name: fedeo-traefik restart: unless-stopped command: - --api.insecure=false - --api.dashboard=false - --providers.docker=true - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --certificatesresolvers.letsencrypt.acme.tlschallenge=true - --certificatesresolvers.letsencrypt.acme.email=${CONTACT_EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json - --accesslog=true - --accesslog.filepath=/logs/access.log ports: - "80:80" - "443:443" volumes: - ./traefik/letsencrypt:/letsencrypt - ./traefik/logs:/logs - /var/run/docker.sock:/var/run/docker.sock:ro networks: - web db: image: postgres:16 container_name: fedeo-db restart: unless-stopped environment: POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - ./postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"] interval: 10s timeout: 5s retries: 10 networks: - internal minio: image: minio/minio:latest container_name: fedeo-minio restart: unless-stopped command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} volumes: - ./minio:/data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 10s timeout: 5s retries: 10 networks: - internal createbuckets: image: minio/mc:latest container_name: fedeo-minio-init depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " mc alias set local http://minio:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD}; mc mb --ignore-existing local/${MINIO_BUCKET}; mc anonymous set private local/${MINIO_BUCKET}; exit 0; " restart: "no" networks: - internal seafile-db: image: ${SEAFILE_DB_IMAGE:-mariadb:10.11} container_name: fedeo-seafile-db restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${INIT_SEAFILE_MYSQL_ROOT_PASSWORD} MYSQL_LOG_CONSOLE: "true" MARIADB_AUTO_UPGRADE: "1" volumes: - ./seafile/mysql:/var/lib/mysql healthcheck: test: [ "CMD", "/usr/local/bin/healthcheck.sh", "--connect", "--mariadbupgrade", "--innodb_initialized", ] interval: 20s start_period: 30s timeout: 5s retries: 10 networks: - internal seafile-redis: image: ${SEAFILE_REDIS_IMAGE:-redis:7-alpine} container_name: fedeo-seafile-redis restart: unless-stopped command: - /bin/sh - -c - redis-server --requirepass "$$REDIS_PASSWORD" environment: REDIS_PASSWORD: ${SEAFILE_REDIS_PASSWORD} networks: - internal seafile: image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:13.0-latest} container_name: fedeo-seafile restart: unless-stopped depends_on: seafile-db: condition: service_healthy seafile-redis: condition: service_started volumes: - ./seafile/data:/shared environment: SEAFILE_MYSQL_DB_HOST: seafile-db SEAFILE_MYSQL_DB_PORT: 3306 SEAFILE_MYSQL_DB_USER: ${SEAFILE_MYSQL_DB_USER:-seafile} SEAFILE_MYSQL_DB_PASSWORD: ${SEAFILE_MYSQL_DB_PASSWORD} INIT_SEAFILE_MYSQL_ROOT_PASSWORD: ${INIT_SEAFILE_MYSQL_ROOT_PASSWORD} SEAFILE_MYSQL_DB_CCNET_DB_NAME: ${SEAFILE_MYSQL_DB_CCNET_DB_NAME:-ccnet_db} SEAFILE_MYSQL_DB_SEAFILE_DB_NAME: ${SEAFILE_MYSQL_DB_SEAFILE_DB_NAME:-seafile_db} SEAFILE_MYSQL_DB_SEAHUB_DB_NAME: ${SEAFILE_MYSQL_DB_SEAHUB_DB_NAME:-seahub_db} TIME_ZONE: ${TIME_ZONE:-Europe/Berlin} INIT_SEAFILE_ADMIN_EMAIL: ${INIT_SEAFILE_ADMIN_EMAIL} INIT_SEAFILE_ADMIN_PASSWORD: ${INIT_SEAFILE_ADMIN_PASSWORD} SEAFILE_SERVER_HOSTNAME: ${SEAFILE_SERVER_HOSTNAME:-${DOMAIN}} SEAFILE_SERVER_PROTOCOL: ${SEAFILE_SERVER_PROTOCOL:-https} SITE_ROOT: ${SEAFILE_SITE_ROOT:-/files/} NON_ROOT: ${SEAFILE_NON_ROOT:-false} JWT_PRIVATE_KEY: ${SEAFILE_JWT_PRIVATE_KEY} SEAFILE_LOG_TO_STDOUT: ${SEAFILE_LOG_TO_STDOUT:-true} ENABLE_GO_FILESERVER: ${SEAFILE_ENABLE_GO_FILESERVER:-true} ENABLE_SEADOC: ${SEAFILE_ENABLE_SEADOC:-false} CACHE_PROVIDER: redis REDIS_HOST: seafile-redis REDIS_PORT: 6379 REDIS_PASSWORD: ${SEAFILE_REDIS_PASSWORD} ENABLE_NOTIFICATION_SERVER: ${SEAFILE_ENABLE_NOTIFICATION_SERVER:-false} ENABLE_SEAFILE_AI: ${SEAFILE_ENABLE_AI:-false} ENABLE_FACE_RECOGNITION: ${SEAFILE_ENABLE_FACE_RECOGNITION:-false} MD_FILE_COUNT_LIMIT: ${SEAFILE_MD_FILE_COUNT_LIMIT:-100000} healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 30s labels: - traefik.enable=true - traefik.http.middlewares.fedeo-seafile-strip.stripprefix.prefixes=/files - traefik.http.routers.fedeo-seafile.rule=Host(`${DOMAIN}`) && PathPrefix(`/files`) - traefik.http.routers.fedeo-seafile.entrypoints=websecure - traefik.http.routers.fedeo-seafile.tls.certresolver=letsencrypt - traefik.http.routers.fedeo-seafile.middlewares=fedeo-seafile-strip - traefik.http.services.fedeo-seafile.loadbalancer.server.port=80 - traefik.docker.network=fedeo_web networks: - web - internal backend: image: git.federspiel.tech/flfeders/fedeo/backend:dev container_name: fedeo-backend restart: unless-stopped depends_on: db: condition: service_healthy minio: condition: service_healthy createbuckets: condition: service_completed_successfully environment: NODE_ENV: production FEDEO_RUN_MIGRATIONS: ${FEDEO_RUN_MIGRATIONS:-true} HOST: ${HOST:-0.0.0.0} PORT: ${PORT:-3100} COOKIE_SECRET: ${COOKIE_SECRET} JWT_SECRET: ${JWT_SECRET} ENCRYPTION_KEY: ${ENCRYPTION_KEY} DATABASE_URL: ${DATABASE_URL} MAILER_SMTP_HOST: ${MAILER_SMTP_HOST} MAILER_SMTP_PORT: ${MAILER_SMTP_PORT} MAILER_SMTP_SSL: ${MAILER_SMTP_SSL} MAILER_SMTP_USER: ${MAILER_SMTP_USER} MAILER_SMTP_PASS: ${MAILER_SMTP_PASS} MAILER_FROM: ${MAILER_FROM} S3_ENDPOINT: ${S3_ENDPOINT} S3_REGION: ${S3_REGION} S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} S3_BUCKET: ${S3_BUCKET} FEDEO_FILE_BACKEND: ${FEDEO_FILE_BACKEND:-s3} SEAFILE_BASE_URL: ${SEAFILE_BASE_URL} SEAFILE_INTERNAL_URL: ${SEAFILE_INTERNAL_URL} SEAFILE_ADMIN_EMAIL: ${INIT_SEAFILE_ADMIN_EMAIL} SEAFILE_ADMIN_PASSWORD: ${INIT_SEAFILE_ADMIN_PASSWORD} M2M_API_KEY: ${M2M_API_KEY} API_BASE_URL: ${API_BASE_URL} GOCARDLESS_BASE_URL: ${GOCARDLESS_BASE_URL} GOCARDLESS_SECRET_ID: ${GOCARDLESS_SECRET_ID} GOCARDLESS_SECRET_KEY: ${GOCARDLESS_SECRET_KEY} DOKUBOX_IMAP_HOST: ${DOKUBOX_IMAP_HOST} DOKUBOX_IMAP_PORT: ${DOKUBOX_IMAP_PORT} DOKUBOX_IMAP_SECURE: ${DOKUBOX_IMAP_SECURE} DOKUBOX_IMAP_USER: ${DOKUBOX_IMAP_USER} DOKUBOX_IMAP_PASSWORD: ${DOKUBOX_IMAP_PASSWORD} OPENAI_API_KEY: ${OPENAI_API_KEY} STIRLING_API_KEY: ${STIRLING_API_KEY} FEDEO_BOOTSTRAP_ADMIN_EMAIL: ${FEDEO_BOOTSTRAP_ADMIN_EMAIL:-} FEDEO_BOOTSTRAP_ADMIN_PASSWORD: ${FEDEO_BOOTSTRAP_ADMIN_PASSWORD:-} FEDEO_BOOTSTRAP_ADMIN_FIRST_NAME: ${FEDEO_BOOTSTRAP_ADMIN_FIRST_NAME:-Admin} FEDEO_BOOTSTRAP_ADMIN_LAST_NAME: ${FEDEO_BOOTSTRAP_ADMIN_LAST_NAME:-Benutzer} FEDEO_BOOTSTRAP_TENANT_NAME: ${FEDEO_BOOTSTRAP_TENANT_NAME:-FEDEO} FEDEO_BOOTSTRAP_TENANT_SHORT: ${FEDEO_BOOTSTRAP_TENANT_SHORT:-FEDEO} MATRIX_HOMESERVER_URL: ${MATRIX_HOMESERVER_URL:-http://matrix-synapse:8008} MATRIX_SERVER_NAME: ${MATRIX_SERVER_NAME:-${DOMAIN}} MATRIX_RTC_HOST: ${MATRIX_RTC_HOST:-${DOMAIN}} MATRIX_RTC_JWT_URL: ${MATRIX_RTC_JWT_URL:-} MATRIX_LIVEKIT_URL: ${MATRIX_LIVEKIT_URL:-} MATRIX_REGISTRATION_SHARED_SECRET: ${MATRIX_REGISTRATION_SHARED_SECRET:-change-this-matrix-registration-secret} MATRIX_SERVICE_USER_LOCALPART: ${MATRIX_SERVICE_USER_LOCALPART:-fedeo_service} LIVEKIT_KEY: ${LIVEKIT_KEY:-fedeo-livekit} LIVEKIT_SECRET: ${LIVEKIT_SECRET:-change-this-livekit-secret-please-replace} NODE_EXPORTER_URL: ${NODE_EXPORTER_URL:-http://node-exporter:9100} labels: - traefik.enable=true - traefik.http.routers.fedeo-backend.rule=Host(`${DOMAIN}`) && PathPrefix(`/backend`) - traefik.http.routers.fedeo-backend.entrypoints=websecure - traefik.http.routers.fedeo-backend.tls.certresolver=letsencrypt - traefik.http.middlewares.fedeo-backend-strip.stripprefix.prefixes=/backend - traefik.http.routers.fedeo-backend.middlewares=fedeo-backend-strip - traefik.http.services.fedeo-backend.loadbalancer.server.port=3100 - traefik.docker.network=fedeo_web networks: - web - internal node-exporter: image: prom/node-exporter:v1.8.2 container_name: fedeo-node-exporter restart: unless-stopped command: - --path.procfs=/host/proc - --path.sysfs=/host/sys - --path.rootfs=/rootfs - --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/) pid: host volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro,rslave networks: - internal frontend: image: git.federspiel.tech/flfeders/fedeo/frontend:dev container_name: fedeo-frontend restart: unless-stopped depends_on: - backend environment: NODE_ENV: production NUXT_PUBLIC_API_BASE: https://${DOMAIN}/backend NUXT_PUBLIC_PDF_LICENSE: ${NUXT_PUBLIC_PDF_LICENSE} NUXT_PUBLIC_MATRIX_ELEMENT_URL: ${NUXT_PUBLIC_MATRIX_ELEMENT_URL:-} labels: - traefik.enable=true - traefik.http.routers.fedeo-frontend.rule=Host(`${DOMAIN}`) - traefik.http.routers.fedeo-frontend.entrypoints=websecure - traefik.http.routers.fedeo-frontend.tls.certresolver=letsencrypt - traefik.http.services.fedeo-frontend.loadbalancer.server.port=3000 - traefik.docker.network=fedeo_web networks: - web matrix-db: image: postgres:16-alpine container_name: fedeo-matrix-db restart: unless-stopped environment: POSTGRES_DB: ${MATRIX_POSTGRES_DB:-synapse} POSTGRES_USER: ${MATRIX_POSTGRES_USER:-synapse} POSTGRES_PASSWORD: ${MATRIX_POSTGRES_PASSWORD:-change-this-matrix-db-password} POSTGRES_INITDB_ARGS: --encoding=UTF8 --lc-collate=C --lc-ctype=C volumes: - ./matrix/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${MATRIX_POSTGRES_USER:-synapse} -d ${MATRIX_POSTGRES_DB:-synapse}"] interval: 10s timeout: 5s retries: 10 networks: - internal matrix-redis: image: redis:7-alpine container_name: fedeo-matrix-redis restart: unless-stopped networks: - internal matrix-synapse: image: ghcr.io/element-hq/synapse:latest container_name: fedeo-matrix-synapse restart: unless-stopped depends_on: matrix-db: condition: service_healthy matrix-redis: condition: service_started environment: DOMAIN: ${DOMAIN} MATRIX_POSTGRES_DB: ${MATRIX_POSTGRES_DB:-synapse} MATRIX_POSTGRES_USER: ${MATRIX_POSTGRES_USER:-synapse} MATRIX_POSTGRES_PASSWORD: ${MATRIX_POSTGRES_PASSWORD:-change-this-matrix-db-password} MATRIX_REGISTRATION_SHARED_SECRET: ${MATRIX_REGISTRATION_SHARED_SECRET:-change-this-matrix-registration-secret} MATRIX_SERVER_NAME: ${MATRIX_SERVER_NAME:-${DOMAIN}} MATRIX_TURN_SHARED_SECRET: ${MATRIX_TURN_SHARED_SECRET:-change-this-turn-secret} SYNAPSE_CONFIG_PATH: /data/homeserver.yaml SYNAPSE_REPORT_STATS: "no" SYNAPSE_SERVER_NAME: ${MATRIX_SERVER_NAME:-${DOMAIN}} entrypoint: /bin/sh command: - -ec - | if [ ! -f /data/homeserver.yaml ]; then /start.py generate fi python - <<'PY' import os import yaml path = "/data/homeserver.yaml" with open(path, "r", encoding="utf-8") as handle: config = yaml.safe_load(handle) or {} domain = os.environ["DOMAIN"] server_name = os.environ.get("MATRIX_SERVER_NAME") or domain config["server_name"] = server_name config["public_baseurl"] = f"https://{domain}/" config["database"] = { "name": "psycopg2", "args": { "user": os.environ.get("MATRIX_POSTGRES_USER", "synapse"), "password": os.environ["MATRIX_POSTGRES_PASSWORD"], "database": os.environ.get("MATRIX_POSTGRES_DB", "synapse"), "host": "matrix-db", "cp_min": 5, "cp_max": 10, }, } config["redis"] = {"enabled": True, "host": "matrix-redis"} config["registration_shared_secret"] = os.environ["MATRIX_REGISTRATION_SHARED_SECRET"] config["turn_uris"] = [ f"turn:{domain}:3478?transport=udp", f"turn:{domain}:3478?transport=tcp", ] config["turn_shared_secret"] = os.environ["MATRIX_TURN_SHARED_SECRET"] config["turn_user_lifetime"] = "1h" config["enable_registration"] = False config["experimental_features"] = { **(config.get("experimental_features") or {}), "msc3266_enabled": True, "msc4222_enabled": True, } config["login_via_existing_session"] = { "enabled": True, "require_ui_auth": False, "token_timeout": "5m", } config["max_event_delay_duration"] = "24h" config["rc_message"] = {"per_second": 0.5, "burst_count": 30} config["rc_delayed_event_mgmt"] = {"per_second": 1, "burst_count": 20} with open(path, "w", encoding="utf-8") as handle: yaml.safe_dump(config, handle, sort_keys=False) PY exec /start.py volumes: - ./matrix/synapse:/data labels: - traefik.enable=true - traefik.http.routers.fedeo-matrix.rule=Host(`${DOMAIN}`) && PathPrefix(`/_matrix`) - traefik.http.routers.fedeo-matrix.entrypoints=websecure - traefik.http.routers.fedeo-matrix.tls.certresolver=letsencrypt - traefik.http.services.fedeo-matrix.loadbalancer.server.port=8008 - traefik.docker.network=fedeo_web networks: - web - internal matrix-well-known: image: nginx:1.27-alpine container_name: fedeo-matrix-well-known restart: unless-stopped command: - /bin/sh - -ec - | mkdir -p /usr/share/nginx/html/.well-known/matrix cat >/usr/share/nginx/html/.well-known/matrix/client </usr/share/nginx/html/.well-known/matrix/server </tmp/livekit.yaml </app/config.json <