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
sudoaccess, 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.
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:
$ 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:
$ sudo mariadb-secure-installation
$ systemctl is-active nginx php8.3-fpm mariadb redis-serverWhich 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:
$ sudo mariadbCREATE 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:
$ 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-datasha256sum -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.
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:
$ 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 nginxIssue 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:
$ sudo apt install -y certbot python3-certbot-nginx
$ sudo certbot --nginx -d YOUR_DOMAIN --redirect --agree-tos -m admin@YOUR_DOMAINCertbot 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:
$ 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-dataThe installer writes /var/www/nextcloud/config/config.php with localhost as the only trusted domain. Add the real domain and the CLI base URL:
$ 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=1Tune PHP and enable caching
The default PHP limits are too low for file uploads. Edit /etc/php/8.3/fpm/php.ini and set:
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 = 1APCu 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:
$ 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=6379Why 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:
$ sudo crontab -u www-data -eAdd the following line:
*/5 * * * * php -f /var/www/nextcloud/cron.php$ sudo -u www-data php /var/www/nextcloud/occ background:job:mode cronVerification
Check the application state, the setup warnings and the HTTP layer:
$ sudo -u www-data php /var/www/nextcloud/occ statusExpected output, with your own version numbers:
- installed: true
- version: 31.0.5.1
- versionstring: 31.0.5
- edition:
- maintenance: false
- needsDbUpgrade: false
- productname: NextcloudOn Nextcloud 28 and newer, occ setupchecks reports the same warnings the admin overview page shows:
$ sudo -u www-data php /var/www/nextcloud/occ setupchecks
$ curl -s https://YOUR_DOMAIN/status.phpThe 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
- Back Up and Restore Nextcloud: Data, Database, Config
- Install Nextcloud All-in-One with Docker
- Mount Nextcloud via WebDAV on Linux, Windows and macOS
- Nextcloud vs ownCloud vs Seafile: Which One Fits?
- Run Nextcloud with Docker Compose
- Set Up Nextcloud Office: Collabora or OnlyOffice
- Updating Nextcloud: Web Updater, occ and a Rollback Plan
- What Is Nextcloud? Architecture, Components and Use Cases
- Which Server for Nextcloud? Sizing RAM, CPU and Storage
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.