
Add a Swap File on Ubuntu and Fix Time Sync on Your VPS
A fresh Linux VPS boots in seconds and feels fast, right up to the night a backup job, a burst of PHP workers and a heavy database query all want memory at the same moment. The kernel runs out of RAM, picks a victim and kills it, very often MySQL. A week later something different breaks: a certificate renewal fails, 2FA codes get rejected, and the timestamps in your logs do not match what actually happened. Both problems come from two small things most server images leave half-done: there is no swap, and nobody checked the clock. In this guide we fix both properly, with a swap file that survives reboots, a sane swappiness value, the right timezone and working NTP synchronization, and we explain every command as we go.
Everything below works on Debian 13 and Ubuntu 24.04, on a KVM VPS, logged in as a regular user with sudo rights. Where the two distributions behave differently, we say so explicitly. If your VPS is an LXC container, read the note in Step 1 first, because some of these settings belong to the host there, not to you.
What you need
- A Linux VPS running Debian 13 or Ubuntu 24.04 (a DreamServer VPS works out of the box).
- SSH access as a user that can run
sudo. - About 2-4 GB of free disk space for the swap file.
- Ten to fifteen minutes. No reboot is required; we only do one at the end to prove the settings stick.
What swap is, and why a small VPS needs it
RAM is the fast working memory where every running program keeps its data. It is limited: a 1 GB or 2 GB VPS fills up quicker than people expect, because the web server, the database, a PHP pool and the operating system itself all live there at the same time.
Swap is a reserved area on disk that the kernel can use as overflow. When RAM gets tight, the kernel moves memory pages that nobody has touched in a while (an idle worker, the start-up code of a daemon, a cache nobody reads) out to swap, and frees the RAM for things that are actually active. Disk is much slower than RAM, so swap is not “extra RAM” you can live on permanently. It is a safety buffer.
Without any swap, when RAM runs out the kernel has only one tool left: the OOM killer (Out Of Memory killer). It chooses a process, usually the one using the most memory, and terminates it on the spot. On a typical server that is the database. With a modest amount of swap, the same spike makes the server a bit slower for a minute instead of taking a service down.
Swap can live on a dedicated disk partition or in an ordinary file. On a VPS a swap file is the better choice: you do not need to repartition anything, you can resize or delete it in a minute, and on modern kernels its performance is equivalent to a partition. Most VPS images, including the Ubuntu cloud images, ship with no swap at all, which is why this is worth doing on day one.
Why the clock matters more than you think
Every server keeps a system clock, internally in UTC (Coordinated Universal Time, the global reference time with no daylight saving). The timezone is only a display setting on top of it: it decides how that UTC moment is shown in logs, which hour “3 AM” means for cron, and what your applications print.
The clock itself drifts. The timer a virtual machine relies on is never perfect, and pausing, migrating or restoring a VM from a snapshot can make it jump. NTP (Network Time Protocol) solves this: a small background service regularly asks public time servers what time it is and gently corrects the local clock.
A wrong clock breaks more than you would expect:
- TLS certificates have a “not before” and a “not after” date. If your clock is behind, a brand new certificate looks “not yet valid”; if it is ahead, a valid one looks expired. Let’s Encrypt renewals,
aptover HTTPS and outgoing API calls can all fail. - 2FA codes (TOTP, the six digits from an authenticator app) are valid for roughly 30 seconds, sometimes with one extra step of tolerance. A server that is a minute off rejects correct codes.
- Logs from different machines cannot be correlated if their clocks disagree, which hurts exactly when you investigate an incident.
- Cron jobs run at the wrong local hour if the timezone is not what you think it is.
The plan: add a swap file on Ubuntu or Debian, then fix the clock
Steps 1 to 4 build and tune the swap file, steps 5 and 6 fix the time, and step 7 proves that everything survives a reboot. The two halves are independent, so you can stop after Step 4 and come back for the clock later.
Step 1: Check memory, disk and existing swap
Before creating anything, let us see what we have. First, find out what kind of virtualization the VPS uses:
systemd-detect-virt
On a KVM VPS this prints kvm. If it prints lxc, you are inside a container that shares the kernel with the host. In an unprivileged LXC container you cannot create or enable swap (swapon fails with “Operation not permitted”), you cannot change vm.swappiness, and you cannot set the clock, because memory limits, swap and time are controlled by the host. You can still set the timezone (Step 5). If you are on LXC and need more memory headroom, ask your provider to raise the memory or swap limit of the container.
Now check memory and current swap:
free -h
swapon --show
free -h shows memory in human-readable units. On a fresh 2 GB VPS it looks roughly like this:
total used free shared buff/cache available
Mem: 1.9Gi 610Mi 880Mi 1.0Mi 600Mi 1.3Gi
Swap: 0B 0B 0B
The columns to watch are total and available (how much memory programs can still get without swapping). The Swap: line shows zeros and swapon --show prints nothing at all: there is no swap yet. If swapon --show already lists a device or file, your image ships with swap and you can jump to Step 4.
Finally, check free disk space and the filesystem type of the root partition:
df -h /
findmnt -no FSTYPE /
You need enough free space for the swap file plus a comfortable margin; never fill a disk to 100%. On Debian and Ubuntu VPS images the filesystem is almost always ext4, which is what the next step assumes. If you see btrfs, read the note in Step 2.
Step 2: Create the swap file
How big should the swap file be?
Old rules like “twice the RAM” come from desktops with hibernation and very little memory. A VPS never hibernates, and a huge swap file only lets a runaway process thrash the disk for longer before it fails anyway. A sensible starting point:
| VPS RAM | Suggested swap | Reasonable range |
|---|---|---|
| 1 GB | 2 GB | 1-2 GB |
| 2 GB | 2 GB | 1-2 GB |
| 4 GB | 2 GB | 2-4 GB |
| 8 GB | 4 GB | 2-4 GB |
| 16 GB or more | 4 GB | 2-4 GB |
We use 2 GB in the examples below. If you picked a different size, replace 2G with your value.
Allocate the file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
ls -lh /swapfile
fallocate reserves 2 GB of disk space for the file instantly, without writing data. chmod 600 makes the file readable and writable only by root, which is essential: swap can contain fragments of anything that was ever in memory, including passwords and private keys. The ls output should look like this:
-rw------- 1 root root 2.0G Nov 10 08:00 /swapfile
If fallocate is not supported on your filesystem, or later swapon complains that the file “has holes”, create it the slower but always safe way, by writing real zeros:
sudo rm -f /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
sudo chmod 600 /swapfile
2048 blocks of 1 MiB give exactly 2 GiB; adjust count for other sizes. On btrfs, an ordinary file cannot be used as swap unless copy-on-write is disabled for it; use sudo btrfs filesystem mkswapfile --size 2g /swapfile instead, which takes care of that for you.
Format it as swap
sudo mkswap /swapfile
mkswap writes a small header that marks the file as swap space. Expected output:
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=3f1c2a9e-7b1d-4c55-9a0e-2d6b8f4e1a77
The UUID will be different on your server, that is normal.
Step 3: Enable swap and make it permanent
Turn the swap file on:
sudo swapon /swapfile
swapon --show
You should see:
NAME TYPE SIZE USED PRIO
/swapfile file 2G 0B -2
Swap is active right now, but it would disappear after a reboot. To make it permanent we add a line to /etc/fstab, the file that tells the system which disks and swap areas to activate at boot. A broken fstab can stop a server from booting cleanly, so we make a backup first:
sudo cp /etc/fstab /etc/fstab.bak
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
The line reads: the device is /swapfile, it has no mount point (none), its type is swap, use default swap options (sw), and the two zeros disable dump and filesystem checks. tee -a appends the line with root rights and echoes it back to the terminal. A plain sudo echo ... >> /etc/fstab would fail, because the >> redirection runs as your normal user, not as root.
Now test the fstab entry without rebooting, by turning swap off and asking the system to enable everything listed in fstab:
sudo swapoff /swapfile
sudo swapon -a
swapon --show
If /swapfile shows up again, the fstab line works. If swapon -a prints an error, open the file with sudo nano /etc/fstab and fix the line, or restore the backup with sudo cp /etc/fstab.bak /etc/fstab. Also check that you did not run the tee -a command twice, which would leave a duplicate line.
Step 4: Tune swappiness
Swappiness is a kernel setting, from 0 to 200 on current kernels, that tells Linux how eagerly to move application memory to swap compared to dropping file cache. The default is 60, a value tuned for desktops. On a server we want the kernel to keep application memory in RAM as long as possible and swap only under real pressure, so a value around 10 works well. Do not use 0: it does not disable swap, but it makes the kernel avoid swap until the very last moment, which brings back much of the OOM risk we are trying to remove.
Check the current value and change it for the running system:
cat /proc/sys/vm/swappiness
sudo sysctl vm.swappiness=10
The second command confirms with vm.swappiness = 10. To keep the value after a reboot, put it in its own file under /etc/sysctl.d/ and reload all sysctl settings:
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system
sysctl --system lists every configuration file it reads; you should see /etc/sysctl.d/99-swappiness.conf among them, followed by vm.swappiness = 10.
A Debian versus Ubuntu note: many older guides tell you to edit /etc/sysctl.conf. On Ubuntu 24.04 that file still exists and is read at boot, but on Debian 13 it is no longer shipped and no longer read at boot, so a setting placed there is silently ignored after a restart. A file in /etc/sysctl.d/ works on both, which is why we use it. You may also see advice to set vm.vfs_cache_pressure=50; the default of 100 is fine for most servers, so leave it alone unless you have measured a reason to change it.
Step 5: Set the timezone
Let us look at the current time configuration:
timedatectl
On a fresh VPS the output usually looks like this:
Local time: Tue 2026-11-10 06:00:12 UTC
Universal time: Tue 2026-11-10 06:00:12 UTC
RTC time: Tue 2026-11-10 06:00:12
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Time zone is the display setting. System clock synchronized and NTP service tell us whether time synchronization works, which we handle in Step 6. RTC in local TZ: no means the virtual hardware clock is kept in UTC, which is correct on Linux; leave it like that.
UTC or local time?
Both are valid; what matters is choosing on purpose. UTC never changes with daylight saving, so there is never a missing or doubled hour in your logs, and servers in different countries line up directly. Many teams keep every server on UTC. Local time is friendlier when the server serves one country and you read logs and schedule jobs in local hours. For a business in Romania, Europe/Bucharest is the natural choice. Find the exact name and set it:
timedatectl list-timezones | grep -i bucharest
sudo timedatectl set-timezone Europe/Bucharest
timedatectl
The Time zone line now shows Europe/Bucharest (EET, +0200) in winter and EEST, +0300 in summer. The underlying system clock did not change at all, only the way it is displayed.
Cron reads the timezone when it starts, so restart it to make scheduled jobs follow the new zone. The service is called cron on both Debian and Ubuntu (some other distributions call it crond):
sudo systemctl restart cron
If this says the unit does not exist, cron is simply not installed, which happens on minimal Debian installs; there is nothing to restart. Keep in mind that some software keeps its own timezone setting: PHP has date.timezone, MySQL and PostgreSQL have their own time zone variables, and Docker containers run in UTC unless you pass a TZ variable or mount /etc/localtime into them.
Step 6: Turn on NTP time sync
Two NTP clients are common on Debian and Ubuntu: systemd-timesyncd, a lightweight client that is perfect for a single VPS, and chrony, a full NTP implementation with more features. You need exactly one of them. Check which one is running:
systemctl is-active systemd-timesyncd chrony
The command prints one line per service, active or inactive. On Ubuntu 24.04 you will normally see timesyncd active, configured to use ntp.ubuntu.com. On Debian 13 it depends on the image: many use timesyncd with the debian.pool.ntp.org servers, some cloud images ship chrony, and minimal installs may have neither. If both lines say inactive, install timesyncd:
sudo apt update
sudo apt install systemd-timesyncd
The two packages conflict on purpose: installing one removes the other, so you never end up with two daemons fighting over the clock.
Configure timesyncd
The defaults work, but we prefer nearby servers from the public NTP pool. Instead of editing the main config file, we add a drop-in file, which survives package upgrades untouched:
sudo mkdir -p /etc/systemd/timesyncd.conf.d
sudo tee /etc/systemd/timesyncd.conf.d/10-servers.conf > /dev/null <<'EOF'
[Time]
NTP=0.ro.pool.ntp.org 1.ro.pool.ntp.org 2.ro.pool.ntp.org
FallbackNTP=0.pool.ntp.org 1.pool.ntp.org
EOF
sudo systemctl restart systemd-timesyncd
sudo timedatectl set-ntp true
NTP= lists the servers we want, here the Romanian zone of the pool; outside Romania use your country zone or simply pool.ntp.org. FallbackNTP= is used only if none of the primary servers answer. set-ntp true makes sure synchronization is switched on. Now check the status:
timedatectl timesync-status
Server: 192.0.2.10 (0.ro.pool.ntp.org)
Poll interval: 34min 8s (min: 32s; max 34min 8s)
Leap: normal
Version: 4
Stratum: 2
Reference: C035676C
Precision: 1us (-24)
Root distance: 1.035ms (max: 5s)
Offset: -312us
Delay: 4.812ms
Jitter: 410us
Packet count: 6
Frequency: +11.204ppm
The lines that matter: Server shows which machine answered, Stratum how many hops it is from a reference clock (2 is great), and Offset how far our clock was from it, here 0.3 milliseconds. Right after a restart the poll interval is short and it grows as the clock stabilizes. Running timedatectl again should now show System clock synchronized: yes.
If your system uses chrony
Skip the timesyncd configuration and check chrony instead:
chronyc tracking
chronyc sources -v
tracking shows the current offset in the System time line, and sources lists the servers; the one marked with * is the one in use. On both Debian and Ubuntu the main config is /etc/chrony/chrony.conf, which also reads extra files from /etc/chrony/sources.d/. To use pool servers of your choice, create /etc/chrony/sources.d/ro-pool.sources containing the single line pool ro.pool.ntp.org iburst, then run sudo chronyc reload sources.
Firewall
An NTP client sends requests from your server to UDP port 123 on the time servers and receives their replies. With ufw in its default mode (deny incoming, allow outgoing) this already works, and you should not open port 123 inbound: your VPS is a client, not a time server. Only if you changed the outgoing policy to deny do you need sudo ufw allow out 123/udp.
Step 7: Verify everything after a reboot
None of the changes above needs a reboot, they are all active already. We reboot once only to prove they come back on their own:
sudo reboot
Log back in after a minute and run:
swapon --show
cat /proc/sys/vm/swappiness
timedatectl
Expect /swapfile listed with its size, 10 for swappiness, your chosen timezone, and System clock synchronized: yes (right after boot it can take a few seconds to turn to yes).
While we are talking about reboots, a Debian versus Ubuntu difference: Ubuntu creates the file /var/run/reboot-required when installed updates need a restart, so ls /var/run/reboot-required is a quick check there. Debian does not reliably create that file; install the needrestart package to find out what needs restarting. Nothing in this guide creates that file on either system.
Keeping an eye on swap
Some swap usage is perfectly normal: idle pages parked on disk cost you nothing. What you want to avoid is constant traffic in and out of swap. Check it with:
vmstat 5 5
This prints five samples, five seconds apart. Look at the si (swap in) and so (swap out) columns. Occasional non-zero values are fine; large values in every sample mean the server is swapping all the time. That is a sign it is short on RAM, and the fix is to reduce memory usage or move to a larger plan, not to make the swap file bigger.
Troubleshooting and common mistakes
swapon: /swapfile: swapon failed: Operation not permitted: you are almost certainly inside an LXC container (checksystemd-detect-virt). Swap is managed by the host there.swapon: /swapfile: insecure permissions 0644, 0600 suggested: you skippedsudo chmod 600 /swapfile. Run it and try again.swapon: /swapfile: swapfile has holesorInvalid argument: the filesystem does not accept a preallocated file. Recreate it with theddcommand from Step 2, thenmkswapagain.- Swap is gone after a reboot: the fstab line is missing or contains a typo. Check
grep swap /etc/fstabandsystemctl status swapfile.swap, the unit systemd generates automatically for/swapfile. sysctl: setting key "vm.swappiness": Read-only file system: again a container; the host decides this value.- Swappiness back to 60 after a reboot on Debian 13: you probably put it in
/etc/sysctl.conf. Move it to/etc/sysctl.d/99-swappiness.conf. System clock synchronized: no: check that a client runs (systemctl status systemd-timesyncd), read its log withjournalctl -u systemd-timesyncd -n 30, and make sure outbound UDP 123 is not blocked. In a container, timesyncd does not start at all by design, andNTP serviceshowsn/aorinactive: the host clock is used.- Cron runs jobs at the old hour: you changed the timezone but did not restart cron.
- “certificate is not yet valid” or expired-certificate errors from
curlorapt: comparedatewith a correct clock. If it is off, fix NTP first, then retry. - The disk filled up: the swap file is too big for a small disk. Shrink it as described in the FAQ below.
Security notes
- Permissions on the swap file are not optional. Swap holds raw memory pages: session tokens, database passwords, decrypted data. Keep it at
600, owned by root. - Swap is not encrypted by default. On a KVM VPS the virtual disk is yours alone, but if your threat model includes someone reading disk images or backups, consider encrypted swap with a random key generated at boot, or avoid swap for processes that hold very sensitive secrets.
- Do not run an open NTP server. Your VPS only needs to query time servers. Keep UDP 123 closed inbound; badly configured public NTP servers have a long history of being abused for amplification attacks.
- Correct time is a security control. TLS validation, 2FA, token expiry and forensic timelines all depend on it. Treat “clock not synchronized” as an alert to fix, not a cosmetic warning.
- Swap does not fix a memory leak. If an application keeps growing, swap only delays the crash. Monitor memory and set limits where you can, for example memory limits on Docker containers.
So, is it worth ten minutes?
Absolutely. A right-sized swap file turns out-of-memory crashes into brief slowdowns, a low swappiness keeps your applications in RAM where they belong, and a synchronized clock with a deliberate timezone keeps certificates, 2FA, cron and logs honest. It is the kind of setup nobody notices when it is done and everybody notices when it is missing.
If you are starting a new project, our VPS plans run on KVM in our own data center in Romania, so everything in this guide works exactly as written. And if you would rather not handle swap, kernel tuning, time sync, updates and monitoring yourself, our server administration team can set up the server and look after it for you.
Frequently asked questions
Will swap make my VPS slower?
Not by itself. Swap is only used when RAM is under pressure, and with swappiness at 10 the kernel moves only memory that is truly idle. Without swap, the same situation ends with a killed process, which is much worse than a short slowdown.
Swap file or swap partition?
On a VPS, a swap file. Performance is equivalent on modern kernels, and a file is far easier to create, resize or remove than a partition.
How do I resize or remove the swap file?
Turn it off with sudo swapoff /swapfile. To resize, run fallocate with the new size, then chmod 600, mkswap and swapon again; the fstab line stays the same. To remove it, delete the line from /etc/fstab and run sudo rm /swapfile. Make sure there is enough free RAM before swapoff, because everything currently in swap has to move back into memory.
Do I still need swap with 16 GB of RAM?
A small swap file of 2-4 GB is still useful as a parking place for idle pages and a buffer for unexpected spikes. It costs only a little disk space.
What about zram?
zram creates a compressed swap device inside RAM. It helps on very small machines and can be combined with a swap file, but it trades CPU time for memory. For most VPS workloads a plain swap file with a sensible swappiness is simpler and good enough.
Should the server use UTC or local time?
If you run servers in several countries or care about correlating logs, use UTC. If everything serves Romania and you prefer reading local hours, Europe/Bucharest is fine. Internally the system clock is UTC either way.