Tutorials  /  Ubuntu

Install Nextcloud on Ubuntu 24.04 with nginx

LLudwig · August 2026 ·9 min read ·Ubuntu, Tutorial

Nextcloud on Ubuntu 24.04 does not come from a distribution package: nginx, PHP 8.3-FPM and MariaDB come from the Ubuntu repositories, the server code as a ZIP archive from nextcloud.com. This tutorial walks through a complete manual installation on a single host, including TLS, Redis-based file locking and the background job Nextcloud needs to stay consistent.

What do you need to run Nextcloud on Ubuntu 24.04?

A Nextcloud installation on Ubuntu 24.04 needs nginx as web server, PHP 8.3-FPM, a MariaDB or PostgreSQL database, at least 2 GB of RAM and a DNS A record pointing at the host so Let's Encrypt can validate the domain.

  • An Ubuntu 24.04 LTS host with sudo access, for example a scalable Cloud-VM with 2 vCPU and 4 GB RAM
  • A domain or subdomain resolving to the host's public IP, referred to below as YOUR_DOMAIN
  • Ports 80 and 443 reachable from the internet
  • Free disk space for /var/nextcloud-data, sized for the files you plan to store

All commands run as a user with sudo rights. Replace every YOUR_* placeholder before pasting.

How the request path works

nginx terminates TLS, serves static assets from the document root and forwards every PHP request over a Unix socket to PHP-FPM. PHP-FPM is the only component that talks to the database, the cache and the data directory.

graph TD
    A["Browser (HTTPS)"] --> B["nginx :443"]
    B -->|"static assets"| C["/var/www/nextcloud"]
    B -->|"FastCGI"| D["/run/php/php8.3-fpm.sock"]
    D --> E["MariaDB: nextcloud"]
    D --> F["Redis: cache and locking"]
    D --> G["/var/nextcloud-data"]
    H["cron.php every 5 minutes"] --> D

Keeping the data directory outside the document root (/var/nextcloud-data, not /var/www/nextcloud/data) means a broken nginx rule can never expose user files over HTTP.

VM

Matching infrastructure at centron

No hardware needed to follow along: ccloud³ VMs with full root access, billed by the hour and ready in seconds. Rent a cloud server →

Install nginx, PHP 8.3-FPM and MariaDB

Install the web server, the PHP extensions Nextcloud requires, the database and Redis in one step:

Console
$ sudo apt update
$ sudo apt install -y nginx mariadb-server redis-server unzip \
  php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-intl php8.3-mbstring \
  php8.3-xml php8.3-zip php8.3-bcmath php8.3-gmp php8.3-apcu php8.3-redis php8.3-imagick
Package group Role
nginx TLS termination, static files, FastCGI proxy
php8.3-fpm + extensions Runs the Nextcloud application code
mariadb-server Stores metadata, shares, users
redis-server, php8.3-apcu Transactional file locking and local cache

Harden the database instance and confirm both services are running:

Console
$ sudo mariadb-secure-installation
$ systemctl is-active nginx php8.3-fpm mariadb redis-server

Which PHP version does Nextcloud need on Ubuntu 24.04?

Ubuntu 24.04 LTS ships PHP 8.3 as its default version, and Nextcloud 28 and newer run on PHP 8.1 to 8.3, so a current Nextcloud release installs on the distribution PHP without a third-party PPA.

If you later upgrade PHP, remember that the FPM socket path contains the version number. A jump to PHP 8.4 changes /run/php/php8.3-fpm.sock to /run/php/php8.4-fpm.sock and requires an edit to the nginx upstream block.

Create the database and user

Nextcloud requires utf8mb4 for 4-byte characters such as emoji in file names. Create the database explicitly with that character set:

Console
$ sudo mariadb
sql
CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'YOUR_DB_PASSWORD';
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Download and unpack Nextcloud

Download the current release together with its checksum file and verify the archive before unpacking it:

