Docs
Skip to content

Self-hosting

Installation_

Step-by-step guide to install Appwrite using Docker. Learn how to set up a self-hosted Appwrite instance with Docker Compose on any operating system.

6 min read

Raw

This guide will walk you through installing Appwrite on your server using Docker. Appwrite is designed to run on any operating system that supports Docker.

System requirements

Before installing Appwrite, ensure your system meets these minimum requirements:

  • 2 CPU cores
  • 4GB of RAM
  • 2GB of swap memory
  • Operating system that supports Docker
  • Docker Compose Version 2

Install with Docker

The easiest way to install Appwrite is using our Docker installer. The installer launches a web-based setup wizard that guides you through the entire process.

Before running the installation command, ensure you have Docker CLI installed on your host machine.

Installation commands

Once the command is running, open your browser and navigate to http://localhost:20080 to access the setup wizard.

Setup wizard

The setup wizard walks you through four steps to configure your Appwrite instance.

Step 1: Setup your app

Configure your Appwrite instance's basic settings.

Setup your app
Setup your app

  • Hostname - The domain or IP address where your Appwrite instance will be accessible.
  • Use HTTPS - Turn this on when your Appwrite domain uses HTTPS, including behind a reverse proxy.
  • Database - Choose PostgreSQL, MariaDB, or MongoDB as your database backend. PostgreSQL is selected by default.
  • Advanced settings - Optionally configure the worker topology under Workers and schedulers, HTTP and HTTPS ports, SSL certificate email, and an OpenAI API key for the Appwrite Assistant.

Step 2: Secure your app

A secret API key is automatically generated for your instance. This key is used to encrypt sensitive data.

Secure your app
Secure your app

You can use the Copy button to copy the key or Regenerate to create a new one.

Step 3: Create your account

Set up the email and password for your Appwrite account. You'll use these credentials to sign in to the Appwrite Console after installation.

Create your account
Create your account

Step 4: Review your setup

Review all your configuration settings. If anything looks wrong, use the Back button to make changes. When you're ready, click Install to begin the installation.

Review your setup
Review your setup

Manual installation

For advanced users who prefer manual setup, you can install Appwrite using Docker Compose directly.

Generate configuration files

