← Teoría

Práctica 34: Nextcloud autoalojado y publicado en internet con Cloudflare Tunnel

Módulo: Práctica adicional - servicios autohospedados con contenedores
Requisito previo: Práctica 33 (Docker Desktop en Windows 11) terminada
Sesiones: práctica extra
Duración estimada: 7-8 horas (puede partirse en dos sesiones)
Modalidad: trabajo individual
Herramientas: Windows 11 anfitrión con Docker Desktop ya funcionando, smartphone Android o iOS, conexión a internet (la del aula sirve, pero al final probarás también desde 4G)
De qué va esta práctica: vas a montar tu propio Google Drive / iCloud / OneDrive en tu portátil. Una nube real, con interfaz web, con clientes para móvil y escritorio, con sincronización de fotos del móvil, con compartición por enlace, en la que tú eres el dueño de los datos. Y la vas a publicar en internet con una URL pública HTTPS sin abrir un solo puerto del router del aula, sin contratar dominio, sin pagar nada. La vas a poder enseñar a tus padres conectándose desde su 4G y verán tus archivos. Es la práctica de Docker que demuestra para qué sirven los contenedores: una herramienta seria, multi-servicio, levantada en cinco minutos.
Por qué Nextcloud: Nextcloud es una alternativa libre y autoalojable a Google Drive, Dropbox, OneDrive y Google Photos juntos. Lo usan miles de empresas, universidades y administraciones europeas para no depender de los gigantes americanos. Sin Docker, instalarlo "a mano" lleva 1-2 horas (Apache, PHP, MariaDB, Redis, certificado SSL, configuración, ajustes del kernel...). Con un 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.
Antes de empezar: necesitas tener la práctica 33 superada y Docker Desktop funcionando en tu Windows 11. Si arrancas un 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

AspectoServicio comercial (Drive, Dropbox)Autohospedado (Nextcloud)
Coste mensual5-10 €/mes por usuarioEl de tu equipo y conexión
CapacidadLo que paguesLo que tengas en disco
PrivacidadSus servidores, sus reglas, sus subcontratistasTus datos no salen de tu equipo
Disponibilidad99.9% gestionada por ellosLa que mantengas tú
Curva de aprendizajeCeroEsta práctica
Dependencia de empresa externaTotalNinguna

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:

ComponenteQué haceCuándo es opcional
App de Nextcloud (PHP + Apache)El servidor web con todo el código de NextcloudImprescindible
Base de datos (MariaDB, PostgreSQL o SQLite)Guarda metadatos: usuarios, archivos, permisos, calendariosImprescindible (SQLite vale para una persona; MariaDB para todo lo demás)
Caché (Redis)Acelera consultas y bloqueos de archivos en accesos concurrentesOpcional pero muy recomendado en producción
CronTareas en segundo plano (limpieza, notificaciones, indexado)Imprescindible (puede correr dentro del propio contenedor de la app)
Proxy / túnelPone HTTPS delante y/o publica el servicioImprescindible 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:

  1. Abrir un puerto en el router (port forwarding) hacia tu portátil: en una red ajena (aula, oficina, hotel) esto no es opción.
  2. Saber tu IP pública en cada momento (DDNS: noip.com, duckdns.org).
  3. Conseguir un certificado HTTPS válido para que los navegadores no chillen (Let's Encrypt requiere un dominio).
  4. Tener un dominio propio.
  5. 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:

  1. El visitante teclea https://random-words.trycloudflare.com.
  2. La petición HTTPS llega a un servidor de Cloudflare en el datacenter más cercano al visitante.
  3. Cloudflare la enruta por el túnel saliente que tu portátil mantiene abierto.
  4. Tu cliente cloudflared recibe la petición, la pasa al contenedor de Nextcloud, recoge la respuesta y la devuelve por el túnel.
  5. Cloudflare la sirve al visitante con HTTPS válido (el certificado lo aporta Cloudflare).
Por qué esto funciona en redes hostiles: el aula, la oficina, el hotel y el 4G del móvil bloquean conexiones entrantes, pero permiten conexiones salientes a HTTPS (como cualquier navegador). Cloudflare Tunnel sólo necesita poder salir hacia los servidores de Cloudflare, y todas las redes lo dejan.

0.6 - Modo quick vs modo nombrado

AspectoModo quick (esta práctica)Modo nombrado (producción)
Cuenta CloudflareNo hace faltaSí (gratuita)
Dominio propioNo hace falta
URLrandom-words.trycloudflare.com generada al vuelonube.tudominio.com
PersistenciaLa URL cambia cada vez que reinicias el túnelPermanente
Para qué sirveDemos, pruebas, talleres, este aulaDespliegue real para usuarios
Coste0 €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:

  1. Levantar Nextcloud sólo en local y verificar que arranca (Parte 1).
  2. Aprender a no perder los datos: volúmenes y backup básico (Parte 2).
  3. Añadir el túnel y publicarlo a internet (Parte 3).
  4. Conectar la app del móvil y activar auto-subida de fotos (Parte 4).
  5. Romper a propósito y diagnosticar (Parte 5).
  6. Endurecer y planear el siguiente paso (Parte 6).
  7. Documentar (Parte 7).
Idea clave: al terminar esta práctica habrás montado, expuesto a internet, sincronizado fotos del móvil y compartido por enlace una nube privada en menos de una jornada. Sin Docker, esto era trabajo de varias semanas y un servidor dedicado.

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

  1. En el Explorador de Windows, crea una carpeta C:\docker\nextcloud.
  2. 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) y app (Nextcloud). El túnel lo añadimos en la Parte 3.
  • El command de MariaDB con READ-COMMITTED y binlog-format=ROW es 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: localhost indica 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) y nc_html (todo el árbol de Nextcloud, que incluye sus archivos). Sobrevivirán a un compose 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

  1. Abre http://localhost:8080 en tu navegador.
  2. Te sale la pantalla de login (no la de instalación: NEXTCLOUD_ADMIN_USER y NEXTCLOUD_ADMIN_PASSWORD ya hicieron la instalación inicial automática).
  3. Entra con admin / cambiame.
  4. 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 personalSeguridadCambiar contraseña. Ponle una contraseña fuerte de verdad: la vas a publicar a internet en la Parte 3.

Crítico: hasta el final de la Parte 3 tu Nextcloud es inalcanzable desde fuera. Pero en cuanto lo expongas, cualquier bot de internet va a probar admin/admin, admin/password, admin/123456 contra tu URL en cuestión de minutos. Cambia la contraseña ahora, no luego.
¿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"

  1. Sube un archivo nuevo desde el navegador, por ejemplo prueba_persistencia.txt.
  2. 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.
  3. Comprueba: docker volume ls | findstr nextcloud — ahí siguen.
  4. Vuelve a levantar el stack:
    docker compose up -d
    Esta vez es rápido (no descarga imágenes ni recrea la BD).
  5. Entra a http://localhost:8080 con 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.

Trampa de novato número 1 con Nextcloud: alguien hace 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
Pregunta de entrevista: "¿cómo se hace backup de un volumen de Docker?". La respuesta canónica es exactamente la del segundo comando: contenedor efímero + dos montajes (volumen y destino) + tar. Apréndete el patrón.

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.com aleatoria que enrute hacia http://app:80 (el servicio Nextcloud, accesible por DNS dentro de la red de Compose con el nombre app).

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:

  1. 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.
  2. Abre el navegador del móvil y entra a la URL del túnel.
  3. Loguéate con admin y la contraseña que pusiste.
  4. Sube una foto desde el móvil arrastrándola al botón +.
  5. 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

  1. En la web, clic en el icono de "compartir" de un archivo.
  2. Pestaña Enlaces compartidos+.
  3. Activa la caducidad a tres días y pon una contraseña.
  4. Copia el enlace y mándatelo por WhatsApp/Telegram a ti mismo.
  5. Á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

  1. En el móvil, abre Play Store (Android) o App Store (iOS).
  2. Busca Nextcloud e instala la app oficial (autor: Nextcloud GmbH; tiene el logo azul en forma de nube).
  3. Ábrela y pulsa Iniciar sesión.
  4. En "Dirección del servidor" pega la URL del túnel (la https://...trycloudflare.com).
  5. 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

  1. Dentro de la app, menú lateral → Auto-subida.
  2. Activa la cámara como carpeta a sincronizar.
  3. Elige carpeta destino en el servidor: Photos es buena opción (la crea Nextcloud por defecto).
  4. Activa la subida también con datos móviles si quieres ser radical (ojo al consumo).
  5. 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"

  1. Cierra la app de Nextcloud (déjala en segundo plano).
  2. Abre la cámara del móvil. Haz una foto cualquiera.
  3. Espera 30-60 segundos. La app de Nextcloud detecta la foto nueva, la sube en segundo plano.
  4. En el portátil, abre https://...trycloudflare.com y entra a la carpeta Photos.
  5. 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:

  1. Descarga el cliente desde nextcloud.com/install, sección "Desktop clients".
  2. Instálalo en tu Windows.
  3. Conecta a la URL del túnel con admin y tu contraseña.
  4. Elige una carpeta local (por ejemplo C:\Users\tu_usuario\Nextcloud) y déjalo sincronizar.
  5. Mueve un archivo a esa carpeta. Se sincroniza al servidor en segundos. Refresca el navegador y aparece.
Reto extra: instala el cliente también en otro equipo (el de un compañero, tu sobremesa, lo que sea). Cuando subas algo en uno, aparece en el otro automáticamente. Eso es exactamente Dropbox/OneDrive y lo has montado tú con software libre.

4.5 - Apps útiles que puedes activar

En el navegador, avatar → Aplicaciones. Algunas que pruebas en cinco segundos y se te quedan:

AppPara qué
CalendarioSustituto de Google Calendar. Sincroniza con el calendario nativo del móvil por CalDAV
ContactosLo mismo para la libreta de direcciones (CardDAV)
NotesSustituto de Google Keep / Apple Notes con sincronización entre dispositivos
TasksLista de tareas con CalDAV
TalkChat y videoconferencia tipo WhatsApp/Zoom dentro de tu propia nube
DeckTableros 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.

Antes de empezar: haz un dump rápido de la BD (Parte 2.4) por si acaso. Y vuelve a apuntar la URL actual del túnel: la vas a perder en el primer caso.

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:

  1. Síntoma del usuario: "ayer funcionaba, hoy desde el móvil no abre la nube".
  2. Primer reflejo: ¿está la app del servidor viva? docker compose ps: sí, los tres contenedores Up.
  3. ¿Responde en local? Abre http://localhost:8080: sí, el portal va.
  4. 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.
  5. 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:

  1. 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
  2. Actualiza overwrite.cli.url y overwritehost con la nueva URL.
  3. En el móvil, en la app de Nextcloud, ve a Configuracióntu cuentaEliminar 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:

  1. Síntoma: la nube devuelve "Internal Server Error" desde cualquier navegador.
  2. docker compose ps: la db aparece "Exited", la app sigue Up. Pista clave en 10 segundos.
  3. docker compose logs --tail 30 app: verás errores PHP del tipo "SQLSTATE[HY000] [2002] Connection refused" o similares.
  4. Comprobación cruzada: docker compose logs db | tail -10 te 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.

Asegúrate de tener los archivos 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.
  1. Para todo y borra los volúmenes:
    docker compose down -v
  2. Confirma el desastre: docker volume ls | findstr nextcloud ya no muestra nada.
  3. 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 con docker 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 -v ejecutado 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.

  1. 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)
  2. Intenta subirlo desde el navegador a tu Nextcloud (a través de la URL del túnel).
  3. Es probable que falle con "Error en la subida" o similar.

Diagnostica:

  • Mira en la web: avatar → Configuración de administraciónResumen. Nextcloud te dice qué problemas detecta.
  • docker compose logs --tail 30 app tras 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_filesize y post_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):

  1. 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
  2. Ahora subiendo desde local (http://localhost:8080) puedes subir archivos grandes.
  3. 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

CasoTiempo 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
Reto adicional (opcional, +30 min): añade Redis al stack como tercer servicio (imagen 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:

  1. 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.
  2. Promociónalo a admin:
    docker compose exec --user www-data app php occ group:adduser admin tu_nick_admin
  3. Entra con el nuevo usuario y, ya logueado, deshabilita o elimina el usuario admin original.

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 personalSeguridad → 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.com cambia 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):

  1. Compra un dominio (los .eu y .com rondan 8-12 €/año en Namecheap, OVH, Porkbun...).
  2. Crea cuenta gratuita en Cloudflare y mete el dominio bajo gestión (cambias los nameservers en el registrador).
  3. En el panel de Cloudflare → Zero TrustNetworksTunnelsCreate a tunnel. Le das nombre (nube) y te genera un token.
  4. En tu compose sustituyes el comando del servicio tunnel por:
    command: tunnel --no-autoupdate run --token TU_TOKEN
  5. En el panel asocias nube.tudominio.com al servicio interno http://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

La diferencia entre un despliegue serio y uno casero está exactamente en este documento. Un servicio sin documento de despliegue se convierte en un problema en cuanto la persona que lo montó deja de estar. Lo has visto en mil empresas y lo verás en muchas más.

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

AspectoLogrado
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
Volver al índice