Introduction
Appwrite est une plateforme open-source Backend-as-a-Service (BaaS) qui rivalise avec Firebase en offrant authentification, bases de données NoSQL, stockage de fichiers, fonctions serverless et realtime, le tout auto-hébergé. En 2026, avec sa maturité (v1.6+), elle excelle en production grâce à sa scalabilité horizontale via Docker Swarm, conformité GDPR native et intégration Kubernetes-ready.
Pourquoi choisir Appwrite pour un projet expert ? Contrairement aux services cloud verrouillés, vous contrôlez vos données sur votre infra (VPS, bare-metal ou cloud), réduisez les coûts (zéro vendor lock-in) et personnalisez via SDKs (JS, Dart, etc.). Ce tutoriel couvre un déploiement prod-ready : persistance PostgreSQL/MariaDB, HTTPS avec Caddy, monitoring Prometheus et exemple d'app client Next.js. À la fin, vous aurez un backend scalable gérant 10k+ users/jour. Temps estimé : 30 min setup + tests.
Prérequis
- Serveur VPS/cloud (Ubuntu 24.04+, 4 vCPU, 8GB RAM, 100GB SSD pour prod initiale)
- Docker 27+ et Docker Compose 2.29+ installés (
curl -fsSL https://get.docker.com | sudo sh) - Domaine DNS pointé (A record vers IP serveur)
- Connaissances avancées en Docker, TypeScript et sécurité (firewall UFW)
- Port 80/443 ouverts, SSH clé-only
- Outils :
htop,jqpour monitoring
Préparer l'environnement et variables
#!/bin/bash
# Créer répertoire dédié
mkdir -p ~/appwrite-prod && cd ~/appwrite-prod
# Générer secrets forts (utilisez pwgen ou équivalent en prod)
APPWRITE_DB_HOST=mariadb
APPWRITE_DB_PORT=3306
APPWRITE_DB_SCHEMA=appwrite
APPWRITE_DB_USER=appwrite
APPWRITE_DB_PASS=$(openssl rand -base64 32)
APPWRITE_DB_ROOT_PASS=$(openssl rand -base64 32)
APPWRITE_REDIS_HOST=redis
APPWRITE_REDIS_PORT=6379
APPWRITE_HOSTNAME=votre-domaine.com
APPWRITE_PORT=80
APPWRITE_HTTPS_PORT=443
APPWRITE_DOCS_URL=https://appwrite.io/docs
# Écrire .env
cat > .env << EOF
${APPWRITE_DB_HOST}=mariadb
${APPWRITE_DB_PORT}=3306
${APPWRITE_DB_SCHEMA}=appwrite
${APPWRITE_DB_USER}=appwrite
${APPWRITE_DB_PASS}
${APPWRITE_DB_ROOT_PASS}
${APPWRITE_REDIS_HOST}=redis
${APPWRITE_REDIS_PORT}=6379
${APPWRITE_HOSTNAME}
${APPWRITE_PORT}=80
${APPWRITE_HTTPS_PORT}=443
${APPWRITE_DOCS_URL}
EOF
chmod 600 .env
sudo ufw allow 80,443/tcp
# Volumes persistants
sudo mkdir -p /data/appwrite/{mariadb,redis,indexes}
sudo chown -R 1000:1000 /data/appwrite
echo '✅ Environnement prêt. Secrets dans .env'Ce script initialise le répertoire, génère des mots de passe forts pour MariaDB/Redis (essentiel en prod pour éviter les breaches), crée un fichier .env sécurisé et prépare les volumes persistants Docker. Piège : Ne commitez jamais .env en Git ; utilisez des secrets manager comme Doppler en prod. Exécutez-le rootless pour sécurité.
Configuration Docker Compose
Maintenant, déployons Appwrite avec un stack complet incluant MariaDB pour persistance (vs SQLite dev), Redis pour cache/sessions, et Caddy pour HTTPS auto (Let's Encrypt). Ce setup est horizontalement scalable via docker swarm init et supporte 100+ req/s.
Fichier docker-compose.yml complet
version: '3.8'
x-appwrite-common: &appwrite-common
image: appwrite/appwrite:1.6.0
restart: always
environment:
- _APP_DOMAIN=${APPWRITE_HOSTNAME}
- _APP_ENV=production
- _APP_OPENSSL_KEY_V1=${APPWRITE_OPENSSL_KEY_V1}
- _APP_MAINTENANCE=${APPWRITE_MAINTENANCE:-false}
- _APP_SYSTEM_SECURITY=${APPWRITE_SYSTEM_SECURITY:-true}
- _APP_SYSTEM_CONSOLE=${APPWRITE_SYSTEM_CONSOLE:-true}
- _APP_SYSTEM_PROJECTS=${APPWRITE_SYSTEM_PROJECTS:-true}
- _APP_SYSTEM_DATABASE=${APPWRITE_SYSTEM_DATABASE:-true}
- _APP_SYSTEM_STORAGE=${APPWRITE_SYSTEM_STORAGE:-true}
- _APP_SYSTEM_LOCALE=${APPWRITE_SYSTEM_LOCALE:-en-US}
- _APP_SYSTEM_X_FRAME=${APPWRITE_SYSTEM_X_FRAME:-true}
volumes:
- ./_APP_DATA:/usr/src/code/app/data:rw
- ./indexes:/usr/src/code/indexes:ro
networks:
- appwrite
depends_on:
- mariadb
- redis
services:
mariadb:
image: mariadb:11
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${APPWRITE_DB_ROOT_PASS}
MYSQL_DATABASE: ${APPWRITE_DB_SCHEMA}
MYSQL_USER: ${APPWRITE_DB_USER}
MYSQL_PASSWORD: ${APPWRITE_DB_PASS}
volumes:
- /data/appwrite/mariadb:/var/lib/mysql
networks:
- appwrite
command: --default-authentication-plugin=mysql_native_password --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-query-cache --max-connections=500
redis:
image: redis:7-alpine
restart: always
volumes:
- /data/appwrite/redis:/data
networks:
- appwrite
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
appwrite:
<<: *appwrite-common
ports:
- "80:80"
- "443:443"
volumes:
- /data/appwrite/indexes:/usr/src/code/indexes:ro
caddy:
image: caddy:2-alpine
restart: always
ports:
- 80:80
- 443:443
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- appwrite
volumes:
caddy_data:
caddy_config:
networks:
appwrite:
driver: bridgeCe docker-compose.yml déploie Appwrite 1.6 avec MariaDB persistant (tunable maxconn=500), Redis optimisé (LRU eviction), et Caddy pour HTTPS gratuit. Anchors YAML (&appwrite-common) évitent la duplication. Piège : Volumes host absolus (/data) pour persistance post-reboot ; testez docker compose up -d puis docker logs appwrite.
Caddyfile pour HTTPS automatique
votre-domaine.com {
reverse_proxy appwrite:80
header {
Strict-Transport-Security "max-age=31536000;"
X-Frame-Options DENY
X-Content-Type-Options nosniff
Referrer-Policy strict-origin-when-cross-origin
}
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}Caddy auto-génère certs Let's Encrypt et ajoute headers sécurité (HSTS, CSP-like). Remplacez par votre domaine ; pour Cloudflare DNS, ajoutez token en .env. Piège : Sans reverse_proxy, Appwrite ne voit pas les headers HTTPS ; vérifiez curl -I https://domaine.com.
Lancer le stack et vérifier
#!/bin/bash
cd ~/appwrite-prod
# Pull images et up
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose pull
docker compose up -d
# Attendre init (5-10min)
sleep 300
docker compose logs appwrite | tail -20
# Health check
curl -f https://votre-domaine.com/health || echo '❌ Health KO'
# Accès console: https://votre-domaine.com
# Default creds: email@getappwrite.io / password
echo '✅ Appwrite prêt. Configurez via https://votre-domaine.com/console'Ce script lance le stack, attend l'init DB (migration auto Appwrite) et check health. Utilisez BUILDKIT pour builds rapides. Piège : Premier démarrage = 10min pour indexes ; surveillez docker stats pour RAM (>4GB requis).
Setup initial et création de projet
Accédez à https://votre-domaine.com/console (creds init: email@getappwrite.io / password). Changez mot de passe, activez 2FA. Créez un projet 'MonApp', générez API key (Settings > API Keys > Full Access). Activez services: Database, Auth, Storage, Functions, Realtime.
Installer SDK et créer une collection DB
import { Client, Account, Databases, ID, Query } from 'node-appwrite';
async function main() {
const client = new Client()
.setEndpoint('https://votre-domaine.com/v1')
.setProject('YOUR_PROJECT_ID') // Remplacez par ID projet console
.setKey('YOUR_API_KEY'); // Full access key
const databases = new Databases(client);
// Créer DB si inexistante
const dbId = ID.unique();
await databases.create(dbId, 'MaBaseDeDonnees');
// Créer collection Users
const collId = ID.unique();
await databases.createCollection(dbId, collId, 'Users', [
{ key: 'userId', type: 'string', status: 'required', array: false },
{ key: 'email', type: 'string', status: 'required', array: false },
{ key: 'role', type: 'string', status: 'required', array: false },
{ key: 'createdAt', type: 'datetime', status: 'required', array: false }
], [
{ sum: 'count', name: 'totalUsers', required: false },
{ average: 'avgRoleLength', name: 'avgRoleLength', required: false }
], [], []);
// Index pour perf
await databases.createStringUniqueIndex(dbId, collId, 'userId_primary', 'userId');
await databases.createStringIndex(dbId, collId, 'email_index', 'email', 100);
console.log(`✅ DB ${dbId}, Collection ${collId} créées.`);
}
main().catch(console.error);Ce script Node.js utilise le SDK server-side pour créer DB + collection avec attributs/indexes (perf queries). Exécutez npm i node-appwrite && ts-node create-collection.ts. Piège : API Key scope 'database.write' requis ; listez via databases.listCollections() pour verify.
Intégration client-side avec Next.js
Pour un frontend Next.js, installez npm i appwrite, configurez env NEXT_PUBLIC_APPWRITE_URL/ENDPOINT. Gérez auth realtime et CRUD DB.
Hook auth et realtime en React/Next.js
import { useEffect, useState } from 'react';
import { Client, Account, Databases, Realtime, ID, Query } from 'appwrite';
import { useRouter } from 'next/navigation';
type User = { $id: string; email: string; role: string };
export function useAppwriteAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const router = useRouter();
const client = new Client()
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_URL!)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!);
const account = new Account(client);
const databases = new Databases(client);
const realtime = new Realtime(client);
useEffect(() => {
// Restore session
account.get().then(
(u) => {
setUser({ $id: u.$id, email: u.email!, role: 'user' });
// Subscribe realtime DB
realtime.subscribe(`databases.MA_BASE_ID.collections.USERS/documents`, (res) => {
console.log('Realtime update:', res);
});
},
() => setUser(null)
).finally(() => setLoading(false));
}, []);
const login = async (email: string, password: string) => {
await account.createEmailPasswordSession(email, password);
router.refresh();
};
const createUserDoc = async (userData: Omit<User, '$id'>) => {
return databases.createDocument(
'MA_BASE_ID',
'USERS_ID',
ID.unique(),
userData
);
};
const logout = () => account.deleteSession('current').then(() => router.refresh());
return { user, loading, login, logout, createUserDoc };
}Ce hook custom gère session persistante, login/logout, CRUD DB et realtime subscribe (push updates). Intégrez dans App.tsx. Piège : Env vars NEXT_PUBLIC_ exposées client-side ; utilisez JWT custom pour prod. Test: npm run dev et login via console.
Scaling avec Docker Swarm
#!/bin/bash
# Init Swarm (manager node)
docker swarm init --advertise-addr IP_SERVEUR
# Deploy stack (réplicas)
docker stack deploy -c docker-compose.yml appwrite-stack --with-registry-auth
# Scale services
docker service scale appwrite-stack_appwrite=3
docker service scale appwrite-stack_mariadb=1
# Worker nodes: docker swarm join --token $(docker swarm join-token worker) IP:2377
# Monitoring
docker service logs appwrite-stack_appwrite
docker stats
# Backup cron
crontab -e
# 0 2 * * * docker exec appwrite-stack_mariadb mysqldump -u root -p${APPWRITE_DB_ROOT_PASS} appwrite > /backups/db-$(date +%Y%m%d).sqlPassez en Swarm pour HA/scaling (3 réplicas Appwrite). docker stack deploy gère replicas/orchestration. Piège : MariaDB single pour simplicité ; utilisez Galera cluster pour true HA. Backup daily via cron mysqldump.
Bonnes pratiques
- Sécurité : API Keys scoped minimal (read-only pour client), WAF (Cloudflare), rate limiting Appwrite via Redis.
- Perf : Indexes DB sur champs query (ex: email), offload storage S3 via Appwrite Storage adapter.
- Monitoring : Intégrez Prometheus/Grafana (expose /metrics Appwrite), alerts sur CPU>80%.
- Backup : Volumes RAID1, snapshots DB/Redis quotidiens vers S3, test restore mensuel.
- Mises à jour :
docker compose pull && up -dtesté en staging d'abord ; pin versions YAML.
Erreurs courantes à éviter
- Volumes non persistants : Perte données sur reboot → Toujours host mounts (/data).
- HTTPS bypass : Appwrite sessions cassées sans proxy headers → Caddy/Traefik obligatoire.
- DB overload : Pas d'index → Queries lentes >1s ; profilez via console.
- Secrets en clair : .env world-readable →
chmod 600, secrets Docker ou Vault.
Pour aller plus loin
Approfondissez avec docs Appwrite, Kubernetes Helm chart ou Functions Deno. Migrez vers Vector DB (Milvus integration). Découvrez nos formations Learni DevOps pour Docker Swarm/K8s expert, ou Backend BaaS avancées.