Linux Servers & VPSGrid Pulsar team··9 min read

Ubuntu Server Performance Tuning for Small VPSes

Optimize an Ubuntu 24.04 LTS VPS by finding CPU, memory and disk bottlenecks, controlling background work, and checking each change against real traffic.

Ubuntu Server Performance Tuning for Small VPSes featured image
On this page
Short answer

You will leave with an Ubuntu 24.04 LTS VPS whose resource bottleneck is identified and whose changes have a clear rollback. Start by observing normal traffic, then reduce competing background work or excessive application concurrency. Check memory pressure and storage latency before changing kernel settings. Keep a change only when application response times improve without growing queues or new errors.

1. Define the symptom and prepare your rollback

Choose one problem you can reproduce, such as slow requests during deployments or a worker that stalls while backups run. Write down the affected operation and when it happens. A quiet server with a reassuring dashboard does not tell you how the application behaves during that event.

Use a sudo-capable account on Ubuntu 24.04 LTS, and keep your current SSH session open while changing services. If the machine is new, complete the initial Ubuntu server setup first. Install the diagnostic tools below before collecting your baseline, so package installation does not contaminate the observation.

bashTested on Ubuntu 24.04
sudo apt-get update
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y procps sysstat
command -v vmstat free pidstat iostat
Check: The final command prints a filesystem path for each diagnostic tool.

Before editing an application configuration, save its current contents and record the command that restores it. Separate tuning from application releases so you can attribute any change in behavior. Schedule changes that restart your only application instance for a maintenance window.

2. Capture the bottleneck while the application is slow

Run these commands while the affected operation is happening, then repeat them during an ordinary period. Keep the output alongside application response times from the same window. The short sampling window below is a starting point; repeat it if the slowdown lasts longer or happens intermittently.

bashTested on Ubuntu 24.04
date -Is
nproc
uptime
free -h
vmstat -w 2 6
Check: You have the visible CPU count, available memory and several successive activity samples covering the slow operation.

In vmstat, interpret activity from the rows after the first, whose activity counters summarize time since boot. The r column shows runnable processes, while b shows processes blocked waiting for I/O. Sustained runnable work beyond the visible CPU count suggests CPU contention; si and so show swap traffic, and st reports CPU time taken away from the guest. See the Ubuntu vmstat reference for field definitions.

Observation during slow requestsInvestigate nextFirst candidate change
Runnable work stays high and CPU idle time is lowApplication and background CPU consumersReduce competing job concurrency
Available memory stays low with active swappingWorker memory and overlapping jobsReduce simultaneous work or add RAM
Blocked work coincides with longer storage waitsDatabase activity and scheduled file operationsSeparate competing disk workloads
Steal time rises while your workload stays similarHost contention or provider CPU limitsCollect evidence for the provider

Treat these observations as leads, not diagnoses. Load average includes work waiting on some forms of I/O, so a high value alone does not establish a CPU problem. If local resources remain comfortable, inspect application locks and upstream request timing before resizing the VPS.

3. Reduce CPU competition before adding workers

Identify which processes consume CPU during the slowdown. Increasing web workers can make a small VPS slower when each worker competes with a database on the same machine. A build or image-processing job can also occupy resources needed by interactive requests.

bashTested on Ubuntu 24.04
pidstat -u 2 5
Check: The repeated samples identify the processes consuming CPU during the affected operation, rather than only showing a machine-wide total.

If a background queue is responsible, reduce its concurrency to one job in the worker's application configuration as your first trial. Let existing work finish before restarting that worker, then observe whether the queue drains between busy periods. If builds are responsible, move artifact creation into your deployment pipeline or schedule it away from interactive traffic.

For a background worker managed by systemd, you can also lower its CPU scheduling priority. If your unit is named background-worker.service, put the following in /etc/systemd/system/background-worker.service.d/override.conf, preserving any existing settings. Substitute your actual unit name in the directory path, run sudo systemctl daemon-reload, and restart that worker when its current job can safely stop.

