If you are running multiple CMS instances on a single server, default settings will eventually throttle your performance. Here is how I tuned my Debian environment to handle the load efficiently.
These are my public notes on what I did to speed up my sites.
I host my sites on a Debian 12 VPS with 8GB RAM from Hetzner and everything is installed from package. Tune accordingly.
This VPS hosts two Joomla sites and three WordPress sites (including the one you are reading).
I run everything from this VPS, and nothing is behind a CDN. That could help make your sites load even faster, but where is the fun in that?
Table of Contents
If you are running multiple CMS instances on a single server, default settings will eventually throttle your performance. Here is how I tuned my Debian environment to handle the load efficiently.
These are my public notes on what I did to speed up my sites.
I host my sites on a Debian 12 VPS with 8GB RAM from Hetzner and everything is installed from package. Tune accordingly.
This VPS hosts two Joomla sites and three WordPress sites (including the one you are reading).
I run everything from this VPS, and nothing is behind a CDN. That could help make your sites load even faster, but where is the fun in that?
Table of Contents
Time To First Byte
This is one way to measure sitespeed. Read more here.
You can use curl — of course — to test the TTFB (from a different host than your VPS).
Lower is better.
for i in {1..5}; do curl -o /dev/null -s -w "%{time_starttransfer}\n" https://j11g.com; done
0.048735
0.056539
0.050968
0.047165
0.055534
These are good numbers.
Cache cache cache
None of the suggestions below will beat good old cache. You can read all these suggestions as *extra *on top of caching.
Nothing will make your site faster than caching i.e. creating static pages — that is more or less what most caching tools do — instead of doing database lookups and parsing PHP.
Or you can of course use Redis, but that’s a whole article by itself. These suggestions focus on tools you are already running and tuning those.
That being said, there are many caching extensions/plugins for Joomla and WordPress. I will provide some suggestions at the end of this article.
So here we go.
PHP
Ditch mod_php for php-fpm
This is easiest win. And for most-people a no-brainer.
I mention it now because for years I ran mod_php, because that was what I knew and what worked (I’ve been running Apache since version 1.3.)
But moving from mod_php to php-fpm (FastCGI Process Manager) is the single biggest upgrade you can make. It allows Apache to handle web requests while php-fpm manages the execution of scripts in the background.
The result: less memory usage, speedier sites.
Optimizing php.ini
After you install php-fpm you should tune some settings.
Here are the relevant/changed parts of my /etc/php/8.5/fpm/php.ini file:
;Prevents a single runaway script from hogging all 8GB of your RAM.
memory_limit = 128M
;We let Apache handle this with mod_deflate, so we set it to off here, to avoid conflicts
zlib.output_compression = Off
;Stores precompiled script bytecode in shared memory, so PHP doesn't have to parse the same script on every request.
[opcache]
opcache.enable=1
;Allocates 128MB of RAM specifically for cached scripts—plenty for 5 CMS sites.
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=30000
opcache.revalidate_freq=2
Tuning the Pool
And here are the relevant parts in my /etc/php/8.5/fpm/pool.d/www.conf file
pm = dynamic
#The max number of simultaneous PHP processes. This prevents the server from crashing under a traffic spike.
pm.max_children = 50
#Keeps 5 processes "warm" and ready to respond instantly.
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
#Restarts a process after 500 requests to prevent memory leaks from poorly written plugins.
pm.max_requests = 500
Apache
I use Apache, and will keep using it. Because.
So we aren’t switching to nginx, but we are making Apache act like it.
- Use HTTP/2 (
a2enmod http2): Allows the browser to download multiple files (CSS, JS, images) over a single connection simultaneously, rather than one by one. - Use mod_deflate (
a2enmod deflate): compresses the server response. This Apache module ensures your content is “zipped” for the journey to the user.
MPM Event Tuning
The Event MPM is the most efficient multi-processing module for Apache: you need this when you run php-fpm.
But you have to tune it.
| RAM VPS | Reserved (OS + DB) | Available Apache/PHP | Suggested MaxRequestWorkers |
| 1 GB | 512 MB | 512 MB | 25 – 40 |
| 2 GB | 800 MB | 1.2 GB | 60 – 100 |
| 4 GB | 1.5 GB | 2.5 GB | 150 – 200 |
| 8 GB | 3.0 GB | 5.0 GB | 400 |
- Set
MaxRequestWorkers 400: This matches my RAM capacity, allowing Apache to handle up to 400 concurrent connections without swapping to disk. MaxConnectionsPerChild 0: Set to 0 (unlimited) because modern Apache modules rarely leak memory, improving stability.
I set my /etc/apache2/mods-enabled/mpm_event.conf to this:
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
MariaDB
By default, MariaDB is configured to run on a toaster. Since we have 8GB of RAM, we want to move as much of the database activity into memory as possible to avoid slow disk I/O.
The “Buffer Pool” Rule
The innodb_buffer_pool_size is the most critical setting for Joomla and WordPress. It determines how much of your database lives in RAM.
- The Goal: You want your entire database to fit in RAM if possible.
- The Math: On a dedicated DB server, you’d use 80% of RAM. On a LAMP VPS, aim for 25% to 40% of your total RAM.
[mariadb]
# Performance & Stability
innodb_flush_method = O_DIRECT
# What it does: Tells MariaDB to write directly to the disk, bypassing the OS cache. This prevents "double buffering" and speeds up writes.
skip-name-resolve = 1
# What it does: Disables DNS lookups for connections. This makes database connections nearly instant.
# Query Cache (Disabled)
query_cache_type = OFF
query_cache_size = 0
# What it does: Modern databases are so fast that the "Global Lock" created by the Query Cache actually slows things down. We turn it off.
# Memory & Caching
innodb_buffer_pool_size = 2G
# What it does: We bumped this from 1G to 2G. This allows more of your posts, pages, and metadata to stay in RAM for lightning-fast retrieval.
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M
# What it does: These act as a "waiting room" for data being written.
# Larger logs allow the database to handle heavy write traffic (like bulk imports or many comments) more smoothly.
# Resource Limits
max_connections = 100
# What it does: Limits simultaneous connections to 100. This is plenty for 5 sites and prevents a "connection spike" from crashing the server.
tmp_table_size = 64M
max_heap_table_size = 64M
# What it does: Allows complex queries (like WordPress searches) to run entirely in RAM rather than creating slow temporary files on disk.
Joomla specific settings
Sessions and caching
You think that you would need Joomla gzip page compression, but you have already enabled mod_deflate so you don’t need it!
Actually: I found out having this on and mod_deflate that my site had a higher TTFB (not good).
Don’t
Conservative caching
Set the session handler to Filesystem and enable Conservative caching. This helps and is almost always safe.

System – Page Cache
This is the silver bullet.
Enable this extension. This will greatly speed up things.
Because of a module complication this is not enabled on one of my Joomla sites.
The sites are otherwise comparable. This plugin however makes the TTFB on the other site seven times faster. No typo. Seven. 7.

Beware: it will take up more space in your site’s folder.
| Conservative Caching (View/Module Level) | System – Page Cache Plugin (Page Level) | |
| How it works | Caches individual parts of a page (like a menu or an article module). | Caches the entire final HTML output of a page. |
| The “Process” | PHP still executes and “assembles” the page from cached pieces. | PHP finds the saved file and sends it instantly; no assembly required. |
| Database Load | Reduced (queries for modules are skipped). | Zero |
| CPU Usage | Moderate (PHP is still active). | Extremely Low (Server acts like a static host). |
| Dynamic Content | More flexible; different modules can have different cache times. | Aggressive; everything on the page is “frozen” in time until the cache expires. |
| Best For | Sites with logged-in users or frequently changing sidebar content. | Maximum Speed. Best for public-facing blogs and static landing pages. |
WordPress Caching
There are many WordPress caching options. I have used multiple, and at this point I advise WP Fastest Cache
Does what it says on the box. These are my settings.

If you do all of the above I have very little to add to make WordPress even faster.
Except one tip: you should always make your images as small as possible, this will also greatly improve site-speed.
So that’s it, any tips I missed?