Your laptop has 4 cores. Maybe 8 if you splurged. CI workflows run on shared GitHub Actions runners with unpredictable performance. A high-CPU VPS with 16 dedicated cores changes the math entirely — your Rust workspace compiles in 90 seconds instead of 12 minutes, your FFmpeg x265 encode runs in real-time instead of 4× slower, and your CI pipeline finishes before you've finished the next sip of coffee.

This guide turns a high-CPU VPS into a serious remote build server: distcc for distributed C/C++ compilation, bazel-remote for cache reuse across builds, FFmpeg pre-tuned for x265 and AV1 encoding, and the kernel-level setup that prevents 'noisy build' problems on a multi-tenant VPS. By the end your laptop will feel slow.

🐾 What you'll need:
  • A high-CPU VPS — at least 8 dedicated cores, NVMe storage
  • SSH access from your laptop / CI runner
  • Roughly 40 minutes

For a build server with the kernel tunings and toolchains pre-installed, see our High CPU VPS plans — 4 to 16 dedicated cores, modern Xeon/EPYC, FFmpeg with H.265/AV1 pre-compiled.

1. Why "dedicated cores" actually matters

Most cloud VPS providers oversubscribe CPUs. A "1 vCPU" on AWS, DigitalOcean, or Linode is a time-share of a physical core — when neighbours are busy, your vCPU stalls. The kernel reports this as "steal time" (run top and look for st%).

On CPU-intensive workloads — compilation, video encoding, scientific compute — steal time destroys throughput. Your 4-hour build becomes a 6-hour build. Your real-time FFmpeg encode falls behind.

Dedicated cores eliminate this. Your 16 cores are 16 physical threads, locked to your VPS, all the time. Run top on a busy build — st% stays at 0.0%. The difference is night and day for CPU-bound work.

2. Prepare the VPS

apt update && apt upgrade -y
apt install -y build-essential cmake ninja-build pkg-config \
  git curl ca-certificates ufw htop iotop sysstat

ufw allow 22/tcp
ufw --force enable

# Non-root user
adduser builder
usermod -aG sudo builder
rsync --archive --chown=builder:builder ~/.ssh /home/builder

Verify you actually have dedicated cores:

# Watch steal time during a busy moment
top -d 1

# Or measure with mpstat
mpstat -P ALL 1 5

The %steal column should stay at 0.00. If it climbs, you're not on dedicated cores. Open a support ticket.

3. Install build toolchains

One-shot install for the major languages:

# GCC and Clang
apt install -y gcc-12 g++-12 clang lld

# Rust (via rustup, as the builder user)
su - builder
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env

# Go
GOVER=1.22.3
curl -fsSL https://go.dev/dl/go${GOVER}.linux-amd64.tar.gz | sudo tar -C /usr/local -xz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

# Java (for Bazel / Gradle workloads)
sudo apt install -y openjdk-21-jdk-headless

# Node.js (for JS toolchains)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Python build deps
sudo apt install -y python3-pip python3-dev python3-venv

4. Parallel make + ninja

The simplest CPU win: tell your build system to actually use all cores.

Make:

# Use all cores
make -j$(nproc)

# Or set globally
echo 'export MAKEFLAGS="-j$(nproc)"' >> ~/.bashrc

Ninja uses all cores automatically. If a project supports both, use Ninja — it parallelises better and has less overhead.

CMake invocation:

cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

