Por qué autoalojar Appwrite en un VPS
Appwrite reúne en una sola plataforma todo lo que una aplicación necesita del lado del servidor: autenticación con más de 30 métodos OAuth, base de datos documental con permisos granulares, almacenamiento de archivos con transformación de imágenes, funciones serverless en varios lenguajes y messaging. Su versión cloud factura por uso y por recursos; al autoalojarla en un VPS, despliega el conjunto mediante Docker y lo pilota desde una consola web elegante, sin tope.
Resulta especialmente adecuado para los desarrolladores de Flutter, React Native o web que quieren un backend listo para usar con SDK oficiales, manteniendo los datos y la lógica en su propia infraestructura. Usted controla las funciones, las claves API y los permisos, y evoluciona a su ritmo — sin estar sujeto a las cuotas o subidas de precios de una nube pública.
Los beneficios concretos de un Appwrite autoalojado
- Backend todo en uno: Auth, Databases, Storage, Functions y Messaging en una consola única.
- SDK oficiales para Flutter, React Native, Web, Android, iOS, Node, Python y más.
- Más de 30 proveedores OAuth integrados (Google, GitHub, Apple...) sin escribir código.
- Funciones serverless self-hosted: ejecute su lógica de negocio sin ningún servicio externo.
- Permisos granulares a nivel de documento y de colección, gestionados desde la consola.
- Sin facturación por ejecución ni cuota de usuarios: tarifa de VPS fija.
- Datos alojados en su propia infraestructura: cumplimiento GDPR simplificado, sin dependencia de nube de terceros.
- Realtime integrado: suscríbase a cambios en documentos, archivos y estado de sesión vía WebSocket.
Arquitectura interna: lo que Docker lanza realmente
Antes de instalar, conviene saber qué orquesta Appwrite. El instalador oficial genera un docker-compose.yml con al menos veinte servicios:
- appwrite — el servidor API principal (PHP, expuesto en el puerto 80/443 mediante Traefik).
- appwrite-console — la consola de administración web (React, servida en el mismo dominio en /).
- appwrite-realtime — el servicio WebSocket para suscripciones en tiempo real.
- appwrite-worker-* — una serie de workers para tareas asíncronas: envío de e-mails, webhooks salientes, limpieza de archivos temporales, etc.
- appwrite-executor — el runtime de ejecución de las Functions serverless (Docker-in-Docker).
- mariadb — la base de datos relacional interna (usuarios, proyectos, reglas de permisos).
- redis — la caché y la cola de tareas (jobs de workers, sesiones, rate-limiting).
- traefik — el reverse proxy integrado que gestiona el enrutamiento HTTPS y los certificados Let's Encrypt.
Para un VPS de desarrollo, solo el nodo core es estrictamente necesario: API, Consola, MariaDB, Redis y Traefik. Los workers y el executor son imprescindibles en producción si usa Functions, webhooks o envío de e-mails. Calcule al menos 4 GB de RAM para esta stack completa.
Requisitos de hardware y software
Para una instancia de desarrollo o pruebas, bastan 2 vCPU y 4 GB de RAM con 40 GB de SSD. Para producción con funciones serverless activas y varias apps cliente, apunte a 4 vCPU, 8 GB de RAM y 80 GB de SSD — cada invocación de Function arranca su propio contenedor efímero, lo que presiona el disco y la CPU.
En cuanto al software: Ubuntu 22.04 o 24.04 LTS, Docker CE y Docker Compose v2 (Appwrite gestiona su propio Traefik para el enrutamiento y el SSL), y un nombre de dominio que apunte a la IP del VPS — por ejemplo api.miapp.com. Los puertos 80 y 443 deben estar libres y abiertos en ufw para que Traefik obtenga los certificados Let's Encrypt mediante el challenge ACME.
Una nota sobre el almacenamiento. Las Functions generan imágenes Docker intermedias que se acumulan en el SSD. Sin purgas periódicas, una instancia que lleva meses en marcha puede saturar su disco. Programe una tarea cron semanal de docker system prune --volumes -f, y monitoree el espacio libre con df -h.
Desplegar Appwrite self-hosted con Docker
Preparar el VPS y abrir los puertos
Instale Docker CE y Docker Compose v2, luego abra los puertos necesarios:
ufw allow 80/tcp ufw allow 443/tcp ufw enableHaga que su dominio (p. ej.,
api.miapp.com) apunte a la IP del VPS mediante un registro A. Espere la propagación DNS antes de ejecutar el instalador — Traefik necesita que el dominio resuelva realmente para pasar el challenge ACME.Lanzar el instalador interactivo oficial
Ejecute el instalador con un solo comando:
docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ appwrite/appwriteEl asistente le pide el dominio principal, el puerto HTTP (80), el puerto HTTPS (443), un e-mail para Let's Encrypt y algunas opciones. Genera un
docker-compose.ymly un archivo.envcon secretos generados aleatoriamente. No toque estos secretos a mano — modifíquelos únicamente mediante las variables de entorno en.env.Verificar la configuración del dominio y el SSL
Tras el arranque (
docker compose up -d), espere 30 a 60 segundos para que Traefik emita el certificado. Compruebe:curl -I https://api.miapp.com/v1/healthLa respuesta debe ser
HTTP/2 200concontent-type: application/json. Si Traefik aún no tiene certificado, obtendrá un error TLS — es normal durante los primeros segundos. Si persiste, compruebe que los puertos 80/443 no están filtrados por un firewall superior y que el dominio resuelve a la IP correcta (dig api.miapp.com).Crear la cuenta de administrador y el primer proyecto
Abra
https://api.miapp.comen su navegador. Appwrite le invita a crear la cuenta de administrador raíz en el primer acceso — esta cuenta es la única con acceso a los ajustes de la plataforma. Desde la consola, cree un proyecto, añada una plataforma (Web, Flutter, Apple…) declarando el hostname autorizado y recupere el ID del proyecto. Esos datos alimentan la inicialización del SDK en el lado del cliente:npm install appwriteimport { Client } from 'appwrite'; const client = new Client() .setEndpoint('https://api.miapp.com/v1') .setProject('<your-project-id>');Endurecer la configuración de producción
Abra el archivo
.envgenerado por el instalador y ajuste las siguientes variables:-
_APP_OPTIONS_ABUSE=enabled— activa el rate-limiting integrado por IP.
-_APP_OPTIONS_FORCE_HTTPS=enabled— redirige todas las peticiones HTTP a HTTPS.
-_APP_SMTP_HOST/_APP_SMTP_PORT/_APP_SMTP_SECURE/_APP_SMTP_USERNAME/_APP_SMTP_PASSWORD— configure su relay SMTP para los e-mails de verificación y restablecimiento de contraseña.
-_APP_CONSOLE_WHITELIST_ROOT=disabledsi quiere permitir el registro abierto en la consola (no recomendado en prod); déjelo enenabledy rellene_APP_CONSOLE_WHITELIST_EMAILScon las direcciones autorizadas.Reinicie los servicios tras la modificación:
docker compose up -d.Configurar las copias de seguridad automatizadas
Dos volúmenes Docker contienen todos los datos persistentes de Appwrite:
-
appwrite-mariadb— la base de datos (usuarios, proyectos, documentos, reglas).
-appwrite-uploads— los archivos subidos por las apps cliente.Programe un dump diario:
docker exec appwrite-mariadb mysqldump \ -u appwrite -p"$MARIADB_ROOT_PASSWORD" appwrite \ > /backups/appwrite-$(date +%Y%m%d).sqlArchive también el volumen
appwrite-uploads(untarde los datos o un snapshot de volumen según su infraestructura). Guarde también_APP_OPENSSL_KEY_V1— Appwrite lo usa para cifrar archivos y ciertos datos sensibles. Sin esta clave, una restauración de base de datos deja los contenidos cifrados permanentemente ilegibles.
Red y Traefik: lo que ocurre entre bastidores
Traefik es el único punto de entrada de red de Appwrite: escucha en los puertos 80 y 443, gestiona los certificados Let's Encrypt y enruta las peticiones al servicio interno correcto. Esta integración es transparente — usted no escribe ninguna configuración de Traefik, la genera el instalador.
Algunos puntos importantes si añade un reverse proxy superior (nginx, Cloudflare Tunnel…):
- No duplique el TLS. Si su proxy superior ya termina el SSL y reenvía en HTTP a Appwrite, desactive el challenge ACME estableciendo _APP_OPTIONS_FORCE_HTTPS=disabled y dejando _APP_SYSTEM_SECURITY_EMAIL_ADDRESS= vacío para evitar que Traefik intente obtener un certificado que no puede validar.
- Transmita la IP real. Añada X-Forwarded-For y X-Real-IP en su proxy superior, y active la confianza en headers en Traefik (ya configurada por defecto en el instalador de Appwrite).
- Puertos de la consola. La consola web y la API se sirven bajo el mismo dominio: no enrute el puerto 9501 (Realtime interno) públicamente — Traefik lo gestiona de forma interna.
Si coloca Appwrite detrás de Cloudflare en modo proxied, establezca el modo SSL de la zona en Full (strict) — en modo Flexible, nginx redirige HTTP→HTTPS, lo que crea un bucle de redirección infinito entre Cloudflare y Traefik.
Resolución de problemas comunes
La consola muestra «Could not connect to the Appwrite API».
Compruebe que las variables _APP_DOMAIN y _APP_DOMAIN_TARGET en .env coincidan exactamente con el dominio que está usando. Un subdominio mal configurado (con o sin www) impide que Traefik enrute correctamente. Ejecute docker compose up -d después de cualquier modificación del .env.
Los e-mails de verificación no llegan.
Appwrite no tiene relay SMTP integrado — debe configurar _APP_SMTP_* con un servicio externo (Mailgun, Resend, su propio servidor). Sin SMTP configurado, los e-mails se encolan y se ignoran. Compruebe los logs del worker appwrite-worker-mails: docker compose logs appwrite-worker-mails --tail 50.
Las Functions serverless expiran por timeout.
Cada Function arranca su propio contenedor Docker. En un VPS con 2 GB de RAM, el arranque en frío suele superar los 10 segundos, lo que dispara el timeout por defecto. Aumente _APP_FUNCTIONS_TIMEOUT en .env y prevea al menos 4 GB de RAM para uso en producción. Monitoree también el espacio en disco — las imágenes de runtime permanecen en el SSD tras la ejecución.
El certificado SSL no se genera.
Traefik necesita que los puertos 80 y 443 respondan desde el exterior para pasar el challenge ACME. Si un firewall superior (reglas de seguridad de su proveedor de VPS) bloquea estos puertos, el challenge falla silenciosamente. Pruebe desde una máquina externa: curl -I http://api.miapp.com debe responder (aunque sea con un 302), no expirar.
MariaDB arranca pero la consola muestra errores de base de datos.
Si ha modificado .env a mano entre reinicios, compruebe que _APP_DB_HOST, _APP_DB_USER y _APP_DB_PASS coinciden con los valores del contenedor MariaDB. Un reinicio parcial (un solo servicio) sin docker compose down puede dejar contenedores huérfanos con variables antiguas en memoria.
Appwrite vs Supabase: ¿cuál autoalojar?
Desplace la tabla
| Criterio | Appwrite | Supabase |
|---|---|---|
| Base de datos | MariaDB, modelo documental | PostgreSQL nativo, SQL completo |
| Enfoque | Orientado a SDK y apps móviles | Orientado a SQL y apps relacionales |
| Funciones serverless | Nativas, multilenguaje, integradas | Edge Functions (Deno) |
| Instalación | Instalador interactivo oficial | Compose que hay que configurar a mano |
| SSL / enrutamiento | Traefik integrado, automático | Reverse proxy externo por añadir |
| Búsqueda vectorial / IA | No nativa | Nativa mediante pgvector |
| Realtime | WebSocket integrado, multi-recurso | Postgres CDC mediante Realtime |
| Ideal para | Flutter, React Native, mobile-first | SQL avanzado, RAG, relacional |
| Consola de administración | Consola rica y guiada | Studio centrado en las tablas SQL |
Actualizaciones y mantenimiento continuo
Para actualizar Appwrite, vuelva a ejecutar el instalador con la nueva versión o modifique el tag de imagen en docker-compose.yml y ejecute docker compose pull && docker compose up -d. Appwrite aplica las migraciones de esquema automáticamente al arrancar el contenedor API — no se necesita ningún comando manual.
Programe también una purga semanal de imágenes Docker huérfanas para evitar la saturación del SSD:
docker system prune --volumes -fGuarde _APP_OPENSSL_KEY_V1 en una caja fuerte separada (gestor de secretos, archivo cifrado fuera del VPS). Sin esta clave, una restauración de base de datos deja los archivos cifrados y ciertos datos sensibles permanentemente ilegibles — es el único punto de no retorno de una instalación de Appwrite.
Esta plantilla aporta el núcleo: las Functions vienen después
El instalador oficial de Appwrite genera más de 25 contenedores, entre ellos workers de segundo plano y un runtime de ejecución para las Functions serverless y los Sites. Para mantener una huella reducida en el VPS, esta plantilla solo aporta el núcleo autosuficiente, el servidor de API, MariaDB, Redis y Traefik, que hace funcionar plenamente Auth, Databases, Storage, Realtime y la Console. Las Functions serverless, los webhooks salientes y el envío de correos en segundo plano requieren los contenedores worker y executor adicionales, y no están activados aquí. Cuando su proyecto lo necesite, pase a la stack docker-compose oficial completa de Appwrite y prevea al menos 4 GB de RAM. Para las copias de seguridad, programe snapshots de los volúmenes Docker appwrite-mariadb (datos) y appwrite-uploads (archivos).