A dedicated server gives you the hardware ceiling. What you do with it determines whether you reach that ceiling or spend months wondering why a powerful machine is still underperforming.
The difference between a poorly optimised dedicated server and a well-optimised one is not incremental. It is the difference between a site that loads in under 500ms and one that consistently hits 2โ3 seconds. The difference between a database that handles 1,000 queries per second and one that starts struggling at 200. The difference between an application that scales gracefully and one that falls over during a traffic spike.
This guide covers every optimisation layer: OS, web server, database, caching, network, and monitoring, with practical steps and real configuration guidance.
๐ Not sure if your hardware is limiting your performance?
Before optimising software, confirm your hardware is right for your workload. Read How to Choose the Best Hardware for Your Dedicated Server, a complete guide to CPU, RAM, storage, and network specifications by workload type.
Layer 1 – Operating System Optimisation
The OS is the foundation. A bloated, misconfigured, or outdated OS wastes resources that your applications could be using.
Remove Unnecessary Services
A freshly provisioned Linux server often runs services you do not need. Each unnecessary service consumes RAM, CPU cycles, and represents an additional attack surface. List all running services and disable anything that is not required:
systemctl list-units --type=service --state=running
systemctl disable servicename
systemctl stop servicename
Common candidates for removal: snapd, avahi-daemon, cups, bluetooth, and any graphical environment components that shipped with the OS.
Keep the Kernel and Packages Updated
Security patches frequently include performance improvements. Furthermore, newer kernel versions often include better hardware support, improved scheduler performance, and networking improvements. Update regularly:
apt update && apt upgrade -y # Debian/Ubuntu
Configure the Kernel for Server Workloads
Linux kernel parameters can be tuned for server performance. Add the following to /etc/sysctl.conf and apply with sysctl -p:
# Increase network buffer sizes
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
# Increase connection backlog
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# Reduce swap usage
vm.swappiness = 10
# Improve file system performance
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
The vm.swappiness = 10 setting is particularly important. By default, Linux begins using swap when RAM is 40% free. Setting swappiness to 10 means the OS keeps much more data in RAM before swapping, critical for database performance.
Use a Minimal OS Profile
Server OS installations should have no graphical environment. A standard Ubuntu Server installation without a desktop environment consumes approximately 200โ400 MB of RAM at idle. Adding a desktop environment adds 500 MB to 2 GB of baseline consumption, RAM that could instead be allocated to your database buffer pool or application processes.
๐ What causes high CPU usage on a server?
Read What Causes High CPU Usage on a Server?, a practical guide to diagnosing CPU bottlenecks before tuning, so you optimise the right layer rather than making changes that do not address the actual constraint.
Layer 2 – Web Server Configuration
The web server is the first application layer that handles user requests. Its configuration determines how efficiently those requests are processed and how many can be handled simultaneously.
Nginx Optimisation
Nginx is the preferred web server for high-performance dedicated server deployments. Key configuration parameters in /etc/nginx/nginx.conf:
nginx
worker_processes auto; # Match CPU core count
worker_connections 65535; # Connections per worker
use epoll; # Efficient I/O model for Linux
multi_accept on; # Accept multiple connections per event
# Buffer optimisation
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
# Keepalive
keepalive_timeout 30;
keepalive_requests 1000;
# Compression
gzip on;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# File descriptor caching
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
Enable HTTP/2 in your server block for clients that support it โ HTTP/2 multiplexes multiple requests over a single connection, reducing connection overhead significantly:
listen 443 ssl http2;
PHP-FPM Optimisation
For PHP applications, PHP-FPM pool configuration directly determines how many concurrent requests your server can handle. In /etc/php/8.x/fpm/pool.d/www.conf:
ini
pm = dynamic
pm.max_children = 50 # Set based on available RAM / per-process RAM usage
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500 # Recycle workers to prevent memory leaks
To calculate pm.max_children: divide the RAM available for PHP by the average memory consumption of a single PHP-FPM process. Check average process memory with:
ps --no-headers -o "rss,cmd" -C php-fpm8.2 | awk '{sum+=$1} END {print int(sum/NR/1024)"MB"}'
If the average PHP process uses 50 MB and you have 4 GB available for PHP, pm.max_children = 80 is appropriate.
Apache Optimisation (if applicable)
If your stack requires Apache, switch to the Event MPM for better concurrency performance:
a2dismod mpm_prefork
a2enmod mpm_event
Configure in /etc/apache2/mods-available/mpm_event.conf:
StartServers 5
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 150
MaxConnectionsPerChild 1000
Enable mod_deflate for compression and mod_expires for cache headers. Disable any module not actively used, each loaded module adds memory overhead.
๐ How does server load affect response times under traffic?
Read Understanding Server Load: How Dedicated Servers Handle High Traffic, a detailed breakdown of how concurrent connection limits, worker pools, and hardware capacity interact to determine performance under load.
Layer 3 – Database Optimisation
For most web applications and SaaS products, the database is the performance bottleneck. Optimising MySQL or PostgreSQL typically delivers the largest performance improvement of any single change.
MySQL / MariaDB – InnoDB Buffer Pool
The InnoDB buffer pool is MySQL’s most important performance parameter. It determines how much of the database’s working dataset fits in memory. When data is in the buffer pool, queries are served from RAM. When it is not, queries require disk reads, orders of magnitude slower even on NVMe storage.
Set the buffer pool to 70โ80% of available RAM on a dedicated database server:
ini
# /etc/mysql/mysql.conf.d/mysqld.cnf
innodb_buffer_pool_size = 48G # On a 64GB dedicated database server
innodb_buffer_pool_instances = 8 # One per GB of buffer pool, max 64
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 2 # Reduces I/O at small durability trade-off
innodb_flush_method = O_DIRECT # Bypass OS cache for database I/O
Check buffer pool hit rate after configuration changes, a hit rate below 99% indicates the buffer pool is too small:
sql
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
MySQL – Query Cache and Connection Optimisation
ini
max_connections = 500
thread_cache_size = 50
table_open_cache = 4000
query_cache_type = 0 # Disable query cache โ it causes contention in MySQL 5.7+
Slow Query Logging
Enabling slow query logging identifies the queries consuming the most time, these are the highest-priority optimisation targets:
ini
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 # Log queries taking more than 1 second
log_queries_not_using_indexes = 1
Analyse slow queries with mysqldumpslow or pt-query-digest to identify missing indexes and inefficient query patterns.
PostgreSQL Optimisation
For PostgreSQL, the equivalent of MySQL’s buffer pool is shared_buffers. Set it to 25% of total RAM, and configure effective_cache_size to 75% of total RAM:
ini
# /etc/postgresql/15/main/postgresql.conf
shared_buffers = 16GB # 25% of 64GB
effective_cache_size = 48GB # 75% of 64GB
work_mem = 256MB # Per sort operation โ monitor for high-concurrency impact
maintenance_work_mem = 2GB
max_connections = 200
๐ How do dedicated servers handle large database workloads?
Read How Dedicated Servers Support Large Databases & Big Data, a practical guide to database infrastructure architecture, buffer pool sizing, and storage configuration for data-intensive applications.
Layer 4 – Caching Strategy
Caching eliminates redundant computation. Every request served from cache is a request that does not hit your application runtime, your database, or your storage. Implementing caching at multiple layers compounds the performance benefit significantly.
Object Caching with Redis
Redis is an in-memory data store that serves as the backbone of application-level caching. Configure Redis with a memory limit and an appropriate eviction policy:
bash
# /etc/redis/redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru # Evict least recently used keys when limit reached
save "" # Disable persistence for pure cache use case
Redis use cases on a dedicated server:
- Session storage – Replace file-based sessions with Redis for faster session reads and better concurrency
- Object caching – Store computed results (database query results, rendered template fragments) in Redis
- Rate limiting – Implement API rate limiting with Redis counters
- Queue backend – Use Redis as a message queue backend for background job processing
Full-Page Caching
For content sites and e-commerce platforms, full-page caching serves entire rendered pages from cache, bypassing PHP execution and database queries entirely.
Nginx FastCGI cache for PHP applications:
nginx
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=MYAPP:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
# In server block
fastcgi_cache MYAPP;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $cookie_logged_in $cookie_woocommerce_items_in_cart;
fastcgi_no_cache $cookie_logged_in $cookie_woocommerce_items_in_cart;
Varnish Cache sits in front of Nginx and caches responses at the HTTP level. For high-traffic content sites, Varnish can handle tens of thousands of requests per second from cache, reducing the load on the application tier to near-zero for cacheable content.
CDN Integration
A CDN distributes static assets (images, CSS, JavaScript, fonts, video) from edge locations close to your users. This reduces the load on your dedicated server for static content and dramatically reduces delivery latency for geographically distributed audiences.
The dedicated server acts as the CDN origin, serving dynamic content and cache-miss requests at full performance while the CDN handles the high-volume static delivery.
๐ How does NVMe storage affect caching and I/O performance?
Read How NVMe Storage Boosts Dedicated Server Performance, a detailed breakdown of how storage technology interacts with caching layers to determine real-world application performance.
Layer 5 – Network and TLS Optimisation
Network configuration affects every user interaction. Optimising how data travels to and from your server reduces latency and improves throughput.
Enable HTTP/2 and HTTP/3
HTTP/2 multiplexes multiple requests over a single TCP connection, eliminating the head-of-line blocking of HTTP/1.1. HTTP/3 uses QUIC, a UDP-based transport protocol that reduces connection establishment time and handles packet loss more efficiently. Enable both where supported.
TLS Optimisation
TLS handshakes add latency to HTTPS connections. Reduce this overhead with:
nginx
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off; # Disable for better security
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# OCSP stapling โ eliminates the client's need to check certificate revocation
ssl_stapling on;
ssl_stapling_verify on;
TCP Optimisation
BBR (Bottleneck Bandwidth and Round-trip time) is a TCP congestion control algorithm developed by Google that significantly improves throughput, particularly for long-distance connections. Enable it in sysctl.conf:
bash
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
Verify BBR is active after applying:
bash
sysctl net.ipv4.tcp_congestion_control
Keepalive Configuration
Keepalive connections reuse TCP connections for multiple requests rather than establishing a new connection for each. This reduces the connection overhead for clients making multiple requests:
nginx
keepalive_timeout 30;
keepalive_requests 1000;
Layer 6 – Storage Optimisation
Storage I/O is a frequent bottleneck for database-heavy and high-traffic workloads. Beyond choosing the right storage type, configuration affects throughput and latency.
I/O Scheduler
The Linux I/O scheduler determines how read and write requests are queued and dispatched to storage devices. For NVMe SSDs, the none (or noop) scheduler is appropriate, NVMe drives handle their own internal I/O optimisation:
bash
echo none > /sys/block/nvme0n1/queue/scheduler
Make this persistent in /etc/udev/rules.d/60-scheduler.rules:
bash
ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"
For SATA SSDs, mq-deadline is the recommended scheduler.
File System Mount Options
Mount options affect file system performance. For ext4 and XFS on SSDs, the noatime option prevents updating file access timestamps on every read, eliminating a write operation that provides no application benefit:
bash
# /etc/fstab
UUID=xxx /data ext4 defaults,noatime,discard 0 2
The discard option enables TRIM for SSDs, maintaining long-term performance by informing the drive which blocks are no longer in use.
๐ How does TTFB relate to server optimisation?
Read What Is Time to First Byte (TTFB) and Why It Matters, a breakdown of how server-side optimisations translate into TTFB improvements, and why TTFB is the most important performance metric for search rankings and user experience.
Layer 7 – Monitoring – Measuring the Impact of Every Optimisation
Optimisation without measurement is guesswork. Every change you make should be validated with before-and-after metrics.
Real-Time System Monitoring
For immediate visibility into what is consuming resources:
bash
htop # CPU and RAM by process
iotop # Disk I/O by process
iftop # Network traffic by connection
nethogs # Network bandwidth by process
Metrics and Alerting
Prometheus with Node Exporter collects system metrics (CPU, RAM, disk, network) and exposes them for querying and alerting. Combined with Grafana, this provides dashboards that visualise resource consumption over time and identify trends before they become incidents.
Datadog and New Relic provide application performance monitoring (APM) that traces requests through your entire stack, from the HTTP request through application code to database queries, identifying where time is actually spent.
Application-Level Performance Testing
Use Apache Benchmark (ab) or wrk to measure response times and throughput before and after configuration changes:
bash
ab -n 10000 -c 100 https://yourdomain.com/
This sends 10,000 requests with 100 concurrent connections and reports requests per second, response times, and error rates.
Database Query Analysis
The MySQL slow query log (configured earlier) combined with pt-query-digest from Percona Toolkit provides a ranked summary of the queries consuming the most total time:
bash
pt-query-digest /var/log/mysql/slow.log
This is the most direct path to identifying database optimisation opportunities, the queries at the top of the list are the highest-priority targets for index optimisation or query rewriting.
๐ What monitoring tools should you use on a dedicated server?
Read Best Tools to Monitor Dedicated Server Performance, a practical guide to the monitoring stack that gives you real-time visibility into CPU, RAM, disk, and network metrics from day one.
The Optimisation Checklist
OS Layer โ Unnecessary services disabled ยท โ OS and kernel updated ยท โ sysctl.conf tuned (swappiness, network buffers, connection limits) ยท โ No graphical environment
Web Server Layer โ Nginx worker processes = CPU cores ยท โ Worker connections maximised ยท โ HTTP/2 enabled ยท โ Gzip/Brotli compression active ยท โ PHP-FPM pool sized for available RAM
Database Layer โ
InnoDB buffer pool = 70โ80% of dedicated DB server RAM ยท โ
Slow query log enabled ยท โ
Indexes reviewed and optimised ยท โ
Query cache disabled (MySQL 5.7+) ยท โ
innodb_flush_method = O_DIRECT
Caching Layer โ Redis configured with memory limit and LRU eviction ยท โ Full-page cache (FastCGI or Varnish) active for cacheable content ยท โ CDN handling static assets
Network Layer โ HTTP/2 enabled ยท โ TLS session cache configured ยท โ BBR congestion control active ยท โ Keepalive connections configured ยท โ OCSP stapling enabled
Storage Layer โ
NVMe scheduler set to none ยท โ
noatime mount option active ยท โ
TRIM enabled for SSDs
Monitoring Layer โ Prometheus + Grafana or equivalent active ยท โ Uptime monitoring configured ยท โ Slow query logging active ยท โ Baseline performance documented
Start With the Right Hardware to Optimise
Swify’s dedicated servers give you NVMe storage, generous RAM configurations, high-core-count CPUs, and European datacenters, the hardware foundation that makes every optimisation in this guide possible.
โ Explore Swify Dedicated Server PlansFrequently Asked Questions
FAQ 1 :: What is the single most impactful optimisation for a dedicated server running a database?
Increasing the MySQL InnoDB buffer pool size to hold the active working dataset in memory. The difference between serving database queries from RAM versus from disk is orders of magnitude, RAM access takes nanoseconds, NVMe disk access takes microseconds. When the buffer pool is too small, every cache miss requires a disk read. When it is sized correctly, the overwhelming majority of queries are served from memory. On a dedicated database server with 64 GB of RAM, setting `innodb_buffer_pool_size = 48G` is typically the highest-impact single change available. Read How Dedicated Servers Support Large Databases & Big Data for a complete guide to database optimisation on dedicated infrastructure.
FAQ 2 :: How do I reduce Time to First Byte (TTFB) on a dedicated server?
TTFB is determined by the time your server takes to process a request and return the first byte of response. The most effective reductions come from: enabling full-page caching to serve cached pages without PHP execution, increasing the InnoDB buffer pool to reduce database query time, tuning PHP-FPM worker pool sizes to avoid request queuing, and enabling Redis object caching to reduce redundant database calls. Geographic proximity also affects TTFB, a server closer to your users delivers lower latency regardless of server-side optimisations. Read What Is Time to First Byte (TTFB) and Why It Matters for a full breakdown of TTFB and its relationship to search rankings.
FAQ 3 :: How many PHP-FPM workers should I configure on a dedicated server?
The formula is: available RAM for PHP divided by average memory consumption per PHP-FPM process. Check average process memory with `ps –no-headers -o “rss,cmd” -C php-fpm8.2 | awk ‘{sum+=$1} END {print int(sum/NR/1024)”MB”}’`. If the average process uses 60 MB and you have 6 GB allocated for PHP, set `pm.max_children = 100`. Setting this too high causes RAM exhaustion and swap usage; too low causes request queuing during traffic spikes. Start conservatively and increase based on monitoring data. Additionally, set `pm.max_requests = 500` to recycle workers periodically and prevent memory leaks in long-running PHP processes.
FAQ 4 :: Should I use Redis or Memcached for caching on a dedicated server?
Redis is the better choice for most dedicated server deployments. Memcached is simpler but limited to pure key-value caching with no persistence. Redis supports more complex data structures (lists, sets, sorted sets, hashes), optional persistence, pub/sub messaging, and atomic operations, making it suitable for session storage, rate limiting, queue backends, and leaderboards in addition to caching. Furthermore, Redis is the standard choice for WordPress object caching, Laravel cache, and most modern application frameworks. Configure Redis with `maxmemory` and `maxmemory-policy allkeys-lru` to ensure it functions as a bounded cache rather than consuming unbounded memory.
FAQ 5 :: How do I know if my dedicated server’s storage is the performance bottleneck?
Use `iotop` to monitor disk I/O by process in real time. High `iowait` percentage in `top` or `htop` indicates processes are spending significant time waiting for storage operations. In MySQL, a buffer pool hit rate below 99% (check with `SHOW STATUS LIKE ‘Innodb_buffer_pool_read%’`) indicates the working dataset is not fitting in memory and queries are reading from disk. The most common solutions are increasing RAM to allow a larger buffer pool, switching from SATA SSD to NVMe storage, or implementing a separate caching layer. Read How NVMe Storage Boosts Dedicated Server Performance for a detailed guide to storage performance on dedicated infrastructure.
FAQ 6 :: What is the best way to monitor dedicated server performance over time?
The most effective monitoring stack for a dedicated server combines Prometheus with Node Exporter for system metrics collection, Grafana for visualisation and alerting, and an external uptime monitor (UptimeRobot or Better Uptime) for availability checks from outside your network. For application-level performance, enable MySQL slow query logging and use pt-query-digest to identify query bottlenecks. For web server performance, analyse Nginx access logs with tools like GoAccess. Document baseline metrics immediately after each optimisation change so you can objectively measure improvement. Read Best Tools to Monitor Dedicated Server Performance for a full guide to the monitoring stack.

