Your App Keeps Dying on Linux and There's No Error Message
Your app was running fine. Then it stopped. No error message. No crash log. No stack trace. It was there, and then it wasn't. You restart it. It runs for an hour, maybe two, maybe twelve. Then it dies again. Same thing. No explanation.
If you're running on a VPS or any Linux server, and your app randomly disappears like this, there's a very good chance Linux itself killed it. On purpose.
Meet the OOM killer
Linux has a built-in mechanism called the OOM killer — short for "Out Of Memory" killer. It works like a bouncer at a crowded bar. When the server runs out of RAM and there's nothing left to give, the OOM killer picks a process, walks up to it, and kills it. Instantly. No warning. No graceful shutdown. No "hey, you should probably save your work." Just dead.
Your app doesn't get a chance to log an error because it doesn't know it's about to die. One moment it's running. The next, the operating system has ended it. The app's own logs will show nothing because the app never saw it coming.
The OOM killer picks its victim based on which process is using the most memory. Your app is probably the biggest thing running on the server. So it gets killed first. Every time.
How to confirm the OOM killer got you
The app didn't leave a note, but the operating system did. Linux logs every OOM kill. You just need to know where to look.
Check the kernel log
dmesg | grep -i "out of memory"
If the OOM killer fired, you'll see something like:
Out of memory: Killed process 12345 (node) total-vm:1048576kB
That's Linux telling you: "I ran out of RAM and killed your Node process." The number after total-vm tells you how much memory the process was using when it died.
You can also search for the kill event directly:
dmesg | grep -i "killed process"
Check the system journal
journalctl -k | grep -i oom
This searches the kernel journal for OOM events. Same information, different way to find it. If your server has been running for a while, add --since "24 hours ago" to narrow it down.
Check the exit code
When the OOM killer terminates a process, it sends signal 9 (SIGKILL). The process exits with code 137 (128 + 9). If you're using systemd:
systemctl status your-app
Look for status=9/KILL or code=killed, signal=KILL. If you're using Docker:
docker inspect your-container --format='{{.State.ExitCode}}'
Exit code 137 means something killed the process with SIGKILL. On a Linux server, that "something" is almost always the OOM killer.
Why this happens on cheap VPS instances
This problem disproportionately hits people running on $5-10/month VPS plans. Here's why.
A cheap VPS typically gives you 1GB of RAM. That sounds like it should be enough for a simple app. But here's what's actually sharing that 1GB:
- The Linux operating system itself: 200-400MB
- Nginx or another web server: 50-100MB
- Your app (Node.js, Python, etc.): 200-500MB
- A database (PostgreSQL, MySQL, Redis): 200-500MB
- SSH, systemd, logging, cron, and other background services: 50-100MB
Add that up. On a good day, you're at 700MB. On a busy day, with a few more requests, a slightly larger dataset, or one function that loads something big into memory — you're over 1GB. The OOM killer fires. Your app dies.
The worst part is that this can work fine for days or weeks. Then one afternoon your app gets a few extra users, or a background job runs at the same time as a request spike, and RAM usage tips over the edge. It seems random because the trigger is random. The underlying problem — not enough RAM — was there the whole time.
Common memory hogs
Certain things eat more memory than people expect:
Node.js
Node.js, by default, will happily use up to 1.5GB of heap memory on a 64-bit system. On a 1GB VPS, that's a death sentence. It won't use all of it immediately, but under load or with a memory leak, it'll creep up until the OOM killer notices.
Python loading data into memory
Python makes it very easy to load an entire file, dataset, or query result into memory at once. data = file.read(), rows = cursor.fetchall(), df = pd.read_csv("big_file.csv") — all of these pull everything into RAM. On a laptop with 16GB, nobody notices. On a VPS with 1GB, this alone can trigger the OOM killer.
Image processing
If your app resizes images, generates thumbnails, or processes uploads, each image gets decoded into raw pixel data in memory. A 5MB JPEG becomes a 50MB+ uncompressed bitmap in RAM. Process a few images at the same time and you've eaten your entire allocation.
Running the database on the same server
This is the biggest trap. Running your app and your database on the same 1GB VPS means they're competing for the same RAM. Databases are designed to use as much memory as they can get — that's how they stay fast. PostgreSQL, MySQL, and Redis will all happily consume hundreds of megabytes. Combined with your app, there's simply not enough to go around.
How to check your memory right now
free -h
This shows your total RAM, how much is used, and how much is free. The important number is the available column — that's how much memory is actually available for new work. If it's under 100MB, you're in the danger zone.
For a more detailed view:
htop
This shows every running process sorted by memory usage. You can see exactly who is eating your RAM. Press M to sort by memory. The top few entries are your suspects. (If htop isn't installed, top works too — press Shift+M to sort by memory.)
Quick fix: add swap space
Swap is disk space that Linux uses as overflow when RAM is full. Instead of the OOM killer immediately terminating your app, the system moves some data from RAM onto the disk to make room. It's a band-aid, not a cure — but it can stop the random kills while you figure out a real solution.
Here's how to create a 2GB swap file:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
To make it permanent (survives reboot), add this line to /etc/fstab:
/swapfile none swap sw 0 0
The catch: swap is slow. Much slower than RAM. If your app is constantly swapping, it'll still run — but it'll be sluggish. On an SSD-backed VPS it's tolerable. On a spinning disk it's painful. Swap buys you time and stability, not performance.
Real fixes
Swap keeps you alive. These actually solve the problem:
Limit your app's memory usage
For Node.js, set a memory ceiling so it doesn't try to eat 1.5GB:
node --max-old-space-size=512 app.js
This caps Node's heap at 512MB. It'll throw an error if it hits the limit instead of silently growing until the OOM killer steps in. An error you can see and debug is infinitely better than a silent kill.
For Python, the fix is usually in your code. Use generators instead of loading entire datasets into memory. Use cursor.fetchone() or cursor.fetchmany(100) instead of cursor.fetchall(). Process files line by line instead of reading the whole thing. Stream large responses instead of building them in memory.
Move the database off the server
The single biggest thing you can do for a memory-starved VPS is stop running the database on it. Use a managed database service — most cloud providers offer one for $5-15/month. Your app server gets all the RAM to itself, and the database gets its own dedicated resources.
Upgrade your VPS
Sometimes the answer is just "you need more RAM." Going from 1GB to 2GB often costs an extra $5-10/month and completely eliminates the problem. It's not glamorous advice, but it's honest. If your app legitimately needs 1.2GB of RAM and you have 1GB, no amount of optimization will fix that.
Set memory limits in Docker
If you're running in Docker, you can set a memory limit per container so one runaway container doesn't kill everything else:
docker run --memory=512m --memory-swap=768m your-app
Or in docker-compose:
services:
app:
deploy:
resources:
limits:
memory: 512M
The container gets killed if it exceeds its limit, but at least it doesn't take the whole server down with it.
Why AI doesn't catch this
This is one of those problems AI is structurally bad at diagnosing. Here's why.
AI doesn't know how much RAM your server has. When you say "my app keeps crashing," it has no way to know you're running on a 1GB VPS. It'll suggest checking logs, restarting services, reinstalling dependencies — all the things you'd do if the app itself had a bug. But the app doesn't have a bug. Linux killed it from the outside, and the app never knew.
AI also generates code that works on a developer's laptop. Your laptop has 8 or 16GB of RAM. Code that casually loads a 200MB file into memory, or spawns a few child processes, or runs a database query that returns 50,000 rows — that's fine on a laptop. Deploy that same code to a $5 VPS with 1GB of RAM and it dies within hours. AI never says "hey, how much RAM does your server have?" because it doesn't think in terms of deployment constraints.
And when you do tell AI that exit code 137 keeps showing up, it might correctly identify "OOM kill" — but its solution will be generic. "Add more RAM" or "optimize your code." It can't look at your htop output and say "your PostgreSQL is using 400MB because shared_buffers is set too high for this server" or "this Python function loads the entire users table into a list — use a generator." That takes someone who can see your specific system.
App keeps dying and you can't figure out why?
MeatButton connects you with a real expert who can look at your server, find the memory problem, and fix it — not just tell you to "add more RAM." First session is free.
Get MeatButton