Custom domains, TCP ports, dedicated addresses and private networks
Four ways to connect sandboxes to the rest of your world. They are for paid
accounts: an account that has not added credit gets payment_required (402).
A custom domain or a TCP port also needs the sandbox it serves to be a paid one.
- Custom domain: a sandbox's web port at your own hostname, with HTTPS.
- TCP port: a public
address:portfor anything that is not HTTP, such as Postgres, Redis, MQTT or a game server. - Dedicated outbound address: every sandbox of your account sends from one address of its own, so you can allow-list it.
- Private network: a WireGuard tunnel from your own network, in any cloud or on your premises, into your sandboxes.
None of them belongs to one sandbox alone, so each is its own product in the CLI,
the SDKs and MCP: runtime domain, runtime port, runtime address and
runtime tunnel; runtime.domains, runtime.ports, runtime.addresses and
runtime.tunnel; runtime_domain_*, runtime_port_*, runtime_address_* and
runtime_tunnel_*. They are not billed yet; the pricing page will
list their prices before they are.
Custom domains
Terminalruntime domain add app.example.com <sandbox> 3000The answer lists two DNS records to set at your DNS provider:
| Record | Name | Value | What it does |
|---|---|---|---|
| TXT | _runtime-challenge.app.example.com |
runtime-verify=<token> |
Proves the name is yours |
| CNAME | app.example.com |
domains.runtimehost.com |
Sends visitors to Runtime |
A name with no subdomain (example.com) cannot have a CNAME; set an A record
to the address the answer gives instead. Then check:
Terminalruntime domain verify app.example.comThe name goes live when the TXT record matches. The first visit gets its
certificate from Let's Encrypt, which takes a few seconds. Your server must
listen on 0.0.0.0 or localhost inside the sandbox, as for a
preview link, and be started with spawn, which keeps
it running. WebSockets work, and a paused sandbox is
woken by a visit, like a preview.
- Ownership is the TXT record. A CNAME pointing at Runtime proves nothing, so a record someone forgot to delete cannot be used to take their name. Each claim has its own token.
- The DNS owner wins. If another account proves the same name later, it takes the name over and your claim ends.
- To move the name to another sandbox or port, run
addagain with the new target. To stop serving it,runtime domain rm app.example.com. - Limits: 50 domains per account, 20 added a day. Certificates are issued for proved names only.
- Reports reach Runtime through the
X-Runtime-Reportheader on every answer and the abuse address, as for previews. Runtime can take a name down; it then stays down for every account.
TCP ports
Terminalruntime port open <sandbox> 5432# 203.0.113.10:23456psql "postgres://app@203.0.113.10:23456/app?sslmode=require"A TCP port carries raw TCP from a public address and port to a port inside the sandbox. Opening the same sandbox and port again returns the same public port.
- Anyone who knows the address can connect. Use your service's own authentication and TLS.
- Only TCP is carried. UDP (most game servers' own traffic, QUIC) is not.
- Limits: 5 ports per sandbox, 20 per account and 50 opened a day. Each sandbox's ports share 256 open connections, 50 new connections a second, and 32 connections from any one client address. Bandwidth and the daily byte quota are the same as the sandbox's outbound ones.
- A closed port rests for a day before anyone else can be given it, so a client still pointed at it never reaches someone else's service.
- A paused sandbox is woken by a connection, and its connections end when it stops, pauses or is deleted.
runtime port lslists them;runtime port close <portId>closes one.
Dedicated outbound addresses
Terminalruntime address reserve# 203.0.113.50From then on every sandbox of your account sends from that address, on every port, so a database, an API provider or a firewall can admit exactly you. No other account sends from it while you hold it.
- One IPv4 address per account, and one IPv6 with
--ipv6. runtime address release <addressId>gives it back, and your sandboxes send from the shared addresses again at once. A released address rests for 30 days before any other account gets it. Remove it from your allow-lists first.- Addresses are added to Runtime as accounts need them. If none is free, the
answer is
no_capacity(503): write to support.
Private networks
A WireGuard tunnel from a machine or router on your network into your sandboxes. Every sandbox gets an address in the tunnel's subnet, and your machines reach any port of it there.
Terminalruntime tunnel create # subnet 10.250.0.0/16 by defaultruntime tunnel peer add office --route 10.0.0.0/16 # writes runtime.confsudo wg-quick up ./runtime.confruntime tunnel get # each sandbox's addresspsql -h 10.250.0.32 appruntime tunnel peer add makes the WireGuard key pair on your machine; the
private key goes only into runtime.conf, which only you can read. Any
WireGuard client works with the file: wg-quick on Linux and macOS, the
WireGuard apps on Windows, macOS, iOS and Android, or your router. To use a
key you already have, pass --public-key.
- Choose a subnet your network does not use, from
/16to/24, when you create the tunnel:--subnet 172.30.0.0/16. --routenames your own ranges behind the peer. List them when your sandboxes will reach your network through the peer.- What a peer reaches: your own account's sandboxes, at their tunnel addresses, on any port except Runtime's own relays inside the sandbox (10800, 10802 and 10853). Nothing else: not another account's sandboxes, not Runtime's servers, not the internet. Only TCP is carried.
- Rotate a key with
runtime tunnel peer rotate <peerId>: the old key stops working within seconds, and connections opened with it end.runtime tunnel peer rm <peerId>removes a peer the same way. - Limits: one tunnel per account, 16 peers. A paused sandbox is woken by a connection.
From the SDKs:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.tunnel.create();const office = await runtime.tunnel.addPeer({ name: "office", routes: ["10.0.0.0/16"] });// office.config is the wg-quick file; with no publicKey given, it holds the// private key Runtime generated for you, shown once.Pythonruntime.tunnel.create()office = runtime.tunnel.add_peer("office", routes=["10.0.0.0/16"])Errors
| Code | Status | Meaning |
|---|---|---|
payment_required |
402 | The account has not added credit, or the sandbox is a trial one |
network_not_allowed |
403 | Runtime turned network features off for the account |
quota_exceeded |
409 | A limit above was reached |
rate_limited |
429 | Too many added today |
no_capacity |
503 | No public port or dedicated address is free just now |
network_unavailable |
503 | The feature is not switched on in this region yet |