Console
$ cd /tmp
$ curl -LO https://download.nextcloud.com/server/releases/latest.zip
$ curl -LO https://download.nextcloud.com/server/releases/latest.zip.sha256
$ sha256sum -c latest.zip.sha256
$ sudo unzip -q latest.zip -d /var/www
$ sudo mkdir -p /var/nextcloud-data
$ sudo chown -R www-data:www-data /var/www/nextcloud /var/nextcloud-data
$ sudo chmod 750 /var/nextcloud-data

sha256sum -c must print latest.zip: OK. If it reports that no file matched, the checksum file lists the versioned archive name instead. Compare the output of sha256sum latest.zip with the file contents manually in that case.

Configure the nginx server block

Create /etc/nginx/sites-available/nextcloud.conf. The block below covers the essentials: PHP routing, service discovery for DAV clients and a deny list for internal directories.

nginx
upstream php-handler {
    server unix:/run/php/php8.3-fpm.sock;
}
server {
    listen 80;
    listen [::]:80;
    server_name YOUR_DOMAIN;
    root /var/www/nextcloud;
    index index.php index.html;
    client_max_body_size 512M;
    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;
    # Service discovery for CalDAV and CardDAV clients
    location = /.well-known/carddav { return 301 /remote.php/dav; }
    location = /.well-known/caldav  { return 301 /remote.php/dav; }
    location ^~ /.well-known { return 301 /index.php$uri; }
    # Never expose internal paths
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
    location / { try_files $uri $uri/ /index.php$request_uri; }
    location ~ \.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 HTTPS on;
        fastcgi_param modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
        fastcgi_read_timeout 300;
    }
    location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|woff2?)$ {
        try_files $uri /index.php$request_uri;
        expires 6M;
        access_log off;
    }
}

Enable the site, drop the default block and test the syntax before reloading:

Console
$ sudo ln -s /etc/nginx/sites-available/nextcloud.conf /etc/nginx/sites-enabled/
$ sudo rm -f /etc/nginx/sites-enabled/default
$ sudo nginx -t
$ sudo systemctl reload nginx

Issue a TLS certificate with Certbot

The Certbot nginx plugin requests the certificate and rewrites the server block for port 443, including the redirect from HTTP:

Console
$ sudo apt install -y certbot python3-certbot-nginx
$ sudo certbot --nginx -d YOUR_DOMAIN --redirect --agree-tos -m admin@YOUR_DOMAIN

Certbot installs a systemd timer for renewal. Verify it with systemctl list-timers certbot.timer and test the renewal path with sudo certbot renew --dry-run.

Run the installation with occ

Run the installation from the command line rather than the web wizard. The occ route is repeatable, scriptable and does not send the admin password through a browser form:

Console
$ sudo -u www-data php /var/www/nextcloud/occ maintenance:install \
  --database mysql --database-name nextcloud \
  --database-user nextcloud --database-pass 'YOUR_DB_PASSWORD' \
  --admin-user admin --admin-pass 'YOUR_ADMIN_PASSWORD' \
  --data-dir /var/nextcloud-data

The installer writes /var/www/nextcloud/config/config.php with localhost as the only trusted domain. Add the real domain and the CLI base URL:

Console
$ sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 1 --value=YOUR_DOMAIN
$ sudo -u www-data php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value=https://YOUR_DOMAIN
$ sudo -u www-data php /var/www/nextcloud/occ config:system:set default_phone_region --value=DE
$ sudo -u www-data php /var/www/nextcloud/occ config:system:set maintenance_window_start --type=integer --value=1

Tune PHP and enable caching

The default PHP limits are too low for file uploads. Edit /etc/php/8.3/fpm/php.ini and set:

ini
memory_limit = 512M
upload_max_filesize = 512M
post_max_size = 512M
max_execution_time = 360
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.save_comments = 1

APCu is disabled for CLI by default, which makes occ fail with a memcache error. Enable it, then wire Nextcloud to APCu for local caching and Redis for distributed locking:

