How to install Nextcloud Server manually with Apache, PHP-FPM and MariaDB
Install Nextcloud Server by hand on Ubuntu or Debian with Apache, PHP-FPM, MariaDB and Redis, then add HTTPS, background jobs, backups and safe upgrades.
- Advanced
- 75 min read
- Updated
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 13
This guide is not available in your language yet, so it is shown in English.
On this page
- Prerequisites
- Step 1 — Install Apache, PHP-FPM, MariaDB and Redis
- Step 2 — Configure PHP
- Step 3 — Create the database
- Step 4 — Download and verify Nextcloud
- Step 5 — Configure Apache
- Step 6 — Install Nextcloud from the command line
- Step 7 — Turn on HTTPS and the firewall
- Step 8 — Enable memory caching
- Step 9 — Run background jobs with a systemd timer
- Step 10 — Clear the security and setup warnings
- Back up and restore
- Update Nextcloud
- Troubleshooting
- Access through untrusted domain
- occ reports that APCu is not available for the local cache
- Pages other than the start page return Not Found
- The overview says background jobs have not run for a long time
- The updater stops because the PHP version is not supported
- Next steps
Nextcloud Server is an open-source platform for file sync and sharing, calendars, contacts and collaboration that you run on your own server. This guide installs it by hand from the official archive, following the Nextcloud administration manual for the current major version, Nextcloud 35. You set up Apache with PHP-FPM, MariaDB, APCu and Redis caching, a verified download, the command-line installer, HTTPS with Certbot, background jobs through a systemd timer, and the backup, restore and upgrade procedures from the manual.
A manual install gives you full control, and also full responsibility for every component. If you prefer containers that update and back up themselves, use Nextcloud All-in-One instead.
Prerequisites
- A server running Ubuntu 26.04 LTS (recommended by Nextcloud), Ubuntu 24.04 LTS or Debian 13. These are the Ubuntu and Debian releases the Nextcloud 35 manual lists.
- A non-root user with
sudorights and SSH key login: see Secure a new Linux server and Set up SSH keys. - A domain such as
cloud.example.comwith an A/AAAA record pointing at the server, and nothing else listening on ports 80 and 443.
Check the versions your release ships against the manual's requirements:
| Component | Nextcloud 35 supports | Ubuntu 24.04 | Ubuntu 26.04 | Debian 13 |
|---|---|---|---|---|
| PHP | 8.3, 8.4; 8.5 recommended | 8.3 | 8.5 | 8.4 |
| MariaDB | 10.11, 11.4, 11.8 (recommended), 12.3 | 10.11 | 11.8 | 11.8 |
The manual gives memory requirements per PHP process, not per server. The suggested values are a conservative starting point for a small team, not official numbers:
| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| RAM | 128 MB per PHP process; 512 MB per process recommended | 2 GB for a few users, more for Office or many users |
| CPU | Not published | 2 vCPUs |
| Disk | Not published | 20 GB SSD for the system plus space for all user files |
Step 1 — Install Apache, PHP-FPM, MariaDB and Redis
The manual lists Apache 2.4 with mod_php or PHP-FPM, or Nginx with PHP-FPM. This guide uses Apache with PHP-FPM, which runs PHP in its own service and lets you tune the number of PHP processes. Install the packages from the manual's Ubuntu example plus PHP-FPM and the cache modules:
sudo apt update && sudo apt upgrade
sudo apt install apache2 mariadb-server redis-server bzip2 php-fpm php-cli php-gd php-mysql php-curl php-mbstring php-intl php-gmp php-xml php-imagick php-zip php-apcu php-redisCheck PHP and the modules:
php -v
php -m | grep -E "apcu|redis|imagick|intl"
systemctl status redis-server mariadb --no-pagerphp -v should report 8.3, 8.4 or 8.5, and the module list should include all four names.
Step 2 — Configure PHP
Store your PHP version in a variable, then set the memory limit the manual asks for. Nextcloud's command-line tool occ also needs APCu enabled for the CLI, which is off by default:
PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
echo $PHP_VER
sudo tee /etc/php/$PHP_VER/fpm/conf.d/90-nextcloud.ini <<'EOF'
memory_limit = 512M
EOF
sudo tee /etc/php/$PHP_VER/cli/conf.d/90-nextcloud.ini <<'EOF'
memory_limit = 512M
apc.enable_cli = 1
EOF
sudo systemctl restart php$PHP_VER-fpm
php -i | grep -E "memory_limit|apc.enable_cli"The last command should show 512M and On.
Step 3 — Create the database
Generate a strong password with openssl rand -hex 24, then open the MariaDB shell with sudo mariadb and run:
CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'change-me';
CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';
FLUSH PRIVILEGES;
quit;Replace change-me with your generated password. Nextcloud creates its tables during installation.
Step 4 — Download and verify Nextcloud
Download the latest release, its checksum and its signature from download.nextcloud.com, plus Nextcloud's public key:
cd /tmp
wget https://download.nextcloud.com/server/releases/latest.tar.bz2
wget https://download.nextcloud.com/server/releases/latest.tar.bz2.sha256
wget https://download.nextcloud.com/server/releases/latest.tar.bz2.asc
wget https://nextcloud.com/nextcloud.asc
sha256sum -c --ignore-missing latest.tar.bz2.sha256
gpg --import nextcloud.asc
gpg --verify latest.tar.bz2.asc latest.tar.bz2sha256sum must print latest.tar.bz2: OK, and gpg must report a good signature. A warning that the key is not certified with a trusted signature is normal for a key you just imported. If either check fails, delete the files and download them again.
Unpack the archive into the web root, and create a data directory outside the web root, as the hardening guide recommends:
sudo tar -xjf latest.tar.bz2 -C /var/www
sudo chown -R www-data:www-data /var/www/nextcloud
sudo mkdir -p /srv/nextcloud/data
sudo chown -R www-data:www-data /srv/nextcloudStep 5 — Configure Apache
Create /etc/apache2/sites-available/nextcloud.conf with sudo nano and add the virtual host from the manual. The FilesMatch block passes the Authorization header to PHP-FPM, which WebDAV clients need:
<VirtualHost *:80>
ServerName cloud.example.com
DocumentRoot /var/www/nextcloud/
<Directory /var/www/nextcloud/>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
ProxyFCGIBackendType FPM
<FilesMatch remote.php>
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</FilesMatch>
</VirtualHost>Enable the modules the manual requires and recommends, connect Apache to PHP-FPM, and switch sites:
PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
sudo a2enmod proxy proxy_fcgi setenvif rewrite headers env dir mime
sudo a2enconf php$PHP_VER-fpm
sudo a2ensite nextcloud.conf
sudo a2dissite 000-default.conf
sudo apache2ctl configtest
sudo systemctl restart apache2
apache2ctl -M | grep -E "rewrite|proxy_fcgi|mpm"configtest should print Syntax OK, and the module list should show rewrite_module, proxy_fcgi_module and mpm_event_module.
Step 6 — Install Nextcloud from the command line
Run the installer as the web server user. It asks for the database password from Step 3 and a new admin password, so neither ends up in your shell history:
sudo -E -u www-data php /var/www/nextcloud/occ maintenance:install \
--database mysql --database-name nextcloud \
--database-user nextcloud \
--admin-user admin \
--data-dir /srv/nextcloud/dataThe mysql type covers MariaDB. When it finishes, it prints that Nextcloud was successfully installed. Now add your domain to the trusted domains, set the public URL and enable URLs without index.php:
cd /var/www/nextcloud
sudo -E -u www-data php occ config:system:set trusted_domains 1 --value=cloud.example.com
sudo -E -u www-data php occ config:system:set overwrite.cli.url --value=https://cloud.example.com
sudo -E -u www-data php occ config:system:set htaccess.RewriteBase --value=/
sudo -E -u www-data php occ maintenance:update:htaccess
sudo -E -u www-data php occ config:system:get trusted_domainsThe last command lists localhost and cloud.example.com. Every hostname you use to reach Nextcloud must be in this list.
Step 7 — Turn on HTTPS and the firewall
Allow only SSH and web traffic, then get a Let's Encrypt certificate with Certbot's Apache plugin. Certbot adds a TLS virtual host and, with --redirect, a redirect from HTTP to HTTPS:
sudo apt install ufw
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d cloud.example.com --redirect
sudo certbot renew --dry-runThis uses the Certbot packages from your distribution, which include a renewal timer. The Certbot team recommends its snap instead, as shown in Nginx reverse proxy with Certbot; either works, but install only one of them.
The hardening guide recommends HTTP Strict Transport Security. Open /etc/apache2/sites-available/nextcloud-le-ssl.conf, the file Certbot created, and add this inside the VirtualHost *:443 block:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
</IfModule>Reload Apache and check the header:
sudo apache2ctl configtest && sudo systemctl reload apache2
curl -sI https://cloud.example.com | grep -i strict-transportIf you prefer Nginx in front, the same principles apply; see Nginx reverse proxy with Certbot.
Step 8 — Enable memory caching
The manual's single-server setup uses APCu for the local cache and Redis for the distributed cache and file locking. Redis on Ubuntu and Debian listens on localhost only by default:
cd /var/www/nextcloud
sudo -E -u www-data php occ config:system:set memcache.local --value='\OC\Memcache\APCu'
sudo -E -u www-data php occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
sudo -E -u www-data php occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
sudo -E -u www-data php occ config:system:set redis host --value=localhost
sudo -E -u www-data php occ config:system:set redis port --value=6379 --type=integer
sudo -E -u www-data php occ config:system:get memcache.lockingThe last command prints the Redis class. Since Redis runs on the same server, the manual also describes a Unix socket connection (/run/redis/redis-server.sock with port 0) as an alternative.
Step 9 — Run background jobs with a systemd timer
Nextcloud needs regular background jobs for cleanup, notifications and previews. Create the two units from the manual. First /etc/systemd/system/nextcloudcron.service:
[Unit]
Description=Nextcloud cron.php job
[Service]
User=www-data
ExecCondition=php -f /var/www/nextcloud/occ status -e
ExecStart=/usr/bin/php -f /var/www/nextcloud/cron.php
KillMode=processThen /etc/systemd/system/nextcloudcron.timer:
[Unit]
Description=Run Nextcloud cron.php every 5 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=nextcloudcron.service
[Install]
WantedBy=timers.targetEnable the timer and switch Nextcloud to cron mode:
sudo systemctl daemon-reload
sudo systemctl enable --now nextcloudcron.timer
sudo -E -u www-data php /var/www/nextcloud/occ background:cron
systemctl list-timers | grep nextcloudStep 10 — Clear the security and setup warnings
Log in at https://cloud.example.com and open Administration settings → Overview. Nextcloud checks your setup and lists warnings with links to the manual. These commands fix common ones on a new server; use your own country code for the phone region:
cd /var/www/nextcloud
sudo -E -u www-data php occ config:system:set default_phone_region --value=GB
sudo -E -u www-data php occ config:system:set maintenance_window_start --type=integer --value=1
sudo -E -u www-data php occ db:add-missing-indices
sudo -E -u www-data php occ maintenance:repair --include-expensivemaintenance_window_start is an hour in UTC; with 1, heavy background jobs run between 01:00 and 05:00 UTC. Reload the overview page until it reports that all checks passed, then turn on two-factor authentication for the admin account under Personal settings → Security.
Nextcloud emails password resets and notifications about shares and file changes; set up the mail server under Administration settings → Basic settings in the Email server section with host smtp.example.com, port 587 and the None/STARTTLS encryption option, then send a test message from the same page.
Back up and restore
The manual lists what to back up: the config folder, the data folder, the themes folder, custom apps if you installed any, and the database. Put Nextcloud into maintenance mode so files and database match, copy the folders, dump the database, and leave maintenance mode:
sudo mkdir -p /opt/backups
cd /var/www/nextcloud
sudo -E -u www-data php occ maintenance:mode --on
sudo rsync -Aax /var/www/nextcloud/ /opt/backups/nextcloud-dirbkp_$(date +%F)/
sudo rsync -Aax /srv/nextcloud/data/ /opt/backups/nextcloud-databkp_$(date +%F)/
sudo mariadb-dump --single-transaction --default-character-set=utf8mb4 -r /opt/backups/nextcloud-sqlbkp_$(date +%F).bak nextcloud
sudo -E -u www-data php occ maintenance:mode --offCopy /opt/backups to another machine, for example with rsync -aAx over SSH, and keep several dated copies.
To restore, enable maintenance mode, copy the folders back, recreate the database and import the dump:
cd /var/www/nextcloud
sudo -E -u www-data php occ maintenance:mode --on
sudo rsync -Aax /opt/backups/nextcloud-dirbkp_2026-10-09/ /var/www/nextcloud/
sudo rsync -Aax /opt/backups/nextcloud-databkp_2026-10-09/ /srv/nextcloud/data/
sudo mariadb -e "DROP DATABASE nextcloud"
sudo mariadb -e "CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"
sudo mariadb nextcloud < /opt/backups/nextcloud-sqlbkp_2026-10-09.bak
sudo -E -u www-data php occ maintenance:mode --offIf the backup is older than what your sync clients last saw, run sudo -E -u www-data php occ maintenance:data-fingerprint so the clients detect the change instead of deleting newer local files.
Update Nextcloud
Read the release notes and make a fresh backup first; the updater does not back up your database or data. Upgrade one major version at a time (for example 35 to 36), always from the latest point release of your current version, and check that the next major version still supports your PHP version. Run the built-in updater as the web server user:
sudo -E -u www-data php /var/www/nextcloud/updater/updater.pharThe updater replaces the code and asks whether to run occ upgrade for you. If you answer no, or if it stops, finish the upgrade yourself:
cd /var/www/nextcloud
sudo -E -u www-data php occ upgrade
sudo -E -u www-data php occ maintenance:mode --off
sudo -E -u www-data php occ db:add-missing-indicesKeep Apache, PHP, MariaDB and Redis updated with sudo apt update && sudo apt upgrade.
Troubleshooting
Access through untrusted domain
You opened Nextcloud under a hostname that is not in trusted_domains. Add it with occ config:system:set trusted_domains 2 --value=other.example.com (use the next free index), or always use the configured domain.
occ reports that APCu is not available for the local cache
APCu is disabled for the PHP CLI. Check that /etc/php/8.x/cli/conf.d/90-nextcloud.ini contains apc.enable_cli = 1 and that php -i | grep apc.enable_cli shows On. The background job service uses the same CLI configuration.
Pages other than the start page return Not Found
URL rewriting is not working. Check that rewrite is enabled with apache2ctl -M, that the Directory block has AllowOverride All, and run occ maintenance:update:htaccess again after changing htaccess.RewriteBase.
The overview says background jobs have not run for a long time
The timer is not running or the job fails. Check systemctl status nextcloudcron.timer and journalctl -u nextcloudcron.service -n 50. A common cause is a wrong path in the service file or missing apc.enable_cli.
The updater stops because the PHP version is not supported
The next Nextcloud major version needs a newer PHP than your release ships. Stay on your current version, which keeps receiving point releases for a while, and move to a newer OS release before upgrading Nextcloud.
Next steps
- Compare this setup with the container-based Nextcloud All-in-One.
- Keep admin access private with a WireGuard VPN server.
- Review the base hardening in Secure a new Linux server.
- Compare servers for file sync and collaboration on the Nextcloud hosting page.
- Read the Nextcloud administration manual for tuning, apps and user management.
Frequently asked questions
Which PHP version does Nextcloud 35 need?
The Nextcloud 35 administration manual lists PHP 8.3 and 8.4 as supported and PHP 8.5 as recommended. Ubuntu 26.04 ships PHP 8.5, Debian 13 ships PHP 8.4 and Ubuntu 24.04 ships PHP 8.3, so all three work with their own packages.
Can I install Nextcloud 35 on Debian 12?
Not with Debian's own packages. Debian 12 ships PHP 8.2, which Nextcloud 35 no longer supports. Use Debian 13 or Ubuntu 24.04 or 26.04 instead, or run Nextcloud All-in-One, which brings its own PHP in containers.
Should I use the manual install or Nextcloud AIO?
Choose the manual install when you want full control over Apache, PHP and the database or need to fit Nextcloud into an existing server. Choose AIO when you want updates, HTTPS and backups handled for you by the official containers.
Can I skip a major version when upgrading Nextcloud?
No. Nextcloud supports upgrades one major version at a time, for example 34 to 35 and then 35 to 36, always from the latest point release of your current version. Downgrades are not supported, so back up before every upgrade.
Which HyperDC servers can run Nextcloud?
Nextcloud runs on a HyperDC Linux VPS, VDS or dedicated server with root access and Ubuntu 24.04, Ubuntu 26.04 or Debian 13. Plan RAM for PHP processes and disk space for your users’ files.