Notas que se autodestruyen: cómo terminé desplegando Enclosed
Notas que se autodestruyen: cómo terminé desplegando Enclosed
Me encontraba buscando una manera de compartir datos sensibles que fuera segura y que no se mantuviera disponible para siempre. Quería algo parecido a esos mensajes de Misión Imposible que se destruían solos después de unos minutos. No necesitaba un sistema enorme ni una plataforma corporativa. Necesitaba algo simple: compartir un dato delicado, que la otra persona pudiera leerlo, y que luego desapareciera.
En medio de esa búsqueda, un compañero me comentó que había leído sobre un software pensado exactamente para eso. Esa conversación fue la que me llevó a revisar Enclosed, y de ahí a implementarlo para este proyecto.
Lo interesante es que Enclosed no intenta ser una suite de colaboración ni un gestor documental. Va directo al punto: permite enviar notas privadas con cifrado de extremo a extremo, con contraseña opcional, tiempo de expiración y destrucción tras lectura. Es decir, el servidor almacena el contenedor cifrado, pero no el contenido en texto plano. Esa idea, por sí sola, ya resolvía buena parte del problema.
El tipo de herramienta que estaba buscando
Cuando uno comparte información sensible suele terminar usando herramientas que no fueron diseñadas para eso. Un chat, un correo, un documento compartido, una nota en la nube. Funcionan, sí, pero dejan demasiados rastros. El dato queda en un historial, en una bandeja, en una carpeta, o en un enlace que alguien puede reenviar meses después.
Por eso el enfoque de Enclosed me pareció tan claro. En lugar de preguntarse cómo compartir más cosas, se pregunta cómo compartir menos tiempo. Ese cambio de lógica es importante. En muchos casos, la seguridad no depende solo del cifrado, sino también de reducir la permanencia del dato.
Enclosed trabaja justamente ahí:
- cifra el contenido en el lado del cliente;
- permite definir un TTL para la nota;
- puede destruir la nota después de la primera lectura;
- admite contraseña adicional;
- y se puede alojar de forma propia.
Para un proyecto donde la privacidad importa, esa combinación tiene bastante sentido.
La primera decisión: alojarlo yo mismo
Después de revisar el proyecto, la siguiente pregunta no fue si usarlo o no, sino dónde desplegarlo. La documentación plantea dos caminos razonables: levantarlo en un VPS con Docker o usar Cloudflare Workers como alternativa serverless.
Mi primera inclinación fue un VPS con Docker. No porque fuera la opción más moderna, sino porque me daba más control. Si el objetivo del proyecto era compartir información sensible, entonces también tenía sentido cuidar dónde quedaban los datos, cómo se hacían los respaldos y qué piezas de infraestructura quedaban bajo mi control.
La arquitectura que terminé considerando era bastante limpia:
Internet -> Nginx con HTTPS -> Enclosed -> volumen persistente para datos
No había demasiada magia. Un contenedor para la aplicación, un proxy inverso delante y almacenamiento persistente para que las notas no se perdieran al reiniciar el servicio. Esa sencillez también fue parte de su atractivo.
El despliegue en VPS: simple, pero bien hecho
El recorrido empezó como empiezan casi todos los despliegues pequeños: preparando el servidor. En este caso, la base era una distro Linux con Docker Engine y el plugin de Docker Compose. Nada raro. Lo importante no era tanto instalar Docker, sino dejar el entorno listo para que Enclosed no quedara expuesto de forma improvisada.
La primera prueba se podía hacer con un docker run muy corto, suficiente para confirmar que la aplicación levantaba y escuchaba en el puerto 8787:
docker run -d \
--name enclosed \
--restart unless-stopped \
-p 8787:8787 \
corentinth/enclosed
Eso servía para validar que todo funcionaba, pero era solo una prueba. Para un uso real, el siguiente paso natural era montar persistencia y pasar a docker compose, porque ahí el despliegue se vuelve más legible y más fácil de mantener.
La configuración base quedaba así:
services:
enclosed:
image: corentinth/enclosed:latest
container_name: enclosed
restart: unless-stopped
ports:
- "127.0.0.1:8787:8787"
volumes:
- enclosed-data:/app/.data
environment:
- PORT=8787
- AUTHENTICATION_JWT_SECRET=CAMBIA_ESTE_VALOR
- PUBLIC_IS_AUTHENTICATION_REQUIRED=false
- PUBLIC_DEFAULT_NOTE_TTL_SECONDS=86400
- TASK_DELETE_EXPIRED_NOTES_ENABLED=true
volumes:
enclosed-data:
driver: local
Hay varias cosas que me gustaron de esta etapa. La primera es que el despliegue no pedía una pila enorme. La segunda es que muchas decisiones importantes estaban expuestas de forma explícita en variables de entorno: el secreto JWT, el tiempo por defecto de expiración, si se exigiría autenticación o no, y si la limpieza de notas expiradas quedaría activada.
Ahí Enclosed deja de ser solo una aplicación curiosa y empieza a sentirse como una herramienta seria.
Cuando la seguridad deja de ser discurso y se vuelve configuración
Una vez que el contenedor estaba en pie, el punto delicado ya no era la aplicación, sino la exposición del servicio. Si iba a usarse para compartir información sensible, no tenía sentido dejarlo colgando directamente por HTTP.
Por eso el siguiente movimiento fue colocar Nginx por delante y emitir certificados con Let’s Encrypt. Ese paso, aunque bastante estándar, era clave porque convertía un experimento funcional en un servicio presentable.
La idea era mantener Enclosed escuchando solo en localhost y dejar que Nginx se encargara del acceso externo, del redireccionamiento a HTTPS y del encabezado correcto hacia el backend.
Un bloque como este resolvía la parte central:
server {
listen 443 ssl http2;
server_name notas.tudominio.com;
ssl_certificate /etc/letsencrypt/live/notas.tudominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/notas.tudominio.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
En este punto el proyecto ya tenía forma: una URL propia, tráfico cifrado y un backend reducido a lo estrictamente necesario.
Lo que más termina importando: expiración, acceso y tamaño
Cuando una herramienta está pensada para privacidad, el valor real aparece en los detalles. Enclosed tiene varios, pero tres me parecieron especialmente importantes.
El primero es el TTL por defecto. Si el servicio iba a usarse para compartir datos temporales, tenía sentido que la caducidad viniera activada desde el inicio, no como una opción que alguien podría olvidar. En mi caso, 86400 segundos, es decir un día, era una base razonable para notas operativas.
El segundo es la posibilidad de exigir autenticación para crear notas. Dependiendo del proyecto, eso puede marcar una gran diferencia. Si se activa PUBLIC_IS_AUTHENTICATION_REQUIRED=true, la aplicación deja de ser un buzón público y pasa a ser un servicio controlado por usuarios autorizados.
El tercero es el tamaño máximo del payload cifrado. No solo porque define si la herramienta servirá para texto o para adjuntos, sino porque obliga a pensar el alcance real del servicio. Eso también me gustó: Enclosed invita a acotar el caso de uso. No intenta ser Dropbox. Intenta ser un mecanismo seguro para compartir algo puntual.
La alternativa que también tiene sentido: Cloudflare Workers
Mientras avanzaba con la opción del VPS, me pareció útil revisar la otra posibilidad: Cloudflare Workers con KV como almacenamiento. La ventaja es obvia. No hay que administrar servidor, actualizaciones del sistema, Nginx ni certificados. El servicio se despliega sobre la infraestructura de Cloudflare y queda disponible con un costo muy bajo o incluso nulo en escenarios pequeños.
Conceptualmente, la arquitectura se reduce mucho:
Usuario -> Cloudflare Workers -> KV Namespace
El despliegue también es bastante directo. Se crea el namespace KV, se configura wrangler.toml, se compila el proyecto y se publica.
name = "enclosed"
main = "packages/app-server/dist/cloudflare/worker.js"
compatibility_date = "2024-01-01"
[[kv_namespaces]]
binding = "notes"
id = "<ID_DEL_NAMESPACE>"
[vars]
STORAGE_DRIVER_CLOUDFLARE_KV_BINDING = "notes"
PUBLIC_IS_AUTHENTICATION_REQUIRED = "false"
Lo veo como una muy buena opción para pruebas, uso personal o equipos pequeños que quieran velocidad de despliegue y poco mantenimiento.
Ahora bien, si la prioridad del proyecto está en la soberanía de datos, el VPS sigue teniendo ventaja. En Cloudflare hay una limitación además importante: la limpieza periódica automática de notas expiradas no está disponible de la misma manera que en Node/VPS. No es un detalle menor si uno está construyendo precisamente alrededor de la idea de caducidad.
Con cuál me quedaría
Si alguien me preguntara hoy por cuál camino empezar, diría algo bastante simple.
Si el proyecto necesita salir rápido, tiene poco tráfico y no exige demasiadas garantías de control sobre la infraestructura, Cloudflare es una alternativa elegante.
Si el proyecto toca información sensible, si importa el control del entorno o si se quiere una operación más predecible, un VPS con Docker y Nginx sigue siendo el mejor camino.
En mi caso, la historia empezó con una necesidad muy concreta: compartir datos sensibles sin dejarlos flotando por ahí indefinidamente. Y terminó en una implementación que me gustó justamente porque no intentaba resolver más de lo necesario.
Enclosed hace una cosa, y la hace bien: tomar una nota privada, cifrarla, compartirla y dejar que desaparezca cuando ya cumplió su propósito.
Al final, eso era exactamente lo que estaba buscando desde el principio. Un pequeño mensaje de Misión Imposible, pero esta vez corriendo en mi propia infraestructura.
Recursos
- Repositorio oficial: CorentinTh/enclosed
- Documentación: docs.enclosed.cc