Console
$ echo 'apc.enable_cli = 1' | sudo tee /etc/php/8.3/cli/conf.d/99-apcu-cli.ini
$ sudo systemctl restart php8.3-fpm
$ sudo -u www-data php /var/www/nextcloud/occ config:system:set memcache.local --value='\OC\Memcache\APCu'
$ sudo -u www-data php /var/www/nextcloud/occ config:system:set memcache.distributed --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=6379

Why does Nextcloud need a background job?

Nextcloud runs maintenance work such as file scans, share expiry, trash cleanup and notification delivery in a background job that must execute cron.php every five minutes, otherwise those tasks never run.

Register the job for the www-data user and switch the mode from AJAX to cron:

Console
$ sudo crontab -u www-data -e

Add the following line:

Console
*/5 * * * * php -f /var/www/nextcloud/cron.php
Console
$ sudo -u www-data php /var/www/nextcloud/occ background:job:mode cron

Verification

Check the application state, the setup warnings and the HTTP layer:

Console
$ sudo -u www-data php /var/www/nextcloud/occ status

Expected output, with your own version numbers:

Console
  - installed: true
  - version: 31.0.5.1
  - versionstring: 31.0.5
  - edition:
  - maintenance: false
  - needsDbUpgrade: false
  - productname: Nextcloud

On Nextcloud 28 and newer, occ setupchecks reports the same warnings the admin overview page shows:

Console
$ sudo -u www-data php /var/www/nextcloud/occ setupchecks
$ curl -s https://YOUR_DOMAIN/status.php

The status.php response must contain "installed":true and "maintenance":false. Then log in at https://YOUR_DOMAIN with the admin account you passed to maintenance:install.

Troubleshooting

502 Bad Gateway on every page. nginx cannot reach the FPM socket. Confirm the path with ls -l /run/php/ and match it against the upstream php-handler block, then check journalctl -u php8.3-fpm -n 50.

"Access through untrusted domain". The requested host is missing from trusted_domains. List the current entries with sudo -u www-data php /var/www/nextcloud/occ config:system:get trusted_domains and add the domain at the next free index.

Desktop or mobile clients fail to connect calendars. The /.well-known/caldav and /.well-known/carddav redirects are missing or shadowed by another location block. Verify with curl -sI https://YOUR_DOMAIN/.well-known/caldav, which must return 301 pointing to /remote.php/dav.

Uploads stop at 2 MB. php.ini was edited under /etc/php/8.3/cli/ instead of /etc/php/8.3/fpm/, or PHP-FPM was not restarted. Confirm the effective values in the Nextcloud admin overview.

Next steps

The instance is production-capable at this point: TLS in place, Redis locking active, background job scheduled. Take a snapshot before installing apps, and set up a database dump plus a copy of /var/nextcloud-data and config/config.php as your restore path. Before any major upgrade, run sudo -u www-data php /var/www/nextcloud/occ upgrade after replacing the code directory, never the other way around.

Read next

Jetzt 200 € Guthaben sichern

Testen Sie Ihr Setup auf ccloud³

Registrieren Sie sich in der ccloud³ und erhalten Sie 200 € Startguthaben für Ihr Projekt – z. B. für eine PostgreSQL-VM mit automatischen Backups.

Ludwig Technische Redaktion

Schreibt bei centron über Linux-Administration, Container und Datenbanken – mit Fokus auf Anleitungen, die im Betrieb tatsächlich funktionieren.

Kategorie Ubuntu
Teilen
Noch offene Fragen?

Our team will help you with your specific setup - in German or English, by people who run the platform themselves.

War dieses Tutorial hilfreich?

Your answer is stored anonymously and helps us improve our tutorials.

Kommentare

No comments yet - be the first to ask a question about this tutorial.

Sign in to comment

Comments are open to centron customers. Sign in to your account to ask a question about this tutorial.

Weiterlesen

Das könnte Sie auch interessieren

Jetzt kostenlos anfangen

Melden Sie sich an und erhalten Sie in den ersten 60 Tagen ein Guthaben von 200 € bei centron.

Dieses Werbeangebot gilt nur für neue Konten. Angebot ausschließlich für Gewerbetreibende.

Jetzt loslegen Sales kontaktieren