¿Por qué Nextcloud con Tailscale?

Nextcloud es la alternativa self-hosted más completa a Google Drive o iCloud. Tailscale resuelve el acceso externo seguro mediante un sidecar — un contenedor que comparte red con Nextcloud y gestiona automáticamente el certificado HTTPS vía MagicDNS. Sin puertos abiertos, sin Let's Encrypt manual.

El stack completo: Tailscale + MariaDB + Redis + Cron

  • Tailscale: sidecar de red y gestor de certificados HTTPS
  • MariaDB: base de datos relacional (SQLite no escala bien)
  • Redis: caché en memoria y bloqueo de archivos
  • Nextcloud: la aplicación principal
  • Cron: tareas en segundo plano

Paso 1: Crear las carpetas en el NAS

Desde el Administrador de Archivos de UGOS, crea esta estructura dentro de tu carpeta docker:

/docker/nextcloud/data
/docker/nextcloud/html
/docker/nextcloud/config
/docker/nextcloud/db
/docker/nextcloud/redis
/docker/nextcloud/tailscale/state
/docker/nextcloud/tailscale/config

Paso 2: Crear el archivo serve.json

Dentro de /docker/nextcloud/tailscale/config/, crea un archivo nuevo llamado serve.json con este contenido:

{
  "TCP": {
    "443": {
      "HTTPS": true
    }
  },
  "Web": {
    "${TS_CERT_DOMAIN}:443": {
      "Handlers": {
        "/": {
          "Proxy": "http://127.0.0.1:80"
        }
      }
    }
  }
}

Paso 3: Crear el Stack en Portainer

Ve a Portainer → StacksAdd Stack. Ponle el nombre nextcloud. Antes de darle Deploy, reemplaza todos los CAMBIA_ESTA_PASS con contraseñas seguras, TU_CLAVE_AQUI con la auth key de Tailscale, y TU-TAILNET con el nombre de tu red:

version: '3.9'

services:

  tailscale:
    image: tailscale/tailscale:latest
    container_name: nextcloud-tailscale
    hostname: nextcloud
    cap_add:
      - NET_ADMIN
      - NET_RAW
    environment:
      - TS_AUTHKEY=tskey-auth-TU_CLAVE_AQUI
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_SERVE_CONFIG=/config/serve.json
      - TS_EXTRA_ARGS=--accept-dns=true
    volumes:
      - /docker/nextcloud/tailscale/state:/var/lib/tailscale
      - /docker/nextcloud/tailscale/config/serve.json:/config/serve.json:ro
      - /dev/net/tun:/dev/net/tun
    devices:
      - /dev/net/tun:/dev/net/tun
    restart: unless-stopped

  db:
    image: mariadb:11
    container_name: nextcloud-db
    environment:
      - MYSQL_ROOT_PASSWORD=CAMBIA_ESTA_PASS_ROOT
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=CAMBIA_ESTA_PASS_DB
    volumes:
      - /docker/nextcloud/db:/var/lib/mysql
    restart: unless-stopped

  redis:
    image: redis:alpine
    container_name: nextcloud-redis
    command: redis-server --requirepass CAMBIA_ESTA_PASS_REDIS
    volumes:
      - /docker/nextcloud/redis:/data
    restart: unless-stopped

  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    network_mode: service:tailscale
    environment:
      - NEXTCLOUD_ADMIN_USER=admin
      - NEXTCLOUD_ADMIN_PASSWORD=CAMBIA_ESTA_PASS_ADMIN
      - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.TU-TAILNET.ts.net
      - TRUSTED_PROXIES=127.0.0.1
      - OVERWRITEPROTOCOL=https
      - OVERWRITECLIURL=https://nextcloud.TU-TAILNET.ts.net
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=CAMBIA_ESTA_PASS_DB
      - REDIS_HOST=redis
      - REDIS_HOST_PASSWORD=CAMBIA_ESTA_PASS_REDIS
      - REDIS_PORT=6379
      - PHP_MEMORY_LIMIT=1G
      - PHP_UPLOAD_LIMIT=10G
      - TZ=America/Puerto_Rico
    volumes:
      - /docker/nextcloud/html:/var/www/html
      - /docker/nextcloud/data:/var/www/html/data
      - /docker/nextcloud/config:/var/www/html/config
    restart: unless-stopped
    depends_on:
      - tailscale
      - db
      - redis

  cron:
    image: nextcloud:latest
    container_name: nextcloud-cron
    entrypoint: /cron.sh
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=CAMBIA_ESTA_PASS_DB
      - REDIS_HOST=redis
      - REDIS_HOST_PASSWORD=CAMBIA_ESTA_PASS_REDIS
    volumes:
      - /docker/nextcloud/html:/var/www/html
      - /docker/nextcloud/data:/var/www/html/data
      - /docker/nextcloud/config:/var/www/html/config
    restart: unless-stopped
    depends_on:
      - nextcloud

Zonas horarias

Cambia el valor de TZ según donde estés:

  • Puerto Rico / República Dominicana: America/Puerto_Rico
  • Cuba: America/Havana
  • México (CDMX): America/Mexico_City
  • Colombia / Perú / Ecuador: America/Bogota
  • Argentina / Uruguay: America/Argentina/Buenos_Aires
  • Chile: America/Santiago
  • Venezuela: America/Caracas
  • EE.UU. Este: America/New_York
  • EE.UU. Oeste: America/Los_Angeles

Acceder a Nextcloud

Con los contenedores en estado running, abre https://nextcloud.TU-TAILNET.ts.net en el navegador. La primera carga puede tardar un par de minutos mientras Nextcloud termina de configurarse.

Mi experiencia personal

Llevo varios meses con este stack corriendo en mi Ugreen NAS. La sincronización de fotos desde el celular va perfecta y el acceso desde fuera de la casa a través de Tailscale es instantáneo y seguro. Sin tocar el router, sin renovaciones manuales de certificados. Google Photos era conveniente pero no era mío — ahora lo es.