Si quieres tener tu propia nube privada tipo Google Drive o Dropbox, Nextcloud es una de las mejores opciones. En esta guía te mostraré cómo instalarlo en Ubuntu Server 24.04 de forma sencilla, incluyendo un script automático que hace casi todo por ti.
¿Qué es Nextcloud?
Nextcloud es una plataforma de almacenamiento en la nube de código abierto que te permite guardar archivos, sincronizarlos entre dispositivos, compartirlos y mucho más, todo en tu propio servidor.
- 📁 Almacenamiento privado
- 🔄 Sincronización de archivos
- 🔐 Control total de tus datos
- 👥 Compartir archivos fácilmente
Requisitos
- Servidor con Ubuntu Server 24.04
- Acceso SSH con permisos sudo
- Conexión a internet
Instalación automática (Script)
Para facilitar todo el proceso, puedes usar el siguiente script que instala Apache, PHP, MariaDB y Nextcloud automáticamente.
#!/bin/bash
# ==========================================
# Instalador automático de Nextcloud
# Ubuntu Server 24.04 (con soporte para PPA sury.org)
# Versión: 4.0 - Definitiva (resuelve conflictos de PHP)
# Adaptado por julio101290
# ==========================================
set -e
# -------------------- CONFIGURACIÓN --------------------
DEFAULT_PORT="${NEXTCLOUD_PORT:-80}"
NC_DIR="${NEXTCLOUD_DIR:-/var/www/nextcloud}"
DB_NAME="${NEXTCLOUD_DB_NAME:-nextcloud}"
DB_USER="${NEXTCLOUD_DB_USER:-ncuser}"
# Generar contraseña segura si no se proporciona
if [ -z "$NEXTCLOUD_DB_PASS" ]; then
DB_PASS=$(openssl rand -base64 24 | tr -d "=+/" | cut -c1-24)
else
DB_PASS="$NEXTCLOUD_DB_PASS"
fi
NONINTERACTIVE="${NONINTERACTIVE:-false}"
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# -------------------- FUNCIONES AUXILIARES --------------------
error_exit() {
echo -e "${RED}ERROR: $1${NC}" >&2
exit 1
}
info() {
echo -e "${GREEN}➡️ $1${NC}"
}
warn() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
confirm() {
if [ "$NONINTERACTIVE" = "true" ]; then
return 0
fi
read -p "$1 [S/n]: " -n 1 -r
echo
[[ $REPLY =~ ^[Ss]$ ]] || [[ -z $REPLY ]]
}
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# -------------------- VERIFICACIONES INICIALES --------------------
if [ "$EUID" -ne 0 ]; then
error_exit "Ejecuta con sudo o como root."
fi
# -------------------- ACTUALIZACIÓN Y REPARACIÓN --------------------
info "Actualizando lista de paquetes..."
apt update -qq
info "Reparando paquetes rotos si los hay..."
apt --fix-broken install -y
# -------------------- APACHE Y PUERTO --------------------
info "Configurando Apache..."
if command_exists apache2; then
warn "Apache ya está instalado."
# Detectar puerto activo
if systemctl is-active --quiet apache2; then
CURRENT_PORT=$(ss -tlnp 2>/dev/null | grep apache2 | grep -oP ':\K\d+' | head -1)
fi
[ -z "$CURRENT_PORT" ] && CURRENT_PORT=$(grep -i "^Listen" /etc/apache2/ports.conf 2>/dev/null | head -1 | awk '{print $2}')
[ -z "$CURRENT_PORT" ] && CURRENT_PORT=80
if [ "$CURRENT_PORT" != "$DEFAULT_PORT" ] && [ "$DEFAULT_PORT" != "80" ]; then
warn "Apache ya escucha en el puerto $CURRENT_PORT. Se usará ese."
PORT=$CURRENT_PORT
else
PORT=$DEFAULT_PORT
fi
else
info "Instalando Apache..."
apt install -y apache2
PORT=$DEFAULT_PORT
fi
# Configurar puerto si es necesario
if [ "$PORT" != "80" ]; then
info "Ajustando Apache al puerto $PORT..."
sed -i "s/^Listen 80/Listen $PORT/g" /etc/apache2/ports.conf
grep -q "^Listen $PORT" /etc/apache2/ports.conf || echo "Listen $PORT" >> /etc/apache2/ports.conf
systemctl restart apache2
fi
# -------------------- PHP Y EXTENSIONES (RESOLUCIÓN DEFINITIVA) --------------------
info "Verificando PHP..."
PHP_INSTALLED=false
USE_SURY=false
if command_exists php; then
PHP_INSTALLED=true
PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;' 2>/dev/null)
warn "PHP $PHP_VER detectado."
# Determinar origen de PHP
if apt-cache policy php | grep -q "sury.org"; then
USE_SURY=true
warn "PHP instalado desde el repositorio 'deb.sury.org'."
fi
else
info "PHP no está instalado. Se instalará desde los repositorios oficiales de Ubuntu."
fi
# Si PHP está presente pero no todas las extensiones, las instalamos según el origen
if [ "$PHP_INSTALLED" = true ]; then
# Extensiones necesarias
NEEDED_EXTS="bcmath gmp imagick mysql zip gd mbstring curl xml intl"
MISSING_EXTS=""
# Verificar qué extensiones faltan
for ext in $NEEDED_EXTS; do
case $ext in
mysql)
if ! php -m | grep -qiE "mysqli|pdo_mysql"; then
MISSING_EXTS="$MISSING_EXTS mysql"
fi
;;
*)
if ! php -m | grep -qi "$ext"; then
MISSING_EXTS="$MISSING_EXTS $ext"
fi
;;
esac
done
if [ -n "$MISSING_EXTS" ]; then
info "Faltan extensiones: $MISSING_EXTS"
# Solución específica para el conflicto de php-imagick
if echo "$MISSING_EXTS" | grep -q "imagick"; then
warn "Se detectó conflicto con php-imagick. Eliminando versión incorrecta..."
apt remove -y php-imagick 2>/dev/null || true
fi
# Instalar según el origen
if [ "$USE_SURY" = true ]; then
info "Instalando extensiones desde el PPA sury.org..."
# Construir lista de paquetes específicos para sury
SURY_PKGS=""
for ext in $MISSING_EXTS; do
case $ext in
mysql) SURY_PKGS="$SURY_PKGS php${PHP_VER}-mysql" ;;
imagick) SURY_PKGS="$SURY_PKGS php${PHP_VER}-imagick" ;;
bcmath) SURY_PKGS="$SURY_PKGS php${PHP_VER}-bcmath" ;;
gmp) SURY_PKGS="$SURY_PKGS php${PHP_VER}-gmp" ;;
zip) SURY_PKGS="$SURY_PKGS php${PHP_VER}-zip" ;;
gd) SURY_PKGS="$SURY_PKGS php${PHP_VER}-gd" ;;
mbstring) SURY_PKGS="$SURY_PKGS php${PHP_VER}-mbstring" ;;
curl) SURY_PKGS="$SURY_PKGS php${PHP_VER}-curl" ;;
xml) SURY_PKGS="$SURY_PKGS php${PHP_VER}-xml" ;;
intl) SURY_PKGS="$SURY_PKGS php${PHP_VER}-intl" ;;
esac
done
apt install -y --allow-downgrades $SURY_PKGS
else
# Repositorios oficiales de Ubuntu
info "Instalando extensiones desde repositorios oficiales..."
OFFICIAL_PKGS=""
for ext in $MISSING_EXTS; do
case $ext in
mysql) OFFICIAL_PKGS="$OFFICIAL_PKGS php-mysql" ;;
imagick) OFFICIAL_PKGS="$OFFICIAL_PKGS php-imagick" ;;
bcmath) OFFICIAL_PKGS="$OFFICIAL_PKGS php-bcmath" ;;
gmp) OFFICIAL_PKGS="$OFFICIAL_PKGS php-gmp" ;;
zip) OFFICIAL_PKGS="$OFFICIAL_PKGS php-zip" ;;
gd) OFFICIAL_PKGS="$OFFICIAL_PKGS php-gd" ;;
mbstring) OFFICIAL_PKGS="$OFFICIAL_PKGS php-mbstring" ;;
curl) OFFICIAL_PKGS="$OFFICIAL_PKGS php-curl" ;;
xml) OFFICIAL_PKGS="$OFFICIAL_PKGS php-xml" ;;
intl) OFFICIAL_PKGS="$OFFICIAL_PKGS php-intl" ;;
esac
done
apt install -y $OFFICIAL_PKGS
fi
else
info "Todas las extensiones necesarias ya están presentes."
fi
else
# Instalación limpia de PHP (sin PPA previo)
info "Instalando PHP 8.3 y extensiones desde repositorios oficiales..."
apt install -y php8.3 php8.3-cli php8.3-common php8.3-mysql php8.3-zip \
php8.3-gd php8.3-mbstring php8.3-curl php8.3-xml php8.3-bcmath \
php8.3-intl php8.3-imagick php8.3-gmp libapache2-mod-php8.3
PHP_VER="8.3"
fi
# Habilitar módulos de Apache
a2enmod rewrite headers env dir mime 2>/dev/null || true
systemctl restart apache2
# -------------------- BASE DE DATOS --------------------
info "Configurando base de datos..."
if command_exists mysql; then
warn "MySQL/MariaDB ya está instalado."
systemctl start mariadb 2>/dev/null || systemctl start mysql 2>/dev/null || true
else
info "Instalando MariaDB..."
apt install -y mariadb-server
systemctl start mariadb
fi
# Crear base de datos y usuario (sin romper existentes)
create_database() {
local db="$1" user="$2" pass="$3"
if mysql -u root -e "exit" 2>/dev/null; then
MYSQL_CMD="mysql -u root"
else
echo -ne "${YELLOW}Contraseña de root de MySQL:${NC} "
read -s root_pass
echo
MYSQL_CMD="mysql -u root -p$root_pass"
fi
if $MYSQL_CMD -e "USE $db" 2>/dev/null; then
warn "Base de datos '$db' ya existe. Se usará la existente."
else
info "Creando base de datos '$db'..."
$MYSQL_CMD -e "CREATE DATABASE $db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
fi
if $MYSQL_CMD -e "SELECT 1 FROM mysql.user WHERE User='$user' AND Host='localhost'" | grep -q 1; then
warn "Usuario '$user' ya existe. Actualizando contraseña..."
$MYSQL_CMD -e "ALTER USER '$user'@'localhost' IDENTIFIED BY '$pass';"
else
info "Creando usuario '$user'..."
$MYSQL_CMD -e "CREATE USER '$user'@'localhost' IDENTIFIED BY '$pass';"
fi
$MYSQL_CMD -e "GRANT ALL PRIVILEGES ON $db.* TO '$user'@'localhost';"
$MYSQL_CMD -e "FLUSH PRIVILEGES;"
}
create_database "$DB_NAME" "$DB_USER" "$DB_PASS"
# -------------------- DESCARGA E INSTALACIÓN DE NEXTCLOUD --------------------
info "Preparando Nextcloud en $NC_DIR..."
mkdir -p "$(dirname "$NC_DIR")"
cd "$(dirname "$NC_DIR")"
if [ -d "$NC_DIR" ] && [ -f "$NC_DIR/config/config.php" ]; then
warn "Parece que Nextcloud ya está instalado."
if confirm "¿Deseas reinstalar (se perderán los datos)?"; then
info "Eliminando instalación anterior..."
rm -rf "$NC_DIR"
else
info "Manteniendo instalación existente. Saliendo."
exit 0
fi
fi
# Descargar Nextcloud
if [ ! -f latest.zip ]; then
info "Descargando Nextcloud..."
wget -q --show-progress https://download.nextcloud.com/server/releases/latest.zip
else
warn "El archivo latest.zip ya existe. Usándolo."
fi
info "Instalando unzip..."
apt install -y unzip
info "Descomprimiendo..."
unzip -q -o latest.zip
rm -f latest.zip
# Si se movió el directorio de instalación
if [ "$NC_DIR" != "/var/www/nextcloud" ] && [ -d "/var/www/nextcloud" ]; then
mv /var/www/nextcloud "$NC_DIR"
fi
# Configurar permisos
chown -R www-data:www-data "$NC_DIR"
chmod -R 755 "$NC_DIR"
# -------------------- CONFIGURACIÓN DE APACHE --------------------
info "Configurando VirtualHost de Apache..."
SERVER_IP=$(hostname -I | awk '{print $1}')
cat > /etc/apache2/sites-available/nextcloud.conf <<EOF
<VirtualHost *:$PORT>
ServerName $SERVER_IP
DocumentRoot $NC_DIR
<Directory $NC_DIR>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
</Directory>
ErrorLog \${APACHE_LOG_DIR}/nextcloud_error.log
CustomLog \${APACHE_LOG_DIR}/nextcloud_access.log combined
</VirtualHost>
EOF
# Deshabilitar sitio por defecto y habilitar Nextcloud
a2dissite 000-default.conf 2>/dev/null || true
a2ensite nextcloud.conf
systemctl reload apache2
# -------------------- RESUMEN FINAL --------------------
echo ""
echo "========================================="
echo -e "${GREEN}✅ INSTALACIÓN COMPLETA${NC}"
echo "========================================="
echo -e "${BLUE}🌐 Accede a Nextcloud en tu navegador:${NC}"
echo -e " http://$SERVER_IP:$PORT"
echo ""
echo -e "${BLUE}📌 Datos de la base de datos:${NC}"
echo " Nombre: $DB_NAME"
echo " Usuario: $DB_USER"
echo " Contraseña: $DB_PASS"
echo " Host: localhost"
echo ""
echo -e "${YELLOW}⚠️ IMPORTANTE: Completa la instalación en el navegador${NC}"
echo " Selecciona 'MySQL/MariaDB' e introduce los datos de arriba."
echo "========================================="
# Guardar credenciales opcionalmente
if [ "$NONINTERACTIVE" != "true" ]; then
if confirm "¿Guardar las credenciales en /root/nextcloud_credentials.txt?"; then
cat > /root/nextcloud_credentials.txt <<EOF
# Credenciales de Nextcloud - $(date)
IP: $SERVER_IP
Puerto: $PORT
Base de datos: $DB_NAME
Usuario DB: $DB_USER
Contraseña DB: $DB_PASS
EOF
chmod 600 /root/nextcloud_credentials.txt
info "Credenciales guardadas en /root/nextcloud_credentials.txt"
fi
fi
echo -e "${GREEN}¡Disfruta de Nextcloud! 🚀${NC}"Cómo ejecutar el script
- Crear el archivo:
nano install_nextcloud.sh - Pegar el script y guardar
- Dar permisos:
chmod +x install_nextcloud.sh - Ejecutar:
./install_nextcloud.sh
Acceso a Nextcloud
Una vez terminado, abre tu navegador y entra a:
http://TU_IPDesde ahí podrás crear el usuario administrador y conectar la base de datos.
Recomendaciones de seguridad
- 🔐 Cambiar la contraseña de la base de datos
- 🔒 Activar HTTPS con Let’s Encrypt
- 🧱 Configurar firewall (UFW)
- 💾 Hacer backups regularmente
Desinstalación
#!/bin/bash
# ==========================================
# Desinstalador automático de Nextcloud
# Ubuntu Server 24.04
# Revierte todos los cambios del instalador
# ==========================================
set -e
# -------------------- CONFIGURACIÓN --------------------
NC_DIR="${NEXTCLOUD_DIR:-/var/www/nextcloud}"
DB_NAME="${NEXTCLOUD_DB_NAME:-nextcloud}"
DB_USER="${NEXTCLOUD_DB_USER:-ncuser}"
APACHE_SITE="nextcloud.conf"
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# -------------------- FUNCIONES --------------------
error_exit() {
echo -e "${RED}ERROR: $1${NC}" >&2
exit 1
}
info() {
echo -e "${GREEN}➡️ $1${NC}"
}
warn() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
confirm() {
read -p "$1 [s/N]: " -n 1 -r
echo
[[ $REPLY =~ ^[Ss]$ ]]
}
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# -------------------- VERIFICACIÓN DE EJECUCIÓN --------------------
if [ "$EUID" -ne 0 ]; then
error_exit "Ejecuta con sudo o como root."
fi
echo ""
echo -e "${RED}=========================================${NC}"
echo -e "${RED} DESINSTALADOR DE NEXTCLOUD${NC}"
echo -e "${RED}=========================================${NC}"
warn "Este script eliminará Nextcloud y sus configuraciones."
warn "Los datos de la base de datos y archivos se perderán permanentemente."
echo ""
if ! confirm "¿Estás seguro de que deseas continuar?"; then
info "Desinstalación cancelada."
exit 0
fi
# -------------------- 1. DETENER SERVICIOS --------------------
info "Deteniendo servicios relacionados..."
systemctl stop apache2 2>/dev/null || true
systemctl stop mariadb 2>/dev/null || true
systemctl stop mysql 2>/dev/null || true
# -------------------- 2. ELIMINAR ARCHIVOS DE NEXTCLOUD --------------------
if [ -d "$NC_DIR" ]; then
info "Eliminando directorio de Nextcloud en $NC_DIR..."
rm -rf "$NC_DIR"
else
warn "El directorio $NC_DIR no existe."
fi
# Buscar y eliminar cualquier otro directorio de Nextcloud en /var/www
if [ -d "/var/www/nextcloud" ] && [ "/var/www/nextcloud" != "$NC_DIR" ]; then
info "Eliminando /var/www/nextcloud..."
rm -rf "/var/www/nextcloud"
fi
# -------------------- 3. ELIMINAR CONFIGURACIÓN DE APACHE --------------------
info "Eliminando configuración de Apache para Nextcloud..."
a2dissite "$APACHE_SITE" 2>/dev/null || true
rm -f "/etc/apache2/sites-available/$APACHE_SITE"
rm -f "/etc/apache2/sites-enabled/$APACHE_SITE"
# Opcionalmente restaurar el sitio por defecto si existe
if [ -f "/etc/apache2/sites-available/000-default.conf" ]; then
a2ensite 000-default.conf 2>/dev/null || true
fi
# Revertir cambios en el puerto si solo se usó para Nextcloud (opcional avanzado)
# Nota: no revertimos automáticamente porque podría haber otros sitios usando ese puerto.
systemctl reload apache2 2>/dev/null || true
# -------------------- 4. ELIMINAR BASE DE DATOS Y USUARIO (OPCIONAL) --------------------
echo ""
if confirm "¿Eliminar la base de datos '$DB_NAME' y el usuario '$DB_USER'?"; then
if command_exists mysql; then
info "Eliminando base de datos y usuario..."
# Determinar comando MySQL con o sin contraseña
if mysql -u root -e "exit" 2>/dev/null; then
MYSQL_CMD="mysql -u root"
else
echo -ne "${YELLOW}Ingresa la contraseña de root de MySQL:${NC} "
read -s root_pass
echo
MYSQL_CMD="mysql -u root -p$root_pass"
fi
$MYSQL_CMD -e "DROP DATABASE IF EXISTS $DB_NAME;" 2>/dev/null && info "Base de datos $DB_NAME eliminada."
$MYSQL_CMD -e "DROP USER IF EXISTS '$DB_USER'@'localhost';" 2>/dev/null && info "Usuario $DB_USER eliminado."
$MYSQL_CMD -e "FLUSH PRIVILEGES;" 2>/dev/null
else
warn "MySQL/MariaDB no está instalado. No se pudo eliminar la base de datos."
fi
else
info "Base de datos conservada."
fi
# -------------------- 5. ELIMINAR PAQUETES (OPCIONAL) --------------------
echo ""
if confirm "¿Eliminar paquetes de Apache, PHP y MariaDB instalados por el script?"; then
info "Eliminando paquetes..."
# Lista de paquetes comunes del instalador
PACKAGES_TO_REMOVE="apache2 mariadb-server mariadb-client"
PHP_PACKAGES="php8.3 php8.3-cli php8.3-common php8.3-mysql php8.3-zip php8.3-gd php8.3-mbstring php8.3-curl php8.3-xml php8.3-bcmath php8.3-intl php8.3-imagick php8.3-gmp libapache2-mod-php8.3"
# Añadir también los nombres genéricos por si acaso
PHP_GENERIC="php php-cli php-common php-mysql php-zip php-gd php-mbstring php-curl php-xml php-bcmath php-intl php-imagick php-gmp libapache2-mod-php"
# Preguntar si se quiere purgar (eliminar también configuraciones)
PURGE=""
if confirm "¿Eliminar también los archivos de configuración (purgar)?"; then
PURGE="--purge"
fi
apt remove $PURGE -y $PACKAGES_TO_REMOVE $PHP_PACKAGES $PHP_GENERIC 2>/dev/null || true
apt autoremove -y
info "Paquetes eliminados."
else
info "Paquetes conservados."
fi
# -------------------- 6. LIMPIEZA ADICIONAL --------------------
info "Limpiando archivos residuales..."
rm -f /var/www/latest.zip 2>/dev/null || true
rm -f /root/nextcloud_credentials.txt 2>/dev/null || true
# -------------------- 7. RESUMEN FINAL --------------------
echo ""
echo "========================================="
echo -e "${GREEN}✅ DESINSTALACIÓN COMPLETA${NC}"
echo "========================================="
echo -e "${YELLOW}Se han eliminado:${NC}"
echo " - Nextcloud (directorio $NC_DIR)"
echo " - Configuración de Apache (sitio nextcloud)"
if confirm "¿Eliminar base de datos?" 2>/dev/null; then
echo " - Base de datos $DB_NAME y usuario $DB_USER"
fi
if confirm "¿Eliminar paquetes?" 2>/dev/null; then
echo " - Paquetes de Apache, PHP y MariaDB (si se seleccionó)"
fi
echo ""
echo -e "${BLUE}Nota: Los datos personales de Nextcloud no son recuperables.${NC}"
echo "========================================="Conclusión
Con este método puedes tener tu propia nube privada funcionando en pocos minutos. Es ideal para uso personal o incluso para pequeñas empresas que quieran tener control total sobre sus datos.
Apóyame
Si esta guía te fue útil y quieres apoyar más contenido como este, puedes hacerlo aquí: