[{"content":" Lusovps # Xen and KVM virtual servers (Linux and Windows) in eight locations, run from Póvoa de Varzim, Portugal. Every plan includes 24/7 support and the SolusVM control panel.\nMain site: lusovps.com\nThis blog # The technical team writes here about the work we do and the things we\u0026rsquo;ve been reading. Posts fall into three areas:\nHosting and VPS: what works well, what doesn\u0026rsquo;t, and how to fix it Linux infrastructure: Docker, KVM, Proxmox, networking and security Artificial intelligence: models, agents, and local LLMs on a VPS We publish one post a week, usually on Wednesdays.\nContact # Sales · info@lusovps.com Support · lusovps.com Stack # The blog is built with Hugo and the Blowfish theme. There\u0026rsquo;s no WordPress, PHP or database involved; nginx serves the pages as static HTML.\n","date":"November 12, 2026","externalUrl":null,"permalink":"/about/","section":"About","summary":"Lusovps # Xen and KVM virtual servers (Linux and Windows) in eight locations, run from Póvoa de Varzim, Portugal. Every plan includes 24/7 support and the SolusVM control panel.\nMain site: lusovps.com\nThis blog # The technical team writes here about the work we do and the things we’ve been reading. Posts fall into three areas:\n","title":"About","type":"about"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/categories/ai/","section":"Categories","summary":"","title":"Ai","type":"categories"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/code-review/","section":"Tags","summary":"","title":"Code-Review","type":"tags"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/gpu/","section":"Tags","summary":"","title":"Gpu","type":"tags"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/categories/hosting/","section":"Categories","summary":"","title":"Hosting","type":"categories"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/llm/","section":"Tags","summary":"","title":"Llm","type":"tags"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/","section":"Lusovps Blog","summary":"","title":"Lusovps Blog","type":"page"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/qwen/","section":"Tags","summary":"","title":"Qwen","type":"tags"},{"content":"Last week we ran Llama 3.1 8B on a plain 8 GB VPS. This time it\u0026rsquo;s Qwen3-Coder 32B on a GPU server, compared against GPT-4 at reading pull requests and pointing out what\u0026rsquo;s wrong with them. Of all the jobs people give LLMs, that\u0026rsquo;s the one where open-source models have been catching up fastest.\nThe setup # Server A, self-hosted on a rented GPU server:\n8 vCPU EPYC Milan 32 GB RAM 200 GB NVMe 1x NVIDIA L40S (48 GB VRAM) Debian 12, Docker, NVIDIA driver 560, CUDA 12.6 Server B, GPT-4 through the OpenAI API:\nModel: gpt-4-turbo-2024-04-09, which is still what most \u0026ldquo;GPT-4\u0026rdquo; integrations default to Billed per token at OpenAI\u0026rsquo;s list price for this model We assumed no system-side prompt caching The local model is Qwen3-Coder 32B Instruct (Apache 2.0), served with vLLM 0.7 in bf16 with tensor-parallel-size 1 and --max-model-len 65536. It exposes an OpenAI-compatible endpoint on :8000/v1.\nWhy Qwen3-Coder and not a bigger generalist model # In our LLM round-up, Qwen3-Coder 32B beat Llama 3.3 70B on code-specific benchmarks (HumanEval+, SWE-Bench Lite, Aider) at less than half the size. That makes it the obvious self-hosted pick for code review. It also fits on a single 48 GB GPU in bf16 with room to spare, so we didn\u0026rsquo;t need quantization to keep latency down.\nStanding it up in 15 minutes # This assumes the box already has the NVIDIA Container Toolkit installed:\ndocker run -d --name qwen-coder \\ --gpus all \\ -p 8000:8000 \\ -v /srv/hf-cache:/root/.cache/huggingface \\ --ipc=host \\ --restart unless-stopped \\ vllm/vllm-openai:v0.7.3 \\ --model Qwen/Qwen3-Coder-32B-Instruct \\ --max-model-len 65536 \\ --tensor-parallel-size 1 \\ --gpu-memory-utilization 0.90 \\ --served-model-name qwen3-coder The first run pulls about 62 GB of weights into /srv/hf-cache, which takes roughly 15 minutes on a 1 Gbps link. Restarts after that are instant.\nTo check that it\u0026rsquo;s up:\ncurl -s http://localhost:8000/v1/models | jq . If you need it reachable from outside, put nginx in front of it with HTTPS and a static bearer token header. Don\u0026rsquo;t expose vLLM directly to the internet, because it has no authentication of its own.\nThe evaluation # The PRs # We used six pull requests from one of our own internal services, written in Python and Go, with anywhere from 80 to 1,200 lines changed:\n2 bug fixes, one of them with a subtle race condition 2 refactors: one safe, and one broken because it removes a mutex that was actually needed 1 new feature that adds a webhook handler 1 \u0026ldquo;trap\u0026rdquo; PR that looks reasonable but introduces an auth bypass The prompt # Both models got the same prompt, kept short and dull on purpose:\nYou are reviewing a pull request. The diff follows. List concrete issues: bugs, security problems, missed edge cases, style problems that matter. Be specific. Quote lines where relevant. If the PR looks clean, say so. --- diff --- {{diff}} We didn\u0026rsquo;t add chain-of-thought tricks, agentic loops or self-reflection. We wanted to see what each model does with the kind of prompt a typical developer would actually write.\nGrading # Three engineers graded each review blind. None of them was me or the author of the PR. For each review they recorded whether it found the primary issue (yes, no or partial), a signal-to-noise score from 1 to 5 (does the review stay focused, or does it drown in nitpicks?), the number of hallucinations, meaning statements that are wrong about the diff, and whether they would accept the review as it stands.\nResults # Qwen3-Coder 32B GPT-4-turbo Primary issue caught (6 PRs) 5 / 6 6 / 6 - missed the auth bypass no yes Signal-to-noise (avg, 1-5) 4.1 3.7 Hallucinations (total) 2 7 Would-accept (avg across 3) 83 % 78 % The trap PR is where the two models split. GPT-4 caught the auth bypass and Qwen3-Coder missed it. GPT-4\u0026rsquo;s review said \u0026ldquo;this removes the require_auth=True check from the /admin/* route group, which appears unintended given the context\u0026rdquo;. Qwen3-Coder raised three other small issues on the same PR but never connected any of them to auth.\nSo for reviews where security impact is the main concern, GPT-4 still has the edge, and that\u0026rsquo;s the one job we wouldn\u0026rsquo;t hand over yet. Our guess is that it comes down to training data: GPT-4 has probably seen more real-world CVE write-ups than any open model we can download.\nOn everything else Qwen3-Coder was the more pleasant reviewer. GPT-4 has a habit of commenting on everything: variable names, docstring phrasing, \u0026ldquo;you could use a f-string here\u0026rdquo;. On a 1,200-line diff that gets tiring fast. Qwen3-Coder stays much closer to the things that matter, and our reviewers consistently preferred reading its output.\nIt also made fewer things up. GPT-4 twice referred to config files that don\u0026rsquo;t exist, and three times claimed a function behaved differently from what its code shows. Qwen3-Coder had two small hallucinations in total across all six PRs. It was faster too, and the cost works differently, which is covered in the next section.\nOn the remaining four PRs (routine bugs, refactor safety, edge cases and the new feature) the reviews were about equally good. Either model would have caught the real issues.\nSpeed and cost per review # Average per PR (median across the 6):\nQwen3-Coder 32B GPT-4-turbo Input tokens (avg) 3,420 3,420 Output tokens (avg) 720 940 Time to first token 0.4 s 0.9 s Time to full response 8.2 s 22 s API billing none (flat fee) per token The cost calculation is simple, and you should run it with your own numbers:\nAPI cost per review = input_tokens * input_price + output_tokens * output_price breakeven reviews/mo = GPU server monthly price / API cost per review Plug in the token counts above, your API provider\u0026rsquo;s current list price and a real quote for the GPU server you\u0026rsquo;d rent. Below breakeven the API is cheaper, and above it the self-hosted server wins. A single engineering team will usually sit below that line, while a platform running automated review for many teams will usually go well past it.\nThere are reasons to run it locally that have nothing to do with cost. Your code stays on your own network, which some NDAs require outright. Latency is predictable, so you don\u0026rsquo;t get a tail of 40-second API calls whenever OpenAI has a hiccup. And you control the context window: it\u0026rsquo;s 64k on this setup and cheap to extend, whereas on the API you pay for every token regardless.\nWhen to pick which # If you\u0026rsquo;re below breakeven and don\u0026rsquo;t mind code leaving your network, use the GPT-4 API. If you can\u0026rsquo;t send code out, you\u0026rsquo;re above breakeven, or you have latency SLOs to meet, self-host Qwen3-Coder on a GPU server. For security-critical reviews where auth/authz logic matters, run both in parallel and combine their findings until open models catch up on CVE-style reasoning. We expect them to get there within 12 months. ","date":"November 12, 2026","externalUrl":null,"permalink":"/posts/qwen3-coder-32b-gpu-vs-gpt4-code-review/","section":"Posts","summary":"An open coding model on one GPU against a closed frontier API, on six real PRs graded blind by three engineers. GPT-4 caught more on security; Qwen3-Coder was quieter and hallucinated less.","title":"Qwen3-Coder 32B on a GPU server vs. GPT-4 on real code reviews","type":"posts"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/self-hosted/","section":"Tags","summary":"","title":"Self-Hosted","type":"tags"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"November 12, 2026","externalUrl":null,"permalink":"/tags/vps/","section":"Tags","summary":"","title":"Vps","type":"tags"},{"content":"","date":"November 11, 2026","externalUrl":null,"permalink":"/tags/llama/","section":"Tags","summary":"","title":"Llama","type":"tags"},{"content":"This guide sets up Llama 3.1 8B Instruct on an 8 GB VPS with no GPU and serves it through an OpenAI-compatible API on localhost. The model is quantized to Q4_K_M, which is about 4.9 GB on disk and around 6 GB in memory once it\u0026rsquo;s loaded. On CPU it produces roughly 7-9 tokens per second. That\u0026rsquo;s enough for interactive chat and automation, with no GPU or external API to pay for. An optional last step adds Open WebUI as a chat interface.\nThe hardware # The reference box for this walkthrough:\n4 vCPU (AMD EPYC Milan) 8 GB RAM 80 GB NVMe Debian 12 Any machine with similar specs will do. What matters most is RAM bandwidth (DDR4-3200 or better) and having enough memory to hold the model plus its context.\nStep 1 - Prepare the server # Start from a fresh Debian 12 install, update it and install the build tools:\napt update \u0026amp;\u0026amp; apt upgrade -y apt install -y build-essential cmake git curl ca-certificates \\ python3 python3-venv python3-pip Create a non-root user if you don\u0026rsquo;t have one yet:\nadduser llm usermod -aG sudo llm su - llm Everything after this point runs as llm.\nStep 2 - Build llama.cpp # Building from source takes 2 minutes and means you aren\u0026rsquo;t stuck on whatever old version a package happens to ship.\ncd ~ git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build -DGGML_NATIVE=ON -DLLAMA_CURL=ON cmake --build build --config Release -j$(nproc) Check that the build worked:\n./build/bin/llama-cli --version ./build/bin/llama-server --help | head -5 GGML_NATIVE=ON makes the compiler use every SIMD extension your CPU supports, including AVX2 and AVX-512 where available. On our EPYC VPS that made it 2.1x faster than the generic build.\nStep 3 - Download the model # llama.cpp reads GGUF files, so you need the model in that format rather than the raw HuggingFace weights. This pulls Llama 3.1 8B Instruct at Q4_K_M from Bartowski\u0026rsquo;s semi-official mirror:\nmkdir -p ~/models \u0026amp;\u0026amp; cd ~/models curl -L -o llama-3.1-8b-instruct-q4_k_m.gguf \\ https://huggingface.co/bartowski/Meta-Llama-3.1-8B-Instruct-GGUF/resolve/main/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf The file is about 4.9 GB. On our VPS the download took 90 seconds.\nAt 8B, Q4_K_M is the quant where quality loss on chat and instruction tasks becomes essentially invisible; the measured perplexity difference against full precision is under 1%. Q5_K_M is slightly better, but once you add context it gets close to the 8 GB RAM ceiling. The Q3 variants save disk space, and their drop in quality is noticeable.\nStep 4 - Test it from the CLI # Run a quick sanity check:\ncd ~/llama.cpp ./build/bin/llama-cli \\ -m ~/models/llama-3.1-8b-instruct-q4_k_m.gguf \\ -p \u0026#34;Explain what a VPS is in three sentences.\u0026#34; \\ -n 200 \\ -t $(nproc) -t $(nproc) tells it to use all 4 vCPU threads, which is nearly always what you want for CPU inference.\nThe output streams to the terminal, and at the end you get a timing summary that looks roughly like this:\nllama_perf_context_print: eval time = 17912.30 ms / 158 runs ( 113.37 ms per token, 8.82 tokens per second) That\u0026rsquo;s about 8.8 tokens/s, which is fine for interactive use. A medium-length paragraph takes around 15 seconds to generate. That\u0026rsquo;s on the slow side of human reading speed, but still useful.\nStep 5 - Serve it as an API # llama-cli is only for testing. For real use, run llama-server, which exposes an OpenAI-compatible HTTP API:\n./build/bin/llama-server \\ -m ~/models/llama-3.1-8b-instruct-q4_k_m.gguf \\ --host 127.0.0.1 --port 8080 \\ -c 8192 \\ -t $(nproc) \\ --cache-type-k q8_0 --cache-type-v q8_0 What the flags do:\n-c 8192 sets an 8 k context. 128 k would be nice, but at 128 k the KV cache for an 8B model needs more RAM than this box has. --cache-type-k q8_0 --cache-type-v q8_0 quantizes the KV cache. It saves about 40% of the context memory, and the quality loss is negligible. --host 127.0.0.1 binds to loopback only. Don\u0026rsquo;t expose this port directly to the internet unless there\u0026rsquo;s authentication and TLS in front of it. Send it a test request:\ncurl http://127.0.0.1:8080/v1/chat/completions \\ -H \u0026#39;Content-Type: application/json\u0026#39; \\ -d \u0026#39;{ \u0026#34;model\u0026#34;: \u0026#34;llama-3.1-8b\u0026#34;, \u0026#34;messages\u0026#34;: [{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;In one sentence, what is KVM?\u0026#34;}] }\u0026#39; The response is standard OpenAI chat-completion JSON. Any tool that talks OpenAI (your editor, an agent framework, your scripts) now works pointed at http://127.0.0.1:8080/v1.\nStep 6 - Run it as a service # A systemd unit keeps the server running across reboots:\n# /etc/systemd/system/llama.service [Unit] Description=llama.cpp server After=network.target [Service] Type=simple User=llm WorkingDirectory=/home/llm/llama.cpp ExecStart=/home/llm/llama.cpp/build/bin/llama-server \\ -m /home/llm/models/llama-3.1-8b-instruct-q4_k_m.gguf \\ --host 127.0.0.1 --port 8080 \\ -c 8192 -t 4 \\ --cache-type-k q8_0 --cache-type-v q8_0 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target sudo systemctl daemon-reload sudo systemctl enable --now llama sudo systemctl status llama Step 7 - Add a chat UI (optional) # For a browser interface, Open WebUI is the usual choice. It runs in Docker:\ndocker run -d \\ --name open-webui \\ -p 3000:8080 \\ --add-host=host.docker.internal:host-gateway \\ -v open-webui:/app/backend/data \\ -e OPENAI_API_BASE_URL=http://host.docker.internal:8080/v1 \\ -e OPENAI_API_KEY=sk-no-key-required \\ --restart unless-stopped \\ ghcr.io/open-webui/open-webui:main Put nginx in front of port 3000 with a Let\u0026rsquo;s Encrypt certificate and HTTP basic auth (or whatever SSO you already use), and you have your own ChatGPT-style chat at https://chat.yourdomain.com/.\nBenchmark results # These were measured on the VPS described above: 4 vCPU EPYC Milan, DDR4-3200, NVMe. Every run used the same prompt, \u0026ldquo;Write a short paragraph about the history of Linux.\u0026rdquo;, with 200 output tokens, and the figures are the median of 10 runs.\nConfig tok/s RAM used First token Q4_K_M, ctx=8192, kv q8_0 8.9 6.2 GB 240 ms Q4_K_M, ctx=8192, kv f16 8.6 6.9 GB 230 ms Q5_K_M, ctx=4096, kv q8_0 7.1 7.4 GB 310 ms Q4_K_M, ctx=32768, kv q8_0 8.8 7.1 GB 440 ms Q4_K_M, ctx=8192, kv q8_0, -t 2 (2 threads) 5.3 6.2 GB 260 ms Dropping from 4 threads to 2 costs a lot of throughput (last row), so use all the cores. Context size barely changes tokens per second, which llama.cpp handles well, but a bigger context does increase first-token latency. Q5 costs 20% of throughput compared with Q4, and at this model size the quality gain is small.\nBigger models # There isn\u0026rsquo;t much room for them on this box. An 8 GB VPS limits you to roughly 8B models if you want some headroom. For a 24B model such as Mistral-Small-3.1 (covered in last week\u0026rsquo;s post), you need at least 16 GB of RAM.\nA rough rule for budgeting RAM with CPU inference:\nneeded RAM ~ model size * 1.1 + 0.5 GB per 2048 tokens of context (kv q8_0) For the 8B Q4 model at 8 k context, that works out to 5.4 GB plus about 1 GB, so roughly 6.4 GB, which fits.\nCost compared with API calls # A VPS is a flat monthly fee, while an API bills per token. Running flat out, this box generates around 30k tokens per hour (about 22 M a month), and that\u0026rsquo;s its ceiling.\nTo compare the two, take the output tokens you\u0026rsquo;d actually generate in a month, multiply by your API provider\u0026rsquo;s current output price, and put that next to what you pay for the VPS each month. If you keep the box busy, the flat fee wins. If you only send ten requests a day, the API is cheaper.\nThere are non-cost reasons too. Your data stays on your own server, latency is predictable, and the model works offline. Those are often the real reasons to run it yourself.\nWhen this isn\u0026rsquo;t enough # If your tasks need the reasoning of a model bigger than the 32B class, rent a GPU box or use a frontier API. If you have many concurrent users, run vllm on a GPU instead of llama.cpp on CPU. If you need a model that\u0026rsquo;s good at code, swap in Qwen3-Coder on a GPU server. ","date":"November 11, 2026","externalUrl":null,"permalink":"/posts/running-llama-3-1-8b-on-an-8gb-vps/","section":"Posts","summary":"How to run Llama 3.1 8B on a single 8 GB VPS without a GPU, with the full set of commands and the throughput to expect.","title":"Running Llama 3.1 8B on an 8 GB VPS, step by step","type":"posts"},{"content":"","date":"November 11, 2026","externalUrl":null,"permalink":"/tags/tutorial/","section":"Tags","summary":"","title":"Tutorial","type":"tags"},{"content":" The rules # A model had to meet four conditions to get on this list:\nOpen weights you can actually redistribute. Anything under a \u0026ldquo;research only\u0026rdquo; licence is out. It runs on hardware a small team can afford, meaning a consumer GPU or a rented VPS or server. It\u0026rsquo;s current, so released or materially updated in the last ~6 months. It does something specific better than anything else in its class. The numbers below are wall-clock throughput from our own test rig, which is either a single RTX 4090 (24 GB) or CPU inference on a Zen 4 server with 128 GB of RAM. Every model was served with vllm 0.7 or a recent llama.cpp build. Tokens/s figures count output tokens only, with 1 concurrent user.\n1. Llama 3.3 70B: the general-purpose default # If you don\u0026rsquo;t know which model to pick, start with this one. It\u0026rsquo;s Meta\u0026rsquo;s late-2025 refresh at the 70B size, and it lands in a useful spot: it comfortably beats GPT-4-class models on most reasoning benchmarks and still fits in 48 GB of VRAM at Q4.\nContext is 128k. The Llama 3 Community licence allows commercial use, with some restrictions aimed at big tech.\nYou\u0026rsquo;ll need 2x RTX 4090 (48 GB) at Q4_K_M, or a single H100 at bf16. On the two 4090s at Q4 we saw about 28 tok/s. The main weakness is multilingual: quality drops off outside the 8 languages it officially supports. It\u0026rsquo;s a good fit for general chat, agent planning and long-context analysis, and if you only want to run one model, this is the one.\n2. Qwen3-Coder-32B: for code # If 80% of your workload is code, run this instead of a bigger generalist. Alibaba\u0026rsquo;s coder-tuned 32B beats Llama 3.3 70B on nearly every code benchmark we care about (HumanEval+, SWE-Bench Lite, Aider), and it fits on a single 24 GB card.\nThe context window is 262k, which is unusually large, and the licence is Apache 2.0. One RTX 4090 runs it at Q4, where we measured about 58 tok/s. CPU at Q4 is tolerable rather than pleasant, at around 2 tok/s on a fast desktop.\nGeneral chat is fine, but you\u0026rsquo;ll notice it\u0026rsquo;s worse than a tuned generalist of the same size. Where it earns its place is code review, PR analysis, agentic coding workflows and in-editor assistants.\n3. Mistral-Small-3.1 24B: the one that fits on a VPS # When people ask whether they can run an LLM on their VPS, this is the model we point them to. It\u0026rsquo;s the only one on this list that runs comfortably on CPU alone. At 24B it\u0026rsquo;s big enough to be useful and small enough that a Q4 quant on a modern desktop CPU produces tokens fast enough that you\u0026rsquo;d actually sit and read them.\n128k context, Apache 2.0 16 GB RAM for Q4 on CPU, or 1x RTX 3090 at Q5 about 9 tok/s CPU-only on Zen 4 with DDR5-5600, Q4_K_M It won\u0026rsquo;t match 70B+ models on complex reasoning. Use it for chat, summarization, classification, as a RAG backend, or for any high-volume job where latency and cost matter more than peak intelligence.\n4. DeepSeek-V3.1: probably not one to self-host # It\u0026rsquo;s on the list because you\u0026rsquo;ll get asked about it, not because you should run it on your own. DeepSeek-V3.1 is a 671B-parameter MoE with 37B active, and it\u0026rsquo;s genuinely competitive with closed frontier models on hard reasoning and math.\nThe problem is hardware. It needs 8x H100 for bf16, or 4x H100 for Q4, which is a datacentre-class GPU budget. Context is 128k, and the DeepSeek Model License allows commercial use with some restrictions.\nWe have no local numbers for it. We don\u0026rsquo;t run it ourselves, and our testing went through a cloud endpoint. At this size it\u0026rsquo;s worth asking whether a self-hosted inference endpoint makes sense at all compared with just calling one. Keep it for the specific tasks where only a frontier model works and the smaller specialists fail, and even then you\u0026rsquo;ll usually be better off with one of the many providers already hosting it.\n5. Pixtral 12B and Qwen2.5-VL 7B: vision # This slot is a tie, because the two models win in different situations. Open-source vision-language models are finally usable in 2026, and these two stand out:\nPixtral 12B (Mistral, Apache 2.0) is better at OCR and document understanding. Qwen2.5-VL 7B (Alibaba, Apache 2.0) handles charts and UIs better and has a smaller footprint. Both take 128k of text plus images, and either one runs on a single RTX 3090 at Q5. On a 4090 we measured 70 tok/s for Qwen2.5-VL 7B and 42 tok/s for Pixtral 12B. Typical jobs are PDF extraction, turning screenshots into structured data, document QA and UI test agents.\nSummary table # Model Size HW floor Best at Licence Llama 3.3 70B 70B 2x 4090 general / default Llama 3 Community Qwen3-Coder 32B 32B 1x 4090 code Apache 2.0 Mistral-Small 3.1 24B 16 GB RAM (CPU) VPS / high-volume workload Apache 2.0 DeepSeek-V3.1 671B 4-8x H100 frontier reasoning DeepSeek License Pixtral / Qwen2.5-VL 12/7B 1x 3090 vision Apache 2.0 What we left out on purpose # Gemma 3 is good, but its edge over Llama 3.3 isn\u0026rsquo;t big enough to justify learning a second tokenizer. Phi-4 is nice for its size, though we never reach for it when any of the models above will fit. As for anything under ~7B, run them if you must. For most jobs you\u0026rsquo;d be better off calling a hosted small model than running a weak local one.\nA cheap place to start # If someone asked us where to start with LLMs on a VPS, we\u0026rsquo;d suggest this:\na VPS with 16 GB RAM, 4 vCPU and NVMe storage Mistral-Small 3.1 24B in Q4_K_M, served by llama.cpp with llama-server Open WebUI in Docker in front of it Tokens come out slowly, but it\u0026rsquo;s usable, and you get to learn how the pieces fit together. Scale up once you need more.\n","date":"November 4, 2026","externalUrl":null,"permalink":"/posts/5-open-source-llms-worth-running-late-2026/","section":"Posts","summary":"Five models we deploy, the trade-offs of each for chat, code, agents and vision, and the minimum hardware each one needs.","title":"Five open-source LLMs worth running in late 2026","type":"posts"},{"content":"","date":"November 4, 2026","externalUrl":null,"permalink":"/tags/open-source/","section":"Tags","summary":"","title":"Open-Source","type":"tags"},{"content":" Changing the port is not hardening # Moving SSH from 22 to 2222 or 48392 cuts about 99% of the automated noise in your logs. Against a targeted attacker it helps 0%, because a full-range port scan of a /32 with masscan takes around 90 seconds.\nWhat a non-standard port does get you is cleaner logs and less work for fail2ban. That\u0026rsquo;s worth something, but on its own it doesn\u0026rsquo;t make the server any harder to get into.\nThe list below is what we\u0026rsquo;d do instead, roughly in order of impact.\n1. Disable password authentication # # /etc/ssh/sshd_config PasswordAuthentication no ChallengeResponseAuthentication no PermitRootLogin prohibit-password UsePAM yes AuthenticationMethods publickey This is the biggest win. Overnight, 100% of the SSH brute-force attempts in your logs become useless. You can still enforce 2FA on top.\nYou lose the ability to log in from a random laptop with just a password, which is intended. Carry your key.\n2. Use short, strong key types # # on your workstation, once ssh-keygen -t ed25519 -C \u0026#34;you@wherever\u0026#34; Ed25519: fast, short (68 chars), post-2013 crypto. Use it for anything new. RSA 4096: acceptable if you have to support legacy clients. RSA 2048: rotate it out. DSA and ECDSA (nistp256): don\u0026rsquo;t use them. On the server, disable the old host keys:\n# /etc/ssh/sshd_config HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key # remove any dsa / ecdsa HostKey lines 3. Restrict sshd to modern algorithms # The default sshd on Debian 12 is already decent, but tighten it:\n# /etc/ssh/sshd_config KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com Then verify from the outside with ssh-audit (github.com/jtesta/ssh-audit):\nssh-audit your.server.com # aim for all green, no yellow, no red 4. Limit which accounts can log in # # /etc/ssh/sshd_config AllowUsers deploy sysadmin # or by group AllowGroups ssh-users A user who isn\u0026rsquo;t meant to SSH in then can\u0026rsquo;t, even if their account exists for mail or FTP. An explicit allowlist is more reliable than implicit denial.\n5. Configure fail2ban instead of running the defaults # A bare install works, but the defaults are too permissive. Our starting point:\n# /etc/fail2ban/jail.d/sshd.local [sshd] enabled = true mode = aggressive maxretry = 3 findtime = 10m bantime = 24h # recidive: stack bans for repeat offenders Also enable the recidive jail, which bans IPs that keep coming back for weeks:\n# /etc/fail2ban/jail.d/recidive.local [recidive] enabled = true bantime = 1w findtime = 1d maxretry = 5 With key-only auth this is mostly cosmetic, since the bots can\u0026rsquo;t get in anyway, but less log noise is useful on its own.\n6. Rate-limit new SSH connections at the firewall # A second layer on top of fail2ban, using nftables:\ntable inet filter { chain input { type filter hook input priority filter; policy drop; ct state established,related accept iif lo accept # rate-limit new SSH: 5 per minute per source tcp dport 22 ct state new limit rate 5/minute burst 5 packets accept tcp dport 22 drop tcp dport { 80, 443 } accept # ... } } This throttles even a decent brute-force script before fail2ban has to react.\n7. Send auth logs off the server # If an attacker ever gets root, you can\u0026rsquo;t trust the local logs. Ship /var/log/auth.log off the server in real time, to a central log host, a SIEM or anywhere else. rsyslog forwarding to remote syslog works, as does vector / fluent-bit feeding Loki or Elastic.\n8. Smaller sshd settings worth checking # UpdateHostKeys yes rotates host keys cleanly over time. PermitEmptyPasswords no is obvious, but double-check it. X11Forwarding no on servers. LoginGraceTime 20, because 2 minutes is a generous window to give a bot. MaxAuthTries 3 ClientAliveInterval 300 and ClientAliveCountMax 2 kill forgotten sessions. 9. Test the config before reloading # Run sshd -t before restarting. One bad config can lock you out of a remote box.\nsshd -t \u0026amp;\u0026amp; systemctl reload ssh Also keep a second terminal logged in while you test, and close it only once a new session gets in.\nPort knocking, SSO and bastion hosts # Port knocking mostly solves the same problem as moving the port, and in 2026 it\u0026rsquo;s rarely worth the operational cost. SSO (Okta, Google, Teleport, etc.) works well at scale and is overkill for small operations. Start with keys and central logging. A bastion host makes sense once you have more than about 5 servers. SSH to the other servers goes through that one hardened host with ProxyJump, which also gives you a single place to audit. Checking the effective config # To see what sshd is actually running with right now:\nsshd -T | egrep -i \u0026#39;^(port|protocol|password|permitroot|pubkey|kbdinteractive|allow|authenticationmethods|ciphers|kexalgorithms|macs|loginracetime|maxauthtries)\u0026#39; sshd -T prints the effective config after includes and defaults. If anything in the output surprises you, your config file isn\u0026rsquo;t doing what you think.\n","date":"October 28, 2026","externalUrl":null,"permalink":"/posts/hardening-ssh-on-a-hosting-server/","section":"Posts","summary":"Changing the SSH port won’t stop anyone who is looking for your server. This is the list we’d work through instead, in rough priority order, with the reasoning for each item.","title":"Hardening SSH on a hosting server: what's worth doing","type":"posts"},{"content":"","date":"October 28, 2026","externalUrl":null,"permalink":"/tags/hosting/","section":"Tags","summary":"","title":"Hosting","type":"tags"},{"content":"","date":"October 28, 2026","externalUrl":null,"permalink":"/categories/infrastructure/","section":"Categories","summary":"","title":"Infrastructure","type":"categories"},{"content":"","date":"October 28, 2026","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"October 28, 2026","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"","date":"October 28, 2026","externalUrl":null,"permalink":"/tags/ssh/","section":"Tags","summary":"","title":"Ssh","type":"tags"},{"content":"","date":"October 21, 2026","externalUrl":null,"permalink":"/tags/kvm/","section":"Tags","summary":"","title":"Kvm","type":"tags"},{"content":" The question # Every few months a client asks us some version of this:\n\u0026ldquo;Can I run KVM inside my VPS and spin up a few VMs?\u0026rdquo;\nYes, you can, but the conditions attached to that yes matter more than the yes itself.\nDoes nested KVM work at all? # Nested virtualization means your VPS, which is already a KVM guest on your provider\u0026rsquo;s hypervisor, runs KVM itself and hosts its own guests. That gives you three levels: the physical host, your VPS, and the VMs inside your VPS.\nIt only works if all of the following hold:\nThe outer hypervisor has nested virtualization enabled in the CPU flags it exposes to your VPS. The VPS CPU advertises vmx (Intel) or svm (AMD). The kernel on your VPS loads kvm_intel / kvm_amd with nested=1. You can check from inside the VPS:\ngrep -E \u0026#39;vmx|svm\u0026#39; /proc/cpuinfo | head -1 # if you see vmx or svm, nested is exposed cat /sys/module/kvm_intel/parameters/nested 2\u0026gt;/dev/null || \\ cat /sys/module/kvm_amd/parameters/nested 2\u0026gt;/dev/null # should print Y or 1 Whether nested virtualization is exposed depends on the provider and the plan. Many hosts leave it off on shared nodes, since one noisy neighbour spinning up VMs is enough to ruin everyone\u0026rsquo;s day. Run the check above, and if the flags are missing, ask your provider\u0026rsquo;s support before you build anything that depends on them.\nThe performance cost # Nested KVM has real overhead. These numbers come from a test VPS (4 vCPU, 8 GB, NVMe, Debian 12, QEMU 8.1):\nBenchmark Native L1 VPS L2 (nested) overhead vs L1 sysbench cpu prime=20000 4.21 s 4.32 s 4.98 s +15 % fio randread 4k qd=32 (IOPS) 88 k 71 k 42 k -41 % iperf3 single-stream (Gbps) 9.4 9.1 5.2 -43 % The CPU penalty is modest. Disk I/O and network both lose around 40%, which is what you pay when every I/O operation gets translated twice.\nIf a workload is mostly CPU and RAM, like compilers, build agents or small test suites, it runs fine nested. Databases, busy web servers and anything that pushes a lot of network traffic will feel the difference.\nGood uses # Throwaway test environments. If you want to try a Kubernetes install, a new distro or a kernel upgrade, a disposable VM inside your VPS is quicker and cheaper than renting a second VPS. Teaching and labs. One VPS running 3-4 small Alpine VMs for a networking course is good value. Legacy stacks you have to keep alive. An old PHP 5.6 app that you don\u0026rsquo;t want anywhere near your main system can sit isolated in its own small inner VM. Container escape testing. For security work you want a nested target you can wipe without a second thought. Where it goes wrong # Production databases in nested VMs. The -41% on IOPS in the table above is not a typo, and a database that matters shouldn\u0026rsquo;t be living with it. Anything where you care about resources. Your VPS already shares a physical machine with other tenants, and nesting puts a second layer of noisy neighbours on top of that. Reselling slices of your VPS as VPSes. It\u0026rsquo;s technically possible and commercially a disaster: the overhead eats your margin, and the first abuse report lands on you. Windows guests. It can be done, but between the QEMU display, drivers and licensing it\u0026rsquo;s rarely worth the headache. Reducing the overhead # If you do run nested, three changes help a lot.\n1. Use virtio everywhere # \u0026lt;disk type=\u0026#39;file\u0026#39; device=\u0026#39;disk\u0026#39;\u0026gt; \u0026lt;driver name=\u0026#39;qemu\u0026#39; type=\u0026#39;qcow2\u0026#39; cache=\u0026#39;none\u0026#39; io=\u0026#39;native\u0026#39;/\u0026gt; \u0026lt;source file=\u0026#39;/var/lib/libvirt/images/guest.qcow2\u0026#39;/\u0026gt; \u0026lt;target dev=\u0026#39;vda\u0026#39; bus=\u0026#39;virtio\u0026#39;/\u0026gt; \u0026lt;/disk\u0026gt; \u0026lt;interface type=\u0026#39;network\u0026#39;\u0026gt; \u0026lt;source network=\u0026#39;default\u0026#39;/\u0026gt; \u0026lt;model type=\u0026#39;virtio\u0026#39;/\u0026gt; \u0026lt;/interface\u0026gt; The default emulated ide and rtl8139 devices will wreck nested performance. Treat virtio-blk and virtio-net as required, not as a tuning option.\n2. Use raw or preallocated qcow2, not thin # A thin-provisioned qcow2 image on top of a thin-provisioned VPS disk means two layers of sparse allocation, and your fio numbers will show it.\nqemu-img create -f qcow2 -o preallocation=metadata guest.qcow2 20G # or just: qemu-img create -f raw guest.img 20G 3. Pin and reserve, don\u0026rsquo;t over-commit # If your VPS has 4 vCPU and 8 GB RAM, don\u0026rsquo;t give 4 vCPU and 7 GB to a single inner VM. Give it 2 vCPU and 4 GB and keep real headroom. Nested setups get fragile when the host (your VPS, in this case) is under memory pressure: KSM starts fighting for pages and performance falls off non-linearly.\nTry containers first # Nine times out of ten, a client asking for nested KVM really wants isolation rather than a full virtual machine. Docker, systemd-nspawn or LXC inside the VPS add almost no overhead and give you 80% of the isolation benefits.\nIf you need separate kernels, for custom modules, different distro versions or kernel-level testing, nested KVM is the right tool. For everything else, start with containers.\n","date":"October 21, 2026","externalUrl":null,"permalink":"/posts/kvm-inside-vps-when-and-when-not/","section":"Posts","summary":"You can run KVM guests inside a VPS. Some uses make sense, and some will cause you trouble later.","title":"Running KVM inside a VPS: where it helps and where it hurts","type":"posts"},{"content":"","date":"October 21, 2026","externalUrl":null,"permalink":"/tags/virtualization/","section":"Tags","summary":"","title":"Virtualization","type":"tags"},{"content":"","date":"October 14, 2026","externalUrl":null,"permalink":"/tags/benchmark/","section":"Tags","summary":"","title":"Benchmark","type":"tags"},{"content":"","date":"October 14, 2026","externalUrl":null,"permalink":"/tags/hugo/","section":"Tags","summary":"","title":"Hugo","type":"tags"},{"content":"","date":"October 14, 2026","externalUrl":null,"permalink":"/tags/performance/","section":"Tags","summary":"","title":"Performance","type":"tags"},{"content":"","date":"October 14, 2026","externalUrl":null,"permalink":"/tags/wordpress/","section":"Tags","summary":"","title":"Wordpress","type":"tags"},{"content":" The setup # Three VPS, all running Debian 12 on 2 vCPU, 4 GB RAM and NVMe storage, with nginx in front of everything and all of them in a single data centre. Each one ran a different stack:\nServer A: WordPress 6.7, PHP 8.3-FPM, MariaDB 10.11, no cache plugin (yet) Server B: Ghost 5.x on Node.js 20, with SQLite Server C: a Hugo site, with nginx serving /var/www/html/ and nothing else The three sites look the same and carry the same 20 posts, the same images and the same markup. Cloudflare handles DNS for the public URL but nothing more, so there\u0026rsquo;s no proxy and no CDN caching. I\u0026rsquo;m measuring the origin, not the edge.\nFor load I used k6 with 100 virtual users for 60 seconds and a 10s ramp-up. Each server got 3 runs, and the numbers below come from the median run.\nOut of the box # TTFB p50 TTFB p95 RPS errors WordPress (bare) 412 ms 1.38 s 238 0 Ghost 94 ms 198 ms 920 0 Hugo (static) 11 ms 27 ms 14,200 0 At the median, WordPress is already 37x slower than Hugo, and at p95 the gap is around 50x. WordPress pins the CPU within seconds, and MariaDB is where most of that time goes.\nWordPress with caching # Nobody runs bare WordPress in production, so to be fair I added the usual caching setup:\nRedis Object Cache WP Super Cache (page cache to disk) OPcache tuned TTFB p50 TTFB p95 RPS WordPress (full cache) 38 ms 142 ms 3,850 Hugo (static) 11 ms 27 ms 14,200 With full caching, WordPress closes 90% of the gap. It\u0026rsquo;s still about 3.5x slower and serves 3.7x fewer requests per second, but on the happy path a visitor would hardly notice.\nThe trouble is everything off the happy path. Any cache miss (logged-in users, comments, custom endpoints) puts you back at the uncached numbers above. You\u0026rsquo;re also now maintaining a cache stack that has to keep working, because when it doesn\u0026rsquo;t, the site falls over.\nBuild times, attack surface and memory # Benchmark posts rarely cover these, but they matter just as much day to day.\nBuild and deploy time # Running hugo on this site takes 113 ms, and a full deploy (build plus rsync) takes about 5 seconds. Ghost has no build step, but migrations and upgrades need downtime windows. WordPress has no build step either, and every plugin or theme update gets applied to the live site.\nAttack surface # Hugo: no running services apart from nginx. The disk just holds HTML. Ghost: a Node.js process, a SQLite file and an admin UI at /ghost/. WordPress: PHP-FPM, MariaDB, /wp-admin, XML-RPC, the REST API, plus whatever the plugins add. Over 12 months on a honeypot VPS, /wp-login.php was the most requested URL we saw. A static site doesn\u0026rsquo;t have a login page to go after.\nMemory at idle # RSS idle WordPress (full stack) 420 MB Ghost 180 MB Hugo (static) 0 MB # nginx handles it The 420 MB is the floor, not a theoretical figure. As soon as real traffic arrives, PHP-FPM workers take even a modest site well past 1 GB.\nWhen each one makes sense # None of this means everyone should drop WordPress. It exists because content editors who aren\u0026rsquo;t developers need a UI, and that need is real.\nWordPress, if non-technical people edit content every day and you\u0026rsquo;re going to run the cache stack properly. Ghost, if you want a WYSIWYG editor, newsletters and a decent API, and you\u0026rsquo;re comfortable managing a Node app. Hugo (or Astro, or Eleventy), if your writers are fine working with Markdown files and git, and you want the speed and the smaller attack surface without extra effort. This blog runs on Hugo. We write the posts and run the servers ourselves, and we\u0026rsquo;d rather spend that time on infrastructure than on patching plugins.\n","date":"October 14, 2026","externalUrl":null,"permalink":"/posts/wordpress-vs-static-ttfb-benchmark/","section":"Posts","summary":"I built three blogs that look the same, put each one on an identical VPS and load tested them with k6. The gap between them is large.","title":"WordPress vs. static: I measured TTFB on three identical servers","type":"posts"},{"content":"","date":"October 7, 2026","externalUrl":null,"permalink":"/categories/editorial/","section":"Categories","summary":"","title":"Editorial","type":"categories"},{"content":" Why we started a blog # There are plenty of tech blogs, but we didn\u0026rsquo;t have one. For years we\u0026rsquo;ve been talking to clients, fixing problems at 3 a.m., migrating machines, upgrading kernels and learning the hard way how to run serious infrastructure in Portugal. That knowledge lived in support tickets, internal chats and server notes. From now on we\u0026rsquo;ll write it down here.\nWhat we\u0026rsquo;ll write about # Hosting and VPS: practical tutorials, real benchmarks, honest comparisons, and the traps nobody documents. Infrastructure: Linux, Docker, KVM, Proxmox, networking, and backups that actually work when you need them. Artificial intelligence: new models, local LLMs, running agents on a VPS, and what\u0026rsquo;s worth it versus what\u0026rsquo;s hype. We\u0026rsquo;ll publish one post a week. Some will be short and some long, depending on the topic.\nA few rules for ourselves # We won\u0026rsquo;t publish AI-generated posts that nobody has reviewed. We\u0026rsquo;re aware of the irony, since we\u0026rsquo;ll be writing a lot about AI, but a person decides what goes out on this blog.\nYou won\u0026rsquo;t see posts like \u0026ldquo;5 reasons to choose Lusovps\u0026rdquo; either. If you want a reason to pick us, read what we publish over time.\nTitles will describe the content, not bait clicks.\nHow the blog is built # This isn\u0026rsquo;t WordPress. It\u0026rsquo;s Hugo, a static site generator written in Go, so the pages are plain HTML served in milliseconds. There\u0026rsquo;s no database to protect and essentially no attack surface.\nIf the typography, the colours or the structure bother you, tell us. We built this for people who read code before breakfast.\nLusovps ","date":"October 7, 2026","externalUrl":null,"permalink":"/posts/hello-world/","section":"Posts","summary":"A technical blog about VPS hosting, servers and artificial intelligence, without the marketing copy.","title":"Hello, world, and welcome to the Lusovps blog","type":"posts"},{"content":"","date":"October 7, 2026","externalUrl":null,"permalink":"/tags/lusovps/","section":"Tags","summary":"","title":"Lusovps","type":"tags"},{"content":"","date":"October 7, 2026","externalUrl":null,"permalink":"/tags/meta/","section":"Tags","summary":"","title":"Meta","type":"tags"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]