Appwrite is a comprehensive open-source backend-as-a-service — authentication, databases, storage, serverless functions, messaging, and realtime, all behind a clean API and console. It's a Firebase-style platform you can fully self-host. The honest headline: Appwrite is a *substantial* multi-container system, not a single binary. This guide explains the architecture and how to run it responsibly.
Appwrite is a system, not an app
Appwrite ships as a Docker Compose stack with many services. The major pieces:
| Component | Role |
|---|---|
| Appwrite API container | The main entrypoint and orchestrator |
| MariaDB | Primary database (users, collections, metadata) |
| Redis | Cache, pub/sub, queues |
| Worker containers | Background processing (functions, webhooks, mails, etc.) |
| Storage volume | File uploads |
| Traefik (in the default stack) | Routing/proxy |
The official, supported install path is Docker Compose. Trying to hand-split every worker into separate platform services is possible but fights the project's design. The pragmatic approach for most teams self-hosting Appwrite is to run the Compose stack on a VM-like environment or a single compute instance with persistent volumes.
Step 1: Understand what must persist
Three things hold state and must live on durable storage:
- MariaDB data — your entire database.
- Redis (optionally persisted) — cache and queues.
- Uploads volume — user files.
Lose any of these and you lose data. Persistent volumes are mandatory.
Step 2: The installation flow
Appwrite provides a one-line installer that generates a docker-compose.yml and .env for you:
docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:latestThis produces a fully-wired Compose file. The generated .env contains critical secrets:
_APP_OPENSSL_KEY_V1=<encryption key — pin and protect>
_APP_DOMAIN=appwrite.yourdomain.com
_APP_DOMAIN_TARGET=appwrite.yourdomain.com
_APP_DB_HOST=mariadb
_APP_REDIS_HOST=redis
_APP_SMTP_HOST=..._APP_OPENSSL_KEY_V1 encrypts sensitive data — if it changes, encrypted values become unreadable. Treat it like a master key.
Step 3: Deploying on a cloud platform
Because Appwrite is a Compose stack, the cleanest mapping depends on your platform's capabilities. Two realistic patterns:
Pattern A — Compose on a compute instance. Run the generated Compose stack on a single compute instance with attached persistent volumes for MariaDB, Redis, and uploads. This keeps Appwrite's services networked together exactly as designed. Point a custom domain at it and terminate TLS at the platform edge.
Pattern B — Managed data + Appwrite services. Use a managed MariaDB/MySQL (Appwrite supports MySQL 8.x-compatible MariaDB) and managed Redis, then run the Appwrite API and worker containers as apps pointed at those managed data stores via _APP_DB_HOST / _APP_REDIS_HOST. This offloads the trickiest stateful pieces to managed services and lets you scale the stateless workers independently.
On PandaStack, Pattern B is attractive: provision managed MySQL-compatible and Redis instances, then deploy the Appwrite containers linked to them, leaving only the uploads volume as local persistent state.
Step 4: Configure essentials
_APP_ENV=production
_APP_CONSOLE_WHITELIST_ROOT=enabled # restrict console signup
_APP_SMTP_HOST=smtp.yourprovider.com # email for verification/recovery
_APP_STORAGE_LIMIT=... # max upload size- Set
_APP_ENV=productionto harden defaults. - Configure SMTP or transactional email or auth flows won't send verification mails.
- Restrict console access so random users can't create root accounts on your instance.
Step 5: Functions and the executor
Appwrite Functions run user code in isolated containers via an executor service that talks to the Docker socket. If you self-host functions, the executor needs access to a container runtime. This is the most operationally sensitive part of Appwrite — giving a service Docker socket access has security implications. If you don't need serverless functions, you can run a slimmer subset of the stack.
Resource notes
Appwrite's full stack is resource-hungry relative to single-binary backends — multiple worker containers plus MariaDB and Redis. Budget several GB of RAM for a comfortable production instance, more if you enable functions. Start on a memory-generous tier and watch utilization. This is not a tool to cram onto the smallest instance.
Honest caveats
Let me be straight: Appwrite gives you a lot, but you pay in operational weight. Compared to PocketBase (one binary) or Umami-style single-app tools, Appwrite is a real distributed system you now operate — upgrades touch many containers, the function executor needs careful security handling, and resource needs are non-trivial. It's an excellent choice when you genuinely want a Firebase-class feature set on your own infrastructure and a team to run it. For a solo MVP, consider whether PocketBase or Supabase fits better. Also, always upgrade following the official migration guide — Appwrite migrations between major versions require care.
Wrapping up
Self-hosting Appwrite means embracing a multi-container architecture: API plus workers, MariaDB, Redis, and durable storage. The smart approach is to offload MariaDB and Redis to managed services, persist the uploads volume, pin _APP_OPENSSL_KEY_V1, and size generously. Done right, you get a powerful, fully-owned backend platform.
PandaStack's managed MySQL-compatible databases and Redis plus persistent-volume container apps make Pattern B practical, and you can prototype on the free tier before scaling. Get started at https://dashboard.pandastack.io.
References
- Appwrite documentation: https://appwrite.io/docs
- Appwrite self-hosting guide: https://appwrite.io/docs/advanced/self-hosting
- Appwrite environment variables: https://appwrite.io/docs/advanced/self-hosting/environment-variables
- Appwrite functions architecture: https://appwrite.io/docs/products/functions
- Docker Compose docs: https://docs.docker.com/compose/