Instant Linux boxes via SSH for builders and AI agents.

 ██████ ██    ██ ████████ ██       ██       ███████   ██████  ██    ██
██      ██    ██ ██       ██       ██       ██    ██ ██    ██  ██  ██
 █████  ████████ ██████   ██       ██       ███████  ██    ██   ████
     ██ ██    ██ ██       ██       ██       ██    ██ ██    ██  ██  ██
██████  ██    ██ ████████ ████████ ████████ ███████   ██████  ██    ██

Pay per minute for what you actually use. No subscription, no login — your SSH key fingerprint is your account.

ssh shellbox.dev create <name> [xN]      # create a stock box
ssh shellbox.dev create-from-oci <name> <image>  # boot from a prepared OCI image
ssh shellbox.dev list                    # see your boxes
ssh <name>@shellbox.dev                  # connect
ssh shellbox.dev duplicate <src> <new>   # copy (same size)
ssh shellbox.dev keepalive <name>        # always-on
ssh shellbox.dev wakeup <name>           # auto-start on HTTP
ssh shellbox.dev cron <name> <int> [run] # scheduled wake/run/stop
ssh shellbox.dev funds <amount>          # top up balance ($10 min)
x1 base
2 vCPU · 4 GB RAM · 50 GB SSD. Scale to x8.
running
$0.02/hr per x1 slot, billed per minute.
parked
$0.50/mo per x1 slot when stopped.
auth
SSH key fingerprint = account. No signup.

First time you SSH, an account is created from your key fingerprint. No email, no password, no dashboard. Pick a name and a size; you get a URL and an email endpoint immediately.

$ssh shellbox.dev create dev1 x2
Creating box…
Box 'dev1' created  (x2 · 4 vCPU · 8 GB RAM · 100 GB SSD)
URL:   https://dev1-a1b2c3d4.shellbox.dev
Email: dev1-a1b2c3d4@in.shellbox.dev
IPv6:  2a01:4f9:c012:1a2b::dev1

Connect with: ssh dev1@shellbox.dev

OCI-backed boxes

Public linux/amd64 Ubuntu-like OCI images can be prepared into bootable microVM root filesystems.

$ssh shellbox.dev image prepare docker.io/library/debian:bookworm-slim
Image prepared: docker.io/library/debian:bookworm-slim
Digest: sha256:abc123…
Status: ready
$ssh shellbox.dev create-from-oci debbox docker.io/library/debian:bookworm-slim
Box 'debbox' created successfully (x1)
Connect with: ssh debbox@shellbox.dev

Pure SSH. Works with VS Code Remote, Zed, mosh (with direct IPv6), scp, sftp. Stopped boxes resume from a memory snapshot on connect.

$ssh dev1@shellbox.dev
Resuming from snapshot… ready in ~3s
root@dev1:~# _

Connection time is typically ~3 seconds end to end (TCP + key exchange + snapshot resume). Processes, shell history and files are exactly where you left them.

File transfer and forwarding

$scp file.txt dev1@shellbox.dev:/root/
$scp dev1@shellbox.dev:/root/file.txt ./
$sftp dev1@shellbox.dev
$ssh -L 8080:localhost:80 dev1@shellbox.dev

Inspect, copy, switch modes, dispose. Scale by spawning more boxes — sizes are fixed.

$ssh shellbox.dev list
NAME       SIZE  SRC    STATE     MODE                URL
─────────────────────────────────────────────────────────────────────────
dev1       x2    stock  running   keepalive           https://dev1-a1b2c3d4.shellbox.dev
gitea      x1    stock  stopped   wakeup · 30m idle   https://gitea-7f3e9c2a.shellbox.dev
agent-42   x4    stock  stopped   stop                https://agent-42-9b1d.shellbox.dev
cronbox    x1    stock  stopped   cron 60m / run 5m   https://cronbox-3c8a.shellbox.dev

Duplicate

$ssh shellbox.dev duplicate dev1 dev1-fork
Duplicating dev1 → dev1-fork (inherits size: x2)
Filesystem cloned. Memory snapshot copied.
ssh dev1-fork@shellbox.dev   # ready

Modes

stop default
After the last SSH session disconnects, wait 120 seconds, then pause. Snapshot saves processes, shell history, and TCP state; restored on next connect. Run ssh shellbox.dev stop <name> to stop immediately.
keepalive ssh shellbox.dev keepalive name
Stay running regardless of connections. For Gitea, n8n, bots, daemons — anything you want up 24/7.
wakeup ssh shellbox.dev wakeup name [idle-min]
Stopped, but auto-starts on an HTTPS request to its public URL; stops after idle.
cron ssh shellbox.dev cron name int [run]
Wake on a schedule, run a webhook, stop. Periodic jobs without a separate scheduler.

One slot = an x1. Bigger sizes are integer multiples — same price math. No subscription, no minimum, refundable balance.

SlotvCPURAMSSD RunningParked (idle) 8h/day · 22d24/7 · 30d
  • · Per-minute billing while running. No subscription. Top-up only.
  • · Storage is per-instance and instance sizes are fixed. Scale by spawning more boxes.
  • · Boxes auto-stop when balance drops below $5 and are deleted at $0. Refunds for unused funds within 3 months.
  • · Payments via Paddle (merchant of record). No card stored by Shellbox.
Estimate your bill
Slot
Hours running per day
8h
Days per month
22d
Running $0.00 Parked $0.00 Estimated monthly total $0.00
Where it runs
Bare metal in Hetzner Finland (EU). One region today; more on demand.
Auth
SSH keys only. No passwords, no email signup. Your account = your key fingerprint.
Isolation
MicroVMs on Firecracker (default) or Cloud Hypervisor for nested virt.
Pay
Paddle as merchant of record. Pre-paid balance, refundable within 3 months.

Boxes are real microVMs — each with its own kernel and disk. Every new box gets direct public IPv6 for ssh / mosh / raw TCP-UDP. Every box also gets a managed HTTPS endpoint with automatic TLS, email endpoint, and custom domain support.

Frequently asked questions about shellbox.dev.

01Do you support post-quantum encryption?

Yes. Our SSH server supports the sntrup761x25519-sha512@openssh.com hybrid key exchange — a combination of the post-quantum NTRU Prime algorithm and classical X25519. OpenSSH 9.0+ clients (April 2022 onwards) negotiate this automatically. No configuration needed on your end.

02How do I skip the "trust this host?" prompt?

We publish SSHFP DNS records secured with DNSSEC. This lets your SSH client verify our server's identity cryptographically through DNS, instead of asking you to trust on first use. Add this to your ~/.ssh/config:

Host shellbox.dev
    VerifyHostKeyDNS yes

Then connect normally: ssh shellbox.dev help. No fingerprint prompt.

03How do I make SSH commands faster and shorter?

Use an SSH host alias and OpenSSH connection multiplexing. The alias makes commands shorter, and multiplexing reuses an existing SSH transport so repeated commands skip most of the TCP/SSH handshake.

Host sb
    HostName shellbox.dev
    VerifyHostKeyDNS yes
    ControlMaster auto
    ControlPersist 10m
    ControlPath ~/.ssh/shellbox-%C

Then you can write shorter commands:

$ ssh sb list
$ ssh sb create vm1
$ ssh vm1@sb

Multiplexing is per SSH user/host/port, so ssh sb list, ssh vm1@sb, and ssh vm2@sb each use their own control connection. If you use pooling for box logins and want to tear down the master immediately, run ssh -O exit vm1@sb. To stop the box immediately, run ssh sb stop vm1.

04I don't have an SSH key. How do I get started?

Generate one:

$ ssh-keygen -t ed25519

Press Enter to accept defaults. Then:

$ ssh shellbox.dev help

Your SSH key is your identity. No signup, no email, no password.

05Do I need to create an account?

No. The first time you connect, your account is created automatically from your SSH key fingerprint. No registration, no email, no password required.

06What happens when I disconnect?

Your box enters a grace-stop window. By default, after the last SSH session disconnects, Shellbox waits 120 seconds before pausing the box. If you reconnect during that window, the box keeps running and you avoid an unnecessary stop/start cycle.

After the grace period, the box pauses. All processes, shell history, and files are preserved in a memory snapshot. Reconnect and everything resumes exactly where you left off. Billing drops to the idle rate ($0.5/month per x1 slot) while paused.

If you want to stop immediately instead of waiting for the grace period, run: ssh shellbox.dev stop <name>

If you want a box to keep running after disconnect (e.g. for a background job), toggle keepalive: ssh shellbox.dev keepalive <name>

07What is wakeup mode?

Wakeup mode automatically starts your box when an HTTP request arrives at its URL, and stops it after 5 minutes of no TCP activity. This is ideal for web services that don't need to run 24/7 — you only pay while the box is handling traffic.

Enable it with: ssh shellbox.dev wakeup <name>. The first HTTP request after idle will block until the box is ready, then all subsequent requests proceed normally.

08What is cron mode?

Cron mode periodically wakes your box on a schedule, sends a POST request to http://localhost:80/cron on your box, lets it run for a fixed duration, then stops it. This is ideal for scheduled tasks like data processing, backups, or report generation — you only pay while the box is running.

Enable it with: ssh shellbox.dev cron <name> <interval_min> [runtime_min]. For example, cron mybox 60 5 wakes your box every 60 minutes, runs for 5 minutes, then stops. If you SSH into a box during a cron run, it won't be stopped until you disconnect.

09Can I get machine-readable output for scripting?

Yes. Add --json to most commands to get structured JSON output instead of human-formatted text:

$ ssh shellbox.dev list --json
$ ssh shellbox.dev show mybox --json
$ ssh shellbox.dev billing --json

Errors still print as text to stderr with a non-zero exit code. Check the exit code first, then parse stdout as JSON.

For the exact schema of each command's JSON output:

$ ssh shellbox.dev help --json

Fields are only added over time, never removed or renamed. Safe to depend on any field you see today.

10Can a coding agent stop my box when it's done?

Yes. If you run a coding agent (Claude Code, Codex, etc.) inside a keepalive box, you can have it stop the box when the task is complete. This clears keepalive and stops billing for running time.

First, generate an SSH key inside the box and add it to your account:

$ ssh shellbox.dev keepalive mybox
$ ssh mybox@shellbox.dev
root@mybox:~# ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
root@mybox:~# cat ~/.ssh/id_ed25519.pub

Copy the public key output, then from your local machine:

$ ssh shellbox.dev key add <paste-public-key>

Now the agent inside the box can authenticate as you. Start a tmux or zellij session, launch your agent, and disconnect:

root@mybox:~# tmux
root@mybox:~# claude   # or your agent of choice

Instruct the agent to run this command when the task is complete:

ssh shellbox.dev stop mybox

This is the same stop command you'd run yourself. It force-stops the box, clears the keepalive flag, and pauses billing. Your work is preserved in a snapshot — reconnect anytime to pick up where the agent left off.

Alternative: You can copy your existing private key into the box instead (scp ~/.ssh/id_ed25519 mybox@shellbox.dev:/root/.ssh/), though generating a dedicated key is more secure since it can be revoked independently.

11Can I use VS Code, Zed, or other IDEs?

Yes. Full SFTP support means VS Code Remote SSH, Zed, and any IDE with SSH remote capabilities work out of the box. Point your IDE at <name>@shellbox.dev and you're in.

12How do I use SSH port forwarding?

shellbox supports normal OpenSSH port forwarding. Use the same flags you'd use with any other SSH server.

Local forwarding — expose a port from your box on your local machine:

$ ssh -L 8080:localhost:80 mybox@shellbox.dev

Then open http://localhost:8080 on your machine to reach port 80 inside the box.

Remote forwarding — expose a local service to the box:

$ ssh -R 3000:localhost:3000 mybox@shellbox.dev

That makes your local port 3000 reachable from the box at localhost:3000.

SOCKS proxy — route traffic through the box:

$ ssh -D 1080 mybox@shellbox.dev

Configure your browser or tools to use localhost:1080 as a SOCKS5 proxy.

Useful quality-of-life flags: -N to skip opening a shell, and -f to send the SSH client to the background after authentication.

$ ssh -fN -L 8080:localhost:80 mybox@shellbox.dev

You can also make forwards persistent in ~/.ssh/config:

Host mybox
    HostName shellbox.dev
    User mybox
    LocalForward 8080 localhost:80
13How do HTTPS endpoints work?

Each box gets a public URL like https://dev1-a1b2c3d4.shellbox.dev with automatic TLS. HTTP requests to this URL are proxied to port 80 on your box.

14Can I use my own domain name?

Yes. You can attach custom domains to any box. Custom domains route through the same Shellbox reverse proxy as the canonical boxname-hash.shellbox.dev URL, so wakeup mode, idle tracking, and automatic TLS all work identically.

$ ssh shellbox.dev domain add mybox app.example.com

This creates a pending mapping. Next, set up a DNS record pointing your domain to the box's canonical hostname. A CNAME record is recommended for subdomains, but A/AAAA records that resolve to the Shellbox ingress are also accepted. Apex domains may need ALIAS/ANAME support from your DNS provider. DNS must be set to DNS-only (not CDN-proxied):

app.example.com CNAME mybox-a1b2c3d4.shellbox.dev

Then verify:

$ ssh shellbox.dev domain verify mybox app.example.com

Once verified, your box is reachable at https://app.example.com. TLS certificates are issued automatically. The first request after verification may take a few extra seconds while the certificate is obtained. If certificate issuance fails (e.g. rate limits or DNS propagation delay), it will be retried on subsequent requests.

Key details:

  • One box can have multiple custom domains
  • One domain maps to exactly one box
  • Domains survive box rename — they point to the VM, not the box name
  • Only verified (active) domains route traffic
  • v1 supports exact hostnames only, not wildcards
  • Subdomains work well with CNAME; apex domains may also work via A/AAAA/ALIAS/ANAME, depending on your DNS provider
  • DNS must be DNS-only — CDN-proxied records may fail verification because they resolve to CDN IPs, not the Shellbox ingress
  • Ownership is checked when you run domain verify; v1 does not continuously revalidate DNS ownership after activation
  • After activation or removal, changes propagate after the short proxy cache expires (within a few seconds)

Manage domains with: domain add, domain verify, domain remove, domain list. Add --json for machine-readable output.

15Do boxes have public IPv6?

Yes. Every new box gets a stable public IPv6 address derived from the box's network identity. The address is shown in create, create-from-oci, show, and list, and in the corresponding --json output as public_ipv6.

The IPv6 is for direct guest accessssh root@<ipv6>, mosh root@<ipv6>, raw TCP/UDP — while the box is running:

$ ssh root@2001:db8:1234:5678::3
$ mosh root@2001:db8:1234:5678::3

Key details:

  • The IPv6 is stable for the life of the box — rename and restart do not change it
  • Direct IPv6 only works while the box is running; it does not wake stopped boxes
  • It is a separate access plane from the managed HTTPS ingress — custom domains and the canonical https://<box>... URL remain the right path for HTTP, wakeup, idle tracking, and TLS
  • Pricing is unchanged — direct IPv6 is included, not a separate SKU
  • Direct IPv6 is assigned to all new boxes
16Can I use mosh?

Yes. Every new box has direct IPv6, so Mosh works while the box is running. Mosh needs a direct UDP path to the guest, which the managed SSH bastion plane does not provide, so you connect straight to the box's IPv6 address:

$ mosh root@<ipv6>

Use the IPv6 shown for the box in list or show. Mosh does not participate in wakeup or idle tracking, so the box must already be running — start it first through the normal Shellbox flow (e.g. ssh mybox@shellbox.dev, then disconnect with keepalive on, or simply leave it running).

17Can I SSH in as a non-root user?

Through the managed Shellbox SSH endpoint, the SSH username selects the box name: ssh mybox@shellbox.dev connects to box mybox and logs into the guest as root. So non-root guest usernames are not available through that bastion path.

If you want normal Linux users, create them inside the box and use the box's direct IPv6 address:

root@mybox:~# adduser alice
root@mybox:~# mkdir -p /home/alice/.ssh
root@mybox:~# cp /root/.ssh/authorized_keys /home/alice/.ssh/authorized_keys
root@mybox:~# chown -R alice:alice /home/alice/.ssh

$ ssh alice@<ipv6>

Direct IPv6 works while the box is running and does not wake stopped boxes. Start it first through the Shellbox SSH flow, or keep it running with ssh shellbox.dev keepalive mybox. If you only need to become another user occasionally, you can also connect normally and run su - alice or sudo -iu alice inside the box.

18How do email endpoints work?

Each box gets an email address like dev1-a1b2c3d4@in.shellbox.dev. Inbound mail reception is handled by Cloudflare (outside this repo/app), which forwards incoming mail as an HTTP POST request to /email on your box's HTTPS endpoint.

19How do I transfer files?

Standard SCP and SFTP:

$ scp file.txt dev1@shellbox.dev:/root/
$ scp dev1@shellbox.dev:/root/file.txt ./
$ sftp dev1@shellbox.dev
20Which Docker or OCI images are supported?

Current OCI support is intentionally narrow in v1. Supported images should be:

  • public images
  • linux/amd64
  • Ubuntu-like userspaces (Ubuntu, Debian, and derivatives)
  • images with apt-get available so shellbox can inject SSH and guest runtime packages

A good starting point is something like docker.io/library/ubuntu:24.04, docker.io/library/debian:bookworm-slim, or any Ubuntu-derived image that still includes package manager support.

Today, minimal images from other distributions, images for other CPU architectures, private registries, and images without the expected userspace tools may fail preparation.

21Does shellbox run Docker containers or preserve CMD/ENTRYPOINT?

No. shellbox turns a Docker/OCI image into the root filesystem of a normal microVM. It does not run Docker itself inside the product workflow.

That means Docker/container runtime semantics such as CMD, ENTRYPOINT, EXPOSE, health checks, and container namespaces are not preserved as Docker behavior. You SSH into a VM and run whatever processes you want inside it.

The usual workflow is:

$ ssh shellbox.dev image prepare docker.io/library/debian:bookworm-slim
$ ssh shellbox.dev create-from-oci mybox docker.io/library/debian:bookworm-slim
$ ssh mybox@shellbox.dev
22How do I connect to GitHub from my box?

Several options, from quickest to most permanent:

SSH agent forwarding — forward your local GitHub SSH key without copying it into the box:

$ ssh -A mybox@shellbox.dev
root@mybox:~# git clone git@github.com:user/repo.git

Add ForwardAgent yes to your ~/.ssh/config under Host shellbox.dev to make it permanent. Your private key never leaves your machine.

HTTPS with a personal access token — no SSH keys needed:

root@mybox:~# git clone https://github.com/user/repo.git
Username: your-username
Password: ghp_xxxxxxxxxxxx   # paste a personal access token

Generate a token at github.com/settings/tokens. To avoid re-entering it: git config --global credential.helper store

GitHub CLI — interactive login with device code flow:

root@mybox:~# apt install -y gh
root@mybox:~# gh auth login

Generate a key on the box — for a dedicated deploy key:

root@mybox:~# ssh-keygen -t ed25519
root@mybox:~# cat ~/.ssh/id_ed25519.pub

Add the public key to your GitHub account (github.com/settings/keys) or as a deploy key on a specific repo.

23What are the resource limits?

Base box (x1): 2 vCPUs, 4GB RAM, 50GB SSD. Sizes scale up to x8 (16 vCPUs, 32GB RAM, 400GB SSD). Billing scales proportionally. Per account: up to 16 running slots and 64 total slots, where each box counts as its size in slots (e.g., an x4 box uses 4 slots). Network bandwidth is shared and may be throttled if it affects other users.

24What are box sizes?

Box sizes are multipliers from x1 to x8 that scale vCPU, RAM, disk, and billing rates. Create a sized box with ssh shellbox.dev create mybox x2. Size is set at creation and cannot be changed — delete and recreate to resize. Duplicated boxes inherit the source box's size.

25How do I rename a box?
$ ssh shellbox.dev rename mybox newname

This updates the box name instantly. The box's URL and email address will change to reflect the new name. The box can be running or stopped — renaming is safe during active SSH sessions. Custom domains attached to the box are not affected by rename — they point to the VM, not the box name.

26Is my data backed up?

No. We do not perform backups. You are responsible for your data. Use scp or sftp to back up important files. You can also duplicate a stopped box as a point-in-time copy: ssh shellbox.dev duplicate <name> <backup>

27Where are the servers located?

Currently in Europe (Helsinki, Finland). A US region is planned — if that matters to you, upvote or comment on the tracking issue.

28Can I access my box from multiple devices?

Yes, two ways. You can copy your private key to your other devices, or — better — link additional SSH keys to your account: ssh shellbox.dev key add "<pubkey>". Each linked key gets full access to your boxes. Run ssh shellbox.dev key list to manage your keys.

29Does Docker work inside a box?

Yes — in stock boxes. Stock boxes ship with Ubuntu 24.04 LTS and Docker pre-installed. No setup needed:

$ ssh mybox@shellbox.dev
root@mybox:~# docker run hello-world

You can pull images, build containers, and run docker compose like you would on any Linux server.

OCI image-backed boxes (created with create-from-oci) do not include Docker. They use whatever software the source image provides. You can install Docker yourself if the image supports it.

30Is nested virtualization supported?

Yes. Create your box with --ch to use Cloud Hypervisor, which passes through the host CPU virtualization capabilities. /dev/kvm is available inside the box, so you can run KVM-based workloads — including Firecracker, QEMU, or other hypervisors — inside your box.

$ ssh shellbox.dev create mybox --ch

Nested virtualization requires the host to have it enabled (Intel VMX nested or AMD SVM npt). All current shellbox hosts support this.

The default backend (Firecracker) does not support nested virtualization but has faster snapshots. Use --ch when you need /dev/kvm inside the box.

31What happens if I shut down the box from inside?

It works fine. If you run shutdown -h now (or poweroff, halt, etc.) inside the box, the SSH connection will close and the box will stop — just like a normal disconnect. When you reconnect, the box boots fresh from disk with all your files intact. The only difference from a normal disconnect is that the in-memory snapshot is discarded (since the guest OS was halted), so running processes won't be preserved — but everything on disk is safe.

Note: If your box has keepalive (or wakeup/cron) enabled, shutting down from inside will not stop the box from Shellbox's perspective. The box will still show as "running" and bill at the running rate, since Shellbox honors the keepalive flag on disconnect. Use ssh shellbox.dev stop <name> to actually stop a keepalive box — see Can a coding agent stop my box when it's done? for how to do this from inside the box by copying your SSH key in.

shellbox SSH API

Programmatic Linux VM management over SSH. No REST endpoints, no API tokens, no SDK. Your SSH key authenticates every call. Add --json for structured output.

# JSON commands

Generated from the same schema returned by ssh shellbox.dev help --json. If the product schema changes, this tab changes with it.

list --json
List your boxes
Response
boxes: array of: name: string id: string size: integer source: stock | oci backend: fc | ch state: running | stopped | stopping mode: stop | keepalive | wakeup | cron idle_timeout_min: integer | null (wakeup only) cron_interval_min: integer | null (cron only) cron_runtime_min: integer | null (cron only) url: string | null email: string | null public_ipv6: string | null domain_count: integer
show <name> --json
Show detailed box metadata
Response
name: string | null id: string state: running | stopped | stopping size: integer backend: fc | ch backend_label: Firecracker | Cloud Hypervisor source: stock | oci url: string | null email: string | null mode: stop | keepalive | wakeup | cron idle_timeout_min: integer | null (wakeup only) cron_interval_min: integer | null (cron only) cron_runtime_min: integer | null (cron only) image_ref: string | null image_digest: string | null prepared_image_id: string | null public_ipv6: string | null domains: array of: domain: string status: pending | active verified_at: string | null last_error: string | null
billing --json
Account balance and usage
Response
balance: number funds_added: number funds_refunded: number usage_cost: number hourly_rate: number remaining_hours: number | null pending_refunds: array of: amount: number status: string created_at: string boxes: array of: name: string size: integer state: string hourly_rate: number
payments --json
Payment history
Response
pending: array of: amount: number created_at: string recent: array of: amount: number timestamp: string
key list --json
List SSH keys
Response
keys: array of: fingerprint: string type: string comment: string current: boolean
key add "<public-key>" --json
Add an SSH key
Response
fingerprint: string type: string comment: string action: added
key remove <fingerprint-prefix> --json
Remove an SSH key
Response
fingerprint: string action: removed
create <name> [xN] [--fc|--ch] --json
Create a new stock box
Response
name: string id: string size: integer backend: fc | ch url: string email: string connect: string public_ipv6: string | null
create-from-oci <name> <image-ref> [xN] [--fc|--ch] --json
Create a box from a prepared OCI image
Response
name: string id: string size: integer backend: fc | ch image_ref: string image_digest: string url: string email: string connect: string public_ipv6: string | null
duplicate <source> <name> --json
Copy a stopped box
Response
name: string source: string size: integer url: string connect: string public_ipv6: string | null
rename <name> <new-name> --json
Rename a box
Response
old_name: string new_name: string url: string email: string public_ipv6: string | null
stop <name> --json
Stop a box
Response
name: string status: stopping | already_stopped | already_stopping mode_preserved: wakeup | cron | null
delete <name> --json
Delete a box
Response
name: string status: deleted
keepalive <name> --json
Toggle keepalive
Response
name: string keepalive: boolean box_stopped: boolean box_started: boolean
wakeup <name> [idle_minutes] --json
Toggle wakeup
Response
name: string wakeup: boolean idle_timeout_min: integer | null box_stopped: boolean
cron <name> <interval_min> [runtime_min] --json
Toggle cron
Response
name: string cron: boolean interval_min: integer | null runtime_min: integer | null box_stopped: boolean
funds <amount> --json
Add funds (returns checkout URL)
Response
amount: number checkout_url: string
refund <amount> --json
Refund funds
Response
amount: number status: pending
promocode <code> --json
Redeem a promo code
Response
code: string added: number balance: number
image prepare <image-ref> --json
Prepare an OCI image
Response
display_ref: string digest: string status: string state: string rootfs_path: string | null error: string | null
image status <image-ref> --json
Check OCI image preparation status
Response
display_ref: string canonical_ref: string status: string | null digest: string architecture: string guest_layer_version: string rootfs_path: string | null error: string | null
domain add <box> <hostname> --json
Attach a custom domain to a box
Response
domain: string box: string status: pending action: added cname_target: string
domain verify <box> <hostname> --json
Verify DNS and activate a custom domain
Response
domain: string box: string status: pending | active action: verified | verification_failed | already_active error: string | null
domain remove <box> <hostname> --json
Remove a custom domain from a box
Response
domain: string box: string action: removed
domain list <box> --json
List custom domains for a box
Response
box: string canonical_url: string | null domains: array of: domain: string status: pending | active verified_at: string | null last_error: string | null created_at: string | null

# Session / non-JSON commands

These commands are part of the SSH surface area but are interactive or transport-level, so they do not return JSON schemas.

ssh <name>@shellbox.dev
Open an interactive SSH session; starts/resumes the box.
scp file.txt <name>@shellbox.dev:/root/
Standard SCP file upload/download via the SSH bastion.
sftp <name>@shellbox.dev
Standard SFTP subsystem for IDEs and file transfer.
ssh <name>@shellbox.dev -- <command>
Run a non-interactive command inside a box.
ssh -L 8080:localhost:80 <name>@shellbox.dev
Local/remote/SOCKS forwarding through a box.
ssh shellbox.dev help [--json]
Human help, or the canonical JSON schema reference.
ssh shellbox.dev about
Product overview text.

# Stability guarantee

The --json output is stable: fields are only added, not removed or renamed, and existing types do not change. If a breaking change is ever needed, it will ship under a new flag such as --json-v2.

$ ssh shellbox.dev help --json

Product updates and technical notes. Entries are collapsed so the whole archive stays on this page.

01April 8, 2026 — New Features for April 8th, 2026

Two important upgrades are live today: Cloud Hypervisor boxes with nested virtualization, and a stable JSON interface for scripting and automation.

Cloud Hypervisor via --ch

Firecracker remains the default backend for new boxes because it has the fastest snapshot/resume path. But now, when you need nested virtualization, you can create a box on Cloud Hypervisor with --ch.

# create a box on Cloud Hypervisor
$ ssh shellbox.dev create nestedbox --ch

Creating box...

Box 'nestedbox' created successfully (x1)
URL:   https://nestedbox-a1b2c3d4.shellbox.dev
Email: nestedbox-a1b2c3d4@in.shellbox.dev

Connect with: ssh nestedbox@shellbox.dev

Inside a CH-backed box, /dev/kvm is available. That means you can run KVM workloads inside your shellbox box — Firecracker, QEMU, or other virtualization-based tools — as long as the host supports nested KVM.

$ ssh nestedbox@shellbox.dev
root@nestedbox:~# ls -l /dev/kvm

This is especially useful for CI jobs, low-level systems work, sandboxing hypervisors, kernel experiments, and anything else that needs real virtualization inside the guest.

No migration, no surprise backend switch

Backend choice is per box. Existing boxes keep using the backend they were created with. Firecracker boxes stay on Firecracker. CH boxes stay on Cloud Hypervisor. Nothing is silently migrated underneath you.

In practice, that means you can keep using the default Firecracker path for fast snapshots and create CH boxes only when you need nested virt:

# default backend
$ ssh shellbox.dev create fastbox

# nested virtualization backend
$ ssh shellbox.dev create kvmbox --ch

--json for automations

shellbox commands now have a machine-readable mode built for scripts, CI, agents, and automation tooling. Add --json and you get structured output instead of human-formatted text.

# create a box and capture its metadata
$ ssh shellbox.dev create api-box --json
{
  "name": "api-box",
  "id": "a1b2c3d4-...",
  "size": 1,
  "backend": "fc",
  "url": "https://api-box-a1b2c3d4.shellbox.dev",
  "connect": "ssh api-box@shellbox.dev"
}

# list boxes and filter with jq
$ ssh shellbox.dev list --json | jq '.boxes[] | {name, state, backend}'

# delete when done
$ ssh shellbox.dev delete api-box --json

You can use this from shell scripts, Python, GitHub Actions, CI runners, or AI agents without scraping terminal text.

Backward compatibility guarantee

The JSON output is intended to be stable over time. Fields may be added, but existing fields are not removed or renamed, and existing types do not change. If a breaking change is ever necessary, it will ship under a new flag such as --json-v2 rather than changing the meaning of --json.

That means you can build automation against today's output and expect it to keep working as shellbox grows.

Full schema reference

The command-by-command JSON schema reference is live at /ssh-api.html. You can also inspect the current interface directly from the CLI:

$ ssh shellbox.dev help --json

Try it

# fast default box
$ ssh shellbox.dev create dev1

# Cloud Hypervisor box with nested virt support
$ ssh shellbox.dev create dev-kvm --ch

# automation-friendly output
$ ssh shellbox.dev show dev-kvm --json
$ ssh shellbox.dev list --json | jq '.boxes[] | select(.backend=="ch")'

Questions or issues? Open an issue or email support@shellbox.dev.

02March 27, 2026 — Introducing the shellbox SSH API

Every shellbox command now has a documented, stable JSON interface. Add --json to any command and get structured output you can parse, pipe, and build on. The full reference is at /ssh-api.html.

No REST endpoints. No API tokens to rotate. No OAuth dance. No SDK to install. Your SSH key authenticates every call. If you can run ssh, you have an API client.

What it looks like

# create a box programmatically
$ ssh shellbox.dev create mybox --json
{
  "name": "mybox",
  "id": "a1b2c3d4-...",
  "size": 1,
  "url": "https://mybox-a1b2c3d4.shellbox.dev",
  "connect": "ssh mybox@shellbox.dev"
}

# list boxes
$ ssh shellbox.dev list --json | jq '.boxes[] | select(.state=="running")'

# delete when done
$ ssh shellbox.dev delete mybox --json
{"name": "mybox", "status": "deleted"}

Every command is covered

The full API covers box lifecycle (create, list, show, duplicate, rename, stop, delete), modes (keepalive, wakeup, cron), OCI images (image prepare, image status, create-from-oci), billing (billing, funds, payments, refund), and key management (key list, key add, key remove).

Every endpoint is documented with its exact response schema.

Why SSH as an API transport?

SSH gives you authentication, encryption, and multiplexing for free. There are SSH libraries in every language. There's no server to provision, no webhook URL to configure, no token to store in your CI secrets. Your ~/.ssh/id_ed25519 is the only credential you need.

For scripting and automation, it means you can manage infrastructure with a bash one-liner:

# spin up a CI runner, run tests, tear down
$ BOX=$(ssh shellbox.dev create ci-$RANDOM --json | jq -r .name)
$ ssh "$BOX@shellbox.dev" -- make test
$ ssh shellbox.dev delete "$BOX" --json

For AI agents, it means your agent gets a real Linux sandbox with Docker, a public URL, and full root — all accessible via standard SSH that every agent framework already supports.

Stability guarantee

The --json output is a stable interface. Fields are only added, never removed or renamed. Types don't change. If a breaking change is ever necessary, it will ship under a new flag (--json-v2) and the original --json output will continue to work unchanged.

You can also get the full schema reference at any time:

$ ssh shellbox.dev help --json
→ Full SSH API Reference

Complete documentation with response schemas for every command.

03March 10, 2026 — New Features for March 10th, 2026

A big batch of improvements shipping today. Stock boxes get a better base image, Docker works out of the box, you can now create boxes from OCI images, and the SSH rate limit is raised.

Stock Image: Ubuntu 24.04 LTS

The stock box image is now Ubuntu 24.04 LTS (Noble Numbat). Every new box you create with create starts from this image. It's a clean, minimal Ubuntu server install with everything you'd expect.

Docker Works Out of the Box

Stock boxes now ship with Docker pre-installed and ready to go. No setup, no apt install, no adding yourself to the docker group. Just connect and run:

$ ssh dev1@shellbox.dev

Starting box...
Connected!

root@dev1:~# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

docker compose, multi-stage builds, volume mounts — it all works like you'd expect on any Linux server. Pull images, build containers, run your stack.

OCI Image-Backed Boxes

This is the big one. You can now create boxes from public Docker/OCI images. Instead of starting from the stock Ubuntu image, your box boots with the filesystem contents of whatever image you choose.

The workflow is two commands. First, prepare the image (this pulls it and builds a bootable rootfs):

$ ssh shellbox.dev image prepare docker.io/library/debian:bookworm-slim

Preparing image, this may take a couple of minutes...
Image prepared: docker.io/library/debian:bookworm-slim
Digest: sha256:abc123...
Status: ready

Then create a box from it:

$ ssh shellbox.dev create-from-oci mydebian docker.io/library/debian:bookworm-slim

Creating box...

Box 'mydebian' created successfully (x1)
URL:   https://mydebian-a1b2c3d4.shellbox.dev
Email: mydebian-a1b2c3d4@in.shellbox.dev

Connect with: ssh mydebian@shellbox.dev

If the image hasn't been prepared yet, create-from-oci will prepare it for you automatically — you'll see a "Preparing image..." message while it works.

You can check image preparation status anytime:

$ ssh shellbox.dev image status docker.io/library/debian:bookworm-slim

Image: docker.io/library/debian:bookworm-slim
Canonical ref: docker.io/library/debian:bookworm-slim
Status: ready
Digest: sha256:abc123...
Architecture: amd64
Guest layer: v1

Once prepared, images are cached on the server. Creating additional boxes from the same image is instant — no re-downloading.

OCI-backed boxes show up in list with an oci source tag and show displays the image reference and digest:

$ ssh shellbox.dev list

NAME          SIZE  SRC    STATE    URL
──────────────────────────────────────────────────────────────────────────
dev1          x2    stock  running  https://dev1-a1b2c3d4.shellbox.dev
mydebian      x1    oci    stopped  https://mydebian-a1b2c3d4.shellbox.dev

$ ssh shellbox.dev show mydebian

Name: mydebian
State: stopped
Size: x1
Source: oci
Image ref: docker.io/library/debian:bookworm-slim
Image digest: sha256:abc123...

What's Supported

Current OCI support focuses on:

  • Public images (no private registries yet)
  • linux/amd64 architecture
  • Ubuntu-like images with apt-get available (Ubuntu, Debian, and derivatives)

Good starting points:

  • docker.io/library/ubuntu:24.04
  • docker.io/library/debian:bookworm-slim
  • docker.io/library/node:22-bookworm
  • docker.io/library/python:3.13-bookworm
  • docker.io/library/rust:bookworm
  • docker.io/library/golang:1.23-bookworm

What It's Not

OCI-backed boxes are normal microVMs — not Docker containers. The image provides the filesystem contents, but Docker runtime semantics like CMD, ENTRYPOINT, EXPOSE, and health checks are not preserved. You SSH in and run whatever you want. See the FAQ for more details.

SSH Rate Limit Raised to 200/min

The per-IP SSH connection rate limit has been raised from 100 to 200 connections per minute. This helps with workflows that open many short-lived SSH connections in quick succession — automated scripts, CI pipelines, or rapid scp transfers.

If you were hitting the old limit, you shouldn't anymore.

Try It

# create a stock box with Docker
$ ssh shellbox.dev create dev1
$ ssh dev1@shellbox.dev
root@dev1:~# docker run hello-world

# create a box from a Debian image
$ ssh shellbox.dev create-from-oci mydebian docker.io/library/debian:bookworm-slim

# create a box from a Python image
$ ssh shellbox.dev create-from-oci pybox docker.io/library/python:3.13-bookworm

Questions or issues? Open an issue or email support@shellbox.dev.

04January 2026 — Racing to the Bottom, Done Right

We launched on Hacker News. Someone commented: "Have fun racing to the bottom."

They have a point. Beating a $4/month Hetzner box sounds impossible. It's not. This post explains how.

TL;DR: $0.02/hr running. $0.50/month parked. Cheaper than Hetzner under 186 hrs/month.

What is Shellbox?

Shellbox is Linux boxes via SSH. It feels like a 24/7 server - your tmux sessions persist, background jobs resume, scp just works - but when you disconnect, the box stops. And so does billing.

Open VS Code, Zed, or a terminal. Connect. That's it. No web console, no "start instance" button, no CLI tools. When you're done, close your laptop. The box suspends, you stop paying, and everything's still there when you come back.

The Problem with Always-On Pricing

Traditional cloud providers charge you for a VM whether you're using it or not. Hetzner's CX22 (2 vCPU, 4GB RAM, 40GB SSD) costs a flat rate around the clock. Great if you're running a production server. Wasteful if you're a developer who codes a few hours a day.

"But AWS and Azure let you stop instances!" True. AWS t3.medium costs $0.0416/hr when running. Stop it, and you still pay ~$4/month for 50GB EBS storage. Azure B2s is similar. That's 8x our stopped cost, and their running rate is 2x ours.

Developers don't use their dev boxes 24/7. Most of us work 4-8 hours a day, maybe less. Why pay for the other 16-20 hours?

How We Make It Work

The key insight: Hetzner (and most providers) need to reserve memory for each VM, even when it's idle. Memory is expensive. Our boxes can stop and resume instantly. When stopped, we need zero memory - just disk space for the snapshot.

Our bottleneck is disk, not memory. And disk is cheap.

The Math

Let's compare shellbox vs the alternatives for a similar spec (2 vCPU, 4GB RAM, 50GB disk):

Hours/month Shellbox AWS/Azure Hetzner
20 hrs $0.89 $4.83 $4.09
40 hrs $1.27 $5.66 $4.09
80 hrs $2.04 $7.33 $4.09
120 hrs $2.82 $8.99 $4.09
160 hrs $3.59 $10.66 $4.09
186 hrs $4.09 $11.74 $4.09
300 hrs $6.29 $16.48 $4.09
720 hrs (24/7) $14.40 $29.95 $4.09

Shellbox formula: running_hrs * $0.02 + stopped_hrs * $0.000694

AWS/Azure formula: running_hrs * $0.0416 + $4/month storage

If you use your box less than 186 hours per month, shellbox is cheaper than Hetzner. That's ~8.5 hrs every weekday, or ~6 hrs/day if you code weekends too. AWS/Azure with stop/start is never cheaper than either - you're paying premium rates for the privilege of stopping.

What About Abuse?

Won't cheap stopped instances attract crypto miners and other abuse?

Nope. Our running costs are roughly 3x Hetzner's rate. If you want to mine bitcoin or run botnets, you'd do it much cheaper elsewhere. Our pricing model naturally selects for legitimate dev workloads: burst usage with long idle periods.

The Competition

We're not the only ones trying to solve this. Here's how we compare:

Sprites.dev offers persistent Linux environments with checkpoint/restore. Their pricing: $0.07/CPU-hour + $0.04375/GB-hour. For a 2 vCPU, 4GB RAM instance, that's roughly $0.315/hr while running - over 15x our rate. They use Firecracker too, but charge memory by the hour. Also: no real SSH access, only their CLI/API.

Exe.dev offers persistent SSH VMs at $20/month for up to 25 VMs - but here's the catch: all 25 VMs share a pool of just 2 CPUs and 8GB RAM total. Run a few VMs and you're quickly resource-starved. It's a flat subscription, so you pay whether you use them or not.

AWS and Azure offer pay-as-you-go too - but it's not the same experience. You have to log into a web console to start your instance, wait 30-60 seconds for it to boot, and remember to stop it when you're done or you keep paying. That's not "connect and code" - that's instance management.

Service Running Cost Stopped Cost Real SSH Auto Start/Stop
Shellbox $0.02/hr $0.50/month Yes Yes
AWS t3.medium $0.0416/hr ~$4/month Yes No (manual)
Azure B2s $0.0416/hr ~$4/month Yes No (manual)
Sprites ~$0.315/hr storage only No (CLI/API) Yes
Exe $20/month flat Yes Always on
Hetzner ~$4.09/month flat Yes Always on

Shellbox also offers features beyond the basics: duplicate lets you clone a box instantly - useful for testing changes without risking your setup. Each box gets a web endpoint (https://<box>.shellbox.dev) that wakes the VM on request, so you can expose dev servers without keeping the box running 24/7.

How It Works (Technical Details)

We run on Hetzner auction servers - dedicated hardware at steep discounts. This gives us predictable costs and full control.

The stack: Caddy handles TLS and routes traffic. Behind it, a custom Python SSH server built on asyncssh manages connections. HTTP requests to your box's URL endpoint go through an HTTP proxy that wakes the VM if needed.

Each box runs in an isolated microVM. By default, new boxes use Firecracker for fast snapshots. Cloud Hypervisor is also available via --ch when you need Docker and nested virtualization support. Both offer sub-second boot times, strong isolation, and minimal overhead.

Core/External architecture. The server is split into two parts. Core handles SSH connections - it's intentionally dumb, stateless, and stable. External handles all business logic: VM lifecycle, billing, commands. External runs as a subprocess, invoked fresh for each operation.

This split enables two things. First, fast disconnects: when you close your session, Core returns immediately. It fires off a background call to External which handles the snapshot and cleanup - you don't wait for it. Second, hot-swappable logic: we can update pricing, add new commands (like duplicate), or change billing algorithms without restarting the server or disturbing connected users. The next External call just picks up the new code.

Snapshots. When your last session disconnects, the hypervisor pauses the VM and dumps memory to disk. Memory snapshots are memory-mapped files stored on NVMe - the OS pages them efficiently, and resume takes under a second. Rootfs images live on larger HDDs. When you reconnect, we restore from snapshot and you're back exactly where you left off - same processes, same shell history, same everything.

Btrfs and reflinks. Our HDD storage uses btrfs, which enables copy-on-write via reflinks. When you run duplicate to clone a box, we don't copy the entire 50GB disk image - we create a reflink using cp --reflink=auto. This is instant (just metadata), and the clone shares blocks with the original. Space is only consumed as you make changes. Creating a new box from the base image works the same way. This is why duplicate completes in under a second regardless of disk size.

The Honest Take

Shellbox isn't for everyone:

  • Running 24/7? Use Hetzner. We'll cost you 3x more.
  • Need massive RAM? We're currently at 4GB (more options coming).
  • Running production? We don't guarantee uptime.

But if you're a developer who wants a Linux box to hack on for a few hours a day, we're probably the cheapest option that actually works. Real SSH. Real persistence. Real savings.

Try it: ssh shellbox.dev help