# How I run a Discord bot, a website and an AI image scanner on 2 GB of RAM *The whole of VoidBox lives on one $5 server. Here's what fits, and what I had to change to make it fit.* --- VoidBox is a Discord bot I build alone. It does economy, levels, tickets, moderation and AI, and it's in about 250 servers. It also has a website with a dashboard, a blog and an MCP server so people can run their Discord server from Claude. All of it runs on one VPS: - **1 vCPU** - **1.9 GB of RAM**, plus 1 GB of swap - **about $4.76 a month** People assume a bot like this needs a cluster. It doesn't. It needs you to know where every megabyte goes. ## Where the memory goes This is a snapshot from today: | What | Memory | |---|---| | The Discord bot | ~845 MB | | The NSFW image scanner (when loaded) | up to ~620 MB | | The website + API | ~160 MB | | Process manager and the rest | ~150 MB | Add that up and you can see the problem: the bot and the image scanner together already want most of the box. Everything below is about making sure they're never both at full size at the wrong moment. ## 1. Load the heavy thing only when it's needed VoidBox scans images for NSFW content on its own hardware, so no images get sent to a third party. That model is the single biggest thing on the server: about a third of all the RAM while it's loaded. But most servers go long stretches without anyone posting a picture. So the scanner runs as a **separate process** that starts when an image arrives and **shuts itself down after 4 minutes of quiet**. The cost: the first image after a quiet spell waits about 7 seconds while the model loads. The message is already posted, so a moderator would never notice the difference. The benefit: 620 MB goes back to the rest of the system most of the time. I learned this one from a memory alert, not from planning. ## 2. Put a time limit on every cache The Discord library I use keeps the last 200 messages of every channel in memory, and by default it **never throws them away**. With hundreds of channels across 250 servers, that grows forever. I need some cached messages: it's how the bot can show *what* was deleted when someone deletes a message. But almost all deletes and edits happen within minutes. So messages now expire after **6 hours**. Anything older gets logged with an honest "content unavailable". A cache without a limit isn't a cache. It's a slow memory leak. ## 3. Use SQLite, and skip native dependencies Both databases are SQLite files: the bot's is about 82 MB and the website's about 9 MB. There's no database server running in the background using memory. I use **`node:sqlite`, which is built into Node**, so there's no native module to compile. That matters on a tiny box, because compiling things is exactly what eats memory and CPU. ## 4. Deploys can take the server down too The scariest outage I've had wasn't caused by traffic. It was caused by a deploy. My deploy script used to reinstall the bot's dependencies every time. On a 2 GB box, a full `npm install` running next to the live bot **froze the whole server**. Now: - dependencies are only reinstalled when the lockfile actually changed, - the install runs at the **lowest CPU priority**, - and it downloads only a couple of packages at a time. The live bot and the website keep running while it happens. ## 5. Cap the expensive features Voice chat with the AI is the most CPU-hungry thing VoidBox does. With one vCPU, I allow **two servers in voice at once**. When a bigger server comes along, that's the number I'll raise, not something I'll pretend is unlimited. ## 6. Swap is a safety net, not a plan There's 1 GB of swap. Right now about 150 MB of it is in use. It's there so a short spike slows things down instead of killing a process. If swap were full all the time, the answer would be fixing the memory, not adding more swap. ## Why I haven't just upgraded I've looked. Bigger servers from other hosts cost about the same or a bit more. But moving means redoing the encrypted disk, the firewall, the deploy setup and everything else, for no change users would notice. The CPU load sits around **0.0 to 0.1** most of the day and the server has been up for **24 days** straight. When the image scanner and the bot regularly fight for memory, or voice hits its limit, I'll upgrade. Not before. ## What I'd tell another solo founder 1. **Measure before you optimise.** I only knew the scanner was a third of the box because I looked. 2. **Load heavy features on demand and let them exit when idle.** 3. **Every cache gets a lifetime.** "Keep forever" is a bug that just hasn't happened yet. 4. **Watch your deploys,** not just your traffic. They spike memory too. 5. **A small server is a feature.** It forces you to know your system. Upgrade when the numbers tell you to, not when you're nervous. --- *I'm building [VoidBox](https://voidbox.games), one Discord bot that replaces the four or five most servers run. Free to use.* Source: https://voidbox.games/blog/discord-bot-on-2gb-ram