Add a Swap File to a Small VPS
Check memory first, create a swap file that survives reboots, set vm.swappiness with a sysctl drop-in, and remove it cleanly if you change your mind.

A 1 GB VPS runs happily until the day a package upgrade, a build, or a database wants a little more memory than the machine has. Without swap, the kernel’s out-of-memory (OOM) killer picks a process and ends it. It prefers big ones, and on a small server the biggest process is usually the one you care about.
Swap isn’t extra RAM. It’s a place to park memory pages nobody is touching so the active ones still fit, the way winter coats go to the basement so the hallway stays usable. Disk is much slower than RAM, so a machine that swaps constantly is undersized. A machine that occasionally parks a few hundred megabytes of idle pages is using swap exactly as intended.
The steps below target Debian 13 and Ubuntu 24.04 or 26.04 on the usual ext4 root filesystem. Btrfs needs one extra detail, covered where it comes up.
Look before adding anything
free -h
swapon --show
total used free shared buff/cache available
Mem: 957Mi 498Mi 71Mi 1.0Mi 388Mi 459Mi
Swap: 0B 0B 0B
Read available, not free. free counts memory nobody is using at all, while available estimates what a new program could get without swapping, including page cache the kernel can drop. A tiny free next to a healthy available is normal Linux.
If swapon --show prints nothing, no swap is active. If it lists something, you already have swap, maybe a partition or zram, and adding another layer needs a reason.
Check whether the OOM killer has already been busy in the current boot:
sudo journalctl -k | grep -i 'out of memory'
A few hits there make a better case for swap than any rule of thumb. Then check room and filesystem type:
df -h /
findmnt -no FSTYPE --target /
If df shows the disk is already tight, run through the disk space triage first. A swap file that fills the disk swaps one outage for another.
Pick a size
For a small VPS, 1 to 2 GiB is a sensible start. Ubuntu’s server installer is a handy reference: it suggests double the RAM up to 1 GiB, 2 GiB for machines up to 2 GiB, and the same as RAM up to 4 GiB, capped at a quarter of the free disk space. The examples below use 2 GiB.
Create the file
On util-linux 2.41 or newer (Debian 13 and Ubuntu 26.04 have it), mkswap can do the whole job:
mkswap --version
sudo mkswap --file --size 2G /swapfile
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=530f507b-14d6-475a-8990-aa4c372d13f5
That creates the file with 0600 permissions, allocates its blocks, and sets the no-copy-on-write attribute that btrfs requires.
Older util-linux (Debian 12, Ubuntu 24.04) doesn’t have --file, so create the file first:
# Option A: instant, reserves blocks without writing them
sudo fallocate -l 2G /swapfile
# Option B: slower, writes every block
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
sudo chmod 600 /swapfile
sudo mkswap /swapfile
The choice matters because the kernel writes to a swap file directly, without help from the filesystem, so the file can’t contain holes. fallocate works on ext4, and it’s what Ubuntu’s own installer uses there. swapon(8) warns that some filesystems treat preallocated files as having holes, though, so dd is the portable choice. If swapon later says skipping - it appears to have holes, recreate the file with dd. Don’t use truncate or cp, because both produce sparse files.
The chmod isn’t decoration. Swap holds whatever memory was paged out, which can include passwords and keys. If you forget it, mkswap complains: insecure permissions 0644, fix with: chmod 0600 /swapfile.
On btrfs, use mkswap --file or sudo btrfs filesystem mkswapfile --size 2G /swapfile. Keep in mind that a subvolume holding an active swap file can’t be snapshotted, which matters if a snapshot tool manages your root subvolume.
Turn it on and make it stick
sudo swapon /swapfile
swapon --show
NAME TYPE SIZE USED PRIO
/swapfile file 2G 0B -2
A negative PRIO just means the kernel picked the priority. To keep the swap file across reboots, back up /etc/fstab and add a line for it:
sudo cp /etc/fstab /etc/fstab.bak
echo '/swapfile none swap defaults 0 0' | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
daemon-reload makes systemd regenerate its units from fstab now instead of at the next boot. Now check the new line without rebooting:
sudo swapoff /swapfile
sudo swapon -a
swapon --show
swapon -a activates everything marked swap in fstab. If /swapfile comes back, the line is right.
Tune swappiness
vm.swappiness takes a value from 0 to 200 and defaults to 60. It tells the kernel how to weigh swapping out program memory against dropping file cache. Lower values keep program memory in RAM longer, so swap mostly gets used when it’s actually needed.
sysctl vm.swappiness
vm.swappiness = 60
To treat swap as a safety net rather than everyday workspace, lower it with a drop-in file:
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/90-swappiness.conf
sudo sysctl -p /etc/sysctl.d/90-swappiness.conf
vm.swappiness = 10
No single number is right for every server. 10 is a conservative start, and the default is defensible too. Use /etc/sysctl.d/ rather than /etc/sysctl.conf. On Debian 13, systemd-sysctl no longer reads sysctl.conf at boot, so a setting there would work today and quietly disappear after the next reboot.
Watch it for a few days
free -h shows how much swap is in use. vmstat 5 shows the rate: the si and so columns count pages swapped in and out per second. Occasional blips are fine. If those columns stay above zero under normal load, the machine needs more RAM, not more swap.
Remove it cleanly
Order matters. Turn swap off before you delete the file:
free -h
sudo swapoff /swapfile
sudoedit /etc/fstab # delete the /swapfile line
sudo systemctl daemon-reload
sudo rm /swapfile
swapoff has to pull every swapped page back into RAM, so first check free -h and make sure the swap in use fits comfortably inside available. If you added the swappiness drop-in, remove it and restore the default:
sudo rm /etc/sysctl.d/90-swappiness.conf
sudo sysctl -w vm.swappiness=60
References
- swapon(8), Debian 13 manual page
- mkswap(8), Debian 13 manual page
- free(1), Debian 13 manual page
- Btrfs documentation: Swapfile
- Linux kernel documentation: /proc/sys/vm (swappiness)
- sysctl.d(5), Debian 13 manual page
- sysctl(8), Debian 13 manual page
- Debian 13 release notes: systemd-sysctl no longer reads /etc/sysctl.conf
- curtin swap.py: how Ubuntu’s installer sizes and creates swap files
Cover photo: Unsplash.