Nextcloud
AppArmor - Instal·lació - Nextcloud - Tutorial - Ubuntu

Com instal·lar Nextcloud Hub 9 (33.0.5) a Ubuntu 24.04 LTS

Nextcloud és una plataforma de núvol personal i empresarial de codi obert que permet emmagatzemar fitxers, calendaris, contactes i molt més al teu propi servidor. Aquest tutorial explica com instal·lar Nextcloud 33.0.5 a Ubuntu 24.04 LTS amb nginx, PHP 8.3 FPM, MySQL i Redis, incloent la configuració d’AppArmor que la majoria de tutorials ignoren.

Requisits previs

  • Ubuntu 24.04 LTS
  • Accés root al servidor
  • Nom de domini apuntant al servidor (en aquest exemple, nuvol.example.cat)
  • Certificat SSL (usarem Let’s Encrypt)

1. Instal·lació de paquets

apt update && apt upgrade -y

# Nginx
apt install nginx -y

# PHP 8.3 i extensions necessàries
apt install php8.3-fpm php8.3-mysql php8.3-xml php8.3-zip php8.3-curl \
  php8.3-gd php8.3-mbstring php8.3-intl php8.3-bcmath php8.3-gmp \
  php8.3-imagick php8.3-redis php8.3-apcu -y

# MySQL
apt install mysql-server -y

# Redis (instància dedicada per Nextcloud)
apt install redis-server -y

# Certbot per Let's Encrypt
apt install certbot python3-certbot-nginx -y

Nota: No instal·lis libapache2-mod-php8.3 — arrossegarà Apache innecessàriament. Si ja l’has instal·lat: apt remove libapache2-mod-php8.3 && apt autoremove.

2. Descàrrega de Nextcloud

cd /tmp
wget https://download.nextcloud.com/server/releases/nextcloud-33.0.5.zip
unzip nextcloud-33.0.5.zip
mv nextcloud /var/www/nextcloud
chown -R www-data:www-data /var/www/nextcloud

3. Configuració de MySQL

mysql -u root << 'EOF'
CREATE DATABASE nuvol CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'nuvol'@'localhost' IDENTIFIED BY 'CONTRASENYA_SEGURA';
GRANT ALL PRIVILEGES ON nuvol.* TO 'nuvol'@'localhost';
FLUSH PRIVILEGES;
EOF

4. Configuració de Redis dedicat per Nextcloud

Creem una instància Redis separada per no interferir amb altres serveis:

# Copia la configuració base
cp /etc/redis/redis.conf /etc/redis/nuvol-redis.conf

# Edita els paràmetres clau
sed -i 's/^port 6379/port 6387/' /etc/redis/nuvol-redis.conf
sed -i 's/^# requirepass/requirepass CONTRASENYA_REDIS/' /etc/redis/nuvol-redis.conf

Crea el servei systemd /etc/systemd/system/nuvol-redis.service:

[Unit]
Description=Advanced key-value store for Nextcloud
After=network.target

[Service]
ExecStart=/usr/bin/redis-server /etc/redis/nuvol-redis.conf
Restart=always

[Install]
WantedBy=multi-user.target
systemctl enable --now nuvol-redis.service

5. Configuració de PHP-FPM

Crea un pool dedicat per Nextcloud /etc/php/8.3/fpm/pool.d/nuvol.conf:

[nuvol]
user = www-data
group = www-data
listen = /run/php/nuvol.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 10
php_admin_value[upload_max_filesize] = 5G
php_admin_value[post_max_size] = 5G
php_admin_value[max_execution_time] = 600
php_admin_value[max_input_time] = 600
php_admin_value[memory_limit] = 1G
env[PATH] = /usr/local/bin:/usr/bin:/bin

Crea la configuració d’OPcache /etc/php/8.3/fpm/conf.d/99-nextcloud.ini:

opcache.enable=1
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=10000
opcache.memory_consumption=256
opcache.save_comments=1
opcache.revalidate_freq=1
opcache.jit=off
opcache.jit_buffer_size=0
apc.enable_cli=1
systemctl restart php8.3-fpm

6. Configuració d’AppArmor

Avís important: Ubuntu 24.04 porta AppArmor activat per defecte. Si no configures les regles correctament, obtindràs errors críptics de «Permission denied» o «Primary script unknown» sense cap pista útil. Sempre consulta dmesg | grep apparmor quan tinguis problemes de permisos inexplicables.

6.1. Regles per al socket del pool

cat >> /etc/apparmor.d/local/php-fpm << 'EOF'
/run/php/nuvol.sock rwlk,
/var/run/mysqld/mysqld.sock rw,
/run/mysqld/mysqld.sock rw,
/tmp/ rw,
/tmp/** rwk,
/usr/bin/dash rix,
/bin/dash rix,
/usr/share/fonts/ r,
/usr/share/fonts/** r,
/usr/local/share/fonts/ r,
/usr/local/share/fonts/** r,
/var/cache/fontconfig/ r,
/var/cache/fontconfig/** r,
/usr/share/ImageMagick-6/** r,
/etc/ImageMagick-6/** r,
/var/www/nextcloud/ r,
/var/www/nextcloud/** rwk,
network inet stream,
network inet6 stream,
EOF

6.2. Regles per als fitxers de Nextcloud

mkdir -p /etc/apparmor.d/php-fpm.d
cat > /etc/apparmor.d/php-fpm.d/nextcloud << 'EOF'
/var/www/nextcloud/ r,
/var/www/nextcloud/** rwk,
EOF

6.3. Aplica les regles

apparmor_parser -r /etc/apparmor.d/php-fpm

7. Configuració de nginx

Crea /etc/nginx/sites-available/nuvol.conf:

upstream php-handler {
    server unix:/run/php/nuvol.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name nuvol.example.cat;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name nuvol.example.cat;
    root /var/www/nextcloud;

    ssl_certificate /etc/letsencrypt/live/nuvol.example.cat/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/nuvol.example.cat/privkey.pem;

    error_log /var/log/nginx/nuvol.error.log;
    access_log /var/log/nginx/nuvol.access.log;

    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
    add_header X-Robots-Tag "noindex,nofollow" always;

    client_max_body_size 512M;
    fastcgi_buffers 64 4K;

    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/vnd.ms-fontobject 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;

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

    location ^~ /.well-known/carddav {
        return 301 $scheme://$host/remote.php/dav;
    }
    location ^~ /.well-known/caldav {
        return 301 $scheme://$host/remote.php/dav;
    }
    location ^~ /.well-known/webfinger {
        return 301 $scheme://$host/index.php/.well-known/webfinger;
    }
    location ^~ /.well-known/nodeinfo {
        return 301 $scheme://$host/index.php/.well-known/nodeinfo;
    }
    location ^~ /ocm-provider/ {
        return 301 $scheme://$host/index.php/ocm-provider/;
    }

    location / {
        rewrite ^ /index.php;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
        deny all;
    }

    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
        deny all;
    }

    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|oc[ms]-provider/.+|.+/richdocumentscode/proxy)\.php(?:$|/) {
        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 modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
    }

    location ~ ^/(?:updater|oc[ms]-provider)(?:$|/) {
        try_files $uri/ =404;
        index index.php;
    }

    location ~ \.(?:css|js|mjs|woff2?|svg|gif|map|otf|ttf|wasm)$ {
        try_files $uri /index.php$request_uri;
        add_header Cache-Control "public, max-age=15778463";
        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 "noindex,nofollow" always;
        add_header X-XSS-Protection "1; mode=block" always;
        access_log off;
    }

    location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
        try_files $uri /index.php$request_uri;
        access_log off;
    }
}

Afegeix els tipus MIME necessaris a /etc/nginx/mime.types si no hi són:

font/otf    otf;
font/ttf    ttf;

I assegura’t que js i mjs comparteixen la mateixa línia:

application/javascript    js mjs;

Activa el lloc i obtén el certificat SSL:

ln -s /etc/nginx/sites-available/nuvol.conf /etc/nginx/sites-enabled/
certbot --nginx -d nuvol.example.cat
nginx -t && nginx -s reload

8. Instal·lació via wizard web

Obre https://nuvol.example.cat al navegador. Hauries de veure el wizard d’instal·lació de Nextcloud. Omple:

  • Compte d’administració: el teu usuari i contrasenya
  • Carpeta de dades: /var/www/nextcloud/data
  • Base de dades: MySQL/MariaDB
  • Usuari BD: nuvol
  • Contrasenya BD: la que has definit al pas 3
  • Nom BD: nuvol
  • Host BD: localhost

9. Configuració post-instal·lació

# Índexs de base de dades
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-indices

# Migracions MIME
sudo -u www-data php /var/www/nextcloud/occ maintenance:repair --include-expensive

# Finestra de manteniment (hora en UTC, 1 = 01:00-05:00 UTC)
sudo -u www-data php /var/www/nextcloud/occ config:system:set maintenance_window_start --type=integer --value=1

# Regió telefònica
sudo -u www-data php /var/www/nextcloud/occ config:system:set default_phone_region --value='ES'

# URL de la instància
sudo -u www-data php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value="https://nuvol.example.cat"

# Identificador de servidor
sudo -u www-data php /var/www/nextcloud/occ config:system:set serverid --type=integer --value=1

# Redis com a caché
sudo -u www-data php /var/www/nextcloud/occ config:system:set memcache.local --value='\OC\Memcache\Redis'
sudo -u www-data php /var/www/nextcloud/occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
sudo -u www-data php /var/www/nextcloud/occ config:system:set redis host --value='127.0.0.1'
sudo -u www-data php /var/www/nextcloud/occ config:system:set redis port --type=integer --value=6387
sudo -u www-data php /var/www/nextcloud/occ config:system:set redis password --value='CONTRASENYA_REDIS'

# Desactiva Collabora si no el necessites (requereix glibc específic)
sudo -u www-data php /var/www/nextcloud/occ app:disable richdocuments

# Cron de fons cada 5 minuts
echo "*/5 * * * * www-data php -f /var/www/nextcloud/cron.php" > /etc/cron.d/nextcloud
sudo -u www-data php /var/www/nextcloud/occ background:cron

10. Configuració de correu

sudo -u www-data php /var/www/nextcloud/occ config:system:set mail_smtpmode --value="sendmail"
sudo -u www-data php /var/www/nextcloud/occ config:system:set mail_from_address --value="no-reply"
sudo -u www-data php /var/www/nextcloud/occ config:system:set mail_domain --value="nuvol.example.cat"

Resolució de problemes freqüents

«access forbidden by rule» a nginx

La regex ^/(?:.|autotest...) sense escapar el punt bloqueja totes les URLs. Assegura’t que és ^/(?:\.|autotest...) amb el punt escapat.

«Primary script unknown» a php-fpm

Comprova que l’usuari del pool php-fpm té accés als fitxers:

sudo -u www-data cat /var/www/nextcloud/index.php

Si falla, revisa els permisos i AppArmor:

dmesg | grep apparmor | tail -10

«Could not acquire an exclusive lock on the config file»

AppArmor bloqueja flock(). La regla rwk (amb la k de lock) és imprescindible:

/var/www/nextcloud/** rwk,

«Permission denied» inexplicables

Sempre consulta dmesg | grep apparmor — els errors de AppArmor no apareixen als logs de nginx ni de PHP, només al kernel log.

Pool php-fpm no arrenca («Permission denied» al socket)

AppArmor només permet crear sockets amb el patró php*-fpm.sock per defecte. Per a sockets amb noms personalitzats cal afegir explícitament:

/run/php/NOM_SOCKET.sock rwlk,

Conclusió

La instal·lació de Nextcloud a Ubuntu 24.04 amb AppArmor actiu requereix configurar les regles de seguretat correctament. Tot i que pot semblar complicat al principi, un cop entès el patró — qualsevol «Permission denied» inexplicable cal buscar-lo a dmesg | grep apparmor — la configuració és manejable i proporciona una capa de seguretat addicional valuosa.

Avatar photo

De vegades escric tutorials

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *