Knowledge Base

Local LLMs on a 4-core VPS: what actually runs, and how fast

2026-07-18llmlocal-llmvps

Benchmarked 2026-07-17 on the binary.ovh VPS. Every number below was measured on this exact box — not copied from a leaderboard. Try the results live at [brain.binary.ovh](https://brain.binary.ovh).

TL;DR

The host

CPU Intel Haswell (KVM guest), 4 cores / 4 threads
SIMD AVX2 + FMA + F16C — no AVX-512, no AMX
RAM 7.6 GB total, ~5.9 GB available (Caddy, Atlas, herdr, Docker keep running)
GPU none
Runtimes llama.cpp b10064 (upstream) · PrismML fork b9594 (for Bonsai's custom Q1_0 kernels)

What this hardware implies:

  1. Weights must fit in ~4.5 GB to leave room for KV cache, compute buffers, and the rest of the server.
  2. Generation is memory-bandwidth-bound. Tokens/sec scales inversely with model bytes — a 2× smaller quantized model is roughly 2× faster, which is why aggressive quantization (Q4, and now 1-bit) is the whole game on CPU.
  3. Prompt processing is compute-bound on 4 AVX2 cores. Long prompts (RAG, big pastes) hurt more than long answers.

Results: speed (llama-bench, 4 threads, pp512 / tg128)

Model File Prompt tok/s Gen tok/s Feels like
Qwen3.5 0.8B Q4_K_M 0.5 GB 97.1 22.3 instant
Qwen3.5 2B Q4_K_M 1.2 GB 46.6 14.2 comfortable chat
LFM2 2.6B Q4_K_M 1.5 GB 37.0 12.9 comfortable chat
Gemma 4 E2B q4_0 QAT 3.2 GB 39.8 12.7 comfortable chat
SmolLM3 3B Q4_K_M 1.8 GB 32.1 10.8 usable
Qwen3.5 4B Q4_K_M 2.6 GB 19.1 6.6 ask-and-wait
Bonsai 27B Q1_0 (1-bit) 3.6 GB 2.4 1.8 patience of a saint

Reading speeds: >12 tok/s reads faster than most people; 6 tok/s is a slow typist; below ~3 tok/s you'll tab away.

Results: quality spot-checks

Three tasks per model (temperature 0.2): write a dedupe function with doctests, the chickens-and-rabbits puzzle, and strict-JSON contact extraction.

Model Coding Reasoning (23 chickens) JSON extraction
Qwen3.5 0.8B ✅ correct ❌ died thinking ❌ died thinking
Qwen3.5 2B ✅ correct ❌ died thinking ❌ died thinking
Qwen3.5 4B ⚠️ died thinking ✅ elegant solution ❌ died thinking
Gemma 4 E2B ✅ dict-trick + doctests ✅ correct ✅ (fenced, verbose intent)
SmolLM3 3B ✅ correct ✅ correct ✅ (lazy intent field)
LFM2 2.6B ✅ correct ✅ clean algebra cleanest output

"Died thinking" means: the model solved the problem inside its reasoning trace but exhausted the token budget (1.5–2.5k tokens) before emitting a final answer. On a GPU you'd never notice — at 14 tok/s you absolutely do. With thinking disabled, the Qwen models answer these correctly and immediately — that's now the default in the webapp.

The quiet winner is LFM2 2.6B: zero thinking overhead, correct on all three, cleanest structured output ("intent": "demo" — exactly the field you'd want in a CRM). Liquid AI built its hybrid conv-attention architecture specifically for CPU/edge, and it shows.

Bonsai 27B: the "27B on a phone" experiment

PrismML's Bonsai 27B (July 2026) compresses Qwen3.6-27B to 1.125 bits per weight — every weight is a single sign bit, with one FP16 scale per 128 weights. The whole 27B model is 3.6 GB, small enough to run in a browser via WebGPU, on an iPhone (~11 tok/s), and — the question that matters here — on a humble 4-core VPS.

Measured here: 2.4 tok/s prompt processing, 1.8 tok/s generation (1.4 tok/s in a live chat context with KV overhead). And the quality is real — asked the chickens-and-rabbits puzzle, it set up simultaneous equations in a clean reasoning trace and answered exactly 23. Correct, coherent, no quantization gibberish.

But here is the catch, in one number: that single puzzle took 19 minutes end-to-end. The model is a thinking model (Qwen3.6 lineage), so it reasons for a few hundred tokens before answering, and at 1.8 tok/s every hundred tokens of thought costs a minute. A 27B-class intellect that communicates at roughly the speed of a telegraph operator.

So the honest verdict for a 4-core Haswell VPS:

Community consensus (HN) matches what we saw: the compression is real and remarkable, the marketing tok/s numbers are GPU/Apple-silicon numbers, and CPU-server use is at the edge of practical. Quality-wise PrismML claims ~90% of FP16 across 15 benchmarks (coding holds up best at 81.9 HumanEval+-class); community testing found more hallucination and occasional reasoning loops than the benchmarks suggest.

Use-case guide for this box

Want Use Why
Snappy chat, drafts, summaries Qwen3.5 2B (thinking off) best balance, 14 tok/s
Structured extraction, JSON APIs, agent glue LFM2 2.6B instant, cleanest JSON, CPU-first design
Best writing quality / multilingual Gemma 4 E2B QAT Q4 ≈ full quality, best prose, 12.7 tok/s
Hardest problems you'll wait for Qwen3.5 4B strongest that fits; 6.6 tok/s
Autocomplete / classification / bulk tagging Qwen3.5 0.8B 22 tok/s, ~1 GB RAM
Studying how LLMs are trained SmolLM3 3B fully open: weights, data, training recipes
Bragging rights & research Bonsai 27B 1-bit a 27B on a 8 GB VPS. It's the future, arriving early

What runs in a browser or phone now

The same 1-bit wave that made Bonsai fit this VPS is making real models run client-side: Bonsai 27B runs in Chrome via WebGPU (WGSL compute shaders) and on iPhone via MLX at ~11 tok/s. Gemma 4 E2B is explicitly designed for phones ("runs on 5 GB RAM at 4-bit"). The gap between "server model" and "device model" is collapsing — this VPS sits at exactly the hardware class where the two meet.

The webapp

Everything above is now a living thing: [brain.binary.ovh](https://brain.binary.ovh) (also ai.binary.ovh) — a model manager + chat for this box:

Stack: FastAPI + vanilla JS (no build step), llama.cpp servers on localhost, Caddy in front. ~450 lines total.

Method notes