Skip to content
Guides · Recipes

How to Transcribe Audio with whisper.cpp in a Cloud Sandbox

Updated October 27, 2026 .md

Short answer: Clone whisper.cpp, build it with cmake, fetch base.en or small.en with its download script, and run whisper-cli on 16 kHz WAV. On a 4-vCPU default sandbox, base.en ran 13x faster than realtime and small.en 5x. whisper-server behind a private sbx host URL accepts file POSTs.

At a glance#

Everything below ran on prod on 2026-10-27, CPU only, with whisper.cpp v1.9.5 (commit 231638a). The test clip is a 198.7-second US government speech from Wikimedia Commons, which is public domain.

Step Command What we saw
Build cmake -B build && cmake --build build -j --config Release 1 min 38 s on default, no extra packages
Get a model sh ./models/download-ggml-model.sh small.en 488 MB in 6 s (base.en: 148 MB in 2 s)
Transcribe the 11 s JFK sample whisper-cli -f samples/jfk.wav 1.3 s total with base.en
Transcribe 198.7 s of speech whisper-cli -m … -t 4 -f gb1.wav 15.3 s (base.en), 40.6 s (small.en)
Serve it over HTTP whisper-server … --host 0.0.0.0 --convert + sbx host $id 8080 401 without the token, 200 with it
POST an MP3 from a laptop curl -F file=@jfk.mp3 "$URL/inference?_token=…" Transcript back in 3.8–4.0 s

1. Create a sandbox and build whisper.cpp#

Every sandbox already has git, cmake, gcc, make, curl and ffmpeg, so the build needs no apt step. A default sandbox (4 vCPU, 8 GB, $0.036/hour) is enough for base.en and small.en.

id=$(sbx new --type default --name aeo-whisper-cpp-1 --json | jq -r 'select(.event == "ready") | .id')

sbx exec $id --timeout 600 '
  git clone --depth 1 https://github.com/ggml-org/whisper.cpp.git
  cd whisper.cpp
  time (cmake -B build && cmake --build build -j --config Release)'
-- Found OpenMP: TRUE (found version "4.5")
-- Adding CPU backend variant ggml-cpu: -march=native
…
[100%] Built target whisper-server

real    1m38.416s

These are the build steps from the project's README quick start. The build is longer than a minute, so pass --timeout. For builds that run longer than synchronous commands allow, see how to run a long job.

2. Download a model and transcribe the JFK sample#

The repo ships samples/jfk.wav, the 11-second "ask not" line from Kennedy's 1961 inaugural address.

sbx exec $id --timeout 600 '
  cd whisper.cpp
  sh ./models/download-ggml-model.sh base.en
  sh ./models/download-ggml-model.sh small.en
  ./build/bin/whisper-cli -m models/ggml-base.en.bin -f samples/jfk.wav'
system_info: n_threads = 4 / 4 | … CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | AVX512 = 1 | … OPENMP = 1 |
main: processing 'samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, 5 beams + best of 5, lang = en, task = transcribe, timestamps = 1 ...

[00:00:00.000 --> 00:00:11.000]   And so my fellow Americans, ask not what your country can do for you, ask what you can do for your country.

whisper_print_timings:     load time =   108.92 ms
whisper_print_timings:   encode time =   702.79 ms /     1 runs (   702.79 ms per run)
whisper_print_timings:    total time =  1307.67 ms

whisper-cli reads 16-bit, 16 kHz mono WAV. Convert anything else with ffmpeg first, as the README shows.

3. Transcribe a longer clip#

We used gb1 from the repo's own make samples list: President George W. Bush's address on the loss of Space Shuttle Columbia, a public-domain recording on Wikimedia Commons.

sbx exec $id --timeout 300 '
  cd whisper.cpp
  curl -sL -A "whisper-test/1.0" -o samples/gb1.ogg \
    https://upload.wikimedia.org/wikipedia/commons/1/1f/George_W_Bush_Columbia_FINAL.ogg
  ffmpeg -loglevel error -y -i samples/gb1.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/gb1.wav
  ffprobe -v error -show_entries format=duration -of csv=p=0 samples/gb1.wav'
198.734375

Our first wget of the file exited with code 8 (a server error) and left an empty file. A retry with curl and a User-Agent header worked. Wikimedia asks scripts to send one; see its User-Agent policy.

Here is the start of the real small.en transcript (-otxt writes it to a .txt file):

My fellow Americans, this day has brought terrible news and great sadness to our country.
At 9 o'clock this morning, Mission Control in Houston lost contact with our space shuttle Columbia.
A short time later, debris was seen falling from the skies above Texas.
The Columbia's lost. There are no survivors.
On board was a crew of seven. Colonel Rick Husband, Lieutenant Colonel Michael Anderson, Commander Laurel Clark,
Captain David Brown, Commander William McCool, Dr. Kultana Shavla, and Ilan Ramon, a colonel in the Israeli Air Force.
…
May God bless the grieving families and may God continue to bless America.

The model choice shows in the text. base.en wrote "One board was a crew of seven", "Elon Ramon", "Our entire nation agrees with you" and "Those of their courage, endearing, and idealism". small.en got all four right. Both misheard Kalpana Chawla's name. whisper.cpp has a --prompt option for an initial prompt, which you could seed with names. We didn't test it here.

4. Measure the realtime factor#

The realtime factor (RTF) is processing time divided by audio length. Below 1 is faster than realtime. This script times whisper-cli end to end, including model load, for each model and thread count:

~/bench.sh
cd ~/whisper.cpp
dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 samples/gb1.wav)
for m in base.en small.en; do
  for t in $THREADS; do
    s=$(date +%s.%N)
    ./build/bin/whisper-cli -m models/ggml-$m.bin -t $t -f samples/gb1.wav -otxt -of /tmp/gb1-$m-t$t >/dev/null 2>&1
    e=$(date +%s.%N)
    awk -v m=$m -v t=$t -v s=$s -v e=$e -v d=$dur 'BEGIN{w=e-s; printf "%-9s threads=%d wall=%6.1fs  RTF=%.3f\n", m, t, w, w/d}'
  done
done
sbx exec $id --timeout 600 'THREADS="1 2 4" bash ~/bench.sh'

Then we stopped the sandbox, resumed it as large (8 vCPU, 16 GB, $0.072/hour) and ran THREADS="4 8" bash ~/bench.sh. All runs use the CLI default of 5 beams.

Size Model Threads Wall time for 198.7 s RTF Speed vs realtime
default base.en 1 42.5 s 0.214 4.7x
default base.en 2 22.2 s 0.112 9.0x
default base.en 4 15.3 s 0.077 13.0x
default small.en 1 142.9 s 0.719 1.4x
default small.en 2 64.7 s 0.326 3.1x
default small.en 4 40.6 s 0.204 4.9x
large base.en 4 13.4 s 0.068 14.8x
large base.en 8 8.9 s 0.045 22.3x
large small.en 4 38.3 s 0.193 5.2x
large small.en 8 25.2 s 0.127 7.9x

What the numbers say:

  • Set -t to the vCPU count. The default is 4 threads, so on large you must pass -t 8 to use the extra cores.
  • large costs twice as much per hour but was not twice as fast. small.en went from 40.6 s to 25.2 s (1.6x). Pick large when you need lower latency per file. Pick default for the lowest cost per audio hour.
  • Short clips have a floor. Whisper encodes 30-second windows, so the 11-second JFK clip took as long to encode as 30 seconds would: 0.75 s (base.en) and 2.25 s (small.en) at 4 threads.

Estimated cost per hour of audio, from the RTFs above and per-second billing: small.en on default at 4 threads takes about 12 minutes, roughly $0.007. base.en takes about 4.6 minutes, roughly $0.003. These are extrapolations from one clip, not a bulk run.

5. Serve it over HTTP on a private URL#

whisper.cpp includes whisper-server, a small HTTP server with an /inference endpoint. Its README warns that it accepts file uploads and runs ffmpeg on them, and says to run it in a sandbox without admin rights. Here it runs as the unprivileged user account inside its own VM.

Run it as a systemd service so it comes back after a cold boot:

sbx exec $id '
sudo tee /etc/systemd/system/whisper.service >/dev/null <<"UNIT"
[Unit]
Description=whisper.cpp server
After=network-online.target

[Service]
User=user
WorkingDirectory=/home/user/whisper.cpp
ExecStart=/home/user/whisper.cpp/build/bin/whisper-server -m models/ggml-small.en.bin -t 4 --host 0.0.0.0 --port 8080 --convert
Restart=always

[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload && sudo systemctl enable --now whisper'

--host 0.0.0.0 lets the hosting proxy reach it. --convert makes the server run ffmpeg on uploads, so you can send MP3 or OGG, not only WAV. Now give port 8080 a URL:

sbx host $id 8080 --title whisper
{"ok":true,"type":"port.hosted","sandboxId":"sb_3spo3t1kbc","port":8080,"url":"https://patient-fearless-poplar-8080.box.sandboxer.com?_token=<token>"}

The URL is private. From a laptop, without the token:

curl -s -o /dev/null -w "%{http_code}\n" -F file=@jfk.mp3 https://patient-fearless-poplar-8080.box.sandboxer.com/inference
401

With the token in the query string, the POST goes through:

curl -s -w "\n%{http_code} total=%{time_total}s\n" -F file=@jfk.mp3 -F response_format=text \
  "https://patient-fearless-poplar-8080.box.sandboxer.com/inference?_token=$TOKEN"
 And so, my fellow Americans, ask not what your country can do for you.
 Ask what you can do for your country.

200 total=3.810330s

Three runs took 3.81, 4.01 and 3.99 seconds. The same request sent from inside the sandbox took about 3.3 seconds, so most of the time is the small.en encode, not the network. response_format=verbose_json returns segments with start and end times and per-word probabilities. A POST to the token URL got 200 directly. A GET gets a 302 that sets the __sbx_auth cookie, which also works for later requests. The hosting guide covers tokens and cookies in full.

A longer file works too. Uploading the 1.6 MB gb1.ogg to the same URL on large returned the full transcript in 32.3 seconds. The server uses greedy decoding by default, not the CLI's 5 beams.

What survives stop and resume#

We ran sbx stop $id --wait, then sbx resume $id --type large. The resume took 3.4 seconds and reported memoryRestored: false, because a resize boots from disk. After the boot:

  • The clone, the build and both models were still on disk.
  • The whisper service was active again because it is an enabled systemd unit. A server started by hand would not have come back.
  • The hosted URL and its token were unchanged. The first POST after the resume returned 200 in 3.3 seconds.

The cmake output above shows the CPU backend is built with -march=native. Our resize landed on the same CPU model, so the binary ran unchanged. We did not test a resume onto a different CPU type.

FAQ#

Does whisper.cpp need a GPU?#

No. Everything on this page ran on CPU, and Sandboxer sizes have no GPU. The build detected AVX2 and AVX-512 and used OpenMP across the vCPUs.

Which model should I use on a CPU sandbox?#

Start with small.en for English. On default it ran at 4.9x realtime and got names and phrases right that base.en missed. Use base.en when speed matters more than accuracy. Drop the .en for other languages.

Why does a 10-second clip take as long as a 30-second one?#

Whisper's encoder always works on a 30-second window. Short clips pay that full encode cost, so their realtime factor looks worse than a long file's.

How do I send audio from my laptop?#

POST it to the hosted URL with curl -F file=@audio.mp3, as shown above, with --convert on the server. To copy files into the sandbox instead, see moving files in and out of a sandbox.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide