# 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 with one apt command, or Ruby 4.0 from the official Docker image, built once into a sandbox image.** Each sandbox is a Firecracker microVM with its own kernel and `sudo`. The default image includes `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](/docs/pricing)). ## Which Ruby to use | Source | Ruby version on 26 October 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.9`, `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.9 and 3.4.12 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](https://www.ruby-lang.org/en/documentation/installation/)). Ruby is not in the default sandbox image, and the code interpreter does not support it. Run Ruby as a file or script with `exec`. ## Install Ruby and run a file ```ts check import { Sandbox } from "withruntime"; const program = ` words = ARGV.first.split counts = 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 offline await 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 ``` ```python check from withruntime import Sandbox program = """ words = ARGV.first.split counts = 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 unchanged, as `ARGV.first`. An array runs `ruby` with no shell, so quotes and semicolons in the text are plain characters. - Errors and backtraces go to `stderr`, and the exit code is non-zero. - A script that does not end returns `timedOut: true` after `timeoutMs`, with the output it printed up to that point. ## Gems Install gems while the network is on, then turn the network off before you run code you do not trust. You control the sandbox, so `sudo gem install` into the system Ruby works: ```ts check import { 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`, which provides the headers that gems with C extensions build against. The image's `gcc` compiles them. ## A Rails or Bundler project Upload the project, install the bundle, then run the tests with the network off: ```ts check import { 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 defined below. When `timeoutMs` is over 60 seconds, the output streams as it arrives, and the result still holds all of it. ## Ruby in every sandbox A [custom image](/docs/images) can start from any public image, so the official Ruby image gives every sandbox Ruby 4.0 with no install step. Or add Ubuntu's Ruby to the Runtime base image with a recipe: ```ts check import { 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); ``` ```python check from withruntime import Runtime runtime = 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 the Runtime base image, so Python, Node.js and the usual tools are still available next to Ruby. Building is free. A stored image is charged by its size. ## Related - [Run untrusted Python code safely](/languages/python) - [Grade student code](/use-cases/grade-student-code) - [Per-user dev environments](/use-cases/per-user-dev-environments) - [How to run untrusted code from an LLM safely](/use-cases/run-untrusted-llm-code) A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card required: ```bash no-run npx withruntime sandboxes run -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q ruby && ruby --version' ``` ## Sources - Ruby installation: https://www.ruby-lang.org/en/documentation/installation/ (read 26 October 2026) - Ruby downloads, stable 4.0.9 and 3.4.12: https://www.ruby-lang.org/en/downloads/ (read 26 October 2026) - Docker Hub, official `ruby` image tags `4.0.9` and `4.0-slim`: https://hub.docker.com/_/ruby (read 26 October 2026) - Ubuntu 24.04 package indexes (`ruby` 1:3.2~ubuntu1, `ruby3.2` 3.2.3-1ubuntu0.24.04.8, `ruby-full` 1:3.2~ubuntu1): http://archive.ubuntu.com/ubuntu/dists/noble-updates/main/binary-amd64/ and http://archive.ubuntu.com/ubuntu/dists/noble/universe/binary-amd64/ (read 26 October 2026) Facts on this page were checked on 26 October 2026.