--- title: "How to Install Nextcloud on Ubuntu 24.04 with Nginx" description: "Install Nextcloud on Ubuntu 24.04 with Nginx, PHP-FPM 8.3, MariaDB and Redis, secure it with Let's Encrypt, and configure caching and background jobs with occ." category: "Web Applications Hosting" language: en source: https://cubepath.com/docs/web-applications-hosting/nextcloud-installation-and-configuration updated: 2026-09-25 --- # How to Install Nextcloud on Ubuntu 24.04 with Nginx Nextcloud is a self-hosted platform for file sync and sharing, calendars, contacts and collaboration, which keeps your data on a server you control. In this tutorial you will install Nextcloud on Ubuntu 24.04 with Nginx, PHP-FPM 8.3, MariaDB and Redis, run the installation from the command line with `occ`, secure it with Let's Encrypt, and configure caching and background jobs so the admin overview shows no warnings. ## Prerequisites To follow this guide you need: - A server running Ubuntu 24.04 LTS with at least 2 GB of RAM (4 GB for more than a handful of users), for example a CubePath VPS. - Enough disk space for your files. The data directory in this guide is `/srv/nextcloud-data`; mount a separate volume there if you expect a lot of data. - A non-root user with `sudo` privileges. - A subdomain with an A record pointing to the server, referred to as `cloud.your_domain`. - Ports 80 and 443 open to the internet. Don't have a server yet? Get a [Nextcloud VPS](/vps/vps-nextcloud) ready in minutes. ## Step 1 - Installing Nginx, PHP-FPM and the required modules Install Nginx, PHP-FPM and the PHP modules Nextcloud requires or recommends, plus Redis for file locking and `bzip2` to unpack the release archive: ```bash sudo apt update sudo apt install nginx php-fpm php-cli php-mysql php-gd php-curl php-mbstring php-intl php-xml php-zip php-bcmath php-gmp php-imagick php-apcu php-redis redis-server bzip2 ``` Ubuntu 24.04 installs PHP 8.3, which current Nextcloud releases support. Check the services: ```bash systemctl is-active nginx php8.3-fpm redis-server ``` ```output active active active ``` Open the firewall: ```bash sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable ``` ## Step 2 - Tuning PHP for Nextcloud Nextcloud needs more memory and a larger OPcache string buffer than the defaults. Create an override file for PHP-FPM: ```bash sudo nano /etc/php/8.3/fpm/conf.d/90-nextcloud.ini ``` ```ini memory_limit = 512M upload_max_filesize = 1G post_max_size = 1G max_execution_time = 360 output_buffering = Off opcache.memory_consumption = 256 opcache.interned_strings_buffer = 16 ``` The `occ` command line tool runs under PHP CLI, which disables APCu by default. Enable it for the CLI too, otherwise `occ` fails once APCu is configured as the cache in Step 7: ```bash echo 'apc.enable_cli=1' | sudo tee /etc/php/8.3/cli/conf.d/90-nextcloud-apcu.ini ``` PHP-FPM also clears environment variables by default, and Nextcloud warns that it cannot read `PATH`. Open the pool configuration: ```bash sudo nano /etc/php/8.3/fpm/pool.d/www.conf ``` Find the commented `env[PATH]` line and remove the leading `;` so it reads: ```ini env[PATH] = /usr/local/bin:/usr/bin:/bin ``` Restart PHP-FPM and confirm the memory limit: ```bash sudo systemctl restart php8.3-fpm sudo php-fpm8.3 -i | grep ^memory_limit ``` ```output memory_limit => 512M => 512M ``` ## Step 3 - Creating the database Install MariaDB: ```bash sudo apt install mariadb-server ``` Open the MariaDB shell as root: ```bash sudo mariadb ``` Create the database and user. Replace `your_db_password` with a long random password: ```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; ``` Test the new account: ```bash mariadb -u nextcloud -p -e "SELECT CURRENT_USER();" ``` ```output +---------------------+ | CURRENT_USER() | +---------------------+ | nextcloud@localhost | +---------------------+ ``` ## Step 4 - Downloading Nextcloud Download the latest release and its checksum from the official server: ```bash cd /tmp wget https://download.nextcloud.com/server/releases/latest.tar.bz2 wget https://download.nextcloud.com/server/releases/latest.tar.bz2.sha256 ``` Verify the archive before extracting it: ```bash sha256sum -c latest.tar.bz2.sha256 ``` ```output latest.tar.bz2: OK ``` Extract it to `/var/www`, which creates `/var/www/nextcloud`, and create the data directory outside the web root so user files can never be served directly by Nginx: ```bash sudo tar -xjf latest.tar.bz2 -C /var/www sudo mkdir -p /srv/nextcloud-data sudo chown -R www-data:www-data /var/www/nextcloud /srv/nextcloud-data sudo chmod 750 /srv/nextcloud-data ``` ## Step 5 - Installing Nextcloud with occ `occ` is Nextcloud's command line administration tool. It must always run as the web server user, `www-data`. Run the installation, replacing the database password, and choose an admin user name and a strong admin password: ```bash cd /var/www/nextcloud sudo -u www-data php occ maintenance:install \ --database mysql \ --database-name nextcloud \ --database-user nextcloud \ --database-pass 'your_db_password' \ --admin-user 'your_admin' \ --admin-pass 'your_admin_password' \ --data-dir /srv/nextcloud-data ``` ```output Nextcloud was successfully installed ``` By default Nextcloud only accepts requests for `localhost`. Add your domain as a trusted domain and set the URL used when `occ` and background jobs generate links: ```bash sudo -u www-data php occ config:system:set trusted_domains 1 --value=cloud.your_domain sudo -u www-data php occ config:system:set overwrite.cli.url --value=https://cloud.your_domain ``` Check the installation status: ```bash sudo -u www-data php occ status ``` ```output - installed: true - version: 32.0.0.13 - versionstring: 32.0.0 - edition: - maintenance: false - needsDbUpgrade: false - productname: Nextcloud - extendedSupport: false ``` Your version numbers will match the release you downloaded. ## Step 6 - Getting a certificate and configuring Nginx Request the certificate first, so the Nextcloud server block can point to it. The Certbot Nginx plugin answers the validation challenge through the default site that is still active: ```bash sudo apt install certbot python3-certbot-nginx sudo certbot certonly --nginx -d cloud.your_domain ``` ```output Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/cloud.your_domain/fullchain.pem Key is saved at: /etc/letsencrypt/live/cloud.your_domain/privkey.pem ``` Now create the Nextcloud site. This configuration is based on the one in the Nextcloud administration manual, adapted to Nginx 1.24 and PHP-FPM 8.3 on Ubuntu 24.04: ```bash sudo nano /etc/nginx/sites-available/nextcloud.conf ``` ```nginx upstream php-handler { server unix:/run/php/php8.3-fpm.sock; } # Mark versioned static assets as immutable map $arg_v $asset_immutable { "" ""; default ", immutable"; } server { listen 80; listen [::]:80; server_name cloud.your_domain; server_tokens off; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name cloud.your_domain; root /var/www/nextcloud; ssl_certificate /etc/letsencrypt/live/cloud.your_domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.your_domain/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; server_tokens off; client_max_body_size 1G; client_body_timeout 300s; fastcgi_buffers 64 4K; client_body_buffer_size 512k; add_header Strict-Transport-Security "max-age=15768000" always; 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; fastcgi_hide_header X-Powered-By; include mime.types; types { text/javascript mjs; } index index.php index.html /index.php$request_uri; location = / { if ( $http_user_agent ~ ^DavClnt ) { return 302 /remote.php/webdav/$is_args$args; } } location = /robots.txt { allow all; log_not_found off; access_log off; } 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; } location /.well-known/pki-validation { try_files $uri $uri/ =404; } return 301 /index.php$request_uri; } # Hide internal directories and files 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\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /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 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_max_temp_file_size 0; fastcgi_read_timeout 360s; } location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|tflite|map|ogg|flac)$ { try_files $uri /index.php$request_uri; add_header Cache-Control "public, max-age=15778463$asset_immutable"; 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; access_log off; } location ~ \.(otf|woff2?)$ { try_files $uri /index.php$request_uri; expires 7d; access_log off; } location /remote { return 301 /remote.php$request_uri; } location / { try_files $uri $uri/ /index.php$request_uri; } } ``` The security headers are repeated in the static assets block because Nginx does not inherit `add_header` directives into a location that defines its own. `client_max_body_size` matches the PHP upload limit from Step 2. Enable the site, disable the default one and test the configuration: ```bash sudo ln -s /etc/nginx/sites-available/nextcloud.conf /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default sudo nginx -t ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Reload Nginx and check that Nextcloud answers: ```bash sudo systemctl reload nginx curl -s https://cloud.your_domain/status.php ``` ```output {"installed":true,"maintenance":false,"needsDbUpgrade":false,"version":"32.0.0.13","versionstring":"32.0.0","edition":"","productname":"Nextcloud","extendedSupport":false} ``` Certbot renews the certificate automatically with its systemd timer and reloads Nginx through the plugin. Test it with `sudo certbot renew --dry-run`. ## Step 7 - Configuring caching and file locking Nextcloud uses APCu as a fast local cache and Redis for transactional file locking, which prevents corruption when several clients sync the same files. Configure both with `occ`: ```bash cd /var/www/nextcloud sudo -u www-data php occ config:system:set memcache.local --value='\OC\Memcache\APCu' sudo -u www-data php occ config:system:set memcache.locking --value='\OC\Memcache\Redis' sudo -u www-data php occ config:system:set redis host --value=localhost sudo -u www-data php occ config:system:set redis port --value=6379 --type=integer ``` Verify that the settings were stored: ```bash sudo -u www-data php occ config:system:get memcache.locking ``` ```output \OC\Memcache\Redis ``` ## Step 8 - Running background jobs with cron Nextcloud runs maintenance tasks (cleanup, previews, notifications) as background jobs. The default AJAX mode only runs them when someone uses the web interface. Switch to system cron: ```bash sudo -u www-data php occ background:cron ``` Open the crontab of the `www-data` user: ```bash sudo crontab -u www-data -e ``` Add this line to run the job every five minutes: ```text */5 * * * * php -f /var/www/nextcloud/cron.php ``` Also set a maintenance window, so heavy jobs run at night (the value is the hour in UTC), and the default phone region used to validate phone numbers in user profiles: ```bash sudo -u www-data php occ config:system:set maintenance_window_start --type=integer --value=1 sudo -u www-data php occ config:system:set default_phone_region --value=ES ``` Replace `ES` with your ISO 3166-1 country code. After a few minutes, **Administration settings > Basic settings** shows that the last background job ran seconds ago. ## Step 9 - Checking the setup warnings Log in at `https://cloud.your_domain` with the admin account from Step 5 and open **Administration settings > Overview**. Nextcloud runs a series of security and setup checks there. Two common database items can be fixed immediately: ```bash cd /var/www/nextcloud sudo -u www-data php occ db:add-missing-indices sudo -u www-data php occ maintenance:repair --include-expensive ``` Reload the overview page. The remaining warnings, if any, include a link to the relevant section of the documentation. Configure an email server under **Administration settings > Basic settings** so users receive share notifications and password resets. ## Troubleshooting **"Access through untrusted domain".** The host name in the browser is not in `trusted_domains`. List the current values with `sudo -u www-data php occ config:system:get trusted_domains` and add the missing one with a new index. **`occ` prints "Memcache \OC\Memcache\APCu not available".** APCu is disabled for the CLI. Check that `/etc/php/8.3/cli/conf.d/90-nextcloud-apcu.ini` contains `apc.enable_cli=1`. **Large uploads fail with 413 or time out.** Raise `client_max_body_size` in Nginx and `upload_max_filesize` and `post_max_size` in the PHP override together, then reload both services. The desktop and mobile clients upload in chunks and are not affected by these limits. **502 Bad Gateway.** PHP-FPM is not running or the socket path is wrong. Check `sudo systemctl status php8.3-fpm` and that `/run/php/php8.3-fpm.sock` exists. ## Conclusion Nextcloud is now running on Ubuntu 24.04 with Nginx, PHP-FPM 8.3, MariaDB and Redis, with HTTPS, file locking, local caching and system cron. As next steps, install the desktop and mobile clients to sync files, enable apps such as Calendar and Contacts from the **Apps** page, and set up regular backups of `/var/www/nextcloud/config`, `/srv/nextcloud-data` and the database (with `sudo -u www-data php occ maintenance:mode --on` while the backup runs).