Runtime

How to run Ruby code in a sandbox

Install Ruby from Ubuntu in an isolated Linux microVM, or start from the official Ruby image, then run the file with ruby under a timeout.

On Runtime you choose the Ruby: Ubuntu's 3.2 in one apt command, or Ruby 4.0 from the official Docker image, built once into a sandbox image. Every sandbox is a Firecracker microVM with its own kernel and sudo, and the default image already has gcc and make for gems with C extensions. A 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while it waits and $0.08 with both CPUs busy (pricing).

Which Ruby to use

Source Ruby version on 25 September 2026 How
Ubuntu 24.04 ruby package (main) 3.2.3 sudo apt-get install -y ruby
Ubuntu 24.04 ruby-full (universe) 3.2.3, with headers and docs sudo apt-get install -y ruby-full
Official ruby image on Docker Hub 4.0 (tags 4.0.7, 4.0-slim) A custom image built from it, below
rbenv with ruby-build, or mise Any release you build Ruby's recommended version managers

Ruby's own site lists 4.0.7 and 3.4.11 as the stable releases, gives sudo apt-get install ruby-full for Ubuntu, and notes that package managers may install older versions than the latest (Ruby).

Ruby is not in the default sandbox image and not one of the code interpreter's languages, so it runs as a file or a script with exec.

Install Ruby and run a file

TypeScriptimport { Sandbox } from "withruntime";const program = `words = ARGV.first.splitcounts = words.tally.sort_by { |_, n| -n }.first(3)puts counts.map { |w, n| "#{w}=#{n}" }.join(" ")`;await using sbx = await Sandbox.create({ timeoutSeconds: 900, onLeaseEnd: "stop" });await sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q ruby", {  check: true,  timeoutMs: 600_000,});await sbx.network.set({ internet: false }); // the program runs offlineawait sbx.files.write("/workspace/top.rb", program);const run = await sbx.exec(["ruby", "top.rb", "a b a c b a"], { timeoutMs: 30_000 });console.log(run.exitCode, run.stdout); // 0 a=3 b=2 c=1
Pythonfrom withruntime import Sandboxprogram = """words = ARGV.first.splitcounts = words.tally.sort_by { |_, n| -n }.first(3)puts counts.map { |w, n| "#{w}=#{n}" }.join(" ")"""with Sandbox.create(timeout_seconds=900, on_lease_end="stop") as sbx:    sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q ruby",             check=True, timeout_ms=600_000)    sbx.network.set(internet=False)  # the program runs offline    sbx.files.write("/workspace/top.rb", program)    run = sbx.exec(["ruby", "top.rb", "a b a c b a"], timeout_ms=30_000)    print(run.exit_code, run.stdout)  # 0 a=3 b=2 c=1
  • The text reaches the program as ARGV.first exactly as given. An array runs ruby with no shell, so quotes and semicolons in it are just characters.
  • Errors and backtraces are on stderr, with a non-zero exit code.
  • A script that never ends comes back with timedOut: true after timeoutMs and whatever it printed.

Gems

Install gems while the network is on, then close it before the code you do not trust runs. The sandbox is yours, so sudo gem install into the system Ruby is fine:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ timeoutSeconds: 1200, onLeaseEnd: "stop" });await sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q ruby-full", {  check: true,  timeoutMs: 600_000,});await sbx.exec("sudo gem install --no-document rainbow", { check: true, timeoutMs: 300_000 });await sbx.network.set({ internet: false });await sbx.files.write("/workspace/hi.rb", 'require "rainbow"\nputs Rainbow("ok").green');console.log((await sbx.exec(["ruby", "hi.rb"], { timeoutMs: 30_000 })).stdout);

ruby-full depends on ruby-dev, the headers that gems with C extensions build against, with the image's gcc.

A Rails or Bundler project

Upload the project, install the bundle, then run the tests with the network off:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({  image: "ruby4",  diskMiB: 8192,  timeoutSeconds: 3600,  onLeaseEnd: "stop",});await sbx.files.upload("./my-app", "/workspace/app");await sbx.exec("bundle install", { cwd: "/workspace/app", check: true, timeoutMs: 900_000 });await sbx.network.set({ internet: false });const test = await sbx.exec(["bundle", "exec", "rake", "test"], {  cwd: "/workspace/app",  timeoutMs: 1_800_000,  onStdout: (text) => process.stdout.write(text),});console.log("exit", test.exitCode);

This uses the ruby4 image below. A timeoutMs over 60 seconds streams the output, and the result keeps all of it.

Ruby in every sandbox

A custom image can start from any public image, so the official Ruby image gives every sandbox Ruby 4.0 with no install. Or add Ubuntu's Ruby to Runtime's own base with a recipe:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "ruby4", image: "ruby:4.0-slim" });await runtime.images.build({ name: "ruby32", recipe: { apt: ["ruby-full"] } });await using sbx = await runtime.sandboxes.create({ image: "ruby4", network: { internet: false } });console.log((await sbx.exec(["ruby", "--version"])).stdout);
Pythonfrom withruntime import Runtimeruntime = Runtime()runtime.images.build(name="ruby4", image="ruby:4.0-slim")runtime.images.build(name="ruby32", recipe={"apt": ["ruby-full"]})with runtime.sandboxes.create(image="ruby4", network={"internet": False}) as sbx:    print(sbx.exec(["ruby", "--version"]).stdout)

The recipe image keeps Runtime's base, with Python, Node.js and the usual tools next to Ruby. Building is free; a stored image is charged on its size.

New accounts get 50 free sandbox hours, no card:

Terminalnpx withruntime sandbox run --trial -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q ruby && ruby --version'

Sources

Facts on this page were checked on 25 September 2026.