Back to Article List

Nextcloud performance tuning on a small VPS

Nextcloud performance tuning on a small VPS

Last spring my Nextcloud spent a month getting slower and I kept blaming the hardware. The file list took 6 seconds to draw. Photo thumbnails spun forever. The desktop client sat on "checking for changes" so long I assumed it had hung. This is a 4 GB VPS carrying roughly 400 GB of family photos and client project files, and I'd half convinced myself it needed 8 GB. It didn't. The fix was four config changes, none of them hardware: a memory cache, sane PHP-FPM sizing, two missing database indices and pre-generated previews.

This is the sequence I work through on any 2 to 4 GB box, starting with what pays off fastest. My install is Nextcloud 34.0.3 on Ubuntu with Apache, PHP-FPM and MariaDB, though every step applies to nginx setups too. If you deployed from the one-click Nextcloud template on Ubuntu 22.04, it ships deliberately small, and these steps are exactly what I'd run once an instance outgrows the defaults.

Check the admin overview warnings first

Before touching anything, I open Settings, then Administration, then Overview. Nextcloud audits its own configuration there and the warnings map almost one to one onto the steps below: no memory cache configured, "The PHP memory limit is below the recommended value of 512MB", the OPcache warning, missing database indices. Treat that screen as your checklist and this article as the explanation of each line. The server tuning page in the admin manual covers the same ground more formally, with less opinion about ordering.

Work the steps in order. They run from biggest win to smallest, and the later ones behave better once the earlier ones are in place.

Step 1: APCu and Redis caching

An uncached Nextcloud rebuilds a pile of state from the database on every single request: app lists, config values, share state and file metadata. That's the 6-second file list. The docs say a combination of APCu and Redis is the best choice for new installations, and after running exactly that for years I'll co-sign it. On Ubuntu the packages are php-apcu, php-redis and redis-server. Then this goes into /var/www/nextcloud/config/config.php:

'memcache.local' => '\OC\Memcache\APCu',
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
    'host' => '127.0.0.1',
    'port' => 6379,
],

APCu handles the small hot lookups inside each PHP process, Redis handles transactional file locking, which it's required for anyway, past one user I consider it non-negotiable. On a single box the memcache.distributed line matters less, but it costs nothing and saves a config edit if you ever split services out. The caching configuration docs walk through every key if you want the long version.

When Redis runs on the same machine, I switch it to a unix socket and skip the TCP round trip:

'redis' => [
    'host' => '/run/redis/redis-server.sock',
    'port' => 0,
],

For the socket variant, enable unixsocket in redis.conf and add www-data to the redis group, or you'll get an instant internal server error on the next page load. One more gotcha: add apc.enable_cli=1 to your PHP CLI config, otherwise occ and cron jobs run without the local cache and occasionally complain about it.

What about memcached? The docs now file it under older alternatives, and it can't do file locking, so you'd run it alongside Redis rather than instead of it. Two cache daemons on a 4 GB box to do the job one does fine. Skip it.

Step 2: PHP memory limit, OPcache and pm.max_children

Three PHP settings carry this step. First, memory_limit. Nextcloud wants 512M and nags in the admin overview until it gets it. Set it in the php.ini your FPM pool reads (on Ubuntu 26.04 with PHP 8.5 that's under /etc/php/8.5/fpm/), then reload the service. Setting it in the CLI ini and wondering why the warning persists is a mistake I'll admit to making once.

Second, OPcache. It caches compiled PHP bytecode, and Nextcloud is a lot of PHP. Distribution defaults mostly leave it enabled but sized for smaller applications, which is why the admin overview so often shows the OPcache warning, usually pointing at opcache.interned_strings_buffer. On my instance I raised opcache.interned_strings_buffer to 32 and opcache.memory_consumption to 256 and the warning went away. Exact defaults shift between PHP releases, so trust the warning text on your own overview screen over any blog's copy-paste block, mine included.

Third, and this is the one that stops a small VPS from falling over: pm.max_children in the FPM pool. Every PHP-FPM worker eats real memory, and the default cap of 5 workers means the sixth simultaneous request queues behind the others. Sync clients issue lots of parallel requests, so a family photo upload can starve the web UI with the default. Raising it blindly is worse, because too many workers push the box into swap. So measure. With the instance warmed up:

ps --no-headers -eo rss,cmd | awk '/php-fpm: pool/ {sum+=$1; n++} END {printf "%d workers, %.0f MB average\n", n, sum/n/1024}'

My workers average 85 MB with OPcache warm. The budget on 4 GB looks like this: MariaDB takes about 800 MB the way I run it and the OS with Apache and Redis idles around 500 MB. I also hold back a few hundred MB for previews and occ jobs. That leaves roughly 1.1 GB for PHP, and 1100 divided by 85 is about 13. I run pm.max_children at 12 on 4 GB alongside MariaDB, and it hasn't queued or swapped since. Do your own division with your own RSS number, a heavy app list changes it. If the site 502s after you reload FPM, you've fat-fingered the pool file or the socket path, and the FPM log will say which. I keep a map of every log location in where are Nextcloud logs.

Step 3: Database indices and buffer pool

Nextcloud ships some indices as optional because adding them to a huge instance takes a while, so the installer skips them and the admin overview reminds you. Adding them is one command:

sudo -u www-data php /var/www/nextcloud/occ db:add-missing-indices

On my instance this added two indices and cut the 6-second file list to about a second, the single best ratio of effort to result on this page. It's safe to run any time, it does nothing when nothing's missing.

Then give MariaDB a sane innodb_buffer_pool_size. The default of 128 MB means your file metadata keeps falling out of memory and getting reread from disk. The usual advice of 70 to 80 percent of RAM assumes a dedicated database server, which this box is not. On 4 GB shared with PHP I set 512M, and a 2 GB box gets 256M. Watch actual memory use for a day after changing it, MariaDB grabs the whole pool up front.

Step 4: Pre-generate previews

Every image in the web UI needs thumbnails at several sizes, and by default Nextcloud generates them the first time someone looks. That's the spinner over the photos tab. The fix is the Preview Generator app from the app store: it builds previews ahead of time so the UI only ever reads finished files.

After installing it, run the initial pass once:

sudo -u www-data php /var/www/nextcloud/occ preview:generate-all

Budget for this honestly. On my 400 GB photo library the first run took the better part of two days and left about 25 GB of previews in the data directory, with the CPU pinned the whole time. I ran it in tmux and let it grind. After that, the cheap incremental pass on a cron keeps up with new uploads:

*/10 * * * * php -f /var/www/nextcloud/occ preview:pre-generate

That line goes in the www-data crontab. Two config keys shrink the bill before you start. preview_max_x and preview_max_y cap the largest preview Nextcloud will render, and the out-of-the-box cap is far bigger than any screen you'll view photos on, I set both to 1024 and can't tell the difference. And enabledPreviewProviders controls which file types get previews at all. Trimming it to the types you store (for me, common image formats plus PDF and text) means the generator stops burning CPU on videos and office documents nobody browses as thumbnails.

Step 5: System cron for background jobs

New installs default to AJAX background jobs, which only run when someone has the web UI open. On a small family instance that can mean file scans and preview queues sit frozen for days. Switch the setting to Cron in the admin panel and give www-data a crontab entry firing cron.php every 5 minutes. I've written up the details, the Docker variants and the ways it silently breaks in Nextcloud cron and background jobs, so I'll keep this step short: do it, it's two minutes of work.

What doesn't speed up Nextcloud

Some tuning advice circulates because it sounds plausible rather than because it moves numbers. Adding vCPUs to a slow instance rarely helps, because an untuned Nextcloud spends its time waiting rather than computing: on the database for uncached metadata and on disk for previews that don't exist yet. Or simply in line behind five busy FPM workers. Four idle cores wait exactly as fast as two.

The same goes for webserver micro-tuning (HTTP/3, brotli levels, keepalive and buffer tweaks) before the caching step is done. Shaving 20 ms off transport while every page load spends 4 seconds in PHP is polishing the wrong end. And switching databases in the hope of speed mostly relocates the problem, an unindexed instance is slow on PostgreSQL too.

One case where hardware genuinely is the answer: disk space rather than speed. Previews, file versions, trash and a growing photo library will eventually fill any NVMe volume, and that's a storage decision I've covered separately in Nextcloud S3 primary storage.

Work through the steps in order, reload after each one and reopen the admin overview as you go. When the warnings are gone, so is the slowness, in my experience in exactly that order. My file list draws in under a second now, on the same 4 GB it crawled on.

Your idea deserves better hosting

24/7 support 30-day money-back guarantee Cancel anytime
Verrechnungszyklus

VPS.S1

$5.99 Save  17 %
$4.99 Monatlich
  • 2 vCPU AMD EPYC
  • 2 GB RAMRAM
  • 30 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive

VPS.S3

$14.99 Save  33 %
$9.99 Monatlich
  • 4 vCPU AMD EPYC
  • 6 GB RAMRAM
  • 70 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive

EPYC VPS.P1

$8.99 Save  22 %
$6.99 Monatlich
  • 2 vCPU AMD EPYC
  • 4 GB RAMRAM
  • 40 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

EPYC VPS.P2

$16.99 Save  24 %
$12.99 Monatlich
  • 2 vCPU AMD EPYC
  • 8 GB RAMRAM
  • 80 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

EPYC VPS.P4

$29.99 Save  23 %
$22.99 Monatlich
  • 4 vCPU AMD EPYC
  • 16 GB RAMRAM
  • 160 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

EPYC VPS.P5

$39.99 Save  25 %
$29.99 Monatlich
  • 8 vCPU AMD EPYC
  • 16 GB RAMRAM
  • 180 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

EPYC VPS.P6

$59.99 Save  25 %
$44.99 Monatlich
  • 8 vCPU AMD EPYC
  • 32 GB RAMRAM
  • 200 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

EPYC VPS.P7

$69.99 Save  29 %
$49.99 Monatlich
  • 16 vCPU AMD EPYC
  • 32 GB RAMRAM
  • 240 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

Genoa VPS.G2

$24.99 Save  20 %
$19.99 Monatlich
  • 2 vCPUAMD EPYC Genoa 4. Generation 9xx4 mit 3,25 GHz oder ähnlich, auf Zen 4-Architektur. AMD EPYC G4
  • 4 GB DDR5RAM
  • 50 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

Genoa VPS.G4

$44.99 Save  22 %
$34.99 Monatlich
  • 4 vCPUAMD EPYC Prozessor mit dedizierten vCPU Kernen, auf Enterprise Serverhardware. AMD EPYC G4
  • 8 GB DDR5RAM
  • 100 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

Genoa VPS.G6

$89.99 Save  22 %
$69.99 Monatlich
  • 8 vCPUAMD EPYC Prozessor mit dedizierten vCPU Kernen, auf Enterprise Serverhardware. AMD EPYC G4
  • 16 GB DDR5RAM
  • 200 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

Genoa VPS.G7

$159.99 Save  22 %
$124.99 Monatlich
  • 8 vCPUAMD EPYC Prozessor mit dedizierten vCPU Kernen, auf Enterprise Serverhardware. AMD EPYC G4
  • 32 GB DDR5RAM
  • 250 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden. inklusive
  • Kostenloses Auto-BackupEnthält einen Backup-Slot, den du auf täglich, wöchentlich oder monatlich einstellen kannst.

AMD Ryzen VPS.R1

$16.99 Save  18 %
$13.99 Monatlich
  • 1 dedizierter CPU AMD Ryzen 9 7950X mit 4,5 GHz oder ähnlich, auf Zen 4-Architektur. vCPU
  • 4 GB DDR5RAM
  • 50 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6 inklusive IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden.
  • Auto-Backup inklusive

AMD Ryzen VPS.R2

$29.99 Save  17 %
$24.99 Monatlich
  • 2 dedizierte CPUs AMD Ryzen 9 7950X mit 4,5 GHz oder ähnlich, auf Zen 4-Architektur. vCPU
  • 8 GB DDR5RAM
  • 100 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6 inklusive IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden.
  • Auto-Backup inklusive

AMD Ryzen VPS.R4

$109.99 Save  18 %
$89.99 Monatlich
  • 8 dedizierte CPUs AMD Ryzen 9 7950X mit 4,5 GHz oder ähnlich, auf Zen 4-Architektur. vCPU
  • 32 GB DDR5RAM
  • 400 GB NVMeSPEICHER
  • Unbegrenzter Traffic
  • IPv4 & IPv6 inklusive IPv6-Support ist derzeit nicht verfügbar in Frankreich, Finnland oder den Niederlanden.
  • Auto-Backup inklusive

Answers to common questions

Do I need to upgrade my VPS RAM for 10 users?

Probably not. A tuned instance on 4 GB handles 10 light users comfortably, the docs' baseline of 512 MB per process is about PHP limits rather than user counts. I'd upgrade when the tuned box swaps under normal use, which for me would mean heavy Collabora or Talk use rather than files and photos.