Skip to content
Learni
Voir tous les tutoriels
DevOps

Comment déployer Appwrite en production avec Docker en 2026

Read in English

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, jq pour monitoring

Préparer l'environnement et variables

setup-env.sh
#!/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

docker-compose.yml
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: bridge

Ce 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

Caddyfile
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

start.sh
#!/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

create-collection.ts
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

useAppwriteAuth.tsx
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

scale-swarm.sh
#!/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).sql

Passez 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 -d testé 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.

Comment déployer Appwrite en production Docker 2026 | Learni