lunes, 5 de noviembre de 2018

Montar servidor de Nextcloud (nube privada estilo Dropbox) con Docker

Hoy vamos a aprender a montar nuestra propia nube privada de almacenamiento usando contenedores de Docker en nuestro servidor.
Si ya sabes de qué va todo esto de nube privada, Docker, Nextcloud, etc. y lo que quieres es ir al grano puedes hacer click aquí.

Empezaremos por responder a algunas preguntas que pueden surgir al leer el objetivo de este tutorial, vamos allá:

¿Qué es una "nube de almacenamiento"? 

Cuando hablamos de "nube" en un contexto informático nos referimos a los servicios que se ofrecen desde Internet. Es decir, cualquier servicio que se ofrezca a través de Internet como pueden ser el buscador de Google, Netflix, GMail, Dropbox, Facebook, etc.

Sabiendo esto, si hablamos de "almacenamiento en la nube" nos referimos a un servicio a través de Internet para guardar nuestros datos, una especie de disco duro virtual donde guardar nuestros archivos. Servicios como Dropbox, Mega, Box, Google Drive, Google Photos (sólo para fotos), etc. son algunos de ellos, donde se nos ofrece un almacenamiento en sus servidores para guardar nuestra información. Por regla general nos dan un almacenamiento limitado (1 GB, 15 GB, etc) y si queremos ampliarlo tenemos que pasar por caja, es decir, tenemos que pagarlo.

¿Para qué iba a necesitar yo una nube de almacenamiento?

Los usos que se le puede dar a este tipo de servicios son enormes: tener todos tus archivos disponibles en cualquier momento es una ventaja muy importante. Por ejemplo, estoy en casa trabajando con un documento, pero tengo que salir, mientras voy en el metro puedo seguir trabajando con el mismo documento desde el móvil. Tener siempre tu información disponible es muy importante, necesitas cualquier dato y lo puedes buscar al instante entre tus archivos desde cualquier parte del mundo mientras tengas acceso a una conexión a Internet. Una foto, un vídeo, un documento, cualquier cosa que puedas imaginarte la tendrás disponible a un par de clicks desde cualquier dispositivo mientras tengas acceso a Internet.

¿Y qué significa "privada"?

Cuando pones tus archivos en un servicio de los arriba mencionados, estás poniendo en los servidores de una empresa externa tus archivos. Es decir, tus fotos, vídeos, documentos... todos tus datos personales están en servidores que escapan a tu control gestionados por una empresa cuyo principal y único objetivo es ganar dinero. ¿Es esto malo? Para nada, es legítimo, y si no te importa que tus datos estén a merced de un tercero y no te importa pagar por ello no hará falta que sigas leyendo. Pero si para ti es importante tu privacidad, si piensas que tus datos son tuyos y de nadie más, si no quieres que cada GB que necesitas te salga por un ojo de la cara... este es tu tutorial ;-)

Sí, efectivamente cuando decimos "privada" nos referimos a que ese servicio lo gestiones tú mismo desde un ordenador que tengas en casa siempre encendido o incluso en un servidor dedicado o VPS siempre que cifres la información del disco (si queréis saber cómo se hace esto dejadlo en los comentarios).

¿Qué es Nextcloud?

Nextcloud es un desarrollo de código abierto para montar nuestra propia nube privada de almacenamiento. Es decir, podemos instalarlo en un ordenador que tengamos en casa y tener nuestro propio servicio de almacenamiento en la nube. Si queremos más espacio compraremos un disco duro más grande y no nos saldrá por un ojo de la cara comparado con lo que nos cobraría cualquiera de los servicios vistos anteriormente. Por ejemplo, con Dropbox tener 1 TB sale por 10 EUR/mes o 100 EUR/año, mientras que un disco duro de 1 TB nos costaría unos 40 EUR. Pero ya no es sólo la parte económica, es que nuestros datos estarán en nuestro servidor, nadie tendrá acceso a ellos.

¿Por qué pongo en negrita "código abierto"? Porque es muy importante en este tipo de servicios que juegan con nuestros datos más sensibles tener claro qué se hace con dichos datos. El hecho de que sea de código abierto te da la tranquilidad de que el programa hace lo que se supone que tiene que hacer, nada más. Si tienes los conocimientos necesarios podrías comprobar leyendo el código fuente que efectivamente es así, pero si no los tienes, otros los tendrán y lo harán, por eso los programas de código abierto son tan seguros, porque su seguridad no se basa en ocultar lo que hacen, sino en demostrar que lo que hacen está bien hecho.

¿Por qué usar Docker para esto?

Como hemos dicho, la idea es tener nuestro propio servidor con Nextcloud instalado.
Como vimos en la entrada sobre montar una VPN con Docker lo que nos permite hacer Docker es encapsular todo un servicio de nube privada en varios contenedores. Básicamente es como si virtualizáramos un servidor dentro de nuestro servidor. Los que conozcan la virtualización sabrán de sus ventajas, pero en este caso la ventaja es que no tenemos que tocar la configuración de nuestro servidor físico, ni modificar la configuración de la red, ni pelearnos con librerías, etc. Si actualizamos, cambiamos a otro sabor de Linux, cambiamos de servidor, etc. nuestros contenedores Docker funcionarán igual en otro servidor.

Preliminares

En mi caso la instalación la voy a hacer sobre un servidor con una CPU Intel Celeron
N3160 a 2.24 GHZ con 4GB de RAM y sistema operativo Ubuntu Server 18.04.1 LTS. Está fuera del alcance de este tutorial la instalación del sistema operativo, por lo que partiremos con el sistema operativo instalado (por supuesto no es necesario entorno gráfico) y acceso al terminal ya sea directamente o mediante SSH.

Lo primero que tendremos que hacer es instalar Docker en nuestro servidor. Para ello ejecutamos lo siguiente en un shell con permisos de root (o usando "sudo"):


1
2
3
4
5
# apt update
# apt dist-upgrade
# apt autoremove
# apt install docker.io
# apt install docker-compose

Es importante, por seguridad, que usemos Docker desde un usuario que no sea root, por tanto, a dicho usuario habrá que darle permisos para usar Docker. Esto lo hacemos con el siguiente comando cambiando "usuario_no_root" por nuestro usuario sin permisos de root:


1
# usermod -a -G docker usuario_no_root

A partir de aquí ya no necesitaremos permisos de root ya que instalaremos nuestro servidor usando Docker. Si lo hiciéramos de forma tradicional tendríamos que usar root para instalar todo el software necesario, por lo que ya podemos empezar a vislumbrar las ventajas de usar Docker.

Ahora abriremos un nuevo terminal con el "usuario_no_root" y comprobaremos que somos capaces de usar Docker normalmente con el siguiente comando:


$ docker version
Client:
 Version: 17.12.1-ce
 API version: 1.35
 Go version: go1.10.1
 Git commit: 7390fc6
 Built: Wed Apr 18 01:23:11 2018
 OS/Arch: linux/amd64

Server:
 Engine:
  Version: 17.12.1-ce
  API version: 1.35 (minimum version 1.12)
  Go version: go1.10.1
  Git commit: 7390fc6
  Built: Wed Feb 28 17:46:05 2018
  OS/Arch: linux/amd64
  Experimental: false

Debido a que la instalación de Nextcloud requiere de varios servicios vamos a usar docker-compose para automatizar el proceso de creación de los contenedores creando un archivo de texto con todo lo necesario para realizar dicha tarea.

A modo de resumen vamos a necesitar: un contenedor (una especie de máquina virtual) para instalar el propio Nextcloud, otro contenedor para instalar MariaDB (como si fuera MySQL) para la base de datos, otro contenedor para generar los certificados HTTPS para usar conexión segura y un proxy inverso para manejar las conexiones entre los clientes desde Internet y el motor de Nextcloud. No te preocupes si no has entendido todo lo expuesto en este párrafo, lo veremos paso a paso más adelante.

Crear red virtual

Lo primero que vamos a hacer es crear una red virtual dentro de Docker para que nuestros contenedores puedan comunicarse entre ellos. Esto es muy importante y es otra de las ventajas claras de usar Docker, ya que impide que si tenemos un problema de seguridad puedan acceder a nuestra red interna. Para crear la red ejecutamos lo siguiente:


1
$ docker network create nextcloud_network

Definir servidor proxy inverso

Como hemos dicho anteriormente, necesitaremos cuatro contenedores y el primero de ellos será el proxy inverso que será el que reciba las peticiones de los clientes desde Internet y las redirija a nuestro contenedor de Nextcloud.
Para empezar nos creamos un directorio al que llamaremos "nextcloud" desde nuestro usuario sin permisos de root, por ejemplo en su directorio HOME. Además dentro de él crearemos un directorio "proxy":


1
$ mkdir -p ./nextcloud/proxy

Ahora entramos en el directorio que acabamos de crear (cd nextcloud) y empezaremos a crear el fichero "docker-compose.yml" con la definición del proxy inverso. Para ello podemos usar nuestro editor de texto favorito, ya sea "vi", "nano", etc:


1
$ vi docker-compose.yml

Y pegamos lo siguiente en el fichero:


 proxy:
    image: jwilder/nginx-proxy:alpine
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"
    container_name: nextcloud-proxy
    networks:
      - nextcloud_network
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./proxy/conf.d:/etc/nginx/conf.d:rw
      - ./proxy/vhost.d:/etc/nginx/vhost.d:rw
      - ./proxy/html:/usr/share/nginx/html:rw
      - ./proxy/certs:/etc/nginx/certs:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./proxy/uploadsize.conf:/etc/nginx/conf.d/uploadsize.conf:ro
    restart: unless-stopped

Aquí básicamente definimos el contenedor al que llamaremos "nextcloud-proxy", que tendrá abiertos los puertos 80 (HTTP) y 443 (HTTPS) y también le definimos una configuración especial para que el proxy la tenga en cuenta en el fichero "uploadsize.conf" que crearemos enseguida. Además el label "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" es necesario para que luego el contenedor de LetsEncrypt sepa a qué proxy le tiene que crear los certificados SSL.
Ahora vamos a crear el fichero con la configuración especial editándolo con el siguiente comando desde dentro de nuestro directorio "nextcloud":


1
vi ./proxy/uploadsize.conf

Y pondremos dentro del fichero el siguiente contenido:


client_max_body_size 10G;

Con esto conseguimos que el servidor proxy nos deje subir ficheros de hasta 10 GiB, que a priori parece suficiente. Si no pusiéramos esto la configuración por defecto está limitada a 1 MiB, lo que haría inservible nuestro servidor de Nextcloud.

Definir LetsEncrypt

Ahora definiremos el container que nos ayudará a generar y mantener nuestros certificados SSL para que la conexión HTTPS que hagamos con el servidor sea segura. Para quien no lo sepa, LetsEncrypt en un servicio gratuito y seguro para obtener certificados SSL válidos para nuestros dominios.

Para ello añadimos a nuestro fichero docker-compose.yml el siguiente contenido:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nextcloud-letsencrypt
    depends_on:
      - proxy
    networks:
      - nextcloud_network
    volumes:
      - ./proxy/certs:/etc/nginx/certs:rw
      - ./proxy/vhost.d:/etc/nginx/vhost.d:rw
      - ./proxy/html:/usr/share/nginx/html:rw
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped

Como podemos observar, definimos un container con el nombre "nextcloud-letsencrypt" al que le decimos que depende de nuestro container proxy. Gracias al "label" que vimos en la definición del container proxy sabe a qué contenedor tiene que crearle los certificados SSL.

Definir la base de datos MariaDB


Ahora vamos a definir el container que hará la función de base de datos para nuestra instalación de Nextcloud. Para ello hemos elegido MariaDB (un clon de MySQL). Debemos añadir lo siguiente a nuestro fichero docker-compose.yml:


db:
    image: mariadb
    container_name: nextcloud-mariadb
    networks:
      - nextcloud_network
    volumes:
      - db:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro
    environment:
      - MYSQL_ROOT_PASSWORD=contraseña_root_bbdd
      - MYSQL_PASSWORD=contraseña_usuario_nextcloud
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
    restart: unless-stopped

Como podemos observar, vamos a crear un contenedor de nombre "nextcloud-mariadb" y debemos tener presente que tenemos que definir unas variables de entorno que contendrán dos contraseñas:
MYSQL_ROOT_PASSWORD: Es la contraseña que tendrá el usuario root de nuestro motor de base de datos, en realidad no la vamos a usar nunca ya que crearemos un usuario específico para la base de datos de Nextcloud, eso sí, conviene que sea una contraseña segura.
MYSQL_PASSWORD: Es la contraseña que tendrá nuestro usuario "nextcloud" que tendrá acceso de administrador a la base de datos "nextcloud" y es la contraseña que usaremos posteriormente para configurar nuestro servidor de Nextcloud. También es muy importante que sea una contraseña segura.

Algo importante con respecto a ambas contraseñas: ¡¡No pongáis caracteres extraños!! Es decir, usad sólo mayúsculas, minúsculas y letras, pero no símbolos porque por alguna razón a docker-compose no le sienta bien y te volverás loco intentando configurarlo como me pasó a mí.