ini
[Service]
Nice=10
Check: After the worker restarts, its process has the configured nice value in ps -eo pid,ni,comm; application latency improves without an ever-growing job queue.

A higher nice value gives competing ordinary processes a scheduling preference; it does not impose a CPU ceiling or reserve memory. Remove the added setting and reload systemd before restarting the worker if the tradeoff is unacceptable. Change concurrency and scheduling priority in separate trials so you know which adjustment helped.

4. Recover memory headroom and assess swap activity

Start with available memory rather than treating filesystem cache as wasted RAM. Linux can reclaim much of that cache when applications need space. Rank processes by resident memory, but remember that shared pages can appear in several processes, so adding these values does not give an exact application total.

bashTested on Ubuntu 24.04
free -h
ps -eo pid,comm,rss --sort=-rss | head -n 16
Check: The output shows available memory and the largest resident processes; RSS is reported in KiB.

On the VPS itself, inspect configured swap and recent kernel messages for allocation failures or killed processes. These checks need access to the host environment, not a restricted container. Match message timestamps to the slowdown before blaming memory pressure.

bash
sudo swapon --show
sudo journalctl -k -b --no-pager -n 150
Check: You can tell whether swap exists and whether the current boot contains kernel messages reporting out-of-memory kills; an empty swap listing means none is active.

Reduce duplicated application workers or stop overlapping memory-heavy jobs before changing global memory settings. Budget database connection pools across all application processes, since a per-process pool multiplies when you add workers. For persistent automation workloads, use the VPS sizing guide for always-on agents to account for their background demand.

Swap can absorb occasional memory pressure, but sustained swapping during requests calls for less concurrent work or more RAM. An occupied swap area alone does not prove an active problem; compare it with ongoing si and so activity. Do not run swapoff merely to make a dashboard look cleaner, because moving those pages back into RAM can exhaust available memory.

5. Separate storage latency from storage capacity

Check free space and inode availability before investigating storage performance. A filesystem can run out of either, and deleting a few large files will not solve inode exhaustion caused by many tiny files. Inspect the filesystem holding application data as well as the root filesystem.

bashTested on Ubuntu 24.04
df -h
 df -i
Check: The relevant filesystems have available space and free inodes, or you have identified a capacity problem that needs attention first.

Next, sample the VPS block devices during the slow operation. Use r_await and w_await to inspect read and write waiting time, and aqu-sz to inspect queued requests. These wait measurements include queueing and device service time, as documented in the Ubuntu iostat reference.

bash
iostat -xz -y 2 5
Check: You have interval samples from the VPS devices and can compare storage waits during slow requests with waits during ordinary traffic.

If storage waits rise during backups or imports, move one of those jobs to a different window and repeat the observation. If the database remains the source of disk demand, investigate expensive queries and missing indexes using its own diagnostics. Do not disable durable writes to hide slow storage, because that changes what a successful database commit guarantees.

6. Bound log growth without hiding application failures

Check log volume if disk space keeps shrinking or writes remain busy after other workloads finish. Start with journal usage and directory sizes during a quiet period, since directory scans also create storage work. Fix a repeated application error before reducing the detail needed to diagnose it.

bash
sudo journalctl --disk-usage
sudo du -xhd1 /var/log
Check: You can distinguish system journal storage from separate application or proxy log files.

If the journal needs a smaller storage budget, create /etc/systemd/journald.conf.d/60-storage-budget.conf with the example below. Adjust these capacities to the history you need, and export required records before applying a smaller limit because archived journal files can be removed. The persistent and runtime limits apply to different storage locations, as explained in the Ubuntu journal configuration reference.

ini
[Journal]
SystemMaxUse=200M
RuntimeMaxUse=50M

Inspect the merged configuration with sudo systemd-analyze cat-config systemd/journald.conf and check for later files overriding these settings. Apply the change with sudo systemctl restart systemd-journald, then check sudo systemctl is-active systemd-journald and inspect recent entries with sudo journalctl -n 20 --no-pager. Active journal files can keep total usage above the configured limit temporarily.

Check: The journal service reports active, recent entries remain readable, and the merged configuration contains your intended effective limits.

These settings do not rotate application files or container logs, which need limits through their respective logging mechanisms. To undo the policy, remove only the drop-in you added and restart the journal service. Restoring the old policy cannot recover history already removed.

7. Keep kernel defaults unless evidence supports a change

Leave global kernel parameters unchanged when you cannot connect a specific setting to the observed bottleneck. Copying a large sysctl bundle makes later diagnosis harder because several behaviors change together. Inspect existing overrides first, especially on an older server that has accumulated tuning advice.

bash
sysctl vm.swappiness vm.vfs_cache_pressure
sudo grep -RnsE '^[[:space:]]*[^#[:space:]]' /etc/sysctl.conf /etc/sysctl.d
Check: You have the effective memory settings and any uncommented entries in the local override files; no grep matches simply means those files contain no active entries.

Swappiness expresses the relative cost of swapping anonymous memory versus reclaiming filesystem-backed pages. It is not a simple RAM fullness threshold, and lowering it is not a universal speed improvement. The kernel memory parameter documentation explains the tradeoff and warns that dropping caches can create substantial work rebuilding them.

Do not schedule cache dropping as routine maintenance. Likewise, increase file descriptor limits only after actual exhaustion appears in application errors, and investigate listen queues only when connection handling is the demonstrated constraint. For any justified experiment, record the current effective value and establish the runtime rollback before making it persistent.

8. Repeat the workload and schedule the next observation

Repeat the same application operation under comparable traffic after each change. Keep request volume and application code stable enough to make the comparison useful, and let caches warm as they would during normal operation. Watch whether response times improve while background work still finishes within its required window.

Check: Keep the change only if the original symptom improves without new application errors or accumulating queued work; otherwise restore the saved configuration and repeat the observation.

We recommend Claude Code for collecting these read-only diagnostics and reviewing a proposed configuration diff. Give it the affected service and the symptom, and require explicit approval before it changes configuration or restarts anything. Apply the production guardrails for AI agents, particularly when process information or logs could expose secrets.

Before closing the task, schedule an observation during the next deployment or backup window that previously caused trouble. Add application latency and resource-pressure history using the minimum monitoring setup for small servers, with disk-space alerts that leave time to respond. If sustained demand still exceeds the machine after unnecessary work is removed, use the identified resource bottleneck to choose the next capacity change.

FAQ

What is the best way to optimize an Ubuntu VPS?

Start with the operation that feels slow and observe the server while it happens. Identify the process or shared resource causing the delay, then change one workload setting at a time. For small machines, controlling concurrent work is often a better first experiment than global tuning. Preserve the previous configuration and compare application behavior under similar traffic.

Does lowering swappiness improve Ubuntu server performance?

It can help a particular workload, but it can also make memory reclaim less suitable for that workload. The decision depends on storage behavior and which pages applications reuse. First determine whether active swapping coincides with slow requests. If the working set consistently exceeds RAM, adjusting reclaim preferences cannot create the memory the application needs.

Why does Ubuntu use so much RAM when the server is idle?

An idle application does not require Linux to leave RAM empty. Filesystem caching can retain useful data and reduce later disk reads. Look at available memory and how the machine behaves when demand returns. Investigate growing process memory or allocation failures before treating a large cache as something that needs clearing.

Should I disable Ubuntu services to make a small VPS faster?

Disable a service only after establishing that it is unnecessary and consumes resources relevant to your problem. Check what installed it and which other components depend on it. Removing update automation or security controls for speculative savings creates maintenance problems. An idle service is usually a weaker target than a busy background workload.

When should I upgrade a VPS instead of tuning Ubuntu?

Upgrade when ordinary demand continues to exhaust a specific resource after you have removed avoidable competition. Choose additional memory for a working set that cannot fit, or additional CPU capacity for sustained computation. If the evidence points to host contention or storage limits, discuss those constraints with the provider before assuming a larger plan will solve them.

Free ebook

Put this guide in the bigger picture

See how this topic connects to the rest of your product. Our free field guide explains apps, infrastructure and AI, with checklists to help you make business decisions.

We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.