From 850c486a6eff1e58b01bde1bb3cac3bbf42c8fd7 Mon Sep 17 00:00:00 2001 From: David Londono Date: Thu, 28 Aug 2025 16:10:33 -0500 Subject: [PATCH 1/3] add appflowy --- public/svgs/appflowy.svg | 12 ++ templates/compose/appflowy.yaml | 217 ++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 public/svgs/appflowy.svg create mode 100644 templates/compose/appflowy.yaml diff --git a/public/svgs/appflowy.svg b/public/svgs/appflowy.svg new file mode 100644 index 000000000..7853ed36e --- /dev/null +++ b/public/svgs/appflowy.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/templates/compose/appflowy.yaml b/templates/compose/appflowy.yaml new file mode 100644 index 000000000..805134b71 --- /dev/null +++ b/templates/compose/appflowy.yaml @@ -0,0 +1,217 @@ +# documentation: https://docs.appflowy.io/docs/documentation/appflowy-cloud +# slogan: AppFlowy is the AI collaborative workspace where you achieve more without losing control of your data. +# tags: appflowy,notion,open-source,productivity,notes,ai,self-hosted +# logo: svgs/appflowy.svg +# category: productivity +# port: 80 + +services: + appflowy_web: + environment: + - SERVICE_FQDN_APPFLOWYWEB_80 + - APPFLOWY_BASE_URL=${SERVICE_FQDN_APPFLOWYCLOUD_8000} + - APPFLOWY_GOTRUE_BASE_URL=${SERVICE_FQDN_GOTRUE_9999} + - APPFLOWY_WS_BASE_URL=${SERVICE_FQDN_APPFLOWYCLOUD_8000}/ws/v2 + image: appflowyinc/appflowy_web:latest + depends_on: + - appflowy_cloud + + appflowy_cloud: + image: appflowyinc/appflowy_cloud:latest + labels: + - "traefik.http.middlewares.appflowy-cors.headers.customRequestHeaders.X-Request-Id={{.RequestID}}" + - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowMethods=GET,POST,PUT,DELETE,PATCH,OPTIONS" + - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowHeaders=Content-Type,Authorization,Accept,Client-Version,Device-Id" + - "traefik.http.middlewares.appflowy-cors.headers.accessControlMaxAge=3600" + - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowOriginList=*" + - "traefik.http.middlewares.appflowy-cors.headers.addvaryheader=true" + environment: + - SERVICE_FQDN_APPFLOWYCLOUD_8000 + - RUST_LOG=${RUST_LOG:-info} + - APPFLOWY_ENVIRONMENT=production + - APPFLOWY_DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy} + - APPFLOWY_REDIS_URI=redis://redis:6379 + - APPFLOWY_GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} + - APPFLOWY_GOTRUE_JWT_EXP=${GOTRUE_JWT_EXP:-7200} + - APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999 + - APPFLOWY_S3_CREATE_BUCKET=${APPFLOWY_S3_CREATE_BUCKET:-true} + - APPFLOWY_S3_USE_MINIO=true + - APPFLOWY_S3_MINIO_URL=http://minio:9000 + - APPFLOWY_S3_ACCESS_KEY=${SERVICE_USER_MINIO} + - APPFLOWY_S3_SECRET_KEY=${SERVICE_PASSWORD_MINIO} + - APPFLOWY_S3_BUCKET=${APPFLOWY_S3_BUCKET:-appflowy} + - APPFLOWY_S3_REGION=${APPFLOWY_S3_REGION:-us-east-1} + - APPFLOWY_MAILER_SMTP_HOST=${APPFLOWY_MAILER_SMTP_HOST:-smtp.gmail.com} + - APPFLOWY_MAILER_SMTP_PORT=${APPFLOWY_MAILER_SMTP_PORT:-587} + - APPFLOWY_MAILER_SMTP_USERNAME=${APPFLOWY_MAILER_SMTP_USERNAME:-notify@appflowy.io} + - APPFLOWY_MAILER_SMTP_EMAIL=${APPFLOWY_MAILER_SMTP_EMAIL:-notify@appflowy.io} + - APPFLOWY_MAILER_SMTP_PASSWORD=${APPFLOWY_MAILER_SMTP_PASSWORD:-email_sender_password} + - APPFLOWY_MAILER_SMTP_TLS_KIND=${APPFLOWY_MAILER_SMTP_TLS_KIND:-none} + - APPFLOWY_ACCESS_CONTROL=true + - APPFLOWY_DATABASE_MAX_CONNECTIONS=40 + - AI_SERVER_HOST=ai + - AI_SERVER_PORT=5001 + - AI_OPENAI_API_KEY=${AI_OPENAI_API_KEY:-} + - APPFLOWY_WEB_URL=${SERVICE_FQDN_APPFLOWYWEB_80} + depends_on: + gotrue: + condition: service_healthy + postgres: + condition: service_healthy + redis: + condition: service_started + + gotrue: + image: appflowyinc/gotrue:latest + environment: + - SERVICE_FQDN_GOTRUE_9999 + - GOTRUE_API_HOST=0.0.0.0 + - GOTRUE_API_PORT=9999 + - PORT=9999 + - GOTRUE_ADMIN_EMAIL=${GOTRUE_ADMIN_EMAIL:-admin@example.com} + - GOTRUE_ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN} + - GOTRUE_DISABLE_SIGNUP=false + - GOTRUE_SITE_URL=appflowy-flutter:// + - GOTRUE_URI_ALLOW_LIST=** + - GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} + - GOTRUE_JWT_EXP=${GOTRUE_JWT_EXP:-7200} + - GOTRUE_JWT_ADMIN_GROUP_NAME=supabase_admin + - GOTRUE_DB_DRIVER=postgres + - API_EXTERNAL_URL=${SERVICE_FQDN_GOTRUE_9999} + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy}?search_path=auth + - GOTRUE_SMTP_HOST=${GOTRUE_SMTP_HOST} + - GOTRUE_SMTP_PORT=${GOTRUE_SMTP_PORT:-587} + - GOTRUE_SMTP_USER=${GOTRUE_SMTP_USER} + - GOTRUE_SMTP_PASS=${GOTRUE_SMTP_PASS} + - GOTRUE_MAILER_URLPATHS_CONFIRMATION=/verify + - GOTRUE_MAILER_URLPATHS_INVITE=/verify + - GOTRUE_MAILER_URLPATHS_RECOVERY=/verify + - GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE=/verify + - GOTRUE_SMTP_ADMIN_EMAIL=${GOTRUE_SMTP_ADMIN_EMAIL} + - GOTRUE_SMTP_MAX_FREQUENCY=1ns + - GOTRUE_RATE_LIMIT_EMAIL_SENT=100 + - GOTRUE_MAILER_AUTOCONFIRM=true + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: "curl --fail http://127.0.0.1:9999/health || exit 1" + interval: 5s + timeout: 5s + retries: 12 + + admin_frontend: + image: appflowyinc/admin_frontend:latest + environment: + - SERVICE_FQDN_ADMINFRONTEND_3000 + - RUST_LOG=info + - ADMIN_FRONTEND_REDIS_URL=redis://redis:6379 + - ADMIN_FRONTEND_GOTRUE_URL=http://gotrue:9999 + - ADMIN_FRONTEND_APPFLOWY_CLOUD_URL=http://appflowy_cloud:8000 + - ADMIN_FRONTEND_PATH_PREFIX=/console + - ADMIN_FRONTEND_HOST=0.0.0.0 + - ADMIN_FRONTEND_PORT=3000 + - ADMIN_FRONTEND_OAUTH_CLIENT_ID=appflowy_cloud + - ADMIN_FRONTEND_OAUTH_CLIENT_SECRET=${SERVICE_PASSWORD_ADMINOAUTH} + - ADMIN_FRONTEND_OAUTH_ALLOWABLE_REDIRECT_URIS=${SERVICE_FQDN_ADMINFRONTEND_3000} + depends_on: + gotrue: + condition: service_healthy + appflowy_cloud: + condition: service_started + + ai: + image: appflowyinc/appflowy_ai:latest + environment: + - OPENAI_API_KEY=${AI_OPENAI_API_KEY:-} + - AI_SERVER_PORT=5001 + - DEFAULT_AI_MODEL=gpt-4.1-mini # Make sure the model is available in your OpenAI account + - DEFAULT_AI_COMPLETION_MODEL=gpt-4.1-mini # Make sure the model is available in your OpenAI account + - AI_APPFLOWY_HOST=${SERVICE_FQDN_APPFLOWYWEB_80} + - APPFLOWY_GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} + + - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY} + - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT} + - AZURE_OPENAI_API_VERSION=${AZURE_OPENAI_API_VERSION} + - APPFLOWY_S3_ACCESS_KEY=${SERVICE_USER_MINIO} + - APPFLOWY_S3_SECRET_KEY=${SERVICE_PASSWORD_MINIO} + - APPFLOWY_S3_BUCKET=${APPFLOWY_S3_BUCKET:-appflowy} + - APPFLOWY_S3_REGION=${APPFLOWY_S3_REGION:-us-east-1} + - AI_DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy} + - AI_REDIS_URL=redis://redis:6379 + - AI_USE_MINIO=true + - AI_MINIO_URL=http://minio:9000 + depends_on: + postgres: + condition: service_healthy + + appflowy_worker: + image: appflowyinc/appflowy_worker:latest + environment: + - RUST_LOG=info + - APPFLOWY_ENVIRONMENT=production + - APPFLOWY_WORKER_ENVIRONMENT=production + - APPFLOWY_WORKER_REDIS_URL=redis://redis:6379 + - APPFLOWY_WORKER_DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy} + - APPFLOWY_WORKER_DATABASE_NAME=${POSTGRES_DB:-appflowy} + - APPFLOWY_WORKER_IMPORT_TICK_INTERVAL=30 + - APPFLOWY_S3_USE_MINIO=true + - APPFLOWY_S3_MINIO_URL=http://minio:9000 + - APPFLOWY_S3_ACCESS_KEY=${SERVICE_USER_MINIO} + - APPFLOWY_S3_SECRET_KEY=${SERVICE_PASSWORD_MINIO} + - APPFLOWY_S3_BUCKET=${APPFLOWY_S3_BUCKET:-appflowy} + - APPFLOWY_S3_REGION=${APPFLOWY_S3_REGION:-us-east-1} + - APPFLOWY_MAILER_SMTP_HOST=${APPFLOWY_MAILER_SMTP_HOST:-smtp.gmail.com} + - APPFLOWY_MAILER_SMTP_PORT=${APPFLOWY_MAILER_SMTP_PORT:-587} + - APPFLOWY_MAILER_SMTP_USERNAME=${APPFLOWY_MAILER_SMTP_USERNAME:-notify@appflowy.io} + - APPFLOWY_MAILER_SMTP_EMAIL=${APPFLOWY_MAILER_SMTP_EMAIL:-notify@appflowy.io} + - APPFLOWY_MAILER_SMTP_PASSWORD=${APPFLOWY_MAILER_SMTP_PASSWORD:-email_sender_password} + - APPFLOWY_MAILER_SMTP_TLS_KIND=${APPFLOWY_MAILER_SMTP_TLS_KIND:-none} + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + + minio: + image: minio/minio + environment: + - MINIO_ROOT_USER=${SERVICE_USER_MINIO} + - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} + command: server /data --console-address ":9001" + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 5s + timeout: 20s + retries: 10 + volumes: + # Coolify will manage this named volume for persistent object storage. + - minio_data:/data + + postgres: + image: pgvector/pgvector:pg16 + environment: + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB:-appflowy} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_HOST=postgres + volumes: + # Coolify will manage this named volume for persistent database storage. + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: [ "CMD", "pg_isready", "-U", "${SERVICE_USER_POSTGRES}", "-d", "${POSTGRES_DB:-appflowy}" ] + interval: 5s + timeout: 5s + retries: 12 + + redis: + image: redis + volumes: + - "redis_data:/data" + healthcheck: + test: + - CMD-SHELL + - "redis-cli -h localhost -p 6379 ping" + interval: 5s + timeout: 5s + retries: 3 From f7a311149ccf1f02c3b888386c9a3ab225317e6f Mon Sep 17 00:00:00 2001 From: David Londono Date: Wed, 3 Sep 2025 09:08:10 -0500 Subject: [PATCH 2/3] reverse proxy for mobile --- templates/compose/appflowy.yaml | 153 ++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 17 deletions(-) diff --git a/templates/compose/appflowy.yaml b/templates/compose/appflowy.yaml index 805134b71..6f9dfc579 100644 --- a/templates/compose/appflowy.yaml +++ b/templates/compose/appflowy.yaml @@ -6,12 +6,137 @@ # port: 80 services: + nginx: + image: nginx:latest + environment: + - SERVICE_URL_BACKEND + volumes: + - type: bind + source: ./nginx/nginx.conf + target: /etc/nginx/nginx.conf + read_only: true + content: | + # Please do not directly edit this file. + + error_log /var/log/nginx/error.log notice; + pid /var/run/nginx.pid; + + + events { + worker_connections 1024; + } + + + http { + resolver 127.0.0.11 valid=10s; + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + server { + listen 80; + client_max_body_size 10M; + underscores_in_headers on; + + # Backend services + set $appflowy_cloud_backend "http://appflowy_cloud:8000"; + set $gotrue_backend "http://gotrue:9999"; + # GoTrue Authentication Service + location /gotrue/ { + proxy_pass $gotrue_backend; + rewrite ^/gotrue(/.*)$ $1 break; + # Allow headers like redirect_to to be handed over to the gotrue + # for correct redirecting + proxy_set_header Host $http_host; + proxy_pass_request_headers on; + } + + # WebSocket endpoint - handle both /ws and /ws/v2 + location ~ ^/ws(/.*)?$ { + proxy_pass $appflowy_cloud_backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 86400s; + } + + # API endpoints + location /api { + proxy_pass $appflowy_cloud_backend; + + # Headers + proxy_set_header X-Request-Id $request_id; + proxy_set_header Host $http_host; + + # Special handling for publish endpoint + location ~* ^/api/workspace/([a-zA-Z0-9_-]+)/publish$ { + proxy_pass $appflowy_cloud_backend; + proxy_request_buffering off; + client_max_body_size 256M; + } + + # Chat endpoint (streaming) + location /api/chat { + proxy_pass $appflowy_cloud_backend; + + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding on; + proxy_buffering off; + proxy_cache off; + + proxy_read_timeout 600s; + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + } + + # Import endpoint + location /api/import { + proxy_pass $appflowy_cloud_backend; + + proxy_set_header X-Request-Id $request_id; + proxy_set_header Host $http_host; + + proxy_read_timeout 600s; + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + + proxy_request_buffering off; + proxy_buffering off; + proxy_cache off; + client_max_body_size 2G; + } + } + + # Health check endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + } + } + depends_on: + - appflowy_cloud + - gotrue + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + appflowy_web: environment: - - SERVICE_FQDN_APPFLOWYWEB_80 - - APPFLOWY_BASE_URL=${SERVICE_FQDN_APPFLOWYCLOUD_8000} - - APPFLOWY_GOTRUE_BASE_URL=${SERVICE_FQDN_GOTRUE_9999} - - APPFLOWY_WS_BASE_URL=${SERVICE_FQDN_APPFLOWYCLOUD_8000}/ws/v2 + - SERVICE_URL_APPFLOWYWEB + - APPFLOWY_BASE_URL=${SERVICE_URL_CLOUD} + - APPFLOWY_GOTRUE_BASE_URL=${SERVICE_URL_GOTRUE} + - APPFLOWY_WS_BASE_URL=${SERVICE_URL_CLOUD}/ws/v2 image: appflowyinc/appflowy_web:latest depends_on: - appflowy_cloud @@ -26,8 +151,9 @@ services: - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowOriginList=*" - "traefik.http.middlewares.appflowy-cors.headers.addvaryheader=true" environment: - - SERVICE_FQDN_APPFLOWYCLOUD_8000 + - SERVICE_URL_CLOUD_8000 - RUST_LOG=${RUST_LOG:-info} + - APPFLOWY_BASE_URL=${SERVICE_URL_CLOUD} - APPFLOWY_ENVIRONMENT=production - APPFLOWY_DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy} - APPFLOWY_REDIS_URI=redis://redis:6379 @@ -52,7 +178,7 @@ services: - AI_SERVER_HOST=ai - AI_SERVER_PORT=5001 - AI_OPENAI_API_KEY=${AI_OPENAI_API_KEY:-} - - APPFLOWY_WEB_URL=${SERVICE_FQDN_APPFLOWYWEB_80} + - APPFLOWY_WEB_URL=${SERVICE_URL_APPFLOWYWEB} depends_on: gotrue: condition: service_healthy @@ -64,7 +190,7 @@ services: gotrue: image: appflowyinc/gotrue:latest environment: - - SERVICE_FQDN_GOTRUE_9999 + - SERVICE_URL_GOTRUE_9999 - GOTRUE_API_HOST=0.0.0.0 - GOTRUE_API_PORT=9999 - PORT=9999 @@ -75,9 +201,8 @@ services: - GOTRUE_URI_ALLOW_LIST=** - GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} - GOTRUE_JWT_EXP=${GOTRUE_JWT_EXP:-7200} - - GOTRUE_JWT_ADMIN_GROUP_NAME=supabase_admin - GOTRUE_DB_DRIVER=postgres - - API_EXTERNAL_URL=${SERVICE_FQDN_GOTRUE_9999} + - API_EXTERNAL_URL=${SERVICE_URL_GOTRUE} - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy}?search_path=auth - GOTRUE_SMTP_HOST=${GOTRUE_SMTP_HOST} - GOTRUE_SMTP_PORT=${GOTRUE_SMTP_PORT:-587} @@ -103,17 +228,11 @@ services: admin_frontend: image: appflowyinc/admin_frontend:latest environment: - - SERVICE_FQDN_ADMINFRONTEND_3000 + - SERVICE_URL_ADMINFRONTEND_3000 - RUST_LOG=info - ADMIN_FRONTEND_REDIS_URL=redis://redis:6379 - ADMIN_FRONTEND_GOTRUE_URL=http://gotrue:9999 - ADMIN_FRONTEND_APPFLOWY_CLOUD_URL=http://appflowy_cloud:8000 - - ADMIN_FRONTEND_PATH_PREFIX=/console - - ADMIN_FRONTEND_HOST=0.0.0.0 - - ADMIN_FRONTEND_PORT=3000 - - ADMIN_FRONTEND_OAUTH_CLIENT_ID=appflowy_cloud - - ADMIN_FRONTEND_OAUTH_CLIENT_SECRET=${SERVICE_PASSWORD_ADMINOAUTH} - - ADMIN_FRONTEND_OAUTH_ALLOWABLE_REDIRECT_URIS=${SERVICE_FQDN_ADMINFRONTEND_3000} depends_on: gotrue: condition: service_healthy @@ -127,7 +246,7 @@ services: - AI_SERVER_PORT=5001 - DEFAULT_AI_MODEL=gpt-4.1-mini # Make sure the model is available in your OpenAI account - DEFAULT_AI_COMPLETION_MODEL=gpt-4.1-mini # Make sure the model is available in your OpenAI account - - AI_APPFLOWY_HOST=${SERVICE_FQDN_APPFLOWYWEB_80} + - AI_APPFLOWY_HOST=${SERVICE_URL_APPFLOWYWEB} - APPFLOWY_GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY} From cf4270140cfe859c406479302c453a9afe02a4a2 Mon Sep 17 00:00:00 2001 From: David Londono Date: Thu, 16 Oct 2025 11:26:29 -0500 Subject: [PATCH 3/3] fix: update cors and versions --- templates/compose/appflowy.yaml | 95 ++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/templates/compose/appflowy.yaml b/templates/compose/appflowy.yaml index 6f9dfc579..93ac8fe09 100644 --- a/templates/compose/appflowy.yaml +++ b/templates/compose/appflowy.yaml @@ -7,9 +7,9 @@ services: nginx: - image: nginx:latest + image: nginx:1.29.2 environment: - - SERVICE_URL_BACKEND + - SERVICE_URL_ADMIN volumes: - type: bind source: ./nginx/nginx.conf @@ -42,10 +42,13 @@ services: # Backend services set $appflowy_cloud_backend "http://appflowy_cloud:8000"; set $gotrue_backend "http://gotrue:9999"; + set $admin_frontend_backend "http://admin_frontend:3000"; # GoTrue Authentication Service location /gotrue/ { proxy_pass $gotrue_backend; + rewrite ^/gotrue(/.*)$ $1 break; + # Allow headers like redirect_to to be handed over to the gotrue # for correct redirecting proxy_set_header Host $http_host; @@ -53,8 +56,9 @@ services: } # WebSocket endpoint - handle both /ws and /ws/v2 - location ~ ^/ws(/.*)?$ { + location /ws { proxy_pass $appflowy_cloud_backend; + proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; @@ -68,8 +72,6 @@ services: # API endpoints location /api { proxy_pass $appflowy_cloud_backend; - - # Headers proxy_set_header X-Request-Id $request_id; proxy_set_header Host $http_host; @@ -113,6 +115,33 @@ services: } } + # Admin Frontend + # Optional Module, comment this section if you did not deploy admin_frontend in docker-compose.yml + location /console { + proxy_pass $admin_frontend_backend; + + proxy_set_header X-Scheme $scheme; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Connection ""; + + proxy_buffering off; + proxy_cache off; + + proxy_read_timeout 60s; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + } + + # Redirect root path to /console + location = / { + return 301 /console; + } + # Health check endpoint location /health { access_log off; @@ -124,6 +153,7 @@ services: depends_on: - appflowy_cloud - gotrue + - admin_frontend healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] interval: 30s @@ -134,31 +164,22 @@ services: appflowy_web: environment: - SERVICE_URL_APPFLOWYWEB - - APPFLOWY_BASE_URL=${SERVICE_URL_CLOUD} - - APPFLOWY_GOTRUE_BASE_URL=${SERVICE_URL_GOTRUE} - - APPFLOWY_WS_BASE_URL=${SERVICE_URL_CLOUD}/ws/v2 - image: appflowyinc/appflowy_web:latest + - APPFLOWY_BASE_URL=${SERVICE_URL_ADMIN} + - APPFLOWY_GOTRUE_BASE_URL=${SERVICE_URL_ADMIN}/gotrue + - APPFLOWY_WS_BASE_URL=${SERVICE_URL_ADMIN}/ws/v2 + image: appflowyinc/appflowy_web:0.9.132 depends_on: - appflowy_cloud appflowy_cloud: - image: appflowyinc/appflowy_cloud:latest - labels: - - "traefik.http.middlewares.appflowy-cors.headers.customRequestHeaders.X-Request-Id={{.RequestID}}" - - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowMethods=GET,POST,PUT,DELETE,PATCH,OPTIONS" - - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowHeaders=Content-Type,Authorization,Accept,Client-Version,Device-Id" - - "traefik.http.middlewares.appflowy-cors.headers.accessControlMaxAge=3600" - - "traefik.http.middlewares.appflowy-cors.headers.accessControlAllowOriginList=*" - - "traefik.http.middlewares.appflowy-cors.headers.addvaryheader=true" + image: appflowyinc/appflowy_cloud:0.9.149 environment: - - SERVICE_URL_CLOUD_8000 - RUST_LOG=${RUST_LOG:-info} - - APPFLOWY_BASE_URL=${SERVICE_URL_CLOUD} + - APPFLOWY_BASE_URL=${SERVICE_URL_ADMIN} - APPFLOWY_ENVIRONMENT=production - APPFLOWY_DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy} - APPFLOWY_REDIS_URI=redis://redis:6379 - APPFLOWY_GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} - - APPFLOWY_GOTRUE_JWT_EXP=${GOTRUE_JWT_EXP:-7200} - APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999 - APPFLOWY_S3_CREATE_BUCKET=${APPFLOWY_S3_CREATE_BUCKET:-true} - APPFLOWY_S3_USE_MINIO=true @@ -179,6 +200,12 @@ services: - AI_SERVER_PORT=5001 - AI_OPENAI_API_KEY=${AI_OPENAI_API_KEY:-} - APPFLOWY_WEB_URL=${SERVICE_URL_APPFLOWYWEB} + healthcheck: + test: "curl --fail http://127.0.0.1:8000/api/health || exit 1" + interval: 5s + timeout: 5s + retries: 12 + depends_on: gotrue: condition: service_healthy @@ -188,9 +215,8 @@ services: condition: service_started gotrue: - image: appflowyinc/gotrue:latest + image: appflowyinc/gotrue:0.9.149 environment: - - SERVICE_URL_GOTRUE_9999 - GOTRUE_API_HOST=0.0.0.0 - GOTRUE_API_PORT=9999 - PORT=9999 @@ -202,7 +228,7 @@ services: - GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT} - GOTRUE_JWT_EXP=${GOTRUE_JWT_EXP:-7200} - GOTRUE_DB_DRIVER=postgres - - API_EXTERNAL_URL=${SERVICE_URL_GOTRUE} + - API_EXTERNAL_URL=${SERVICE_URL_ADMIN}/gotrue - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-appflowy}?search_path=auth - GOTRUE_SMTP_HOST=${GOTRUE_SMTP_HOST} - GOTRUE_SMTP_PORT=${GOTRUE_SMTP_PORT:-587} @@ -226,13 +252,10 @@ services: retries: 12 admin_frontend: - image: appflowyinc/admin_frontend:latest + image: appflowyinc/admin_frontend:0.9.149 environment: - - SERVICE_URL_ADMINFRONTEND_3000 - - RUST_LOG=info - - ADMIN_FRONTEND_REDIS_URL=redis://redis:6379 - - ADMIN_FRONTEND_GOTRUE_URL=http://gotrue:9999 - - ADMIN_FRONTEND_APPFLOWY_CLOUD_URL=http://appflowy_cloud:8000 + - APPFLOWY_GOTRUE_BASE_URL=${SERVICE_URL_ADMIN}/gotrue + - APPFLOWY_BASE_URL=${SERVICE_URL_ADMIN} depends_on: gotrue: condition: service_healthy @@ -240,7 +263,7 @@ services: condition: service_started ai: - image: appflowyinc/appflowy_ai:latest + image: appflowyinc/appflowy_ai:0.9.149 environment: - OPENAI_API_KEY=${AI_OPENAI_API_KEY:-} - AI_SERVER_PORT=5001 @@ -265,7 +288,7 @@ services: condition: service_healthy appflowy_worker: - image: appflowyinc/appflowy_worker:latest + image: appflowyinc/appflowy_worker:0.9.149 environment: - RUST_LOG=info - APPFLOWY_ENVIRONMENT=production @@ -293,16 +316,16 @@ services: condition: service_started minio: - image: minio/minio + image: minio/minio:RELEASE.2025-09-07T16-13-09Z environment: - MINIO_ROOT_USER=${SERVICE_USER_MINIO} - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} command: server /data --console-address ":9001" healthcheck: - test: ["CMD", "mc", "ready", "local"] - interval: 5s + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s timeout: 20s - retries: 10 + retries: 3 volumes: # Coolify will manage this named volume for persistent object storage. - minio_data:/data @@ -324,7 +347,7 @@ services: retries: 12 redis: - image: redis + image: redis:8.2.2-alpine3.22 volumes: - "redis_data:/data" healthcheck: