İçeriğe Atla
Mustafa Erbay
Technology · 8 min read · görüntülenme Türkçe oku
100%

I Trusted a 1 GB RAM VPS Too Much: The OOM Story and Layered Defense

How I rode out the OOM (Out of Memory) crisis while running 13 containers on a 1 GB RAM VPS, how kcompactd0 captured the CPU, and the fixes I shipped...

I Trusted a 1 GB RAM VPS Too Much: The OOM Story and Layered Defense — cover image

Last Tuesday at 04:12, I woke up to a “Service Down” notification from my uptime monitor. On my own VPS — that tiny 1 GB RAM machine — exactly 13 Docker containers were happily running side by side (or so I thought).

When I tried to SSH in and the terminal just hung, that was the first sign of a big fire inside. When I finally got into the box via VNC from the panel, the scene was familiar: the kcompactd0 process consuming 92% CPU, the system unable to breathe, and the kernel killing whatever it could find in the back.

The Cost of Running 13 Containers on 1 GB RAM

I host my own projects (hesapciyiz.com, spamkalkani.com, including this blog) on the same VPS. The ecosystem I built with tools like Astro, Node.js, SQLite and Nginx normally runs quite efficiently. But that night, an Astro build triggered through GitHub Actions blew everything up.

A build process that normally consumes 200-300 MB RAM, when combined with internal SQLite queries that moment, suddenly started demanding 2.5 GB RAM. On a machine with 1 GB of physical RAM, that’s a direct disaster. The kernel pushed forward kcompactd0 to defragment memory, but the physical limits didn’t allow it.

Symptoms: Why Didn’t SSH Respond?

When the machine froze, not only did my websites go down — my management interfaces went too. Looking at journalctl, I saw sshd: accept: out of memory. The kernel was refusing to allocate even the tiny memory area needed to accept a new connection.

This was worse than the disk-100%-full incident I had on April 28. When the disk was full, at least the running processes kept going somehow; when memory ran out, the kernel went into “Survivor” mode and started killing processes randomly (or by score).

Layered Defense: Taming the OOM Killer

After this crisis I decided to rework the system architecture. It wasn’t a “good enough” situation, because 4 different side products run on this VPS. The first thing I went after was the parameters that determine how the kernel behaves in these situations.

In the table below, you can see the kernel parameter changes I applied that night which improved stability:

ParameterOld ValueNew ValuePurpose
vm.swappiness6010Reduce frequency of swapping out, use RAM to its limit.
vm.overcommit_memory01Respond more flexibly (but more riskily) to memory requests.
vm.vfs_cache_pressure100200Free up cache faster to make room in RAM.

Setting Docker Resource Limits

Running Docker containers with the “let them roam free” mindset is the biggest mistake possible in a 1 GB RAM environment. If one container (e.g. a Next.js app) leaks memory, it takes the whole VPS down with it. To prevent that, I started using strict limits in my docker-compose.yml files.

services:
  nextjs-app:
    image: my-nextjs-app:latest
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M
    restart_policy:
      condition: on-failure

Thanks to this constraint, when an application tries to exceed 256 MB, only that container is affected. Instead of locking the entire system, only the problematic app falls into OOMKilled status and, thanks to restart_policy, restarts with a clean memory area.

Swap Management and the Disk Fire

Swap is the lifebuoy of VPS operations, but when configured wrong, it becomes the executioner. I increased my old 1 GB swap to 4 GB. To avoid stressing the disk, I dialed vm.swappiness down to 10.

# A solid recipe for creating swap
sudo dd if=/dev/zero of=/swapfile bs=1M count=4096
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Pipeline Reliability: Protecting Build Processes

The OOM error I hit during the Astro build taught me this: build process and production traffic can’t use the same resources at the same time. Especially if you use a self-hosted runner via GitHub Actions, the moment the build starts, CPU and RAM hit the ceiling.

To solve that, I wrote a “preflight resource guard.” Before the pipeline runs, it checks the machine’s current RAM state; if there’s less than 20% free, it doesn’t start the build and sends me a Telegram alert. I also added a cleanup step to remove old build leftovers in the _work/_temp directory. I painfully learned in the past that those directories filling with 33 GB of build cache could blow up the disk.

Kernel Security and Unnecessary Loads

Easing the system isn’t only about setting limits — it’s also about removing unnecessary load. For example, by blacklisting kernel modules I don’t use, I closed both a security gap and helped the kernel run “leaner.” To protect against kernel-module-based vulnerabilities like CVE-2026-31431, I disabled modules like algif_aead.

Conclusion and Future Plans

Running this much work on 1 GB RAM is a kind of art, but the risks are big. Right now the system is stable; 13 containers run smoothly, swap usage is minimal, and kcompactd0 is in its sleep again. But that doesn’t mean the next crisis won’t come.

In the coming days I plan to migrate the SQLite databases on this VPS to a central Postgres container. Having a separate SQLite operation inside each container has started becoming inefficient on disk IO and memory management. In a future post I’ll go through the performance gains and probable “we exploded again” moments from that migration.

How are things on your VPS right now? When you run free -m, does the table you see scare you, or do you say “good enough” and move on?

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Comments

Server-side AI Moderation

Comments are AI-moderated server-side and stored permanently.

?
0/2000

Server-side AI moderation

✉️ Free · No spam · Unsubscribe anytime

Curated digest, hand-picked by me — not the AI

Once a week: the most important post of the week, behind-the-scenes notes, and a "what I actually used this week" section. Less noise, more signal.

  • 📌
    Best of the week Single most-worth-reading post
  • 🔧
    Toolbox notes Real tools I used this week
  • 🧠
    Behind-the-scenes Notes that don't make it to blog

We don't spam. Unsubscribe anytime. · Tracked only by Umami (self-hosted, no Google).

Your Reading Stats

0

Posts Read

0m

Reading Time

0

Day Streak

-

Favorite Category

Related Posts