Skip to content
Guides · Recipes

How to Run a HashiCorp Vault Dev Server in a Cloud Sandbox

Updated October 27, 2026 .md

Short answer: Install Vault from HashiCorp's apt repo, run vault server -dev under systemd, and vault kv put and kv get work at once. The dev server is in-memory and unsealed, for learning and testing only. Its secrets survived stop and resume with memory, and were gone after a restart or a cold boot.

At a glance#

We ran everything below on production on October 27, 2026, with Vault 2.2.1 on a small sandbox (2 vCPU, 4 GB). For the cold boot we resized it to default. Each number is from a single run, and yours will differ. Every secret value on this page is fake.

Step Result
Install with apt 10.3 s
systemctl enable --now to a working server 232 ms
KV read over HTTP, inside the sandbox (100 reads) median 0.3 ms
vault kv get with the CLI, inside the sandbox 83 ms per call, mostly process start
KV read from a laptop through the private hosted URL (20 reads) median 192 ms
Memory about 160 MB RSS per server
sbx stop --wait then sbx resume (memory restored) Dev server kept running; secrets intact
sudo systemctl restart vault-dev All secrets gone; old tokens invalid
Resume on a bigger size (boots from disk) Dev server empty; file-storage server came back sealed, then had its data after unseal

What the dev server is, and what it isn't#

HashiCorp's dev server docs list what vault server -dev does. It stores all data encrypted in memory. It initializes and unseals itself. It listens on 127.0.0.1:8200 without TLS. It mounts a KV v2 engine at secret/. It also stores a root token so the vault CLI works right away. The same page calls it insecure and says it loses data on every restart.

So use it to learn Vault, to test code that reads secrets, or to give an agent a throwaway Vault. Don't put real secrets in it. To give a sandbox a real secret, see Pass secrets to a sandbox safely. This page doesn't repeat that guide.

1. Install Vault and run the dev server under systemd#

Use HashiCorp's own apt repository (install page). Put the commands in install.sh:

set -e
wget -qO - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list >/dev/null
sudo apt-get update -qq && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq vault >/dev/null
vault version
sbx new --name vault-dev --type small --no-env
id=sb_66mil9w3dd    # the id that sbx new printed

sbx scp ./install.sh $id:/home/user/
sbx exec $id --timeout 600 "bash install.sh"
Vault v2.2.1 (0e7c41b936218bd2401ab0f891c93bec10e2e8e4), built 2026-10-22T16:27:49Z

sbx exec stops a command after 30 s by default, so keep --timeout 600 on installs.

Run the server as a systemd unit, not a background shell command. The unit runs it as user with HOME set, so the dev server writes its root token to /home/user/.vault-token (mode 600). The CLI then reads it from there, and you never have to copy or print the token. Save this as vault-dev.service:

[Unit]
Description=Vault dev server (in-memory, for testing only)
After=network-online.target

[Service]
User=user
Environment=HOME=/home/user
ExecStart=/usr/bin/vault server -dev -dev-listen-address=127.0.0.1:8200
Restart=always

[Install]
WantedBy=multi-user.target
sbx scp ./vault-dev.service $id:/home/user/
sbx exec $id "sudo mv vault-dev.service /etc/systemd/system/ && sudo systemctl daemon-reload && sudo systemctl enable --now vault-dev
export VAULT_ADDR=http://127.0.0.1:8200
until vault status >/dev/null 2>&1; do sleep 0.1; done
vault status"
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         2.2.1
…
Storage Type    inmem
…
HA Enabled      false

Sealed false and Storage Type inmem sum up the dev server. The unit has its own name, vault-dev, so it won't collide with a unit for a configured server.

2. kv put and kv get#

sbx exec $id "export VAULT_ADDR=http://127.0.0.1:8200
vault kv put secret/myapp/db username=app password=fake-password-123
vault kv get secret/myapp/db"
==== Secret Path ====
secret/data/myapp/db

======= Metadata =======
Key                Value
---                -----
created_time       2026-10-27T10:16:01.592293466Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
…
====== Data ======
Key         Value
---         -----
password    fake-password-123
username    app

KV v2 keeps versions. After a second put with password=fake-password-456, vault kv get -version=1 -field=password secret/myapp/db still returned fake-password-123. Note the path: the CLI takes secret/myapp/db, and the HTTP API uses secret/data/myapp/db.

Reads are fast inside the sandbox. A loop of 100 curl reads against /v1/secret/data/myapp/db had a median of 0.3 ms (min 0.2 ms, max 2.5 ms). A vault kv get with the CLI took 83 ms per call, and nearly all of that is starting the vault binary. So in a hot loop, call the HTTP API or use a client library.

3. Give a client a narrow token#

The root token can do everything. Code under test should get a token that can only read its own path. Run this policy.sh in the sandbox. It writes the new token to a mode-600 file and prints only its length:

umask 077
vault policy write myapp-read - <<'P'
path "secret/data/myapp/*" {
  capabilities = ["read"]
}
P
vault token create -policy=myapp-read -ttl=1h -field=token > ~/myapp-read.token
wc -c < ~/myapp-read.token
Success! Uploaded policy: myapp-read
95

4. Reach the API from your laptop on a private URL#

The dev server listens on 127.0.0.1, so host it with --localhost (hosting docs):

sbx host $id 8200 --localhost --title "Vault dev"
{"ok":true,"type":"port.hosted","sandboxId":"sb_66mil9w3dd","port":8200,"url":"https://mossy-bright-fennel-8200.box.sandboxer.com?_token=<token>","access":"private","isProtected":true,"localhost":true}

Copy the read-only token out with sbx scp $id:/home/user/myapp-read.token ./read.token. Then put it in a header file, so it stays out of your shell history and ps:

B=https://mossy-bright-fennel-8200.box.sandboxer.com
umask 077; printf 'X-Vault-Token: %s\n' "$(cat read.token)" > vh.txt

curl -s -o /dev/null -w "no token: %{http_code}\n" $B/v1/sys/health
curl -s -o /dev/null -w "with token: %{http_code}\n" -c jar.txt "$B/?_token=<token>"
curl -s -b jar.txt $B/v1/secret/data/myapp/db
curl -s -b jar.txt -H @vh.txt $B/v1/secret/data/myapp/db | jq -c .data.data
curl -s -b jar.txt -H @vh.txt -X POST -d '{"data":{"x":"y"}}' $B/v1/secret/data/myapp/db
no token: 401
with token: 302
{"errors":["permission denied"]}
{"password":"fake-password-456","username":"app"}
{"errors":["1 error occurred:\n\t* permission denied\n\n"]}

Here two locks work in turn. Without the hosted URL's token, Sandboxer's proxy returns 401, and Vault never sees the request. Past the proxy, Vault returns 403 until you send a Vault token. The read-only token can read but not write. /ui/ returned 200 through the same URL, so the Vault web UI works there too. You log in to it with a Vault token. Twenty reads from our laptop took a median of 192 ms, most of it network distance to the sandbox.

Keep the URL private. A dev server has no TLS of its own and an all-powerful root token. The hosted URL adds HTTPS, but with --public the only lock left would be Vault's own token check.

5. What happens to the data on stop, restart and cold boot#

We also ran a second Vault on the same sandbox with file storage (step 6), so we could compare the two.

What happened Dev server (inmem) File storage server
sbx stop $id --wait (2.2 s), then sbx resume $id (1.3 s), memoryRestored: true Same process (ActiveEnterTimestamp unchanged). Secret still there. The hosted URL and its cookie worked again Same process, still unsealed
sudo systemctl restart vault-dev No value found at secret/data/myapp/db. The read-only token from before was rejected: permission denied, invalid token Not affected
sbx resume $id --type default (memoryRestored: false, resumeReason: "resized") systemd started a fresh, empty dev server with a new root token in ~/.vault-token systemd started it; "sealed":true until unsealed, then the secret was there

A resume with memory restored keeps the dev server's data because the process never stops. You can't count on that, though. A resume boots from disk when you change the size. It also boots from disk when no machine with the same CPU type is free (snapshots docs). A restart of the service wipes it too. Any time the dev server process starts again, it starts empty, and every token you handed out stops working. If your test needs its secrets, seed them in a setup script that runs after each start.

6. Optional: a single node with file storage#

To keep data across a cold boot, run a normal server with the filesystem storage backend. HashiCorp's docs say it's officially supported and has no high availability. This is still a test setup: one node, no TLS, and here the unseal key sits on the same disk as the data. Save config.hcl:

storage "file" {
  path = "/home/user/vault-file/data"
}

listener "tcp" {
  address     = "127.0.0.1:8210"
  tls_disable = true
}

api_addr      = "http://127.0.0.1:8210"
disable_mlock = true
ui            = true

vault-file.service is the dev unit with ExecStart=/usr/bin/vault server -config=/home/user/vault-file/config.hcl. Copy both files to the sandbox and enable the unit. Then initialize the server with one key share and write the output to a mode-600 file, not your terminal:

umask 077
mkdir -p ~/vault-file/data && mv ~/config.hcl ~/vault-file/
sudo mv ~/vault-file.service /etc/systemd/system/ && sudo systemctl daemon-reload && sudo systemctl enable --now vault-file
export VAULT_ADDR=http://127.0.0.1:8210
vault operator init -key-shares=1 -key-threshold=1 -format=json > ~/vault-file/init.json

Unseal with unseal.sh. It sends the key on stdin, so the key never appears in a command line. We tried vault operator unseal - first, and Vault 2.2.1 rejected it with 'key' must be a valid hex or base64 string.

jq '{key: .unseal_keys_b64[0]}' ~/vault-file/init.json | curl -s -X PUT -d @- http://127.0.0.1:8210/v1/sys/unseal | jq -c '{sealed, progress}'
bash unseal.sh
export VAULT_TOKEN=$(jq -r .root_token ~/vault-file/init.json)
vault secrets enable -path=secret kv-v2
vault kv put secret/myapp/db password=fake-file-password >/dev/null
vault kv get -field=password secret/myapp/db
{"sealed":false,"progress":0}
Success! Enabled the kv-v2 secrets engine at: secret/
fake-file-password

A non-dev server doesn't mount secret/ for you, which is why secrets enable is there. After the cold boot in step 5, the server came up sealed. One bash unseal.sh brought back fake-file-password. For anything beyond testing, follow HashiCorp's production guidance: use integrated storage, TLS, and auto-unseal or key holders who aren't the server itself.

7. Clean up#

sbx delete $id --yes

After the delete, sbx info returned 404 not_found, and so did the hosted URL. A small sandbox bills at half the default rate of $0.036/hour while it runs, and nothing while it's stopped.

Vault's license, and OpenBao#

As of October 27, 2026, the LICENSE file in hashicorp/vault is the Business Source License 1.1. It covers Vault 1.15.0 and later. Its additional use grant allows production use, except offering Vault to third parties as a hosted or embedded product that competes with the licensor's paid versions. Each version converts to MPL 2.0 four years after it's published. HashiCorp announced the switch from MPL 2.0 to BSL 1.1 on August 10, 2023. The LICENSE file names IBM as the licensor today.

OpenBao describes itself as an open source, community-driven fork of Vault, managed by the Linux Foundation's OpenSSF, where it is a Sandbox project. Its GitHub repository is licensed MPL-2.0. We didn't test OpenBao for this page. If you use it, check its docs for its binary name and dev mode.

FAQ#

Is the Vault dev server safe for real secrets?#

No. HashiCorp documents it as insecure: in-memory, auto-unsealed, no TLS, with a root token stored on disk for the CLI. Use fake values, and use Pass secrets to a sandbox safely for real ones.

Do my dev-server secrets survive an auto-stop?#

Only if the resume restores memory (memoryRestored: true). In our tests, a restart of the service or a boot from disk started an empty server, and old tokens stopped working. If you need data across boots, use file storage (step 6) or re-seed after each start.

Why does my old token say "invalid token"?#

The dev server started again, maybe after a restart or a boot from disk. Every start makes a new root token and an empty token store. Read the new root token from ~/.vault-token inside the sandbox and create fresh child tokens.

Which size do I need?#

small (2 vCPU, 4 GB) was enough. Each Vault server used about 160 MB of memory.

Why does the hosted URL return 401 before Vault answers?#

The URL is private by default. Open the full URL with ?_token= once and it sets a cookie. Requests without it are stopped by Sandboxer's proxy and never reach Vault.

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