Diagnose a slow website
A slow website is not a diagnosis, it is a symptom. Slowness can come from DNS, the TLS handshake, the server, the database, an application query or the user's network. Without a baseline measurement you change several settings at once and no longer know which one helped.
Measure before touching anything
Break response time down with curl:
curl -o /dev/null -sS -w 'dns %{time_namelookup} | connect %{time_connect} | tls %{time_appconnect} | ttfb %{time_starttransfer} | total %{time_total}\n' https://your-domain.tld/TTFB (time_starttransfer) separates network time from server processing time. If DNS or the TLS handshake dominates, look at the network or certificate. If TTFB dominates, the problem is on the server or in the application. Repeat the measurement from another network: your browser cache and local connection distort the reading.
Server and database
CPU, memory, disk.
uptime
free -h
vmstat 1 5
iostat -x 1 5
ss -sCompare load average with the vCPU count (nproc). A load consistently above the core count means saturation. High %iowait in iostat points to the disk; non-zero si/so columns in vmstat point to memory. In a system container these figures reflect your quota, not the whole platform.
Slow queries.
Enable the slow query log on MariaDB:
sudo mariadb -e "SET GLOBAL slow_query_log=ON; SET GLOBAL long_query_time=1;"Make it permanent in /etc/mysql/mariadb.conf.d/50-server.cnf, then read the file reported by SHOW VARIABLES LIKE 'slow_query_log_file';. On PostgreSQL, enable pg_stat_statements and sort by total_exec_time.
For each slow query, run EXPLAIN: a full table scan on a large table is often a missing index. Watch for SELECT * and queries executed inside a loop.
Nginx and application
Add a log format that measures processing time and upstream time:
log_format timing '$remote_addr "$request" $status $request_time $upstream_response_time';
access_log /var/log/nginx/timing.log timing;After reloading, sort the slowest URLs to know where to look. Also check the error log, PHP-FPM pool saturation (pm.max_children, queue) and whether static files are served by Nginx rather than the application.
Cache and delivery
Caching hides slowness without fixing it. Always measure with caching disabled before concluding. Only then: OPcache for PHP, page cache, Cache-Control headers, compression, correctly sized images. A CDN helps with assets and latency, not with a slow SQL query.
Verify after each change
Run the exact same curl command, from the same place, and compare TTFB and total. Change one setting at a time, record the date and the effect. A site that becomes fast again after a restart is not fixed: look for a memory leak or connections piling up.
Advertisement
Was this article helpful?
Read next
- Clean logs and cacheFree disk space without breaking a service by handling logs, packages, caches and Docker images in the right order.
- Migrate to a new VPSPrepare the target, transfer files and databases, switch DNS and keep a usable rollback.
- Understanding VPS swapWhat swap does, what a system container actually allows, and how to reduce memory pressure another way.