docker compose up -d de un YAML de 30 líneas, tienes el mismo resultado en 90 segundos. Esa diferencia es el motivo por el que Docker se ha comido el mundo del despliegue.
docker run hello-world y no responde, vuelve a la 33 y arregla la instalación antes de seguir. Esta práctica va a tirar de los fundamentos que aprendiste allí (volúmenes, redes, Compose, logs, exec).
Objetivos de la práctica
- Entender qué es Nextcloud y por qué tiene sentido autohospedar servicios en lugar de depender de la nube comercial.
- Diseñar un stack multi-servicio realista (aplicación + base de datos + túnel) y describirlo en un único
docker-compose.yml. - Resolver el problema clásico del acceso desde el exterior sin tocar el router, sin IP fija y sin dominio, mediante Cloudflare Tunnel en modo quick.
- Comprender la diferencia entre exponer puertos hacia internet "a la antigua" (port forwarding + DDNS + certificado SSL) y un túnel saliente.
- Configurar Nextcloud con su CLI (
occ) desde dentro del contenedor:trusted_domains,overwriteprotocol,overwrite.cli.url. - Conectar la app móvil de Nextcloud a tu servidor publicado y activar la auto-subida de fotos: cuando hagas una foto con el móvil, aparecerá segundos después en el navegador del portátil.
- Compartir archivos por enlace público con caducidad y contraseña.
- Diagnosticar cinco fallos típicos de un despliegue Nextcloud detrás de túnel: URL del túnel cambiada, base de datos caída, volumen mal montado, archivo demasiado grande, túnel sin conectividad.
- Distinguir la opción gratuita y temporal (
trycloudflare.com) de un despliegue serio con dominio propio y túnel nombrado, y saber cuándo elegir cada una. - Documentar el despliegue en una ficha técnica reutilizable.
Parte 0 - Conceptos previos (60 min)
0.1 - Qué es Nextcloud
Nextcloud es una plataforma libre de servicios "tipo nube" autoalojable. Lo más conocido es la sincronización y compartición de archivos (estilo Dropbox), pero por encima incluye fotos (estilo Google Photos), calendario y contactos (compatible con CalDAV/CardDAV, sustituye a Google Calendar), notas, tareas, ofimática colaborativa (Collabora/OnlyOffice), videoconferencia (Talk), chat tipo Slack (Deck), gestor de contraseñas... todo en una sola interfaz web y un solo conjunto de usuarios.
Lo usan administraciones europeas (gobierno francés, Comisión Europea), universidades, hospitales y miles de pymes que no quieren que sus datos sensibles vivan en Google o Microsoft.
0.2 - Autohospedar vs nube comercial
| Aspecto | Servicio comercial (Drive, Dropbox) | Autohospedado (Nextcloud) |
|---|---|---|
| Coste mensual | 5-10 €/mes por usuario | El de tu equipo y conexión |
| Capacidad | Lo que pagues | Lo que tengas en disco |
| Privacidad | Sus servidores, sus reglas, sus subcontratistas | Tus datos no salen de tu equipo |
| Disponibilidad | 99.9% gestionada por ellos | La que mantengas tú |
| Curva de aprendizaje | Cero | Esta práctica |
| Dependencia de empresa externa | Total | Ninguna |
No es "uno mejor que otro": son herramientas distintas. Para una pyme de cinco personas que mueve documentos sensibles, Nextcloud autoalojado en un NAS o un servidor barato es perfectamente razonable. Para un usuario doméstico que no quiere mantener nada, Google Drive es más sensato.
0.3 - Arquitectura típica de Nextcloud
Nextcloud no es un único proceso, son varios servicios trabajando juntos:
| Componente | Qué hace | Cuándo es opcional |
|---|---|---|
| App de Nextcloud (PHP + Apache) | El servidor web con todo el código de Nextcloud | Imprescindible |
| Base de datos (MariaDB, PostgreSQL o SQLite) | Guarda metadatos: usuarios, archivos, permisos, calendarios | Imprescindible (SQLite vale para una persona; MariaDB para todo lo demás) |
| Caché (Redis) | Acelera consultas y bloqueos de archivos en accesos concurrentes | Opcional pero muy recomendado en producción |
| Cron | Tareas en segundo plano (limpieza, notificaciones, indexado) | Imprescindible (puede correr dentro del propio contenedor de la app) |
| Proxy / túnel | Pone HTTPS delante y/o publica el servicio | Imprescindible si lo expones a internet |
En esta práctica vas a montar tres contenedores: app, base de datos y túnel. Sin Redis (innecesario para uno o dos usuarios) y con cron embebido en la app. Es una configuración suficiente para cuatro o cinco usuarios reales.
0.4 - El problema clásico del acceso desde el exterior
Tu portátil tiene una IP privada (192.168.x.x). El router del aula tiene una IP pública asignada por el ISP, pero esa IP suele cambiar cada poco tiempo y, sobre todo, hay un router de por medio que no deja entrar conexiones por defecto. Para publicar un servicio a la antigua usanza necesitarías:
- Abrir un puerto en el router (port forwarding) hacia tu portátil: en una red ajena (aula, oficina, hotel) esto no es opción.
- Saber tu IP pública en cada momento (DDNS: noip.com, duckdns.org).
- Conseguir un certificado HTTPS válido para que los navegadores no chillen (Let's Encrypt requiere un dominio).
- Tener un dominio propio.
- Asumir que tu IP queda expuesta a escaneos automáticos de internet (botnets que buscan servicios mal configurados 24/7).
Con Cloudflare Tunnel resuelves los cinco puntos a la vez sin tocar nada.
0.5 - Cómo funciona Cloudflare Tunnel
El truco es invertir el sentido de la conexión. En lugar de que internet llame a tu portátil (lo que requiere abrir puertos), tu portátil establece una conexión saliente hacia los servidores de Cloudflare y la mantiene abierta. Cuando alguien quiere acceder a tu servicio:
- El visitante teclea
https://random-words.trycloudflare.com. - La petición HTTPS llega a un servidor de Cloudflare en el datacenter más cercano al visitante.
- Cloudflare la enruta por el túnel saliente que tu portátil mantiene abierto.
- Tu cliente
cloudflaredrecibe la petición, la pasa al contenedor de Nextcloud, recoge la respuesta y la devuelve por el túnel. - Cloudflare la sirve al visitante con HTTPS válido (el certificado lo aporta Cloudflare).
0.6 - Modo quick vs modo nombrado
| Aspecto | Modo quick (esta práctica) | Modo nombrado (producción) |
|---|---|---|
| Cuenta Cloudflare | No hace falta | Sí (gratuita) |
| Dominio propio | No hace falta | Sí |
| URL | random-words.trycloudflare.com generada al vuelo | nube.tudominio.com |
| Persistencia | La URL cambia cada vez que reinicias el túnel | Permanente |
| Para qué sirve | Demos, pruebas, talleres, este aula | Despliegue real para usuarios |
| Coste | 0 € | 0 € (sólo el dominio, ~10 €/año) |
En esta práctica usamos modo quick porque "no tenemos dominio". Al final mencionaremos cómo se daría el salto a modo nombrado el día que tengas uno.
0.7 - Metodología de la práctica
Vamos en este orden, idéntico al de la práctica 33:
- Levantar Nextcloud sólo en local y verificar que arranca (Parte 1).
- Aprender a no perder los datos: volúmenes y backup básico (Parte 2).
- Añadir el túnel y publicarlo a internet (Parte 3).
- Conectar la app del móvil y activar auto-subida de fotos (Parte 4).
- Romper a propósito y diagnosticar (Parte 5).
- Endurecer y planear el siguiente paso (Parte 6).
- Documentar (Parte 7).
Parte 1 - Levantar Nextcloud en local con Compose (50 min)
Primero vas a montar Nextcloud sólo accesible desde tu propio Windows en http://localhost:8080. Sin túnel, sin internet, sólo verificar que el stack funciona. Cuando esté firme añadiremos la publicación.
1.1 - Crear la carpeta de trabajo
- En el Explorador de Windows, crea una carpeta
C:\docker\nextcloud. - Dentro de ella crearás un único archivo,
docker-compose.yml. Los datos no irán aquí: Docker los mete en volúmenes propios para que sobrevivan a borrar el contenedor.
1.2 - El docker-compose.yml inicial
Crea el archivo C:\docker\nextcloud\docker-compose.yml con este contenido. Usa Visual Studio Code o cualquier editor de texto (Notepad también sirve, pero asegúrate de que al guardar no le añade .txt: en el diálogo "Guardar como", elige "Todos los archivos" en el desplegable de tipo).
services:
db:
image: mariadb:11
restart: unless-stopped
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
environment:
MARIADB_ROOT_PASSWORD: rootsecreto
MARIADB_DATABASE: nextcloud
MARIADB_USER: nextcloud
MARIADB_PASSWORD: ncsecreto
volumes:
- db:/var/lib/mysql
app:
image: nextcloud:stable
restart: unless-stopped
ports:
- "8080:80"
environment:
MYSQL_HOST: db
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: ncsecreto
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: cambiame
NEXTCLOUD_TRUSTED_DOMAINS: localhost
depends_on:
- db
volumes:
- nc_html:/var/www/html
volumes:
db:
nc_html:
Lee el archivo entero antes de seguir. Los puntos clave:
- Dos servicios ahora mismo:
db(MariaDB) yapp(Nextcloud). El túnel lo añadimos en la Parte 3. - El command de MariaDB con
READ-COMMITTEDybinlog-format=ROWes lo que pide la documentación oficial de Nextcloud para evitar bloqueos extraños bajo carga. - Las contraseñas en texto plano son aceptables para una práctica, pero en producción se usan secrets de Compose o variables de entorno externas, nunca el archivo en git.
NEXTCLOUD_TRUSTED_DOMAINS: localhostindica desde qué dominios admite peticiones. Si entras desde un dominio que no esté en la lista, Nextcloud te bloquea. Esta sutileza generará el primer fallo de la Parte 5.- Dos volúmenes con nombre:
db(datos de MariaDB) ync_html(todo el árbol de Nextcloud, que incluye sus archivos). Sobrevivirán a uncompose down.
1.3 - Primer arranque
Abre PowerShell, sitúate en la carpeta y arranca:
cd C:\docker\nextcloud docker compose up -d docker compose ps
El primer up tarda un par de minutos: descarga las imágenes (Nextcloud son ~700 MB, MariaDB ~150 MB) e inicializa la base de datos. Mira los logs en directo en otra ventana de PowerShell para entender qué pasa:
docker compose logs -f app
Verás líneas como "Initializing nextcloud...", "Installing with MySQL database", "Apache/2.4.x ... configured -- resuming normal operations". Cuando aparezca esa última línea, Nextcloud está listo. Ctrl+C para salir del log (no para el contenedor, sólo deja de mostrar logs).
| Tiempo aproximado de arranque del primer up | |
STATUS de los dos contenedores en docker compose ps |
1.4 - Primera entrada por el navegador
- Abre
http://localhost:8080en tu navegador. - Te sale la pantalla de login (no la de instalación:
NEXTCLOUD_ADMIN_USERyNEXTCLOUD_ADMIN_PASSWORDya hicieron la instalación inicial automática). - Entra con
admin/cambiame. - Cierra el tour de bienvenida si aparece.
Ya estás dentro de tu Nextcloud. Tienes una nube privada en local. Date una vuelta:
- Subir un archivo arrastrándolo desde el escritorio.
- Crear una carpeta y subir varios archivos dentro.
- Botón + → "Plantillas": Nextcloud trae plantillas de documentos.
- Esquina superior derecha → tu avatar → Aplicaciones: ojea el catálogo enorme de aplicaciones que se pueden activar.
| Nombre del primer archivo que has subido | |
| Tamaño que reporta Nextcloud para ese archivo |
1.5 - Cambiar la contraseña de admin
"cambiame" es un nombre que pide a gritos que lo cambies. Hazlo desde la propia interfaz: avatar → Configuración personal → Seguridad → Cambiar contraseña. Ponle una contraseña fuerte de verdad: la vas a publicar a internet en la Parte 3.
| ¿Has cambiado la contraseña de admin? |
1.6 - Comprobar la línea de comandos de Nextcloud (occ)
Nextcloud trae una herramienta CLI llamada occ que permite hacer absolutamente todo desde dentro: gestionar usuarios, configurar parámetros, reparar la BD, generar informes. Vas a usarla mucho en la Parte 3 y en los diagnósticos. Pruébala ahora:
docker compose exec --user www-data app php occ status docker compose exec --user www-data app php occ user:list docker compose exec --user www-data app php occ config:system:get trusted_domains
El --user www-data es necesario porque Apache/PHP corre como ese usuario y los archivos pertenecen a él; ejecutar occ como root da problemas de permisos.
Versión de Nextcloud que reporta occ status | |
| Trusted domains actuales |
Acabas de levantar Nextcloud con dos contenedores y un YAML de 30 líneas. Calcula a ojo cuánto tardarías en montar lo mismo "a mano" en una Ubuntu virgen (instalar Apache, PHP con sus 15 módulos, MariaDB, configurar el virtualhost, descomprimir Nextcloud, ajustar permisos, ejecutar el asistente). ¿Por qué esta diferencia es la razón por la que Docker se ha extendido tanto?
Parte 2 - Persistencia y backup básico (30 min)
Antes de exponer nada a internet, tienes que demostrarte a ti mismo que los datos sobreviven a borrar contenedores. Si esto falla, lo descubres ahora; no cuando tengas 200 fotos del móvil sincronizadas.
2.1 - Inspeccionar los volúmenes
docker volume ls | findstr nextcloud docker volume inspect nextcloud_db docker volume inspect nextcloud_nc_html
El prefijo nextcloud_ lo añade Compose porque se llama así la carpeta. Anota la ruta del campo Mountpoint: ahí dentro de WSL2 viven tus datos.
Mountpoint del volumen nc_html |
2.2 - El experimento "borro y recreo"
- Sube un archivo nuevo desde el navegador, por ejemplo prueba_persistencia.txt.
- Para los contenedores conservando los volúmenes:
docker compose down
Verás que para y elimina los dos contenedores y la red. Los volúmenes no se tocan. - Comprueba:
docker volume ls | findstr nextcloud— ahí siguen. - Vuelve a levantar el stack:
docker compose up -d
Esta vez es rápido (no descarga imágenes ni recrea la BD). - Entra a
http://localhost:8080con tu usuario admin: el archivo prueba_persistencia.txt sigue ahí.
2.3 - Lo que NO hay que hacer
docker compose down -v
El flag -v elimina también los volúmenes. Es la forma de empezar de cero, pero borra todos los datos sin preguntar. Memoriza la diferencia: down sin flag conserva datos; down -v los pulveriza.
docker compose down -v "para reiniciar el problema desde cero" y se carga 6 meses de datos sincronizados. Por eso, en producción nunca se ejecuta ese comando sin un backup previo.
2.4 - Backup mínimo viable
Backup serio = dump de la BD + copia del volumen de archivos. Para esta práctica te basta saber el patrón:
# 1. Dump de la base de datos a un archivo del host
docker compose exec db sh -c "mariadb-dump -uroot -prootsecreto nextcloud" > backup_db.sql
# 2. Copiar el contenido del volumen de archivos a un .tar dentro del host
docker run --rm -v nextcloud_nc_html:/data -v ${PWD}:/backup alpine `
tar czf /backup/backup_nc_html.tgz -C /data .
El segundo comando levanta un contenedor Alpine efímero, le monta el volumen de Nextcloud en /data y la carpeta actual de Windows en /backup, y comprime los datos en un .tgz dentro de tu carpeta. Es el patrón canónico para hacer backup de un volumen Docker desde el anfitrión sin instalar nada.
Ejecútalo y comprueba que se generan dos archivos en la carpeta C:\docker\nextcloud. Apunta el tamaño del .tgz: te da una idea de cuánto pesa Nextcloud "vacío".
Tamaño de backup_db.sql | |
Tamaño de backup_nc_html.tgz |
Parte 3 - Publicar en internet con Cloudflare Tunnel (60 min)
Hasta aquí tienes una nube privada que sólo tú ves desde tu Windows. Ahora vas a darle URL pública HTTPS sin tocar nada del router.
3.1 - Añadir el servicio cloudflared al compose
Edita C:\docker\nextcloud\docker-compose.yml y añade un tercer servicio al final, justo antes del bloque volumes::
services:
db:
# ... lo de antes, sin cambios
app:
# ... lo de antes, sin cambios
tunnel:
image: cloudflare/cloudflared:latest
restart: unless-stopped
command: tunnel --no-autoupdate --url http://app:80
depends_on:
- app
volumes:
db:
nc_html:
El comando tunnel --url http://app:80 en modo quick (sin token, sin cuenta) hace dos cosas:
- Establece una conexión saliente al edge de Cloudflare.
- Solicita una URL
*.trycloudflare.comaleatoria que enrute haciahttp://app:80(el servicio Nextcloud, accesible por DNS dentro de la red de Compose con el nombreapp).
3.2 - Levantar el túnel
docker compose up -d docker compose ps docker compose logs tunnel
En los logs verás algo parecido a esto:
tunnel-1 | 2026-... INF +--------------------------------------------------------------------------------------------+ tunnel-1 | 2026-... INF | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): | tunnel-1 | 2026-... INF | https://random-words-here.trycloudflare.com | tunnel-1 | 2026-... INF +--------------------------------------------------------------------------------------------+
Esa URL es tuya, ahora mismo, accesible desde cualquier dispositivo con internet en el mundo. Cópiala. Para verla cómodamente en cualquier momento:
docker compose logs tunnel | Select-String trycloudflare
| URL pública que te ha dado el túnel |
3.3 - El primer susto: "Access through untrusted domain"
Abre la URL del túnel en tu navegador. Te aparecerá una pantalla blanca con texto del tipo:
Access through untrusted domain Please contact your administrator. If you are an administrator, edit the "trusted_domains" setting in config/config.php like the example in config.sample.php.
Es el comportamiento de seguridad que mencionamos en la Parte 1.4. Nextcloud sólo acepta peticiones desde dominios autorizados. localhost está en la lista, random-words.trycloudflare.com no.
3.4 - Añadir el dominio del túnel a trusted_domains
Sustituye random-words.trycloudflare.com por la URL real que te dio tu túnel (sin https://) y ejecuta:
docker compose exec --user www-data app php occ config:system:set ` trusted_domains 1 --value=random-words.trycloudflare.com
El "1" es la posición en el array de dominios (la 0 está ocupada por localhost que vino del compose). Si ahora consultas:
docker compose exec --user www-data app php occ config:system:get trusted_domains
...verás los dos dominios. Recarga la URL del túnel en el navegador. Esta vez aparece el login de Nextcloud.
3.5 - Configurar URLs absolutas para el túnel
Hay dos parámetros más que es importante poner cuando Nextcloud está detrás de un túnel/proxy con HTTPS terminado fuera (caso de Cloudflare):
docker compose exec --user www-data app php occ config:system:set ` overwriteprotocol --value=https docker compose exec --user www-data app php occ config:system:set ` overwrite.cli.url --value=https://random-words.trycloudflare.com docker compose exec --user www-data app php occ config:system:set ` overwritehost --value=random-words.trycloudflare.com
Sin esto Nextcloud puede generar enlaces internos en HTTP (cuando todo el mundo le habla por HTTPS), o usar localhost en URLs de notificaciones por correo. Estos tres parámetros le dicen "ignora lo que veas en las cabeceras y asume siempre esta URL pública".
3.6 - Probar desde otro dispositivo
El acid test:
- Coge tu móvil. Desactiva el WiFi y déjalo con datos 4G/5G. Eso garantiza que la conexión no pasa por la red del aula y demuestra que la URL es realmente pública.
- Abre el navegador del móvil y entra a la URL del túnel.
- Loguéate con admin y la contraseña que pusiste.
- Sube una foto desde el móvil arrastrándola al botón +.
- Vuelve al portátil y refresca: la foto está ahí.
Acabas de hacer subir un archivo desde tu móvil con 4G a un servidor que tienes en tu portátil del aula sin abrir un puerto. Esto es el "wow" de la práctica. Si funciona, todo el resto va a fluir.
| ¿Cargó el login de Nextcloud desde el móvil con 4G? | |
| ¿Aparece la foto subida en el navegador del portátil al refrescar? | |
| Latencia subjetiva (rápido / normal / lento) |
3.7 - Compartir un archivo por enlace público
- En la web, clic en el icono de "compartir" de un archivo.
- Pestaña Enlaces compartidos → +.
- Activa la caducidad a tres días y pon una contraseña.
- Copia el enlace y mándatelo por WhatsApp/Telegram a ti mismo.
- Ábrelo en el móvil. Te pide la contraseña, la metes y descargas el archivo.
Esto es lo que hace WeTransfer. Acabas de implementarlo en tu propio servidor en cinco clics. Sin límite de 2 GB, sin publicidad, sin caducidad obligatoria a los tres días.
Explica con tus palabras qué papel juega Cloudflare en esta arquitectura. ¿Por qué tu portátil no tiene que abrir ningún puerto en el router? ¿Qué pasa si tu portátil pierde la conexión a internet durante 30 segundos?
Parte 4 - App móvil y auto-subida de fotos (40 min)
El navegador del móvil sirve para empezar, pero la experiencia "Google Photos" la da la app oficial de Nextcloud: corre en segundo plano y va subiendo cada foto que haces a tu servidor automáticamente.
4.1 - Instalar la app oficial
- En el móvil, abre Play Store (Android) o App Store (iOS).
- Busca Nextcloud e instala la app oficial (autor: Nextcloud GmbH; tiene el logo azul en forma de nube).
- Ábrela y pulsa Iniciar sesión.
- En "Dirección del servidor" pega la URL del túnel (la
https://...trycloudflare.com). - La app abre el navegador del móvil, te pide login (admin + contraseña), pulsas Conceder acceso, y vuelve a la app.
Si todo va bien, la app muestra tus archivos. Si te da error de SSL o "no se puede conectar", revisa que la URL del túnel sigue activa (docker compose logs tunnel) y que has añadido el dominio a trusted_domains.
4.2 - Activar auto-subida de fotos
- Dentro de la app, menú lateral → Auto-subida.
- Activa la cámara como carpeta a sincronizar.
- Elige carpeta destino en el servidor: Photos es buena opción (la crea Nextcloud por defecto).
- Activa la subida también con datos móviles si quieres ser radical (ojo al consumo).
- Acepta los permisos que pida Android/iOS para acceder a la galería en segundo plano.
4.3 - El experimento "haz una foto y mírala en el portátil"
- Cierra la app de Nextcloud (déjala en segundo plano).
- Abre la cámara del móvil. Haz una foto cualquiera.
- Espera 30-60 segundos. La app de Nextcloud detecta la foto nueva, la sube en segundo plano.
- En el portátil, abre
https://...trycloudflare.comy entra a la carpeta Photos. - Ahí está la foto recién hecha.
Acabas de implementar Google Photos en tu propio servidor. Cualquier foto que hagas, mientras la app esté instalada y haya internet, irá a tu nube privada en menos de un minuto.
| Hora exacta a la que hiciste la foto de prueba | |
| Hora a la que apareció en el portátil | |
| Tiempo total de propagación |
4.4 - Cliente de escritorio (opcional, +20 min)
Si quieres replicar el comportamiento de "carpeta de Dropbox", también hay cliente de escritorio para Windows/Mac/Linux:
- Descarga el cliente desde nextcloud.com/install, sección "Desktop clients".
- Instálalo en tu Windows.
- Conecta a la URL del túnel con admin y tu contraseña.
- Elige una carpeta local (por ejemplo
C:\Users\tu_usuario\Nextcloud) y déjalo sincronizar. - Mueve un archivo a esa carpeta. Se sincroniza al servidor en segundos. Refresca el navegador y aparece.
4.5 - Apps útiles que puedes activar
En el navegador, avatar → Aplicaciones. Algunas que pruebas en cinco segundos y se te quedan:
| App | Para qué |
|---|---|
| Calendario | Sustituto de Google Calendar. Sincroniza con el calendario nativo del móvil por CalDAV |
| Contactos | Lo mismo para la libreta de direcciones (CardDAV) |
| Notes | Sustituto de Google Keep / Apple Notes con sincronización entre dispositivos |
| Tasks | Lista de tareas con CalDAV |
| Talk | Chat y videoconferencia tipo WhatsApp/Zoom dentro de tu propia nube |
| Deck | Tableros tipo Trello para organizar proyectos |
Parte 5 - Provocar y diagnosticar tus propios fallos (90 min)
Igual que en las dos prácticas anteriores, vas a romper a propósito cinco cosas, hacer como si te las acabases de encontrar y diagnosticar. Esta vez los fallos son los típicos de un Nextcloud expuesto detrás de un túnel.
5.1 - Caso A - El túnel se reinicia y la URL cambia
Qué rompes: reinicias el contenedor del túnel. Modo quick = URL nueva al arrancar. Resultado: tu app móvil deja de conectar, los enlaces compartidos que mandaste por WhatsApp dan 404, los clientes de escritorio fallan.
docker compose restart tunnel docker compose logs tunnel | Select-String trycloudflare
La nueva URL es distinta de la anterior. Si abres la antigua en el navegador, ya no responde.
Diagnostica:
- Síntoma del usuario: "ayer funcionaba, hoy desde el móvil no abre la nube".
- Primer reflejo: ¿está la app del servidor viva?
docker compose ps: sí, los tres contenedores Up. - ¿Responde en local? Abre
http://localhost:8080: sí, el portal va. - Por tanto el problema está entre el túnel y el cliente.
docker compose logs tunnel | Select-String trycloudflare: la URL actual del túnel es distinta de la que tenías guardada en el móvil. - Verifica entrando con la URL nueva en el navegador del portátil: vuelve a salir el login (o el "Access through untrusted domain" si todavía no añadiste la nueva URL a trusted_domains).
Repara:
- Añade la nueva URL a trusted_domains:
docker compose exec --user www-data app php occ config:system:set ` trusted_domains 1 --value=NUEVA-URL.trycloudflare.com
- Actualiza
overwrite.cli.urlyoverwritehostcon la nueva URL. - En el móvil, en la app de Nextcloud, ve a Configuración → tu cuenta → Eliminar cuenta y vuelve a iniciar sesión con la URL nueva.
Por qué pasa: el modo quick de Cloudflare Tunnel está pensado para demos y pruebas, no para servicios estables. La URL es efímera por diseño. Solución definitiva: dominio propio + túnel nombrado (Parte 6).
| URL antigua | |
| URL nueva tras el restart | |
| ¿Cuántos sitios has tenido que actualizar la URL? |
5.2 - Caso B - La base de datos se cae
Qué rompes: paras el contenedor de la base de datos. Nextcloud queda vivo pero sin BD detrás. Es la simulación clásica de "la BD se quedó sin disco" o "alguien reinició el servidor de BD por error".
docker compose stop db docker compose ps
Recarga la URL del túnel en el navegador. Tras un par de segundos verás un error "Internal Server Error" o una pantalla "MySQL server has gone away".
Diagnostica:
- Síntoma: la nube devuelve "Internal Server Error" desde cualquier navegador.
docker compose ps: la db aparece "Exited", la app sigue Up. Pista clave en 10 segundos.docker compose logs --tail 30 app: verás errores PHP del tipo "SQLSTATE[HY000] [2002] Connection refused" o similares.- Comprobación cruzada:
docker compose logs db | tail -10te dirá por qué se paró (en este caso, porque tú lo paraste; en producción podría ser un OOM-kill, falta de espacio, etc.).
Repara:
docker compose start db docker compose ps # vuelve a Up # espera 10-15 s a que MariaDB acabe de arrancar docker compose logs --tail 5 db
Recarga el navegador: Nextcloud vuelve. Apunta el tiempo desde que arrancas la BD hasta que el portal responde:
| Mensaje exacto que mostró el navegador | |
Línea más reveladora de docker compose logs app | |
Tiempo entre start db y "todo va" |
5.3 - Caso C - Se borró el volumen de datos sin querer
Qué rompes: simulas el horror absoluto. Alguien hace down -v "para reiniciar limpio" y se carga el volumen de la BD. Vas a ver la pantalla de bienvenida de Nextcloud como si fuese el primer día y a recuperar los datos del backup que (por suerte) hiciste en la Parte 2.
backup_db.sql y backup_nc_html.tgz en C:\docker\nextcloud. Si no los tienes, vuelve a la Parte 2.4 y créalos antes de seguir. Sin backup este caso te deja a cero de verdad.
- Para todo y borra los volúmenes:
docker compose down -v
- Confirma el desastre:
docker volume ls | findstr nextcloudya no muestra nada. - Levanta de nuevo:
docker compose up -d. Como los volúmenes se crearon vacíos, Nextcloud te recibirá con el asistente de instalación inicial (o pantalla de login con admin recién creado).
Diagnostica:
- Síntoma: "ayer tenía 200 fotos y hoy no hay nada en mi nube".
docker volume ls: hay volúmenes nuevos creados al instante (mira la columna CREATED condocker volume inspect).- Comparado con tu apunte de la Parte 2.1, son volúmenes distintos: los anteriores se borraron y se crearon otros vacíos.
- Causa:
docker compose down -vejecutado por alguien.
Repara restaurando los backups:
# 1. Restaurar el contenido del volumen de archivos
docker compose stop app
docker run --rm -v nextcloud_nc_html:/data -v ${PWD}:/backup alpine `
sh -c "cd /data && tar xzf /backup/backup_nc_html.tgz"
# 2. Restaurar la base de datos
docker compose start app
docker compose exec -T db sh -c "mariadb -uroot -prootsecreto nextcloud" < backup_db.sql
# 3. Reiniciar la app
docker compose restart app
Tras esto entras al portal y todos tus datos están ahí.
| Estado tras el down -v | |
| ¿Recuperaste todo lo que tenías? | |
| Tiempo total del incidente y restauración |
5.4 - Caso D - "Archivo demasiado grande"
Qué rompes: intentas subir un archivo de varios GB y la subida casca. Es uno de los problemas más comunes con Nextcloud detrás de un proxy/túnel: hay límites en varios sitios distintos y hay que tocarlos todos.
- Ten a mano un archivo grande. Genera uno rápido en PowerShell:
$arr = New-Object byte[] (1024 * 1024 * 1024) # 1 GB de bytes a cero [System.IO.File]::WriteAllBytes("C:\docker\nextcloud\big.bin", $arr) - Intenta subirlo desde el navegador a tu Nextcloud (a través de la URL del túnel).
- Es probable que falle con "Error en la subida" o similar.
Diagnostica:
- Mira en la web: avatar → Configuración de administración → Resumen. Nextcloud te dice qué problemas detecta.
docker compose logs --tail 30 apptras el intento: busca líneas con "upload" o "PHP Fatal error".- Por defecto PHP en la imagen de Nextcloud limita las subidas a algunos cientos de MB con
upload_max_filesizeypost_max_size. - Adicionalmente Cloudflare en plan gratuito limita las cargas a 100 MB por petición. Esto es una restricción externa que no se arregla tocando Nextcloud.
Repara (parcialmente):
- Sube el límite de PHP creando un archivo en el contenedor. Para no perder el cambio al recrear, en producción se usaría un volumen extra o una imagen propia. Para esta práctica vale con:
docker compose exec app sh -c "echo 'upload_max_filesize=2G' >> /usr/local/etc/php/conf.d/uploads.ini" docker compose exec app sh -c "echo 'post_max_size=2G' >> /usr/local/etc/php/conf.d/uploads.ini" docker compose restart app
- Ahora subiendo desde local (
http://localhost:8080) puedes subir archivos grandes. - Si lo subes por la URL del túnel, Cloudflare seguirá limitándolo a 100 MB por trozo. La solución es la subida fragmentada que el cliente de escritorio y la app móvil sí hacen automáticamente; el navegador no.
| Mensaje exacto al intentar la subida | |
| ¿Subió por localhost tras tocar PHP? | |
| ¿Subió por el túnel desde el cliente de escritorio? |
5.5 - Caso E - El túnel se queda sin internet
Qué rompes: simulas pérdida de conectividad de salida del túnel. La app del aula sigue funcionando (puede acceder por http://localhost:8080), pero los clientes externos no.
Forma sencilla de provocarlo: pausar el contenedor del túnel.
docker compose pause tunnel docker compose ps
El estado de tunnel aparece como Paused. Desde el móvil con 4G la URL del túnel deja de responder (o devuelve 530/502 desde Cloudflare).
Diagnostica:
- Síntoma: el usuario externo dice "no me carga". Tú internamente accedes sin problema.
docker compose ps: el túnel está Paused (o Exited, según el caso).docker compose logs --tail 20 tunnel: si está parado por un fallo real, verás errores de conexión a los edges de Cloudflare ("failed to dial", "context canceled").- En 4G, la respuesta HTTP de Cloudflare 530 o 1033 indica "el origen no está disponible": confirma que el problema está en tu lado.
Repara:
docker compose unpause tunnel docker compose logs tunnel | Select-String trycloudflare
Como el contenedor sólo se pausó, al despausarlo la conexión se restablece y la URL es la misma (no cambia, porque no se ha reiniciado la negociación inicial). Si hubieras hecho restart, sí cambiaría (eso es el Caso A).
| Código HTTP que devolvía Cloudflare en 4G mientras pausado | |
| ¿La URL se mantuvo tras unpause? |
5.6 - Tabla resumen de los cinco casos
| Caso | Tiempo total (min) | Comando que dio la pista clave | ¿Lo resolverías hoy en 5 minutos? |
|---|---|---|---|
| A - URL del túnel cambiada | |||
| B - BD caída | |||
| C - Volumen borrado | |||
| D - Archivo grande | |||
| E - Túnel pausado |
redis:alpine) y configura Nextcloud para usarlo como caché y para los bloqueos de archivos. Deberás tocar el config.php con varias entradas (memcache.local, memcache.locking, redis.host). Comprueba en la página de Resumen de la administración que los avisos de "memoria caché no configurada" desaparecen.
Parte 6 - Endurecimiento y siguientes pasos (30 min)
Lo que tienes ahora mismo es funcional pero "de juguete". Para que sea algo de lo que fiarte hay tres frentes a cerrar.
6.1 - Cuenta admin como Dios manda
Si todavía tienes la contraseña que pusiste en la Parte 1.5, evalúa en la página haveibeenpwned.com si está filtrada. En cualquier caso:
- Crea un usuario admin nuevo con un nombre no obvio:
docker compose exec --user www-data app php occ user:add ` --display-name="Tu Nombre" tu_nick_admin
Te pide la contraseña por stdin. - Promociónalo a admin:
docker compose exec --user www-data app php occ group:adduser admin tu_nick_admin
- Entra con el nuevo usuario y, ya logueado, deshabilita o elimina el usuario
adminoriginal.
Cualquier bot que escanee URLs de Nextcloud va a probar primero admin como usuario. Quitarle ese vector es un upgrade enorme con coste casi cero.
6.2 - Activar segundo factor (2FA)
En el portal: avatar → Configuración personal → Seguridad → activa TOTP (autentificador) y escanéalo con Google Authenticator, Aegis o el que uses. A partir de aquí cualquier login pide tu código del móvil.
6.3 - Limitaciones serias del modo quick
Recapitulando lo que has visto:
- La URL
trycloudflare.comcambia al reiniciar el túnel (Caso A). - Cloudflare puede capar uploads grandes a través del túnel quick.
- No puedes apuntar tu propio dominio a esa URL.
- Los términos de servicio dicen explícitamente que es para desarrollo y pruebas, no para producción.
Para algo serio el siguiente paso es:
6.4 - El día que tengas dominio: túnel nombrado
Es un procedimiento corto (lo dejamos como referencia, no para hacerlo en clase si no tenéis dominio):
- Compra un dominio (los
.euy.comrondan 8-12 €/año en Namecheap, OVH, Porkbun...). - Crea cuenta gratuita en Cloudflare y mete el dominio bajo gestión (cambias los nameservers en el registrador).
- En el panel de Cloudflare → Zero Trust → Networks → Tunnels → Create a tunnel. Le das nombre (nube) y te genera un token.
- En tu compose sustituyes el comando del servicio tunnel por:
command: tunnel --no-autoupdate run --token TU_TOKEN
- En el panel asocias
nube.tudominio.comal servicio internohttp://app:80.
Ya tienes URL fija con HTTPS válido y certificado renovado automáticamente. La parte de Nextcloud no cambia: el mismo occ config:system:set de las Partes 3.4 y 3.5.
6.5 - Backup automatizado
El backup de la Parte 2.4 es manual. En producción se programa con el Programador de tareas de Windows o, mejor, dentro del propio compose con un servicio que ejecute el dump cada noche y suba el resultado a un almacenamiento externo (otro NAS, S3, Backblaze B2). Patrón típico: contenedor con cron que ejecuta el dump y un cliente como restic o rclone. Fuera del alcance de esta práctica, pero anótalo como deberes.
De los tres frentes (cuenta admin segura, 2FA, dominio propio), ¿cuál harías el primer día y cuál puede esperar? ¿Por qué?
Parte 7 - Documentar el despliegue (25 min)
Esta vez la ficha cambia: en lugar de una incidencia puntual, vas a documentar el despliegue completo. Es el documento que dejarías a un compañero para que pueda mantener el servicio si tú no estás.
FICHA DE DESPLIEGUE - NEXTCLOUD AUTOALOJADO
Conclusiones y autoevaluación
Has montado, expuesto y usado una nube privada en una jornada. Sin Docker, calcula a ojo cuánto te habría llevado y cuántas cosas distintas habrías tenido que aprender (LAMP, certificados, port forwarding, DDNS, configuración de Apache...). ¿Qué función concreta de Docker te ha ahorrado más tiempo?
Compara la solución "abrir puertos del router + DDNS + Let's Encrypt" con "Cloudflare Tunnel". ¿Qué ventajas e inconvenientes tiene cada una en términos de seguridad, mantenimiento y dependencia de un tercero?
Una pyme de 8 empleados quiere dejar de pagar 80 €/mes en Microsoft 365 y montar su propia nube. ¿Recomendarías Nextcloud autoalojado? Lista al menos tres condiciones que tendrían que cumplir para que sea sensato.
El responsable de seguridad te pregunta si exponer Nextcloud a internet con Cloudflare Tunnel es seguro. ¿Qué respondes y qué medidas mínimas le pedirías al usuario para considerarlo "razonablemente seguro"?
Compara las prácticas 33 (Docker básico) y 34 (Nextcloud + Tunnel). ¿Qué concepto de la 33 te ha parecido más útil al hacer la 34? ¿Hay algo de la 33 que no hayas necesitado?
Autoevaluación
| Aspecto | Logrado |
|---|---|
| Entiendo qué es Nextcloud y qué problema resuelve frente a la nube comercial | |
| Sé describir la arquitectura mínima del stack (app + BD + túnel) | |
He levantado el stack con un único docker compose up -d | |
He probado que los datos sobreviven a un compose down (sin -v) | |
| Sé hacer backup y restore de un volumen Docker con un contenedor efímero + tar | |
| Entiendo cómo funciona Cloudflare Tunnel (conexión saliente, sin puertos abiertos) | |
He resuelto el aviso "Access through untrusted domain" con occ | |
| He accedido a mi nube desde el móvil con 4G, sin pasar por la WiFi del aula | |
| Tengo la app móvil de Nextcloud sincronizando fotos automáticamente | |
| He compartido al menos un archivo por enlace público con caducidad y contraseña | |
| He provocado y resuelto los cinco fallos de la Parte 5 | |
| Diferencio modo quick (URL temporal) de modo nombrado (URL fija con dominio) | |
| He cambiado la contraseña de admin a una contraseña fuerte | |
| He rellenado la ficha de despliegue completa |