Instalar Nextcloud en tu propio servidor
Del servidor vacío a una página de resumen sin avisos: servidor web, módulos de PHP, base de datos, permisos del directorio de datos, trusted_domains, límites de subida y tareas en segundo plano por cron.
Nextcloud se descomprime rápido. La parte que cuesta tiempo viene después: en una instalación recién hecha, la página de resumen que hay bajo Ajustes de administración muestra casi siempre una lista de avisos amarillos y rojos, las subidas se cortan a los 2 MB y el acceso por dirección IP acaba con "You are accessing the site from an untrusted domain.". Este artículo recorre el camino completo y se detiene justo en los puntos donde la mayoría de las guías se quedan.
Decidir antes: versión de PHP, base de datos y ubicación de los datos
Nextcloud depende de la versión de PHP mucho más que casi cualquier otro software de servidor. Las series actuales 33 y 34 exigen como mínimo PHP 8.2, y la serie 32 todavía arranca a partir de PHP 8.1. Por eso es la distribución la que decide si te basta con lo que trae de serie:
| Sistema | PHP de la distribución | Base de datos de la distribución | Valoración |
|---|---|---|---|
| Debian 13 (trixie) | 8.4 | MariaDB 11.8 | sirve sin repositorio externo |
| Debian 12 (bookworm) | 8.2 | MariaDB 10.11 | sirve, pero justo en el límite |
| Ubuntu 24.04 LTS | 8.3 | MariaDB 10.11, MySQL 8.0 | sirve sin repositorio externo |
| Ubuntu 22.04 LTS | 8.1 | MariaDB 10.6, MySQL 8.0 | demasiado antiguo para Nextcloud 33 y 34 |
| Debian 11 (bullseye) | 7.4 | MariaDB 10.5 | queda descartado |
Debian 11 es el caso más duro y, aun así, suele notarse tarde, porque la instalación de los paquetes termina sin ningún error. Allí el metapaquete php arrastra PHP 7.4, y la versión actual de Nextcloud se detiene con eso en la primera llamada desde el navegador con un HTTP 500 y el mensaje "This version of Nextcloud requires at least PHP 8.2". Debian 11 ya ha salido además del soporte regular, así que para una instalación nueva es la base equivocada. Si no te queda otro remedio, añade antes el repositorio Sury e instala expresamente paquetes con versión, es decir php8.2-fpm, php8.2-cli, php8.2-mysql y así sucesivamente, en lugar de los metapaquetes sin versión.
En Ubuntu 22.04 te estrellas de forma igual de inevitable en cuanto instalas la versión actual de Nextcloud. O te quedas conscientemente en la serie 32, o traes PHP desde el conocido PPA:
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt-get update
sudo apt-get install -y php8.3-fpm php8.3-cli php8.3-mysql
Otros dos puntos que se fijan al principio y que luego solo se cambian a base de esfuerzo: Debian no incluye por norma ningún paquete mysql-server, allí MariaDB es lo establecido. Y el directorio de datos no va bajo /var/www/nextcloud/data, sino fuera de la raíz del servidor web, por ejemplo en /var/nextcloud-data. La ruta predeterminada solo resulta peligrosa porque una configuración rota del servidor web serviría entonces todos los archivos de los usuarios. Nextcloud avisa en ese caso con "Your data directory and files are probably accessible from the internet", pero justo después de que el fallo ya exista.
Configurar el servidor web, PHP y la base de datos
Nosotros usamos nginx con PHP-FPM. Si prefieres Apache con mod_php, el camino está descrito en Apache, PHP y MySQL en Debian, y los temas de PHP de más abajo se aplican sin cambios. Una instalación básica de nginx la encuentras en instalar nginx.
sudo apt-get update
sudo apt-get install -y nginx mariadb-server
sudo apt-get install -y php-fpm php-cli php-mysql php-gd php-curl php-mbstring php-intl php-gmp php-bcmath php-xml php-zip php-imagick php-apcu
Esta lista es deliberadamente más larga que el mínimo. bcmath y gmp los necesita Nextcloud para el inicio de sesión sin contraseña, intl para ordenar correctamente los acentos y los caracteres especiales, imagick para las miniaturas y apcu para la caché local. Si falta alguno de los módulos obligatorios, no pasas siquiera del asistente de instalación: la página enumera entonces por su nombre los módulos que faltan.
Comprueba después qué se ha cargado realmente:
php -v
php -m
El segundo tropiezo habitual: hay dos configuraciones de PHP separadas, una para la línea de comandos y otra para FPM. php --ini te muestra la de la línea de comandos, mientras que la del servidor web está en /etc/php/<version>/fpm/php.ini. Los cambios en el archivo equivocado no surten ningún efecto, y eso es lo que más tiempo cuesta según la experiencia.
Ahora la base de datos. Asegura primero MariaDB, mira asegurar MariaDB y MySQL, y después:
sudo mariadb -e "CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
sudo mariadb -e "CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'UnaClaveLarga';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"
El utf8mb4 del primer comando no es un detalle menor. Si creas la base de datos con utf8, Nextcloud avisa más tarde con "MySQL is used as database but does not support 4-byte characters", y hacer el cambio con el sistema en marcha resulta bastante más incómodo que poner el CREATE DATABASE correcto desde el principio. Si falla el inicio de sesión del usuario de base de datos, te ayuda solucionar Access denied for user.
Descomprimir y asignar permisos
sudo apt-get install -y wget unzip
wget https://download.nextcloud.com/server/releases/latest.zip
sudo unzip -q latest.zip -d /var/www
sudo mkdir -p /var/nextcloud-data
sudo chown -R www-data:www-data /var/www/nextcloud
sudo chown -R www-data:www-data /var/nextcloud-data
sudo chmod 750 /var/nextcloud-data
Los permisos son el punto en el que más a menudo se hace el trabajo a medias. Tres síntomas y su causa:
- "Cannot write into config directory":
/var/www/nextcloud/configno pertenece al usuario del servidor web. En Debian y Ubuntu ese usuario eswww-data, mientras que en AlmaLinux y Rocky esapacheonginx. Unchown www-datacopiado a ciegas no sirve de nada en la familia Red Hat. - "Can't create or write into the data directory": la ruta no existe, no es una ruta absoluta, o algún directorio superior no es accesible para
www-data. - "Your data directory is readable by other users": permisos demasiado amplios. Basta con un
chmod 750sobre el directorio de datos.
Resiste la tentación de aplastar el problema con chmod -R 777. Nextcloud te devuelve exactamente el aviso que querías quitarte de encima y, de paso, has dejado cada archivo legible para cualquier usuario local.
La configuración de nginx
Nextcloud necesita bastante más que un bloque PHP estándar, entre otras cosas las reescrituras para el descubrimiento de servicios bajo /.well-known/ y los bloqueos de los directorios internos. Lo siguiente es la versión abreviada de la plantilla oficial y funciona tal cual:
upstream php-handler {
server unix:/run/php/php8.3-fpm.sock;
}
server {
listen 80;
server_name cloud.example.com;
root /var/www/nextcloud;
client_max_body_size 10G;
client_body_timeout 300s;
fastcgi_buffers 64 4K;
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
index index.php index.html /index.php$request_uri;
location ^~ /.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; }
return 301 /index.php$request_uri;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
location ~ \.php(?:$|/) {
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+) /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 front_controller_active true;
fastcgi_pass php-handler;
fastcgi_request_buffering off;
fastcgi_max_temp_file_size 0;
}
location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|map|woff2)$ {
try_files $uri /index.php$request_uri;
expires 6M;
access_log off;
}
location / {
try_files $uri $uri/ /index.php$request_uri;
}
}
La ruta al socket de FPM tienes que adaptarla a tu versión de PHP. En Debian 13 se llama php8.4-fpm.sock, en Debian 12 php8.2-fpm.sock, en Ubuntu 24.04 php8.3-fpm.sock y en Ubuntu 22.04 php8.1-fpm.sock. Si el nombre no coincide, obtienes un 502 Bad Gateway. El nombre real lo muestra:
systemctl enable --now php8.4-fpm
ls /run/php/
La primera línea forma parte del asunto, porque el archivo de socket no aparece hasta que arranca el servicio. Antes, /run/php/ está vacío o directamente no existe, y ls responde con No such file or directory. En un servidor normal el propio paquete arranca el servicio durante la instalación, pero después de una reinstalación o dentro de un container eso no está garantizado. Ajusta el número de versión del nombre del servicio a tu instalación. Después, nginx -t y recargar.
Instalación, HTTPS y trusted_domains
Puedes recorrer la instalación a golpe de clic en el navegador o resolverla directamente en la línea de comandos. La segunda variante es reproducible y se puede meter en un script:
cd /var/www/nextcloud
sudo -u www-data php occ maintenance:install --database "mysql" --database-name "nextcloud" --database-user "nextcloud" --database-pass "UnaClaveLarga" --admin-user "admin" --admin-pass "OtraClaveLarga" --data-dir "/var/nextcloud-data"
Dos trampas aquí. Primera, el comando tiene que ejecutarse desde el directorio de Nextcloud, si no PHP se detiene con un Fatal Error. Segunda, occ nunca debe ejecutarse como root, porque entonces aparece "Console has to be executed with the user that owns the file config/config.php" y, en el peor de los casos, los archivos recién creados acaban perteneciendo al usuario equivocado.
Ahora HTTPS. Sin certificado, las aplicaciones móviles se niegan a funcionar y Nextcloud avisa en la página de resumen:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.com
Para varios subdominios merece la pena un certificado wildcard. Añade después en el bloque de servidor TLS la cabecera Strict-Transport-Security "max-age=15552000; includeSubDomains" always;, porque si no se queda ahí el aviso "The Strict-Transport-Security HTTP header is not configured to at least 15552000 seconds".
El clásico para terminar: llamas a la página con un nombre distinto al que usaste en la instalación y solo ves "You are accessing the site from an untrusted domain." Nextcloud acepta exclusivamente los nombres de host que figuran en trusted_domains. Para añadirlo sin editar el archivo a mano:
sudo -u www-data php occ config:system:set trusted_domains 1 --value=cloud.example.com
sudo -u www-data php occ config:system:get trusted_domains
El índice empieza a contar en 0, y el 0 suele estar ya ocupado. Si asignas dos veces el mismo índice, sobrescribes la entrada existente y puede que acabes dejándote fuera a ti mismo. Si te pasa: config/config.php es un archivo PHP totalmente normal, y la entrada se puede corregir ahí con el editor. Define además overwrite.cli.url con la dirección HTTPS definitiva, porque si no las tareas en segundo plano generan enlaces con el nombre de host equivocado.
Tamaño de subida y límite de memoria
Los valores predeterminados de PHP se quedan cortos para Nextcloud. upload_max_filesize suele estar en 2M y memory_limit en 128M. Nextcloud recomienda al menos 512M de memoria y avisa en caso contrario con "The PHP memory limit is below the recommended value of 512MB".
Aquí hay tres sitios, y no basta con tocar uno de ellos:
- La configuración de FPM en
/etc/php/<version>/fpm/php.ini:memory_limit = 512M,upload_max_filesize = 10G,post_max_size = 10G,max_execution_time = 3600. Después reinicia FPM, porque recargar nginx no basta. - El archivo
.user.inidel directorio de Nextcloud: Nextcloud trae sus propios valores y, como.user.inise aplica por directorio, gana frente alphp.iniglobal. Justo ahí encalla la búsqueda de errores una y otra vez. Ajusta también allí los valores. PHP guarda ese archivo en caché durante cinco minutos de forma predeterminada, así que tu cambio surte efecto con retraso. - La directiva de nginx
client_max_body_size: si falta o es demasiado baja, la subida se corta con "413 Request Entity Too Large" antes de que se llegue siquiera a preguntar a PHP.
Para comprobar qué llega al final, ayuda la página Ajustes de administración, donde figura el límite realmente efectivo. En la línea de comandos:
grep -E '^(memory_limit|upload_max_filesize|post_max_size)' /etc/php/8.4/fpm/php.ini
Consulta expresamente el archivo de FPM y no el de la línea de comandos. Un php -r "echo ini_get('memory_limit');" lee la SAPI de CLI, y esa devuelve -1 en todas las distribuciones comprobadas, es decir sin límite. Quien se fía de eso da el valor por suficiente y aun así choca más tarde con errores de memoria, porque en el archivo de FPM sigue estando memory_limit = 128M. Lo que realmente llega al navegador lo muestra php-fpm8.4 -i o un info.php depositado brevemente con phpinfo(), que borras enseguida después.
Si al subir archivos grandes el kernel termina el proceso, lo que falta sencillamente es RAM. Entonces ayuda configurar swap como remedio de urgencia, aunque más RAM es mejor.
Pasar las tareas en segundo plano a cron
Después de la instalación, Nextcloud funciona en modo AJAX: las tareas en segundo plano solo se ejecutan cuando alguien tiene la interfaz abierta. Ese es el motivo por el que la búsqueda de texto completo, las tareas de limpieza y las notificaciones parecen no ocurrir nunca en instancias poco usadas. Cambia a cron de verdad, Nextcloud espera una ejecución cada cinco minutos. Los fundamentos están en configurar un cron job en Linux.
sudo crontab -u www-data -e
Ahí se añade:
*/5 * * * * php -f /var/www/nextcloud/cron.php
Después hay que comunicarle a Nextcloud el cambio de modo:
cd /var/www/nextcloud
sudo -u www-data php occ background:cron
Quien prefiera trabajar sin demonio de cron, usa un servicio systemd con temporizador. La unidad nextcloudcron.service llama a /usr/bin/php -f /var/www/nextcloud/cron.php como usuario www-data, y el temporizador correspondiente define OnBootSec=5min y OnUnitActiveSec=5min.
Si aun así se mantiene el aviso "Last background job execution ran X hours ago. Something seems wrong", comprueba en este orden: ¿el trabajo se ejecuta con el usuario correcto? ¿La ruta existe de verdad? Y algo muy importante: ¿es cron.php ejecutable con la configuración de PHP de la línea de comandos, o falta allí un módulo que solo se instaló para FPM? La prueba más honesta es la llamada a mano, porque así ves cada mensaje de error en texto claro:
sudo -u www-data php -f /var/www/nextcloud/cron.php
Resolver los avisos de la página de resumen
La lista que hay bajo Ajustes de administración y Visión general no es un adorno, cada línea tiene un motivo concreto. Los avisos más frecuentes y su solución:
- "No memory cache has been configured": APCu está instalado, pero no registrado.
occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Para queoccy las ejecuciones de cron también se beneficien, define ademásapc.enable_cli=1en/etc/php/<version>/mods-available/apcu.ini. - "Transactional file locking is disabled": instala Redis (
apt-get install -y redis-server php-redis) y ponmemcache.lockingen\OC\Memcache\Redis. En instancias de un solo usuario se puede prescindir de ello, pero en cuanto sincronizan varios usuarios a la vez, ya no. - "Your web server is not properly set up to resolve /.well-known/caldav": faltan las reescrituras del bloque
location ^~ /.well-known. Se puede probar directamente concurl -I https://cloud.example.com/.well-known/caldav, y lo esperado es un 301 hacia/remote.php/dav/. - "Your installation has no default phone region set":
occ config:system:set default_phone_region --value="AT", para EspañaES. El valor es un código de país según ISO 3166-1. - "Server has no maintenance window start time configured":
occ config:system:set maintenance_window_start --type=integer --value=1. El valor es la hora de inicio en UTC, así los trabajos diarios costosos se ejecutan de noche y no en pleno horario de uso. - "The database is missing some indexes":
occ db:add-missing-indices, y a juego con élocc db:add-missing-columnsyocc db:add-missing-primary-keys. Estos comandos son lentos en instancias grandes, pero no entrañan ningún riesgo. - "PHP does not seem to be setup properly to query system environment variables": en el archivo de pool de FPM
/etc/php/<version>/fpm/pool.d/www.confhay que descomentar la líneaenv[PATH] = /usr/local/bin:/usr/bin:/biny reiniciar FPM. - "Module php-imagick in this instance has no SVG support": esto no es un fallo de Nextcloud, sino una biblioteca delegate que falta en ImageMagick. Si no necesitas vistas previas de SVG, puedes dejar el aviso tal cual.
Cómo saber que de verdad funciona
Cuatro comprobaciones que, tomadas en conjunto, resultan concluyentes:
cd /var/www/nextcloud
sudo -u www-data php occ status
sudo -u www-data php occ check
sudo -u www-data php occ config:app:get core lastcron
occ status tiene que devolver installed: true y la versión esperada, y occ check no debe producir ninguna salida. El tercer comando devuelve una marca de tiempo Unix. Conviértela: no puede tener más de cinco minutos, y solo entonces tu cron está trabajando de verdad.
Desde fuera:
curl -s https://cloud.example.com/status.php
La respuesta es un objeto JSON con "installed":true, "maintenance":false y el número de versión. Si aquí llega HTML, alguna de tus reglas location abarca demasiado. Si llega una redirección a la página de inicio de sesión, todo está en orden, pero has usado la URL equivocada.
Por último, la prueba práctica que ninguna página de estado sustituye: subir un archivo de varios gigabytes por la interfaz web y sincronizarlo después con el cliente de escritorio. Solo así se ve si client_max_body_size, post_max_size, los timeouts y el espacio libre en disco encajan entre sí. Si de repente deja de funcionar todo, merece la pena echar un vistazo a los discos llenos, porque Nextcloud crea vistas previas y versiones que crecen de forma perceptible.
Cuando algo sale mal
Nextcloud escribe su registro en /var/nextcloud-data/nextcloud.log, es decir dentro de tu directorio de datos y no en /var/log. Ese es el primer archivo que deberías mirar, no el log de nginx. Para una salida legible:
sudo -u www-data php occ log:watch
Si la instancia se queda atascada en modo mantenimiento tras una actualización interrumpida, occ maintenance:mode --off la devuelve a la normalidad. Si la interfaz ya no es accesible en absoluto, pon 'maintenance' => false directamente en config/config.php.
Antes de tocar la base de datos o la configuración, haz un backup de las dos cosas. Un backup del directorio por sí solo no basta, porque Nextcloud no vale nada sin la base de datos que le corresponde:
sudo -u www-data php occ maintenance:mode --on
sudo mariadb-dump --single-transaction nextcloud > /root/nextcloud-db.sql
sudo -u www-data php occ maintenance:mode --off
Y un consejo de fondo: termina de montar el servidor antes de hacerlo accesible públicamente. Un firewall, un acceso SSH asegurado y los puntos de la lista de comprobación para servidores root nuevos van antes del primer inicio de sesión, no después. Una instancia de Nextcloud con la contraseña predeterminada se encuentra en cuestión de horas.
Preguntas frecuentes
¿Qué versión de PHP necesito para Nextcloud?
¿Por qué me aparece "You are accessing the site from an untrusted domain"?
¿Por qué se cortan las subidas pese a haber ampliado php.ini?
¿Por qué no se ejecutan mis tareas en segundo plano?
¿Qué permisos necesita el directorio de datos?
¿Cómo me quito el aviso sobre la caché de memoria que falta?
¿Puedo usar Nextcloud también con PostgreSQL?
2026 KernelHost GmbH. Todos los derechos reservados. Esta guía está protegida por derechos de autor. Su publicación en otros sitios web, aunque sea de forma parcial o modificada, no está permitida sin nuestro consentimiento por escrito. Las citas con indicación de la fuente y un enlace son muy bienvenidas.

