# Development overrides for the Appwrite stack. # This file is automatically loaded by `docker compose up` alongside docker-compose.yml. # It adds source-code volume mounts, build configuration, debug ports, and dev tools. services: traefik: ports: - 8080:80 - 9500:8080 appwrite: build: context: . target: development args: DEBUG: false TESTING: true VERSION: dev ports: - 9501:80 dns: - 172.16.238.100 volumes: - /var/run/docker.sock:/var/run/docker.sock # Only needed for tests - ./docker-compose.yml:/usr/src/code/docker-compose.yml # Only needed for tests - ./.env:/usr/src/code/.env # Only needed for tests - ./phpunit.xml:/usr/src/code/phpunit.xml - ./tests:/usr/src/code/tests - ./app:/usr/src/code/app - ./docs:/usr/src/code/docs - ./public:/usr/src/code/public - ./src:/usr/src/code/src - ./dev:/usr/src/code/dev # - ./vendor/utopia-php/framework:/usr/src/code/vendor/utopia-php/framework depends_on: - coredns appwrite-realtime: ports: - 9505:80 volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-audits: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-webhooks: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - request-catcher-sms - request-catcher-webhook appwrite-worker-deletes: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-databases: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-builds: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-screenshots: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-certificates: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-executions: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-functions: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-mails: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - maildev appwrite-worker-messaging: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-migrations: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src - ./tests:/usr/src/code/tests appwrite-task-maintenance: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-task-interval: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-task-stats-resources: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-stats-resources: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-worker-stats-usage: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-task-scheduler-functions: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-task-scheduler-executions: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src appwrite-task-scheduler-messages: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src # Testing infrastructure coredns: # DNS server for testing purposes (Proxy APIs) image: coredns/coredns:1.12.4 container_name: appwrite-coredns restart: unless-stopped logging: driver: "json-file" options: max-file: "5" max-size: "10m" command: ["-conf", "/mnt/resources/Corefile"] networks: appwrite: ipv4_address: 172.16.238.100 volumes: - ./tests/resources/coredns:/mnt/resources:ro # Dev Tools ------------------------------------------------------------------------------------------ # # The Appwrite Team uses the following tools to help debug, monitor and diagnose the Appwrite stack # # Here is a description of the different tools and why are we using them: # # MailCatcher - An SMTP server. Catches all system emails and displays them in a nice UI. # RequestCatcher - An HTTP server. Catches all system https calls and displays them using a simple HTTP API. Used to debug & tests webhooks and HTTP tasks # Redis Insight - A nice UI for exploring Redis data # Adminer - A nice UI for exploring MariaDB data # GraphQl Explorer - A nice UI for exploring GraphQL API maildev: # used mainly for dev tests image: appwrite/mailcatcher:1.1.1 container_name: appwrite-mailcatcher logging: driver: "json-file" options: max-file: "5" max-size: "10m" ports: - "9503:1080" networks: - appwrite - gateway labels: - "traefik.enable=true" - "traefik.constraint-label-stack=appwrite" - "traefik.docker.network=gateway" - "traefik.http.services.appwrite_maildev.loadbalancer.server.port=1080" - "traefik.http.routers.appwrite_maildev_http.entrypoints=appwrite_web" - "traefik.http.routers.appwrite_maildev_http.rule=Host(`mail.localhost`)" - "traefik.http.routers.appwrite_maildev_http.service=appwrite_maildev" - "traefik.http.routers.appwrite_maildev_https.entrypoints=appwrite_websecure" - "traefik.http.routers.appwrite_maildev_https.rule=Host(`mail.localhost`)" - "traefik.http.routers.appwrite_maildev_https.service=appwrite_maildev" - "traefik.http.routers.appwrite_maildev_https.tls=true" environment: - MAILDEV_INCOMING_USER=${_APP_SMTP_USERNAME} - MAILDEV_INCOMING_PASS=${_APP_SMTP_PASSWORD} request-catcher-webhook: # used mainly for dev tests (mock HTTP webhook) image: appwrite/requestcatcher:1.0.0 container_name: appwrite-requestcatcher-webhook logging: driver: "json-file" options: max-file: "5" max-size: "10m" ports: - "9504:5000" networks: - appwrite request-catcher-sms: # used mainly for dev tests (mock SMS auth secret) image: appwrite/requestcatcher:1.0.0 container_name: appwrite-requestcatcher-sms logging: driver: "json-file" options: max-file: "5" max-size: "10m" ports: - "9507:5000" networks: - appwrite adminer: image: adminer container_name: appwrite-adminer logging: driver: "json-file" options: max-file: "5" max-size: "10m" restart: always ports: - 9506:8080 networks: - appwrite - gateway environment: - ADMINER_DESIGN=pepa-linha - ADMINER_DEFAULT_SERVER=mariadb - ADMINER_DEFAULT_USERNAME=root - ADMINER_DEFAULT_PASSWORD=rootsecretpassword - ADMINER_DEFAULT_DB=appwrite configs: - source: adminer-index.php target: /var/www/html/index.php mode: 0755 labels: - "traefik.enable=true" - "traefik.constraint-label-stack=appwrite" - "traefik.docker.network=gateway" - "traefik.http.services.appwrite_adminer.loadbalancer.server.port=8080" - "traefik.http.routers.appwrite_adminer_http.entrypoints=appwrite_web" - "traefik.http.routers.appwrite_adminer_http.rule=Host(`mysql.localhost`)" - "traefik.http.routers.appwrite_adminer_http.service=appwrite_adminer" - "traefik.http.routers.appwrite_adminer_https.entrypoints=appwrite_websecure" - "traefik.http.routers.appwrite_adminer_https.rule=Host(`mysql.localhost`)" - "traefik.http.routers.appwrite_adminer_https.service=appwrite_adminer" - "traefik.http.routers.appwrite_adminer_https.tls=true" redis-insight: image: redis/redisinsight:latest restart: unless-stopped networks: - appwrite - gateway environment: - RI_PRE_SETUP_DATABASES_PATH=/mnt/connections.json configs: - source: redisinsight-connections.json target: /mnt/connections.json mode: 0755 labels: - "traefik.enable=true" - "traefik.constraint-label-stack=appwrite" - "traefik.docker.network=gateway" - "traefik.http.services.appwrite_redisinsight.loadbalancer.server.port=5540" - "traefik.http.routers.appwrite_redisinsight_http.entrypoints=appwrite_web" - "traefik.http.routers.appwrite_redisinsight_http.rule=Host(`redis.localhost`)" - "traefik.http.routers.appwrite_redisinsight_http.service=appwrite_redisinsight" - "traefik.http.routers.appwrite_redisinsight_https.entrypoints=appwrite_websecure" - "traefik.http.routers.appwrite_redisinsight_https.rule=Host(`redis.localhost`)" - "traefik.http.routers.appwrite_redisinsight_https.service=appwrite_redisinsight" - "traefik.http.routers.appwrite_redisinsight_https.tls=true" ports: - "8081:5540" graphql-explorer: container_name: appwrite-graphql-explorer image: appwrite/altair:0.3.0 restart: unless-stopped networks: - appwrite ports: - "9509:3000" environment: - SERVER_URL=http://localhost/v1/graphql mariadb: ports: - "3306:3306" redis: ports: - "6379:6379" # Dev Tools End ------------------------------------------------------------------------------------------ configs: redisinsight-connections.json: content: | [ { "compressor": "NONE", "id": "104dc90a-21ef-4d5e-8912-b30baabb152f", "host": "redis", "port": 6379, "name": "redis:6379", "db": 0, "username": "default", "password": null, "connectionType": "STANDALONE", "nameFromProvider": null, "provider": "REDIS", "lastConnection": "2025-10-16T09:22:02.591Z", "modules": [ { "name": "ReJSON", "version": 20808, "semanticVersion": "2.8.8" }, { "name": "search", "version": 21015, "semanticVersion": "2.10.15" } ], "tls": false, "tlsServername": null, "verifyServerCert": null, "caCert": null, "clientCert": null, "ssh": false, "sshOptions": null, "forceStandalone": false, "tags": [] } ] adminer-index.php: content: | $$_ENV['ADMINER_DEFAULT_SERVER'], 'driver' => 'server', /* seems to autodetect the driver from server settings */ 'username' => $$_ENV['ADMINER_DEFAULT_USERNAME'], 'password' => $$_ENV['ADMINER_DEFAULT_PASSWORD'], 'db' => $$_ENV['ADMINER_DEFAULT_DB'], ]; } include './adminer.php';