For C++ specifically, also use lld (LLVM's linker) — significantly faster than GNU ld for large projects:

# Tell GCC/Clang to use lld
export LDFLAGS="-fuse-ld=lld"

# For CMake projects
cmake -B build -DCMAKE_LINKER_TYPE=LLD -DCMAKE_BUILD_TYPE=Release

5. distcc for distributed C/C++ builds

If your build is so big that a single 16-core VPS isn't enough, distcc lets you fan out compilation across multiple build servers. Useful for Chromium-class projects.

On the build server VPS:

sudo apt install -y distcc

# Edit /etc/default/distcc
sudo sed -i 's/^STARTDISTCC.*/STARTDISTCC="true"/' /etc/default/distcc
sudo sed -i 's/^ALLOWEDNETS.*/ALLOWEDNETS="10.0.0.0\/8 100.64.0.0\/10"/' /etc/default/distcc

sudo systemctl restart distcc

On your laptop (the build coordinator):

apt install -y distcc

# Point at the build server
export DISTCC_HOSTS="builder-vps-ip/16,lzo"

# Build through distcc
CC="distcc gcc" CXX="distcc g++" make -j32   # 2× nproc for distcc

For maximum throughput, combine with ccache for compiler-output caching. The combination ccache+distcc is the de-facto setup for serious C++ build farms.

6. bazel-remote for cache reuse

Bazel and Buck2 fans: a remote cache shared across your laptop, CI, and the build server VPS dramatically cuts rebuild time. Same artifact gets built once, downloaded everywhere.

# Install bazel-remote
GOPATH=$HOME/go go install github.com/buchgr/bazel-remote@latest

# Run with 100 GB cache
mkdir -p ~/cache
~/go/bin/bazel-remote --dir ~/cache --max_size 100 --grpc_address 0.0.0.0:9092 --http_address 0.0.0.0:9091

In your .bazelrc (laptop and CI):

build --remote_cache=grpc://builder-vps-ip:9092
build --remote_upload_local_results=true

First build populates the cache. Subsequent builds (yours, your colleague's, CI's) hit the cache and skip compilation entirely. Typical cache hit rate on stable codebases: 80–95% — meaning a 10-minute build runs in 30 seconds.

🐾 Build environment pre-installed

Our High CPU VPS plans ship with GCC 12, Clang, Rust, Go, JDK 21, Node LTS, and Python 3.12 pre-installed — plus FFmpeg with libx265 and SVT-AV1 compiled and ready. Skip the toolchain marathon.

See High CPU Plans →

7. FFmpeg CPU encoding (x265, AV1)

FFmpeg with libx265 and SVT-AV1 is the gold standard for CPU-based video encoding when GPU isn't available (or when you care more about quality-per-bit than speed). Even more so on AV1 where CPU SVT-AV1 produces excellent quality.

Install the version with x265 and AV1 support:

# The Ubuntu default ffmpeg is fine
sudo apt install -y ffmpeg

# Verify support
ffmpeg -encoders 2>/dev/null | grep -E 'x265|av1|x264'

Real-world encoding commands:

# H.265 at "balanced" CRF 22 — good quality, decent size
ffmpeg -i input.mp4 -c:v libx265 -preset medium -crf 22 \
  -c:a aac -b:a 192k -threads 0 output.mp4

# AV1 (slower, much smaller files for the same quality)
ffmpeg -i input.mp4 -c:v libsvtav1 -preset 6 -crf 30 \
  -c:a aac -b:a 192k output.mkv

# H.264 (universal compatibility, larger files)
ffmpeg -i input.mp4 -c:v libx264 -preset slow -crf 20 \
  -c:a aac -b:a 192k output.mp4

Speed comparison on a 16-core High CPU VPS (encoding a 1080p 5-minute clip):

Codec / presetTimeOutput sizeQuality
libx264 fast22s (13.6× real-time)~210 MBGood
libx264 slow56s (5.4× real-time)~165 MBBetter
libx265 medium2m 10s (2.3× real-time)~110 MBBest (per-bit)
libsvtav1 preset 63m 40s (1.4× real-time)~95 MBBest-modern

8. Rust and Go fast paths

Rust: parallel compilation is on by default; tune incremental rebuilds with sccache:

cargo install sccache
echo 'export RUSTC_WRAPPER=sccache' >> ~/.bashrc

# Build a project — first build populates sccache
cargo build --release

Subsequent cargo build calls hit sccache and skip recompilation of unchanged crates. On a Rust workspace with 50+ crates, this typically cuts incremental rebuild times by 70–90%.

Go: parallelism is automatic and very efficient. The main lever is the build cache, which Go manages itself in ~/.cache/go-build/. To share across CI and developers, mount this directory as a network drive or use go mod download + S3 caching.

9. Reference: benchmarks and tuning

Workload to plan mapping

WorkloadRecommended plan
Personal Rust/Go projects, CI runnerStarter ($7.99, 4 cores)
Small C++ project, occasional FFmpegPro ($15.99, 8 cores)
Chromium/LLVM builds, video farm, ML training prepPremium ($35.99, 16 cores)

Single-thread vs multi-thread

Some workloads are stubbornly single-threaded — old build systems, certain compression algorithms, parts of Rust's compilation. Check your CPU's base + boost clocks. Modern Xeon Gold runs ~3.5 GHz boost; modern EPYC runs ~3.7 GHz. Within a generation, base clock matters more than core count for these workloads.

Hourly billing for batch workloads

If you only need the box for 50 hours/month — Friday-night render jobs, weekend ML experiments — ask about hourly billing. Pay only when running; spin down between sessions. Cost-effective for spiky workloads.

SSD/NVMe scratch space

Builds generate huge intermediate output. A Rust workspace can produce 10–30 GB of object files. Always build on local NVMe (the VPS root disk), not on network-mounted storage. The 3 GB/s read/write of NVMe vs 100 MB/s of remote storage makes a 10× difference in link times.

Tmpfs for scratch builds

For builds that produce many small files, mount a tmpfs and build in RAM:

sudo mount -t tmpfs -o size=16G,mode=0777 tmpfs /tmp/buildspace
cd /tmp/buildspace
# ... clone, build ...

Caveat: lose power and the build is gone. Fine for ephemeral CI work; not for in-progress development.

CPU governor

Some VPS providers default to a power-saving governor that under-clocks the CPU. Check and set to performance:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

# Set to performance (won't persist on most VPS — but try)
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

FAQ

Why CPU-only video encoding when GPU is faster?

CPU encoders (x265, SVT-AV1) produce 20–40% smaller files at the same visual quality compared to GPU encoders (NVENC, QSV). For archival or distribution where storage / bandwidth costs matter, that's huge. GPU encoders win on live streaming (real-time matters) and high-volume short-form (where speed beats efficiency). For Plex/Jellyfin libraries, FFmpeg CPU is the better long-term choice.

Is hyper-threading 'dedicated cores'?

Depends on the provider. Some count each hyper-thread as a 'dedicated core' (cheap definition), some count physical cores only (honest definition). When in doubt, ask before buying — the difference is real for CPU-bound work. Our plans count physical cores.

Can I use this VPS as a GitHub Actions self-hosted runner?

Yes — that's a great use case. Register the runner on your repo, point GHA workflows at the self-hosted label, and your CI runs on dedicated cores instead of GitHub's shared infrastructure. Typical speedup: 3–5× for compute-heavy builds. The setup is documented at GitHub's docs.

What about ARM (Graviton, Ampere) for build servers?

ARM builds are competitive on price-performance for native ARM workloads. For cross-compilation or x86 emulation builds, x86_64 is still the better choice. Most of our High CPU plans are x86 (Xeon/EPYC); ask if you need ARM specifically.

Does CPU pinning help build performance?

On dedicated-core VPS plans, not noticeably — the kernel scheduler already does a good job and there's no contention with other tenants. CPU pinning helps when you're running multiple isolated workloads on one box and want to prevent cross-talk (e.g. a build container shouldn't share L3 cache with a database container).

Can I run distcc + bazel-remote on the same VPS?

Yes — they don't conflict. distcc uses port 3632 by default, bazel-remote uses 9091/9092. Both can run on the same machine, and combining them gives you the best of both worlds: distcc for cross-developer C++ compilation, bazel-remote for cache reuse on Bazel-based projects.

🐱
OliveVPS Team

We use a Premium High CPU plan as our internal CI runner. Builds that take 14 minutes on GitHub's shared runners finish in 3:20 on dedicated cores. Same source, same build steps, no caching tricks — just real cores.