name: fluxer x-fluxer-postgres-env: &fluxer-postgres-env FLUXER_DATABASE_BACKEND: postgres FLUXER_POSTGRES_HOST: postgres FLUXER_POSTGRES_PORT: "5432" FLUXER_POSTGRES_DATABASE: fluxer FLUXER_POSTGRES_USERNAME: fluxer FLUXER_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} FLUXER_POSTGRES_SSL: "false" FLUXER_POSTGRES_PREPARED_STATEMENTS: ${FLUXER_POSTGRES_PREPARED_STATEMENTS:-true} x-fluxer-env: &fluxer-env <<: *fluxer-postgres-env FLUXER_ENV: production NODE_ENV: production FLUXER_SELF_HOSTED: "true" FLUXER_BASE_DOMAIN: ${FLUXER_DOMAIN:?set FLUXER_DOMAIN in .env} FLUXER_PUBLIC_SCHEME: ${FLUXER_PUBLIC_SCHEME:-https} FLUXER_PUBLIC_PORT: ${FLUXER_PUBLIC_PORT:-443} FLUXER_TRUST_CLIENT_IP_HEADER: "true" FLUXER_CLIENT_IP_HEADER_NAME: x-forwarded-for FLUXER_API_HEADERS_TIMEOUT_MS: ${FLUXER_API_HEADERS_TIMEOUT_MS:-30000} FLUXER_API_REQUEST_TIMEOUT_MS: ${FLUXER_API_REQUEST_TIMEOUT_MS:-120000} FLUXER_KV_URL: redis://valkey:6379/0 FLUXER_NATS_URL: nats://nats:4222 FLUXER_NATS_JETSTREAM_URL: nats://nats:4222 FLUXER_SVC_NATS_URL: nats://nats:4222 FLUXER_SVC_SHARD_COUNT: "1" FLUXER_SEARCH_ENGINE: meilisearch FLUXER_SEARCH_URL: http://meilisearch:7700 FLUXER_SEARCH_API_KEY: ${MEILI_MASTER_KEY:?set MEILI_MASTER_KEY in .env} FLUXER_S3_ENDPOINT: http://seaweedfs:8333 FLUXER_S3_PUBLIC_ENDPOINT: http://seaweedfs:8333 FLUXER_S3_REGION: us-east-1 FLUXER_S3_ACCESS_KEY_ID: ${FLUXER_S3_ACCESS_KEY:?set FLUXER_S3_ACCESS_KEY in .env} FLUXER_S3_SECRET_ACCESS_KEY: ${FLUXER_S3_SECRET_KEY:?set FLUXER_S3_SECRET_KEY in .env} FLUXER_S3_FORCE_PATH_STYLE: "true" FLUXER_S3_BUCKET_CDN: fluxer FLUXER_S3_BUCKET_UPLOADS: fluxer-uploads FLUXER_S3_BUCKET_DOWNLOADS: fluxer-downloads FLUXER_S3_BUCKET_REPORTS: fluxer-reports FLUXER_S3_BUCKET_HARVESTS: fluxer-harvests AWS_ACCESS_KEY_ID: ${FLUXER_S3_ACCESS_KEY:?} AWS_SECRET_ACCESS_KEY: ${FLUXER_S3_SECRET_KEY:?} AWS_DEFAULT_REGION: us-east-1 AWS_EC2_METADATA_DISABLED: "true" FLUXER_LIVEKIT_ENABLED: "true" FLUXER_LIVEKIT_API_KEY: ${LIVEKIT_API_KEY:?set LIVEKIT_API_KEY in .env} FLUXER_LIVEKIT_API_SECRET: ${LIVEKIT_API_SECRET:?set LIVEKIT_API_SECRET in .env} FLUXER_LIVEKIT_INTERNAL_URL: http://livekit:7880 FLUXER_LIVEKIT_WEBHOOK_URL: http://api:8080/webhooks/livekit FLUXER_LIVEKIT_DEFAULT_REGION: '{"id":"default","name":"Default","emoji":"🌍","latitude":0,"longitude":0}' FLUXER_LIVEKIT_URL: ${FLUXER_LIVEKIT_URL:-${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/livekit} FLUXER_KLIPY_API_KEY: ${FLUXER_KLIPY_API_KEY:-} FLUXER_EMAIL_ENABLED: ${FLUXER_EMAIL_ENABLED:-false} FLUXER_EMAIL_PROVIDER: ${FLUXER_EMAIL_PROVIDER:-none} FLUXER_EMAIL_FROM_EMAIL: ${FLUXER_EMAIL_FROM_EMAIL:-noreply@localhost} FLUXER_EMAIL_FROM_NAME: ${FLUXER_EMAIL_FROM_NAME:-Fluxer} FLUXER_EMAIL_APP_BASE_URL: ${FLUXER_EMAIL_APP_BASE_URL:-} FLUXER_EMAIL_SMTP_HOST: ${FLUXER_EMAIL_SMTP_HOST:-} FLUXER_EMAIL_SMTP_PORT: ${FLUXER_EMAIL_SMTP_PORT:-587} FLUXER_EMAIL_SMTP_USERNAME: ${FLUXER_EMAIL_SMTP_USERNAME:-} FLUXER_EMAIL_SMTP_PASSWORD: ${FLUXER_EMAIL_SMTP_PASSWORD:-} FLUXER_EMAIL_SMTP_SECURE: ${FLUXER_EMAIL_SMTP_SECURE:-true} FLUXER_SMS_ENABLED: "false" FLUXER_CAPTCHA_ENABLED: ${FLUXER_CAPTCHA_ENABLED:-false} FLUXER_CAPTCHA_PROVIDER: ${FLUXER_CAPTCHA_PROVIDER:-none} FLUXER_STRIPE_ENABLED: "false" FLUXER_NCMEC_ENABLED: "false" FLUXER_CLAMAV_ENABLED: "false" FLUXER_DISCOVERY_ENABLED: ${FLUXER_DISCOVERY_ENABLED:-true} FLUXER_SUDO_MODE_SECRET: ${FLUXER_SUDO_MODE_SECRET:?set FLUXER_SUDO_MODE_SECRET in .env} FLUXER_CONNECTION_INITIATION_SECRET: ${FLUXER_CONNECTION_INITIATION_SECRET:?set FLUXER_CONNECTION_INITIATION_SECRET in .env} FLUXER_SSO_ALLOW_PRIVATE_ADDRESSES: ${FLUXER_SSO_ALLOW_PRIVATE_ADDRESSES:-false} FLUXER_VAPID_PUBLIC_KEY: ${FLUXER_VAPID_PUBLIC_KEY:?set FLUXER_VAPID_PUBLIC_KEY in .env} FLUXER_VAPID_PRIVATE_KEY: ${FLUXER_VAPID_PRIVATE_KEY:?set FLUXER_VAPID_PRIVATE_KEY in .env} FLUXER_VAPID_EMAIL: ${FLUXER_VAPID_EMAIL:-admin@${FLUXER_DOMAIN}} FLUXER_PASSKEY_RP_ID: ${FLUXER_PASSKEY_RP_ID:-${FLUXER_DOMAIN}} FLUXER_PASSKEY_RP_NAME: ${FLUXER_PASSKEY_RP_NAME:-Fluxer} FLUXER_PASSKEY_ADDITIONAL_ALLOWED_ORIGINS: ${FLUXER_PASSKEY_ADDITIONAL_ALLOWED_ORIGINS:-${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}} FLUXER_GATEWAY_RPC_AUTH_TOKEN: ${FLUXER_GATEWAY_RPC_AUTH_TOKEN:?set FLUXER_GATEWAY_RPC_AUTH_TOKEN in .env} FLUXER_MEDIA_PROXY_SECRET_KEY: ${FLUXER_MEDIA_PROXY_SECRET_KEY:?set FLUXER_MEDIA_PROXY_SECRET_KEY in .env} FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64: ${FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64:?set FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64 in .env} FLUXER_ADMIN_SECRET_KEY_BASE: ${FLUXER_ADMIN_SECRET_KEY_BASE:?set FLUXER_ADMIN_SECRET_KEY_BASE in .env} FLUXER_ADMIN_OAUTH_CLIENT_SECRET: ${FLUXER_ADMIN_OAUTH_CLIENT_SECRET:?set FLUXER_ADMIN_OAUTH_CLIENT_SECRET in .env} FLUXER_INTERNAL_API_ENDPOINT: http://api:8080 FLUXER_INTERNAL_GATEWAY_ENDPOINT: http://gateway:8080 FLUXER_INTERNAL_MEDIA_PROXY_ENDPOINT: http://media-proxy:8080 FLUXER_MARKETING_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}} FLUXER_MEDIA_PROXY_ENDPOINT: http://media-proxy:8080 FLUXER_MEDIA_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media FLUXER_MEDIA_PROXY_UPLOAD_RELAY_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media x-fluxer-service: &fluxer-service restart: unless-stopped networks: [fluxer] x-fluxer-svc-healthcheck: &fluxer-svc-healthcheck test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/8090 && printf 'GET /_health HTTP/1.0\\r\\n\\r\\n' >&3 && head -n 1 <&3 | grep -q ' 200 '"] interval: 10s timeout: 5s retries: 30 start_period: 60s start_interval: 1s services: caddy: image: caddy:2.10-alpine deploy: resources: limits: memory: ${FLUXER_CADDY_MEMORY_LIMIT:-256mb} restart: unless-stopped networks: [fluxer] ports: - "${FLUXER_HTTP_PORT:-80}:80" - "${FLUXER_HTTPS_PORT:-443}:443" - "${FLUXER_HTTPS_PORT:-443}:443/udp" environment: FLUXER_CADDY_SITE_ADDRESS: ${FLUXER_CADDY_SITE_ADDRESS:?set FLUXER_CADDY_SITE_ADDRESS in .env} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy-data:/data - caddy-config:/config healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"] interval: 10s timeout: 5s retries: 10 depends_on: api: {condition: service_started} gateway: {condition: service_healthy} media-proxy: {condition: service_started} static-proxy: {condition: service_started} admin: {condition: service_started} postgres: image: postgres:16-alpine deploy: resources: limits: memory: ${FLUXER_POSTGRES_MEMORY_LIMIT:-5gb} reservations: memory: ${FLUXER_POSTGRES_MEMORY_RESERVATION:-3gb} restart: unless-stopped networks: [fluxer] command: > postgres -c max_connections=${FLUXER_POSTGRES_SERVER_MAX_CONNECTIONS:-150} -c shared_buffers=${FLUXER_POSTGRES_SHARED_BUFFERS:-512MB} -c effective_cache_size=${FLUXER_POSTGRES_EFFECTIVE_CACHE_SIZE:-2GB} -c work_mem=${FLUXER_POSTGRES_WORK_MEM:-8MB} -c maintenance_work_mem=256MB -c autovacuum_work_mem=128MB -c random_page_cost=1.1 -c effective_io_concurrency=200 -c default_statistics_target=200 -c jit=off -c min_wal_size=512MB -c max_wal_size=2GB -c checkpoint_completion_target=0.9 -c wal_buffers=16MB -c wal_compression=zstd -c bgwriter_delay=50ms -c bgwriter_lru_maxpages=1000 -c autovacuum_vacuum_scale_factor=0.05 -c autovacuum_analyze_scale_factor=0.02 -c autovacuum_vacuum_cost_limit=2000 -c track_io_timing=on -c shared_preload_libraries=pg_stat_statements shm_size: 256mb environment: POSTGRES_DB: fluxer POSTGRES_USER: fluxer POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U fluxer -d fluxer"] interval: 10s timeout: 5s retries: 10 valkey: image: valkey/valkey:8.1-alpine deploy: resources: limits: memory: ${FLUXER_VALKEY_MEMORY_LIMIT:-256mb} restart: unless-stopped networks: [fluxer] command: ["valkey-server", "--appendonly", "yes", "--appendfsync", "everysec", "--dir", "/data", "--maxmemory", "${FLUXER_VALKEY_MAXMEMORY:-192mb}", "--maxmemory-policy", "${FLUXER_VALKEY_MAXMEMORY_POLICY:-noeviction}"] volumes: - valkey-data:/data healthcheck: test: ["CMD", "valkey-cli", "ping"] interval: 10s timeout: 5s retries: 10 nats: image: nats:2.14-alpine deploy: resources: limits: memory: ${FLUXER_NATS_MEMORY_LIMIT:-256mb} restart: unless-stopped networks: [fluxer] command: ["-js", "-sd", "/data", "-m", "8222"] volumes: - nats-data:/data healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8222/healthz"] interval: 10s timeout: 5s retries: 10 meilisearch: image: getmeili/meilisearch:v1.12 deploy: resources: limits: memory: ${FLUXER_MEILISEARCH_MEMORY_LIMIT:-768mb} restart: unless-stopped networks: [fluxer] environment: MEILI_ENV: production MEILI_NO_ANALYTICS: "true" MEILI_MAX_INDEXING_MEMORY: 384mb MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:?set MEILI_MASTER_KEY in .env} volumes: - meilisearch-data:/meili_data healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:7700/health"] interval: 10s timeout: 5s retries: 10 seaweedfs: image: chrislusf/seaweedfs:4.34 deploy: resources: limits: memory: ${FLUXER_SEAWEEDFS_MEMORY_LIMIT:-512mb} restart: unless-stopped networks: [fluxer] command: ["server", "-s3", "-dir=/data"] volumes: - seaweedfs-data:/data healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8333/"] interval: 10s timeout: 5s retries: 20 seaweedfs-init: image: chrislusf/seaweedfs:4.34 deploy: resources: limits: memory: ${FLUXER_SEAWEEDFS_INIT_MEMORY_LIMIT:-128mb} networks: [fluxer] depends_on: seaweedfs: {condition: service_healthy} restart: "no" entrypoint: - /bin/sh - -c - > buckets="fluxer fluxer-uploads fluxer-downloads fluxer-reports fluxer-harvests"; missing="$$buckets"; for attempt in $$(seq 1 60); do if ! nc -z seaweedfs 9333 2>/dev/null; then sleep 2; continue; fi; listed=$$(echo "s3.bucket.list" | timeout 10 weed shell -master=seaweedfs:9333 2>&1); missing=""; for b in $$buckets; do echo "$$listed" | grep -q "^[[:space:]]*$$b[[:space:]]" || missing="$${missing:+$$missing }$$b"; done; if [ -z "$$missing" ]; then echo "buckets ready"; exit 0; fi; for b in $$missing; do echo "s3.bucket.create -name $$b" | timeout 10 weed shell -master=seaweedfs:9333 >/dev/null 2>&1; done; sleep 2; done; echo "seaweedfs-init could not verify buckets: $$missing" >&2; exit 1; livekit: image: livekit/livekit-server:v1.12.0 deploy: resources: limits: memory: ${FLUXER_LIVEKIT_MEMORY_LIMIT:-512mb} restart: unless-stopped networks: [fluxer] command: ["--config", "/etc/livekit.yaml"] environment: LIVEKIT_KEYS: "${LIVEKIT_API_KEY:?set LIVEKIT_API_KEY in .env}: ${LIVEKIT_API_SECRET:?set LIVEKIT_API_SECRET in .env}" volumes: - ./livekit.yaml:/etc/livekit.yaml:ro ports: - "${FLUXER_LIVEKIT_TCP_PORT:-7881}:7881" - "${FLUXER_LIVEKIT_UDP_PORT:-7882}:7882/udp" healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:7880/"] interval: 10s timeout: 5s retries: 10 api: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-api:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_API_MEMORY_LIMIT:-2560mb} reservations: memory: ${FLUXER_API_MEMORY_RESERVATION:-1gb} environment: <<: *fluxer-env FLUXER_API_PORT: "8080" NODE_OPTIONS: --enable-source-maps${FLUXER_API_NODE_HEAP_MB:+ --max-old-space-size=$FLUXER_API_NODE_HEAP_MB} FLUXER_API_PRESIGNED_ATTACHMENT_UPLOADS_ENABLED: "true" FLUXER_POSTGRES_MAX_CONNECTIONS: "25" healthcheck: test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:8080/_health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] interval: 10s timeout: 5s retries: 30 start_period: 90s start_interval: 1s depends_on: postgres: {condition: service_healthy} valkey: {condition: service_healthy} nats: {condition: service_healthy} meilisearch: {condition: service_healthy} seaweedfs-init: {condition: service_completed_successfully} gifs: {condition: service_healthy} gifs-shard: {condition: service_healthy} snowflakes: {condition: service_healthy} snowflakes-shard: {condition: service_healthy} messages: {condition: service_healthy} messages-shard: {condition: service_healthy} users: {condition: service_healthy} users-shard: {condition: service_healthy} worker: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-api:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_WORKER_MEMORY_LIMIT:-2560mb} reservations: memory: ${FLUXER_WORKER_MEMORY_RESERVATION:-1gb} working_dir: /usr/src/app/fluxer_api command: ["node", "dist/WorkerEntrypoint.js"] environment: <<: *fluxer-env NODE_OPTIONS: --enable-source-maps${FLUXER_WORKER_NODE_HEAP_MB:+ --max-old-space-size=$FLUXER_WORKER_NODE_HEAP_MB} FLUXER_API_WORKER_MODE: all_lanes FLUXER_API_WORKER_ENABLE_CRON_SCHEDULER: "true" FLUXER_API_WORKER_ENABLE_VOICE_RECONCILIATION: "true" FLUXER_POSTGRES_MAX_CONNECTIONS: "25" healthcheck: test: ["CMD", "node", "-e", "const age=Date.now()-require('node:fs').statSync('/tmp/fluxer-worker-heartbeat').mtimeMs;if(age>30000){console.error('worker heartbeat is '+Math.round(age)+'ms old');process.exit(1)}"] interval: 10s timeout: 5s retries: 3 start_period: 90s start_interval: 1s depends_on: postgres: {condition: service_healthy} valkey: {condition: service_healthy} nats: {condition: service_healthy} seaweedfs-init: {condition: service_completed_successfully} snowflakes-shard: {condition: service_healthy} messages-shard: {condition: service_healthy} users-shard: {condition: service_healthy} gateway: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-gateway:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_GATEWAY_MEMORY_LIMIT:-1gb} reservations: memory: ${FLUXER_GATEWAY_MEMORY_RESERVATION:-384mb} environment: <<: *fluxer-env FLUXER_GATEWAY_PORT: "8080" FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media FLUXER_GATEWAY_STATIC_CDN_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}} FLUXER_GATEWAY_LOGGER_LEVEL: info healthcheck: test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://127.0.0.1:8080/_health/ready"] interval: 10s timeout: 5s retries: 30 start_period: 90s depends_on: nats: {condition: service_healthy} valkey: {condition: service_healthy} media-proxy: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-media-proxy:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_MEDIA_PROXY_MEMORY_LIMIT:-512mb} environment: <<: *fluxer-env FLUXER_MEDIA_PROXY_HOST: 0.0.0.0 FLUXER_MEDIA_PROXY_PORT: "8080" FLUXER_MEDIA_PROXY_MODE: upload FLUXER_MEDIA_PROXY_STORAGE_BACKEND: s3 depends_on: seaweedfs-init: {condition: service_completed_successfully} nats: {condition: service_healthy} static-proxy: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-static:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_STATIC_PROXY_MEMORY_LIMIT:-256mb} healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/avatars/0.png"] interval: 10s timeout: 5s retries: 10 app-proxy: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-app-proxy-self-hosted:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_APP_PROXY_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-postgres-env FLUXER_APP_PROXY_HOST: 0.0.0.0 FLUXER_APP_PROXY_PORT: "8080" DISCOVERY_UPSTREAM_URL: http://caddy:8088/api/.well-known/fluxer PUBLIC_BOOTSTRAP_API_ENDPOINT: /api PUBLIC_BOOTSTRAP_API_PUBLIC_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/api FLUXER_CSP_EXTRA_DEFAULT_SRC: ${FLUXER_CSP_EXTRA_DEFAULT_SRC:-} FLUXER_CSP_EXTRA_CONNECT_SRC: ${FLUXER_CSP_EXTRA_CONNECT_SRC:-} FLUXER_CSP_EXTRA_IMG_SRC: ${FLUXER_CSP_EXTRA_IMG_SRC:-} FLUXER_CSP_EXTRA_MEDIA_SRC: ${FLUXER_CSP_EXTRA_MEDIA_SRC:-} FLUXER_CSP_EXTRA_FONT_SRC: ${FLUXER_CSP_EXTRA_FONT_SRC:-} FLUXER_CSP_EXTRA_SCRIPT_SRC: ${FLUXER_CSP_EXTRA_SCRIPT_SRC:-} FLUXER_CSP_EXTRA_STYLE_SRC: ${FLUXER_CSP_EXTRA_STYLE_SRC:-} FLUXER_CSP_EXTRA_FRAME_SRC: ${FLUXER_CSP_EXTRA_FRAME_SRC:-} FLUXER_CSP_EXTRA_WORKER_SRC: ${FLUXER_CSP_EXTRA_WORKER_SRC:-} FLUXER_CSP_EXTRA_MANIFEST_SRC: ${FLUXER_CSP_EXTRA_MANIFEST_SRC:-} FLUXER_CSP_REPORT_URI: ${FLUXER_CSP_REPORT_URI:-} FLUXER_POSTGRES_MAX_CONNECTIONS: "5" depends_on: api: {condition: service_healthy} caddy: {condition: service_healthy} postgres: {condition: service_healthy} snowflakes: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-snowflakes:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_SNOWFLAKES_MEMORY_LIMIT:-128mb} environment: <<: *fluxer-env FLUXER_SVC_NAME: snowflakes FLUXER_SVC_MODE: router healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} snowflakes-shard: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-snowflakes:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_SNOWFLAKES_SHARD_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-env FLUXER_SVC_NAME: snowflakes FLUXER_SVC_MODE: shard FLUXER_SVC_SHARD_ID: "0" healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} users: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-users:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_USERS_MEMORY_LIMIT:-128mb} environment: <<: *fluxer-env FLUXER_SVC_MODE: router FLUXER_SVC_MAX_CONCURRENT_REQUESTS: "${FLUXER_SVC_MAX_CONCURRENT_REQUESTS:-20}" healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} users-shard: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-users:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_USERS_SHARD_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-env FLUXER_SVC_MODE: shard FLUXER_SVC_SHARD_ID: "0" FLUXER_POSTGRES_MAX_CONNECTIONS: "20" FLUXER_SVC_MAX_CONCURRENT_REQUESTS: "20" healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} postgres: {condition: service_healthy} gifs: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-gifs:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_GIFS_MEMORY_LIMIT:-128mb} environment: <<: *fluxer-env FLUXER_SVC_NAME: gifs FLUXER_SVC_MODE: router FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} gifs-shard: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-gifs:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_GIFS_SHARD_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-env FLUXER_SVC_NAME: gifs FLUXER_SVC_MODE: shard FLUXER_SVC_SHARD_ID: "0" FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} messages: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-messages:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_MESSAGES_MEMORY_LIMIT:-128mb} environment: <<: *fluxer-env FLUXER_SVC_NAME: messages FLUXER_SVC_MODE: router FLUXER_SVC_MAX_CONCURRENT_REQUESTS: "${FLUXER_SVC_MAX_CONCURRENT_REQUESTS:-20}" healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} messages-shard: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-messages:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_MESSAGES_SHARD_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-env FLUXER_SVC_NAME: messages FLUXER_SVC_MODE: shard FLUXER_SVC_SHARD_ID: "0" FLUXER_POSTGRES_MAX_CONNECTIONS: "20" FLUXER_SVC_MAX_CONCURRENT_REQUESTS: "20" healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} postgres: {condition: service_healthy} unfurl: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-unfurl:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_UNFURL_MEMORY_LIMIT:-128mb} environment: <<: *fluxer-env FLUXER_SVC_MODE: router FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media FLUXER_STATIC_CDN_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}} healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} unfurl-shard: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-unfurl:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_UNFURL_SHARD_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-env FLUXER_SVC_MODE: shard FLUXER_SVC_SHARD_ID: "0" FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media FLUXER_STATIC_CDN_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}} healthcheck: *fluxer-svc-healthcheck depends_on: nats: {condition: service_healthy} admin: <<: *fluxer-service image: ${FLUXER_REGISTRY:-ghcr.io/${FLUXER_REGISTRY_OWNER:-fluxerapp}}/fluxer-admin:${FLUXER_IMAGE_TAG:-v1} deploy: resources: limits: memory: ${FLUXER_ADMIN_MEMORY_LIMIT:-256mb} environment: <<: *fluxer-env FLUXER_ADMIN_HOST: 0.0.0.0 FLUXER_ADMIN_PORT: "8080" FLUXER_ADMIN_BASE_PATH: /admin FLUXER_API_ENDPOINT: http://api:8080 FLUXER_ADMIN_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/admin FLUXER_APP_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}} FLUXER_MEDIA_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/media FLUXER_STATIC_CDN_ENDPOINT: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}} FLUXER_ADMIN_OAUTH_REDIRECT_URI: ${FLUXER_PUBLIC_ORIGIN:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN}}/admin/oauth2_callback healthcheck: test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/8080 && printf 'GET /_health HTTP/1.0\\r\\n\\r\\n' >&3 && head -n 1 <&3 | grep -q ' 200 '"] interval: 10s timeout: 5s retries: 30 start_period: 60s start_interval: 1s depends_on: api: {condition: service_healthy} networks: fluxer: driver: bridge volumes: caddy-data: caddy-config: postgres-data: valkey-data: nats-data: meilisearch-data: seaweedfs-data: