Nextcloud es una serie de programas cliente-servidor que permiten la creación de servicios de alojamiento de archivos. Nextcloud permite a los usuarios crear servidores privados. Su modelo de desarrollo abierto permite añadir y/o modificar la funcionalidad del software del servidor en forma de aplicaciones. Nextcloud es una bifurcación de OwnCloud que también es un software de servicio de alojamiento en la nube.

En este tutorial

Después de completar este tutorial, tendremos:

  • Un servidor NextCloud recién instalado.
  • Almacenamiento caché de PHP proporcionado por ACPu y Redis para notar un aumento de velocidad cuando se navegue en la nube.
  • Enlaces amigables, eliminamos el /index.php de la URL.
  • SSL habilitado con certificados de Let’s Encrypt y todo el tráfico redirigido a HTTPS.
  • Nuestra nube completamente cifrada.

Utilizaremos durante todo el tutorial el dominio para representar una configuración válida. Recuerda que deberás de cambiar en todos los pasos ese dominio por el tuyo -que puede ser un subdominio o bien un dominio-.

Instalación de servidor web, APCu y Redis

Para la instalación del servidor Web deberemos de seguir las instrucciones de este otro tutorial de cómo instalar un servidor web en Ubuntu 20.04. En este caso usaremos Nginx en vez de Apache.

Instalación de servidor web LEMP en Ubuntu 20.04
A continuación vamos a instalar un servidor LEMP completo en Ubuntu 20.04 «Focal Fossa«. Hay algunas cosas que han cambiado respecto a otras versiones de Ubuntu, por ejemplo algunos datos importantes a tener en cuenta:

Instalación de servidor LEMP

Como siempre, lo primero actualizamos los repositorios y actualizamos los paquetes:

# apt update
# apt upgrade

Iniciaremos los servicios del servidor web y los añadiremos al arranque:

# systemctl enable nginx mariadb 
# systemctl start nginx mariadb

Instalamos los paquetes necesarios para APCu y Redis:

# apt install php7.4-apcu php7.4-redis redis-server

Habilitamos Redis para el inicio:

# systemctl enable redis-server

Finalmente, instalamos los paquetes necesarios de PHP para NextCloud:

# apt install php7.4-zip php-dompdf php7.4-xml php7.4-mbstring php7.4-curl unzip php7.4-gd php7.4-mysql php7.4-intl php7.4-bcmath php7.4-gmp php7.4-imagick imagemagick

Configuración previa de PHP

Deberemos de modificar la configuración de PHP:

# nano /etc/php/7.4/fpm/php.ini

Y cambiamos:

memory_limit = 128MB


memory_limit = 1G

Luego modificamos este otro fichero y descomentamos estas líneas:

# nano /etc/php/7.4/fpm/pool.d/www.conf

env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

Y reiniciamos FPM:

# systemctl restart php7.4-fpm.service

Configuración Nginx y activación de SSL

Lo primero que haremos será crear un Server para nuestro NextCloud, vamos a ello:

# cp /etc/nginx/sites-available/default /etc/nginx/sites-available/nextcloud.conf

Y editamos el fichero para que quede con el siguiente contenido:

upstream php-handler {
    server unix:/var/run/php/php7.4-fpm.sock;

server {
    listen 80;
    listen [::]:80;

    # Enforce HTTPS
    return 301 https://$server_name$request_uri;

server {
    listen 443      ssl http2;
    listen [::]:443 ssl http2;

    access_log /var/www/vhosts/;
    error_log /var/www/vhosts/;
    # Use Mozilla's guidelines for SSL/TLS settings
    ssl_certificate /etc/letsencrypt/live/; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    # HSTS settings
    # WARNING: Only add the preload option once you read about
    # the consequences in This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;

    # set max upload size and increase upload timeout:
    client_max_body_size 512M;
    client_body_timeout 300s;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/ application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    # Pagespeed is not supported by Nextcloud, so if your server is built
    # with the `ngx_pagespeed` module, uncomment this line to disable it.
    #pagespeed off;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Referrer-Policy                      "no-referrer"   always;
    add_header X-Content-Type-Options               "nosniff"       always;
    add_header X-Download-Options                   "noopen"        always;
    add_header X-Frame-Options                      "SAMEORIGIN"    always;
    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
    add_header X-Robots-Tag                         "none"          always;
    add_header X-XSS-Protection                     "1; mode=block" always;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    # Path to the root of your installation
    root /var/www/vhosts/;

    # Specify how to handle directories -- specifying `/index.php$request_uri`
    # here as the fallback means that Nginx always exhibits the desired behaviour
    # when a client requests a path that corresponds to a directory that exists
    # on the server. In particular, if that directory contains an index.php file,
    # that file is correctly served; if it doesn't, then the request is passed to
    # the front-end controller. This consistent behaviour means that we don't need
    # to specify custom rules for certain paths (e.g. images and other assets,
    # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
    # `try_files $uri $uri/ /index.php$request_uri`
    # always provides the desired behaviour.
    index index.php index.html /index.php$request_uri;

    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
    location = / {
        if ( $http_user_agent ~ ^DavClnt ) {
            return 302 /remote.php/webdav/$is_args$args;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;

    # Make a regex exception for `/.well-known` so that clients can still
    # access it despite the existence of the regex rule
    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
    # for `/.well-known`.
    location ^~ /.well-known {
        # The rules in this block are an adaptation of the rules
        # in `.htaccess` that concern `/.well-known`.

        location = /.well-known/carddav { return 301 /remote.php/dav/; }
        location = /.well-known/caldav  { return 301 /remote.php/dav/; }

        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /index.php$request_uri;

    # Rules borrowed from `.htaccess` to hide certain paths from clients
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
        # Required for legacy support
        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;

        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        set $path_info $fastcgi_path_info;

        try_files $fastcgi_script_name =404;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param HTTPS on;

        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
        fastcgi_param front_controller_active true;     # Enable pretty urls
        fastcgi_pass php-handler;

        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;

    location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite)$ {
        try_files $uri /index.php$request_uri;
        expires 6M;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets

        location ~ \.wasm$ {
            default_type application/wasm;

    location ~ \.woff2?$ {
        try_files $uri /index.php$request_uri;
        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets

    # Rule borrowed from `.htaccess`
    location /remote {
        return 301 /remote.php$request_uri;

    location / {
        try_files $uri $uri/ /index.php$request_uri;

Creamos los directorios necesarios:

# mkdir -p /var/www/vhosts/{www,logs}

Activamos el espacio web y reiniciamos Nginx:

# ln -s /etc/nginx/sites-available/nextcloud.conf /etc/nginx/sites-enabled/nextcloud.conf
# touch /var/www/vhosts/{nextcloud.access,nextcloud.error}
# systemctl restart nginx

Activamos SSL

Para SSL usaremos Let’s Encrypt, así que instalaremos los paquetes necesarios:

# apt install certbot python3-certbot-nginx

Y creamos el certificado de la siguiente forma:

# certbot

Y añadimos un e-mail que funcione:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices) (Enter ‘c’ to

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1

A partir de aquí se crearán ficheros de configuración y el CSR entre otras cosas importantes para crear el certificado. Hasta que nos preguntará por que tipo de acceso HTTPS queremos:

Please choose whether HTTPS access is required or optional.
1: Easy – Allow both HTTP and HTTPS access to these sites
2: Secure – Make all requests redirect to secure HTTPS access
Select the appropriate number [1-2] then [enter] (press ‘c’ to cancel):

Sin dudarlo, escogeremos la opción 2 y acabará de crear el certificado:

Congratulations! You have successfully enabled
You should test your configuration at:

En este punto tenemos un servidor web con un Server que permite acceder por subdominio y tiene todos los paquetes necesarios para poder instalar NextCloud.

Instalación de NextCloud

Ahora viene lo interesante de todo esto. Tendremos que descargar la última versión de NextCloud y crear una base de datos para que funcione. Por otro lado continuaremos con la instalación mediante el navegador.

Descargar NextCloud y configurar permisos

Lo primero que haremos será descargarnos la última versión de NextCloud dentro de la ruta de nuestra web:

cd /var/www/html/vhost/

Y descomprimimos el fichero


Movemos los ficheros y eliminamos directorio:

mv nextcloud/* . && mv nextcloud/.* . && rm -rf netxcloud && rm

Cambiamos permisos:

chown -R www-data:www-data .*

Creación de la base de datos

Lo siguiente será crear la base de datos y el usuario, para ello nos iniciamos sessión en MariaDB:

mysql -u root -p

Creamos la base de datos con esto:

CREATE USER 'ncuser'@'localhost' IDENTIFIED BY 'ncpassword';
GRANT ALL PRIVILEGES ON nextcloud . * TO 'ncuser'@'localhost';

Instalación de NextCloud

Abre tu navegador favorito y pon la URL que has configurado para acceder a NextCloud y así iniciar la instalación. Si no has creado un puntero antes, tendrás que esperar a que se propague el DNS.

Aquí tendremos que configurar un nombre de usuario para la cuenta administrador así como una contraseña segura. También tendrás que configurar una ruta donde se guardarán los datos que se suban de en la nube. Este directorio es donde van todos los ficheros, yo recomiendo ponerlo fuera de la ruta de la web para evitar problemas. Así que lo que haremos será crear un usuario y dentro de ese usuario crearemos un directorio:

useradd -m -d /bin/nologin nextcloud

Creamos directorio y cambiamos permisos:

mkdir -p /home/voidnulles/cloud
chown www-data.voidnulles -R /home/voidnulles

Hecho esta parte, configuramos la base de datos. Tendremos que rellenar los datos y finalmente hacer clic en Completar la instalación.

Si es todo correcto, iniciará la instalación y obtendremos la siguiente imagen una vez finalice:

Configuración de NextCloud

Ahora mismo ya tenemos un NextCloud funcional y que se puede utilizar, pero hay una configuración muy recomendable e interesante para hacer a NextCloud y eso mismo vamos a explicar. Para empezar, si vamos a Configuración > Ajustes Básicos veremos que nos aparecen varios errores que podemos corregir con esta configuración:

Configuración de la memoria caché

Al principio hemos instalado Redis pero no lo hemos configurado. Para ello editaremos el fichero /etc/redis/redis.conf y tenemos que buscar el parámetro port 6379 y lo cambiamos por port 0. Buscaremos la siguiente línea unixsocket /var/run/redis/redis.sock y la descomentaremos. Debajo de esa línea nos encontraremos con unixsocketperm 700 el cual también descomentaremos y cambiaremos por unixsocketperm 770. Guardamos y salimos.

Añadimos el usuario redis al grupo de Apache:

# usermod -a -G redis www-data

Finalmente, reiniciamos los servicios de Apache y Redis:

# systemctl restart nginx
# systemctl enable redis-server
# systemctl restart redis-server

Hecho esto, tendremos que configurar NextCloud para que use Redis, para ello tendremos que modificar el fichero de configuración de NextCloud que se encuentra en /var/www/html/vhost/

Añadiremos lo siguiente:

'memcache.local' => '\\OC\\Memcache\\APCu',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'filelocking.enabled' => 'true',
'redis' =>
  array (
    'host' => '',
    'port' => 6379,
    'timeout' => 0.0,

Es posible que sea necesario reiniciar el servidor para que esto empiece a funcionar correctamente, así que una vez guardado esto, reiniciamos el servidor.

Configurar OPcache de PHP

Desde Nextcloud 12, se requiere una configuración adicional para configurar correctamente Opcache de PHP. Se muestra el error «La OPcache de PHP no está bien configurada. Para mejorar el rendimiento se recomienda usar las siguientes configuraciones en el php.ini«. Para ello tendremos que editar el fichero /etc/php/7.4/fpm/php.ini.

Al final del fichero añadimos lo siguiente:

; Nextcloud Opcache settings

Y reiniciamos PHP-FPM:

systemctl restart php7.4-fpm

Carga máxima de ficheros

Generalmente, hasta que no carguemos algún fichero grande no nos daremos cuenta de este «problema». Por defecto PHP se configura con una limitación de carga de archivos de unos 2MB. Como estamos instalando una nube personal que puede contener archivos de un tamaño de gigabytes, podemos cambiar la configuración de PHP para permitir mucha más flexibilidad.

Para ello modificaremos el fichero /etc/php/7.4/fpm/php.ini y modifcaremos los parámetros upload_max_filesize y post_max_size y les pondremos el valor de 2048M. Finalmente, reiniciaremos PHP-FPM para que surja efecto.

Enlaces amigables

Otra cosa interesante es configurar enlaces amigables para que las URL’s sean visualmente más facil de recordar o más «simpáticas» -quería decir bonitas, pero no me parecen bonitas unas URL’s-. Tras esta pequeña broma sin sentido, lo que haremos será modificar el fichero de configuración de NextCloud /var/www/html/vhost/ y añadimos lo siguiente:

'htaccess.RewriteBase' => '/',

Y si reiniciamos el servicio del Nginx veremos que de las URL pasaremos a


Y con todo esto tendríamos nuestra nube personal en nuestro servidor. Desde hace varios años que estoy usando NextCloud y podría decir que es de lo mejor que tenemos en el mundo del Software Libre. Lo utilizo para todo, para tener mis ficheros -antes lo usaba mucho para clase-, también tengo mis calendarios, mis contactos -con los que podéis sincronizar en Android con DavDroid- también tengo mi nube federada con otras nubes de amigos. Es una locura todo lo que se puede hacer, yo recomiendo investigar.

No puedo acabar este artículo sin mencionar que es importante repasar la documentación que tienen los de NextCloud en su web. Si algo de este tutorial no funciona, porque han cambiado algo y no me ha dado tiempo de actualizar, en la documentación deberías e estar la respuesta.