Nextcloud is an open source platform for storing, syncing and sharing files, similar to Google Drive or Dropbox but running on a server you control. It also includes calendars, contacts and desktop and mobile sync clients. In this tutorial you will install Nextcloud on Ubuntu 24.04 with Apache, PHP 8.3 and MariaDB, secure it with a Let's Encrypt certificate, and configure memory caching and background jobs so it runs without warnings.

Prerequisites

To follow this tutorial you need:

  • A server running Ubuntu 24.04 LTS with at least 2 GB of RAM, for example a CubePath VPS. Plan the disk size according to how much data you will store.
  • A non-root user with sudo privileges.
  • A domain name, referred to as your_domain in this guide, with a DNS A record pointing to your server's public IP. A domain is required to get a TLS certificate.
  • Ports 80 and 443 reachable from the Internet.

Step 1 - Installing Apache, PHP and MariaDB

Ubuntu 24.04 ships PHP 8.3, which is supported by current Nextcloud releases, so everything can come from the Ubuntu repositories. Install Apache, MariaDB, PHP and the PHP modules Nextcloud needs:

sudo apt update
sudo apt install apache2 mariadb-server libapache2-mod-php php-gd php-mysql php-curl php-mbstring php-intl php-gmp php-bcmath php-xml php-imagick php-zip php-apcu unzip

Check that Apache and MariaDB are running:

systemctl is-active apache2 mariadb
active
active

Allow SSH and web traffic through UFW, then enable the firewall:

sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enable

Step 2 - Creating the database

Run the MariaDB hardening script. On Ubuntu the MariaDB root account already authenticates through the Unix socket, so you can answer n to switching to unix_socket authentication and to changing the root password, and Y to the remaining questions (remove anonymous users, disallow remote root login, remove the test database):

sudo mariadb-secure-installation

Open the MariaDB shell:

sudo mariadb

Create a database and a dedicated user for Nextcloud. Replace your_strong_password with a long random password and keep it for Step 4:

CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Verify that the new user can log in and see its database:

mariadb -u nextcloud -p -e "SHOW DATABASES;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| nextcloud          |
+--------------------+

Step 3 - Downloading Nextcloud

Download the latest Nextcloud Server release and its checksum file:

cd /tmp
wget https://download.nextcloud.com/server/releases/latest.zip
wget https://download.nextcloud.com/server/releases/latest.zip.sha256

Verify the archive before extracting it:

sha256sum -c latest.zip.sha256
latest.zip: OK

Extract it to /var/www, which creates /var/www/nextcloud. Create a separate data directory outside the web root so that uploaded files can never be served directly by Apache, and give both directories to the www-data user:

sudo unzip -q latest.zip -d /var/www
sudo mkdir /var/www/nextcloud-data
sudo chown -R www-data:www-data /var/www/nextcloud /var/www/nextcloud-data

Step 4 - Running the installer

Nextcloud includes a command line tool, occ, that must always run as www-data. Use it to perform the installation instead of the web wizard, so the database password and admin credentials never travel over plain HTTP. Replace your_strong_password with the database password from Step 2, and your_admin_user and your_admin_password with the credentials of the Nextcloud administrator you want to create:

cd /var/www/nextcloud
sudo -u www-data php occ maintenance:install \
  --database mysql \
  --database-name nextcloud \
  --database-user nextcloud \
  --database-pass 'your_strong_password' \
  --admin-user 'your_admin_user' \
  --admin-pass 'your_admin_password' \
  --data-dir /var/www/nextcloud-data
Nextcloud was successfully installed

Nextcloud only answers requests for the hostnames listed as trusted domains. Add your domain and set the URL used by command line jobs:

sudo -u www-data php occ config:system:set trusted_domains 1 --value=your_domain
sudo -u www-data php occ config:system:set overwrite.cli.url --value=https://your_domain

Check the installation status:

sudo -u www-data php occ status
  - installed: true
  - version: 32.0.0.13
  - versionstring: 32.0.0
  - edition:
  - maintenance: false
  - needsDbUpgrade: false

Your version number will match the release you downloaded.

Step 5 - Configuring the Apache virtual host

Create a virtual host for Nextcloud:

sudo nano /etc/apache2/sites-available/nextcloud.conf

Add the following configuration, replacing your_domain:

<VirtualHost *:80>
    ServerName your_domain
    DocumentRoot /var/www/nextcloud

    <Directory /var/www/nextcloud/>
        Require all granted
        AllowOverride All
        Options FollowSymLinks MultiViews

        <IfModule mod_dav.c>
            Dav off
        </IfModule>
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/nextcloud_error.log
    CustomLog ${APACHE_LOG_DIR}/nextcloud_access.log combined
</VirtualHost>

AllowOverride All is required because Nextcloud ships its own .htaccess rules, and Dav off disables Apache's WebDAV module so that Nextcloud handles WebDAV itself.

Enable the site and the modules Nextcloud relies on, and disable the default site:

sudo a2ensite nextcloud.conf
sudo a2dissite 000-default.conf
sudo a2enmod rewrite headers env dir mime

Test the configuration and reload Apache:

sudo apache2ctl configtest
sudo systemctl reload apache2
Syntax OK

Step 6 - Enabling HTTPS with Let's Encrypt

Install Certbot with its Apache plugin:

sudo apt install certbot python3-certbot-apache

Request a certificate. Certbot creates an HTTPS virtual host based on the one from Step 5 and adds a redirect from HTTP to HTTPS:

sudo certbot --apache -d your_domain

Nextcloud recommends sending an HSTS header. Open the HTTPS virtual host that Certbot created:

sudo nano /etc/apache2/sites-available/nextcloud-le-ssl.conf

Add this line inside the <VirtualHost *:443> block, below ServerName:

Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"

Reload Apache and confirm that the header is returned:

sudo systemctl reload apache2
curl -sI https://your_domain/ | grep -i strict
strict-transport-security: max-age=15552000; includeSubDomains

Certbot installs a systemd timer that renews the certificate automatically. You can test the renewal with sudo certbot renew --dry-run.

Step 7 - Tuning PHP and enabling caching

Nextcloud recommends at least 512 MB of PHP memory and a larger upload size. Open the PHP configuration used by Apache:

sudo nano /etc/php/8.3/apache2/php.ini

Find and change these directives:

memory_limit = 512M
upload_max_filesize = 2G
post_max_size = 2G
opcache.interned_strings_buffer = 16

Background jobs run through the PHP command line, so APCu must also be enabled for the CLI. Open the APCu module file:

sudo nano /etc/php/8.3/mods-available/apcu.ini

Add this line at the end:

apc.enable_cli=1

Restart Apache to load the changes, then tell Nextcloud to use APCu as its local memory cache and set your default phone region (an ISO 3166-1 code such as US or ES):

sudo systemctl restart apache2
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 default_phone_region --value=US

Enable pretty URLs, which removes index.php from the links:

sudo -u www-data php /var/www/nextcloud/occ config:system:set htaccess.RewriteBase --value=/
sudo -u www-data php /var/www/nextcloud/occ maintenance:update:htaccess

Step 8 - Running background jobs with cron

Nextcloud performs maintenance tasks such as cleanup and file scanning in background jobs. The most reliable method is a system cron job that runs every 5 minutes as www-data. Open the crontab of that user:

sudo crontab -u www-data -e

Add this line:

*/5 * * * * php -f /var/www/nextcloud/cron.php

Switch Nextcloud to cron mode:

sudo -u www-data php /var/www/nextcloud/occ background:cron
Set mode for background jobs to 'cron'

Step 9 - Logging in and checking the setup

Open https://your_domain in your browser and log in with the administrator account you created in Step 4. Then go to Administration settings > Overview. Nextcloud runs a series of security and setup checks there; with the steps above, the list should show no errors. Any remaining informational warnings include a link to the relevant section of the Nextcloud documentation.

To test the full upload path, drag a file into the Files app and confirm that it appears under /var/www/nextcloud-data/your_admin_user/files/ on the server:

sudo ls /var/www/nextcloud-data/your_admin_user/files/

Troubleshooting

  • "Access through untrusted domain": the hostname you used is not in trusted_domains. List the current values with sudo -u www-data php /var/www/nextcloud/occ config:system:get trusted_domains and add the missing one.
  • Uploads of large files fail: check that upload_max_filesize and post_max_size were changed in /etc/php/8.3/apache2/php.ini (not only in the CLI php.ini) and that Apache was restarted.
  • occ fails with "Memcache \OC\Memcache\APCu not available": apc.enable_cli=1 is missing from /etc/php/8.3/mods-available/apcu.ini.
  • Errors in the web interface: read the Nextcloud log with sudo tail -n 50 /var/www/nextcloud-data/nextcloud.log and Apache's log in /var/log/apache2/nextcloud_error.log.

Conclusion

You now have a private Nextcloud instance on Ubuntu 24.04, served over HTTPS with Apache, MariaDB, APCu caching and cron based background jobs. As next steps, install the Nextcloud desktop and mobile clients to sync your files, add Redis for file locking if several users work at the same time, and set up regular backups of /var/www/nextcloud, /var/www/nextcloud-data and the nextcloud database.