Definir el servidor de Nextcloud

Ahora vamos a definir el contenedor que hará de servidor de aplicaciones para nuestro Nextcloud. Es decir, este será el contenedor que responderá a las peticiones de los clientes que vendrán directamente de nuestro contenedor proxy, por tanto, este servidor no tendrá acceso directo a Internet, sólo a través del proxy. Veamos qué tenemos que añadir a nuestro fichero docker-compose.yml:


 app:
    image: nextcloud:latest
    container_name: nextcloud-app
    networks:
      - nextcloud_network
    depends_on:
      - db
      - proxy
      - letsencrypt
    volumes:
      - nextcloud:/var/www/html
      - ./app/config:/var/www/html/config
      - ./app/custom_apps:/var/www/html/custom_apps
      - ./app/data:/var/www/html/data
      - ./app/themes:/var/www/html/themes
      - /etc/localtime:/etc/localtime:ro
    environment:
      - VIRTUAL_HOST=nuestro.dominio.com
      - LETSENCRYPT_HOST=nuestro.dominio.com
      - LETSENCRYPT_EMAIL=nuestroemail
    restart: unless-stopped

Según podemos ver arriba vamos a crear un container llamado "nextcloud-app" que depende de los otros tres que hemos definido (db, proxy y letsencrypt), y vamos a definir una serie de volúmenes y variables de entorno que merece la pena que nos detengamos a verlos poco a poco.
Comenzamos por la variables de entorno:
VIRTUAL_HOST: Aquí tendremos que decirle el dominio que está apuntando a la IP de nuestro servidor. Mediante esta variable nuestro servidor proxy sabe a qué contenedor redirigirle la petición. Si estamos montando esta infraestructura en nuestra casa, lo normal es que tengamos una IP dinámica, lo que no es impedimento para conseguir un dominio apuntando a nuestra IP. Si queréis saber cómo hacerlo dejadlo en los comentarios y lo explico.
LETSENCRYPT_HOST y LETSENCRYPT_EMAIL: Es otra vez nuestro dominio que apunta a la IP de nuestro servidor y nuestro email para que LetsEncrypt pueda certificar nuestro dominio.
De los volúmenes que tenemos que definir quiero pararme en este:


./app/data:/var/www/html/data

Ya que a la izquierda de los ":" estamos definiendo la ruta donde se albergarán los datos que subamos a Nextcloud. Es decir, esta ruta debe apuntar al disco donde queramos que estén nuestros datos. Si queremos mantener la ruta "app/data" para tenerlo todo junto, siempre podemos usar un "mount bind" para que esa ruta esté apuntando en realidad a otro disco, por ejemplo:


1
$ sudo mount --bind /mi/disco/duro/nextcloud/ /home/usuario_no_root/nextcloud/app/data/

Como vemos, estamos montando la ruta "/mi/disco/duro/nextcloud/" en la ruta "/home/usuario_no_root/nextcloud/app/data/" y así lo tendremos todo centralizado en el directorio nextcloud de nuestro HOME, aunque en realidad los datos estarán en el otro disco.
Como digo, también podemos poner este mismo directorio en el fichero docker-compose.yml:


- /mi/disco/duro/nextcloud:/var/www/html/data

Cualquiera de las dos opciones son válidas.

Y por último, debemos completar nuestro fichero docker-compose.yml con lo siguiente para especificar los volúmenes y la red que vamos a usar:


volumes:
  nextcloud:
  db:

networks:
  nextcloud_network:

Resumen

Con todo lo expuesto arriba, nuestro fichero docker-compose.yml quedaría así:


version: '3'

services:

 proxy:
    image: jwilder/nginx-proxy:alpine
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"
    container_name: nextcloud-proxy
    networks:
      - nextcloud_network
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./proxy/conf.d:/etc/nginx/conf.d:rw
      - ./proxy/vhost.d:/etc/nginx/vhost.d:rw
      - ./proxy/html:/usr/share/nginx/html:rw
      - ./proxy/certs:/etc/nginx/certs:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./proxy/uploadsize.conf:/etc/nginx/conf.d/uploadsize.conf:ro
    restart: unless-stopped

 letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: nextcloud-letsencrypt
    depends_on:
      - proxy
    networks:
      - nextcloud_network
    volumes:
      - ./proxy/certs:/etc/nginx/certs:rw
      - ./proxy/vhost.d:/etc/nginx/vhost.d:rw
      - ./proxy/html:/usr/share/nginx/html:rw
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped

 db:
    image: mariadb
    container_name: nextcloud-mariadb
    networks:
      - nextcloud_network
    volumes:
      - db:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro
    environment:
      - MYSQL_ROOT_PASSWORD=contraseña_root_bbdd
      - MYSQL_PASSWORD=contraseña_usuario_nextcloud
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
    restart: unless-stopped

 app:
    image: nextcloud:latest
    container_name: nextcloud-app
    networks:
      - nextcloud_network
    depends_on:
      - db
      - proxy
      - letsencrypt
    volumes:
      - nextcloud:/var/www/html
      - ./app/config:/var/www/html/config
      - ./app/custom_apps:/var/www/html/custom_apps
      - ./app/data:/var/www/html/data
      - ./app/themes:/var/www/html/themes
      - /etc/localtime:/etc/localtime:ro
    environment:
      - VIRTUAL_HOST=nuestro.dominio.com
      - LETSENCRYPT_HOST=nuestro.dominio.com
      - LETSENCRYPT_EMAIL=nuestroemail
    restart: unless-stopped

volumes:
  nextcloud:
  db:

networks:
  nextcloud_network:

Puesta en marcha


Bueno, ya lo tenemos todo preparado en los dos ficheros que hemos creado "docker-compose.yml" y "uploadsize.conf".
Antes de ponerlo en marcha, tenemos que asegurarnos de que los puertos 80 y 443 están redirigidos en nuestro router hasta la IP interna de nuestro servidor, algo que se conoce como NAT. Si no sabes cómo hacerlo tendrás que buscar en Google el nombre de tu router seguido de "port forwarding" o "NAT".

Y por fin, nos situamos en el directorio donde hemos puesto nuestro fichero docker-compose.yml y ejecutamos la siguiente orden:


$ docker-compose up -d

Tendremos que dejar al servidor unos minutos para que le dé tiempo a generar los certificados SSL. Pasados unos minutos, accedemos a nuestra URL: https://nuestro.dominio.com

Y veremos algo parecido a esto:


Tenemos que elegir un usuario administrador y una contraseña para él. ¡¡NO PONER "admin" COMO NOMBRE DE USUARIO!! El problema de poner "admin" es que si dejamos nuestro servidor abierto a Internet recibiremos ataques intentando conseguir nuestra contraseña de admin y el usuario que probarán será "admin", "administrator" e incluso "administrador", por tanto, elegid otro nombre distinto y una contraseña segura.

Luego tenemos que elegir la opción de "Storage & database" (puede que salga en Español) y nos saldrá la configuración de la siguiente ventana cuando le demos a la opción "MySQL/MariaDB":


En "Database user" (usuario de la base de datos) y "Database name" (nombre de la base de datos)  tenemos que poner "nextcloud".
En "Database password" (Contraseña de la base de datos) tenemos que poner la contraseña que hemos definido en nuestro fichero "docker-compose.yml" en la variable MYSQL_PASSWORD.
En donde pone "localhost" lo cambiamos por "db" que es el nombre que le hemos dado al servidor de la base de datos.

Por último le damos a "Finish setup" (Finalizar configuración) y ya tenemos nuestro servidor de Nextcloud funcionando.

Lo ideal ahora es logarnos con nuestro usuario administrador y en la parte superior derecha hacer click en el círculo con la primera letra del nombre de nuestro usuario "admin" para desplegar el menú y luego la opción de "Usuarios" para crear los usuarios que necesitemos, dejando al usuario administrador sólo para tareas administrativas.

Una vez tengamos nuestros usuarios creados ya podemos bajarnos cualquier cliente de Nextcloud para los dispositivos que tengamos desde https://nextcloud.com/install/ en el apartado donde pone "Sync your data" donde podemos elegir los clientes para los diferentes sistemas operativos (Windows, Linux, macOS, Android y iOS).

Y esto es todo, recordad que si necesitáis saber cómo redirigir un dominio a una IP dinámica (como la de vuestra casa) me lo digáis en los comentarios para hacer un tutorial sobre ello.

¡Hasta la próxima!


Documentación

https://docs.nextcloud.com/server/14/admin_manual/
https://blog.ssdnodes.com/blog/installing-dropbox-alternative-nextcloud-with-docker/
https://github.com/nextcloud/docker/issues/371
https://github.com/jwilder/nginx-proxy
https://letsencrypt.org/docs/faq/