Database
Workers and schedulers
Appwrite Assistant
x-logging:
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
services:
traefik:
image: traefik:3.6
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-traefik
command:
- --providers.file.directory=/storage/config
- --providers.file.watch=true
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`)
- --entrypoints.appwrite_web.address=:80
- --entrypoints.appwrite_websecure.address=:443
ports:
- ${_APP_HTTP_PORT:-80}:80
- ${_APP_HTTPS_PORT:-443}:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- appwrite-config:/storage/config:ro
- appwrite-certificates:/storage/certificates:ro
depends_on:
- appwrite
networks:
- gateway
- appwrite
appwrite:
container_name: appwrite
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
image: appwrite/appwrite:1.9.6
healthcheck:
test:
- CMD-SHELL
- 'curl -fsS -o /dev/null -H "Host: $${_APP_DOMAIN:-localhost}" http://localhost/v1/health/version'
interval: 5s
timeout: 5s
retries: 12
start_period: 120s
networks:
- appwrite
labels:
- traefik.enable=true
- traefik.constraint-label-stack=appwrite
- traefik.docker.network=appwrite
- traefik.http.services.appwrite_api.loadbalancer.server.port=80
- traefik.http.routers.appwrite_api_http.entrypoints=appwrite_web
- traefik.http.routers.appwrite_api_http.rule=PathPrefix(`/`)
- traefik.http.routers.appwrite_api_http.service=appwrite_api
- traefik.http.routers.appwrite_api_https.entrypoints=appwrite_websecure
- traefik.http.routers.appwrite_api_https.rule=PathPrefix(`/`)
- traefik.http.routers.appwrite_api_https.service=appwrite_api
- traefik.http.routers.appwrite_api_https.tls=true
volumes:
- appwrite-uploads:/storage/uploads:rw
- appwrite-imports:/storage/imports:rw
- appwrite-cache:/storage/cache:rw
- appwrite-config:/storage/config:rw
- appwrite-certificates:/storage/certificates:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
depends_on:
- redis
- postgresql
- appwrite-embedding
- appwrite-geo
environment:
- _APP_ENV
- _APP_EDITION
- _APP_WORKER_PER_CORE
- _APP_POOL_ADAPTER
- _APP_LOCALE
- _APP_COMPRESSION_ENABLED
- _APP_COMPRESSION_MIN_SIZE_BYTES
- _APP_CONSOLE_WHITELIST_ROOT
- _APP_CONSOLE_WHITELIST_EMAILS
- _APP_CONSOLE_SESSION_ALERTS
- _APP_CONSOLE_WHITELIST_IPS
- _APP_CONSOLE_HOSTNAMES
- _APP_CONSOLE_SCHEMA
- _APP_SYSTEM_EMAIL_NAME
- _APP_SYSTEM_EMAIL_ADDRESS
- _APP_SYSTEM_TEAM_EMAIL
- _APP_EMAIL_SECURITY
- _APP_SYSTEM_RESPONSE_FORMAT
- _APP_OPTIONS_ABUSE
- _APP_OPTIONS_ROUTER_PROTECTION
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_ROUTER_AUTO_CERTIFICATES
- _APP_OPENSSL_KEY_V1
- _APP_NOTIFICATIONS_TRACKING_SECRET
- _APP_DOMAIN
- _APP_CONSOLE_DOMAIN
- _APP_CONSOLE_URL_SCHEME=root
- _APP_CONSOLE_TRUSTED_PROJECTS
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DB_ADAPTER_VECTORSDB
- _APP_DB_HOST_VECTORSDB
- _APP_DB_PORT_VECTORSDB
- _APP_DB_SCHEMA_VECTORSDB
- _APP_DB_USER_VECTORSDB
- _APP_DB_PASS_VECTORSDB
- _APP_SMTP_HOST
- _APP_SMTP_PORT
- _APP_SMTP_SECURE
- _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD
- _APP_STORAGE_LIMIT
- _APP_STORAGE_PREVIEW_LIMIT
- _APP_STORAGE_ANTIVIRUS
- _APP_STORAGE_ANTIVIRUS_HOST
- _APP_STORAGE_ANTIVIRUS_PORT
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
- _APP_STORAGE_DO_SPACES_BUCKET
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- _APP_STORAGE_BACKBLAZE_SECRET
- _APP_STORAGE_BACKBLAZE_REGION
- _APP_STORAGE_BACKBLAZE_BUCKET
- _APP_STORAGE_LINODE_ACCESS_KEY
- _APP_STORAGE_LINODE_SECRET
- _APP_STORAGE_LINODE_REGION
- _APP_STORAGE_LINODE_BUCKET
- _APP_STORAGE_WASABI_ACCESS_KEY
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_COMPUTE_SIZE_LIMIT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
- _APP_FUNCTIONS_RUNTIMES
- _APP_SITES_RUNTIMES
- _APP_DOMAIN_SITES
- _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST
- _APP_BUILDS_VOLUME
- _APP_JOBS_HOST
- _APP_JOBS_SECRET
- _APP_JOBS_ENDPOINT
- _APP_LOGGING_CONFIG
- _APP_LOGGING_FORMAT
- _APP_LOCKING_ENABLED
- _APP_MAINTENANCE_INTERVAL
- _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER
- _APP_SMS_FROM
- _APP_GRAPHQL_INTROSPECTION
- _APP_GRAPHQL_MAX_BATCH_SIZE
- _APP_GRAPHQL_MAX_COMPLEXITY
- _APP_GRAPHQL_MAX_DEPTH
- _APP_VCS_GITHUB_APP_NAME
- _APP_VCS_GITHUB_PRIVATE_KEY
- _APP_VCS_GITHUB_APP_ID
- _APP_VCS_GITHUB_WEBHOOK_SECRET
- _APP_VCS_GITHUB_CLIENT_SECRET
- _APP_VCS_GITHUB_CLIENT_ID
- _APP_VCS_GITEA_ENDPOINT
- _APP_VCS_GITEA_BROWSER_ENDPOINT
- _APP_VCS_GITEA_CLIENT_ID
- _APP_VCS_GITEA_CLIENT_SECRET
- _APP_VCS_GITEA_WEBHOOK_SECRET
- _APP_VCS_GITLAB_CLIENT_ID
- _APP_VCS_GITLAB_CLIENT_SECRET
- _APP_VCS_GITLAB_WEBHOOK_SECRET
- _APP_VCS_BITBUCKET_CLIENT_ID
- _APP_VCS_BITBUCKET_CLIENT_SECRET
- _APP_VCS_BITBUCKET_WEBHOOK_SECRET
- _APP_VCS_ORIGIN_CLIENT_ID
- _APP_VCS_ORIGIN_PRIVATE_KEY
- _APP_VCS_WEBHOOK_URL
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_ASSISTANT_OPENAI_API_KEY
- _APP_CONSOLE_COUNTRIES_DENYLIST
- _APP_EXPERIMENT_LOGGING_PROVIDER
- _APP_EXPERIMENT_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
- _APP_DATABASE_SHARED_NAMESPACE
- _APP_FUNCTIONS_CREATION_ABUSE_LIMIT
- _APP_CUSTOM_DOMAIN_DENY_LIST
- _APP_TRUSTED_HEADERS
- _APP_MIGRATION_HOST
- _APP_GEO_SECRET
- _APP_GEO_ENDPOINT
appwrite-console:
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-console
image: appwrite/new:0.5.5
restart: unless-stopped
networks:
- appwrite
environment:
- VITE_CONSOLE_PROFILE=self-hosted
- APPWRITE_ENDPOINT_SAME_ORIGIN=true
- VITE_GROWTH_ENDPOINT=https://growth.appwrite.io/v1
labels:
- traefik.enable=true
- traefik.constraint-label-stack=appwrite
- traefik.docker.network=appwrite
- traefik.http.services.appwrite_console.loadbalancer.server.port=3000
- traefik.http.routers.appwrite_console_http.entrypoints=appwrite_web
- traefik.http.routers.appwrite_console_http.rule=(Host(`${_APP_DOMAIN:-localhost}`) || Host(`${_APP_CONSOLE_DOMAIN:-localhost}`)) && !PathPrefix(`/v1`) && !PathPrefix(`/.well-known`) && !HeaderRegexp(`x-appwrite-hostname`, `.+`)
- traefik.http.routers.appwrite_console_http.service=appwrite_console
- traefik.http.routers.appwrite_console_https.entrypoints=appwrite_websecure
- traefik.http.routers.appwrite_console_https.rule=(Host(`${_APP_DOMAIN:-localhost}`) || Host(`${_APP_CONSOLE_DOMAIN:-localhost}`)) && !PathPrefix(`/v1`) && !PathPrefix(`/.well-known`) && !HeaderRegexp(`x-appwrite-hostname`, `.+`)
- traefik.http.routers.appwrite_console_https.service=appwrite_console
- traefik.http.routers.appwrite_console_https.tls=true
appwrite-realtime:
entrypoint: realtime
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-realtime
image: appwrite/appwrite:1.9.6
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.constraint-label-stack=appwrite
- traefik.docker.network=appwrite
- traefik.http.services.appwrite_realtime.loadbalancer.server.port=80
- traefik.http.routers.appwrite_realtime_ws.entrypoints=appwrite_web
- traefik.http.routers.appwrite_realtime_ws.rule=PathPrefix(`/v1/realtime`)
- traefik.http.routers.appwrite_realtime_ws.service=appwrite_realtime
- traefik.http.routers.appwrite_realtime_wss.entrypoints=appwrite_websecure
- traefik.http.routers.appwrite_realtime_wss.rule=PathPrefix(`/v1/realtime`)
- traefik.http.routers.appwrite_realtime_wss.service=appwrite_realtime
- traefik.http.routers.appwrite_realtime_wss.tls=true
networks:
- appwrite
depends_on:
- postgresql
- redis
- appwrite-embedding
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPTIONS_ABUSE
- _APP_OPTIONS_ROUTER_PROTECTION
- _APP_REALTIME_TAIL_RATE
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DB_ADAPTER_VECTORSDB
- _APP_DB_HOST_VECTORSDB
- _APP_DB_PORT_VECTORSDB
- _APP_DB_SCHEMA_VECTORSDB
- _APP_DB_USER_VECTORSDB
- _APP_DB_PASS_VECTORSDB
- _APP_LOGGING_CONFIG
- _APP_LOGGING_FORMAT
- _APP_LOGGING_CONFIG_REALTIME
- _APP_DATABASE_SHARED_TABLES
- _APP_POOL_ADAPTER=swoole
appwrite-worker:
entrypoint: worker
restart: unless-stopped
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-worker
image: appwrite/appwrite:1.9.6
networks:
- appwrite
depends_on:
- redis
- postgresql
- appwrite-embedding
volumes:
- appwrite-uploads:/storage/uploads:rw
- appwrite-cache:/storage/cache:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
- appwrite-certificates:/storage/certificates:rw
- appwrite-config:/storage/config:rw
- appwrite-imports:/storage/imports:rw
extra_hosts:
- host.docker.internal:host-gateway
environment:
- _APP_ENV
- _APP_WORKERS_NUM=1
# Pool sizing only (sum of per-queue caps). Each queue keeps its own maxCoroutines in PHP; databases stays at 1.
- _APP_WORKER_MAX_COROUTINES=69
- _APP_WORKER_PER_CORE
- _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_EMAIL_SECURITY
- _APP_EMAIL_CERTIFICATES
- _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DB_ADAPTER_VECTORSDB
- _APP_DB_HOST_VECTORSDB
- _APP_DB_PORT_VECTORSDB
- _APP_DB_SCHEMA_VECTORSDB
- _APP_DB_USER_VECTORSDB
- _APP_DB_PASS_VECTORSDB
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_LOGGING_CONFIG
- _APP_LOGGING_FORMAT
- _APP_LOGGING_PROVIDER
- _APP_QUEUE_NAME
- _APP_DATABASE_SHARED_TABLES
- _APP_CONSOLE_URL_SCHEME=root
- _APP_CONSOLE_DOMAIN
- _APP_CONSOLE_TRUSTED_PROJECTS
- _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS
- _APP_DOMAIN_SITES
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_WEBHOOK_MAX_FAILED_ATTEMPTS
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
- _APP_STORAGE_DO_SPACES_BUCKET
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- _APP_STORAGE_BACKBLAZE_SECRET
- _APP_STORAGE_BACKBLAZE_REGION
- _APP_STORAGE_BACKBLAZE_BUCKET
- _APP_STORAGE_LINODE_ACCESS_KEY
- _APP_STORAGE_LINODE_SECRET
- _APP_STORAGE_LINODE_REGION
- _APP_STORAGE_LINODE_BUCKET
- _APP_STORAGE_WASABI_ACCESS_KEY
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST
- _APP_DOCKER_HUB_USERNAME
- _APP_DOCKER_HUB_PASSWORD
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
- _APP_OPEN_RUNTIMES_NFT
- _APP_COMPUTE_SIZE_LIMIT
- _APP_VCS_GITHUB_APP_NAME
- _APP_VCS_GITHUB_PRIVATE_KEY
- _APP_VCS_GITHUB_APP_ID
- _APP_VCS_GITEA_ENDPOINT
- _APP_VCS_GITEA_BROWSER_ENDPOINT
- _APP_VCS_GITEA_CLIENT_ID
- _APP_VCS_GITEA_CLIENT_SECRET
- _APP_VCS_GITEA_WEBHOOK_SECRET
- _APP_VCS_GITLAB_CLIENT_ID
- _APP_VCS_GITLAB_CLIENT_SECRET
- _APP_VCS_GITLAB_WEBHOOK_SECRET
- _APP_VCS_BITBUCKET_CLIENT_ID
- _APP_VCS_BITBUCKET_CLIENT_SECRET
- _APP_VCS_BITBUCKET_WEBHOOK_SECRET
- _APP_VCS_ORIGIN_CLIENT_ID
- _APP_VCS_ORIGIN_PRIVATE_KEY
- _APP_VCS_WEBHOOK_URL
- _APP_BUILDS_VOLUME
- _APP_JOBS_HOST
- _APP_JOBS_SECRET
- _APP_JOBS_ENDPOINT
- _APP_BROWSER_HOST
- _APP_WORKER_SCREENSHOTS_ROUTER
- _APP_NOTIFICATIONS_TRACKING_SECRET
- _APP_SYSTEM_EMAIL_NAME
- _APP_SYSTEM_EMAIL_ADDRESS
- _APP_SMTP_HOST
- _APP_SMTP_PORT
- _APP_SMTP_SECURE
- _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD
- _APP_SMS_FROM
- _APP_SMS_PROVIDER
- _APP_SMS_PROJECTS_DENY_LIST
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_MIGRATION_HOST
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
appwrite-task-scheduler:
entrypoint: schedule
restart: unless-stopped
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-task-scheduler
image: appwrite/appwrite:1.9.6
networks:
- appwrite
depends_on:
- postgresql
- redis
- appwrite-embedding
environment:
- _APP_ENV
- _APP_LOGGING_FORMAT
# Combined mode runs functions/executions/messages timers + enqueue coroutines
# against shared console/cache pools; floor must cover concurrent ticks.
- _APP_WORKER_MAX_COROUTINES=8
- _APP_WORKER_PER_CORE
- _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_OPTIONS_FORCE_HTTPS
- _APP_DOMAIN
- _APP_CONSOLE_DOMAIN
- _APP_CONSOLE_SCHEMA
- _APP_DOMAIN_FUNCTIONS
- _APP_DOMAIN_SITES
- _APP_MIGRATION_HOST
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DATABASE_SHARED_TABLES
- _APP_FUNCTIONS_SCHEDULE_SPREAD
appwrite-task-maintenance:
entrypoint: maintenance
restart: unless-stopped
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-task-maintenance
image: appwrite/appwrite:1.9.6
networks:
- appwrite
depends_on:
- postgresql
- redis
environment:
- _APP_ENV
- _APP_LOGGING_FORMAT
- _APP_WORKER_PER_CORE
- _APP_POOL_ADAPTER
- _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS
- _APP_EDITION
- _APP_ROUTER_AUTO_CERTIFICATES
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_MAINTENANCE_INTERVAL
- _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_MAINTENANCE_START_TIME
- _APP_DATABASE_SHARED_TABLES
appwrite-task-interval:
entrypoint: interval
restart: unless-stopped
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-task-interval
image: appwrite/appwrite:1.9.6
networks:
- appwrite
depends_on:
- postgresql
- redis
environment:
- _APP_ENV
- _APP_LOGGING_FORMAT
- _APP_WORKER_PER_CORE
- _APP_POOL_ADAPTER
- _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS
- _APP_DOMAIN_SITES
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DATABASE_SHARED_TABLES
- _APP_INTERVAL_DOMAIN_VERIFICATION
- _APP_INTERVAL_CLEANUP_STALE_EXECUTIONS
appwrite-assistant:
container_name: appwrite-assistant
image: appwrite/assistant:0.8.4
networks:
- appwrite
environment:
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
container_name: appwrite-browser
image: appwrite/browser:0.3.3
networks:
- appwrite
appwrite-geo:
container_name: appwrite-geo
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
image: appwrite/geo:0.3.1
restart: unless-stopped
networks:
- appwrite
environment:
- GEO_SECRET=$_APP_GEO_SECRET
healthcheck:
test: 'php -r "exit(json_decode(file_get_contents(''http://localhost/v1/health''))->status === ''ok'' ? 0 : 1);"'
interval: 10s
timeout: 5s
retries: 3
start_period: 5s
openruntimes-executor:
container_name: exc1
hostname: exc1
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
stop_signal: SIGINT
image: openruntimes/executor:0.25.4
restart: unless-stopped
networks:
- appwrite
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- appwrite-builds:/storage/builds:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- /tmp:/tmp:rw
environment:
- OPR_EXECUTOR_IMAGES=$_APP_EXECUTOR_IMAGES
- OPR_EXECUTOR_INACTIVE_THRESHOLD=$_APP_COMPUTE_INACTIVE_THRESHOLD
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_COMPUTE_MAINTENANCE_INTERVAL
- OPR_EXECUTOR_NETWORK=$_APP_COMPUTE_RUNTIMES_NETWORK
- OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
- OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
- OPR_EXECUTOR_ENV=$_APP_ENV
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
- OPR_EXECUTOR_RUNTIME_VERSIONS=v5
- OPEN_RUNTIMES_NFT=$_APP_OPEN_RUNTIMES_NFT
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
- OPR_EXECUTOR_CONNECTION_STORAGE=${_APP_EXECUTOR_CONNECTION_STORAGE:-local://localhost}
- OPR_EXECUTOR_CONNECTION_BUILD_CACHE_STORAGE=
healthcheck:
test:
- CMD-SHELL
- 'curl -fsS -H "Authorization: Bearer $$OPR_EXECUTOR_SECRET" http://localhost/v1/health
>/dev/null'
interval: 5s
timeout: 3s
retries: 20
start_period: 5s
orchestrator-jobs:
container_name: orchestrator-jobs
hostname: orchestrator-jobs
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
image: ghcr.io/open-runtimes/orchestrator/jobs-service:1.3.0
restart: unless-stopped
user: root
networks:
- appwrite
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- ORCHESTRATOR_BACKEND=docker
- ORCHESTRATOR_NETWORK=appwrite
- ARTIFACT_ENDPOINT=http://orchestrator-jobs:8080
- JOB_SIDECAR_IMAGE=ghcr.io/open-runtimes/orchestrator/job-sidecar:0.18.0
postgresql:
image: appwrite/postgres:0.1.0
container_name: appwrite-postgresql
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
networks:
- appwrite
volumes:
- appwrite-postgresql:/var/lib/postgresql/18/data:rw
environment:
- POSTGRES_DB=${_APP_DB_SCHEMA}
- POSTGRES_USER=${_APP_DB_USER}
- POSTGRES_PASSWORD=${_APP_DB_PASS}
healthcheck:
test:
- CMD-SHELL
- pg_isready -U ${_APP_DB_USER} -d ${_APP_DB_SCHEMA}
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
command:
- postgres
- -c
- fsync=off
- -c
- synchronous_commit=off
- -c
- full_page_writes=off
appwrite-embedding:
image: appwrite/embedding:0.1.0
environment:
EMBEDDING_MODELS: ${_APP_EMBEDDING_MODELS:-nomic-embed-text}
container_name: appwrite-embedding
restart: unless-stopped
volumes:
- appwrite-models:/home/embedder/models
networks:
- appwrite
redis:
image: redis:7.4.7-alpine
logging:
driver: json-file
options:
max-file: "5"
max-size: 10m
container_name: appwrite-redis
command:
- redis-server
- --maxmemory
- 512mb
- --maxmemory-policy
- allkeys-lru
- --maxmemory-samples
- "5"
networks:
- appwrite
volumes:
- appwrite-redis:/data:rw
healthcheck:
test:
- CMD
- redis-cli
- ping
interval: 5s
timeout: 5s
retries: 12
networks:
gateway:
name: gateway
appwrite:
name: appwrite
runtimes:
name: runtimes
volumes:
appwrite-postgresql: null
appwrite-redis: null
appwrite-cache: null
appwrite-uploads: null
appwrite-imports: null
appwrite-certificates: null
appwrite-functions: null
appwrite-sites: null
# Pinned name (unprefixed) so the jobs-service can attach it to build workers
# by a stable name across environments (see _APP_BUILDS_VOLUME).
appwrite-builds:
name: appwrite-builds
appwrite-config: null
appwrite-models: null
openruntimes-node-modules-cache: null

Install Appwrite

  1. Create a directory named appwrite and place the generated files inside. Every installation needs docker-compose.yml and .env; MongoDB installations also need mongo-init.js and mongo-entrypoint.sh
  2. Edit the .env file to customize your installation. At minimum, update _APP_OPENSSL_KEY_V1 and _APP_EXECUTOR_SECRET with unique secret values
  3. Start the Appwrite stack:
Bash
docker compose up -d --remove-orphans

Post-installation

After installation completes:

  1. Access the Console - Navigate to your machine's hostname or IP address in your browser
  2. Create your first project - Set up your development environment

SDK version compatibility

The tables below map each released self-hosted Appwrite version to the SDK versions that were current at the time of that release. Use this to pin your SDK to a version known to work with your server. The latest stable self-hosted Appwrite release is 1.9.6.

Client SDKs

Appwrite WebFlutterReact NativeAppleAndroid
1.7.018.0.016.0.00.9.010.0.08.0.0
1.7.1 to 1.7.318.0.016.0.00.9.010.0.08.0.0
1.7.418.1.117.0.00.10.010.0.08.0.0
1.7.518.1.117.0.00.10.010.0.08.0.0
1.8.021.4.020.3.00.18.013.3.011.3.0
1.8.123.0.022.0.00.25.015.0.013.0.0
1.9.024.1.123.0.00.27.116.0.014.1.0
1.9.526.1.025.2.00.33.018.2.025.2.0
1.9.626.2.025.3.00.34.018.3.026.0.0

Server SDKs

Appwrite Node.jsPythonPHPDartRuby.NETGoSwiftKotlinCLI
1.7.017.0.011.0.015.0.016.0.016.0.00.13.0v0.7.010.0.09.0.06.2.3
1.7.1 to 1.7.317.0.011.0.015.0.016.0.016.0.00.13.0v0.7.010.0.09.0.06.2.3
1.7.417.1.011.0.015.0.016.1.016.0.00.13.0v0.7.010.0.09.0.08.0.0
1.7.517.1.011.0.015.0.016.1.016.0.00.13.0v0.7.010.0.09.0.08.0.0
1.8.020.2.113.4.117.5.019.3.019.3.00.22.0v0.13.113.2.212.3.012.0.1
1.8.122.1.316.0.020.2.121.3.021.1.01.0.0v1.0.015.2.014.1.015.0.0
1.9.023.1.017.0.021.0.022.0.022.0.02.0.0v2.0.016.0.015.0.017.4.0
1.9.526.2.021.0.026.1.025.1.025.1.05.1.0v5.1.019.1.018.1.022.3.0
1.9.627.0.022.1.027.0.026.0.026.0.06.0.0v6.0.020.0.019.0.023.0.0

Managing your installation

Stop Appwrite

To stop your Appwrite containers:

Bash
docker compose stop

Restart Appwrite

To restart your Appwrite containers:

Bash
docker compose start

Uninstall Appwrite

To completely remove Appwrite and all its data:

Bash
docker compose down -v

Next steps

After successfully installing Appwrite, you can:

Deploy on cloud platforms - Learn how to deploy on AWS, DigitalOcean, and other cloud providers

Configure services - Set up email, SMS, storage, and other services

Configure databases - Learn more about MongoDB and MariaDB configuration

Production setup - Prepare your installation for production use

Update Appwrite - Keep your installation up to date

Was this page helpful?

Share what worked or what we should fix. Once approved, our agents automatically apply suggested updates to the docs.