Inbound access control
To expose a service at creation time, pass the guest port in the create request, start a process that listens on that port, and wait for the listener endpoint to become ready:expose/unexpose
(see Add or remove ports at runtime).
Sail supports two inbound protocols:
- HTTP, which returns a public HTTPS URL and supports HTTP and WebSocket traffic.
- Raw TCP, which returns a public
hostandportfor protocols such as SSH, Postgres, or custom TCP servers.
HTTP and WebSocket services
Expose a guest port over HTTP (in Python, a bare port number iningress_ports means HTTP). The listener resolves to a routable HTTPS URL.
https:// with wss://
when the process inside the Sailbox speaks WebSocket on that port.
Raw TCP ports
Expose a port as raw TCP instead of HTTP when the protocol is not HTTP-aware or the service already implements its own authentication. The listener resolves to a publichost and port that any TCP client can dial directly.
SSH access
For a quick interactive shell, useSailbox.shell() or
sail box shell: it streams a terminal over the same channel as exec, uses
no ingress port, and while open it forwards the Sailbox’s localhost servers and
browser opens to your machine. Set up SSH when you want a standard SSH endpoint: a devbox,
your own client, scp, or port forwarding. It exposes guest port 22 as raw
TCP, which counts against your org’s raw-TCP endpoint limit.
SSH access is organization-scoped: a Sailbox trusts your org’s SSH certificate
authority, so anyone in the org can connect with a short-lived certificate
signed for their key. There are no per-Sailbox keys to manage. A private Sailbox
is the exception: its SSH server accepts only its creator’s certificates.
Enable SSH at create time, or with
enable_ssh() on a Sailbox that already
exists. Both install the org CA as trusted, start sshd, and expose port 22.
enable_ssh() is idempotent; re-run it to bring sshd back up if it stops.
sail box ssh CLI and use the Sailbox’s
<name>.sail shortcut:
alias fetches your certificate and writes the shortcut into your SSH config.
The shortcut is what presents the certificate, so alias a Sailbox before you
connect. Run it on each machine you connect from, whether you or a teammate
enabled the Sailbox; it only touches local config and never wakes or changes the
Sailbox. sail box ssh enable <id> enables SSH on an existing Sailbox and runs
alias for you in one step, as does creating a Sailbox with
sail box create --enable-ssh.
To restrict which sources may connect, pass an allowlist of addresses or ranges:
sb.enable_ssh(allowlist=["203.0.113.0/24"]) in Python,
box.enableSsh({ allowlist: ["203.0.113.0/24"] }) in TypeScript, the
allowlist argument of enable_ssh in Rust, or sail box ssh enable <id> --allowlist 203.0.113.0/24 from the CLI. A new allowlist replaces the current
one, so re-running can tighten or relax access. Disabling SSH
(sail box ssh disable) removes the port-22 listener along with its
restriction.
Your ssh-agent is the program on your computer that holds your SSH keys.
Forwarding it lets programs on the box act as you toward other services, for
example git push to GitHub, without copying any key onto the box. While it
is forwarded, anything running on the box can use it, so Sail forwards it only
to a private devbox you created. Your org’s administrators can still get root
on any Sailbox, and that access is logged.
The generated <name>.sail shortcut sets ForwardAgent no, which tells ssh
not to forward your ssh-agent, even if your own SSH config forwards by
default. That is because a Sailbox can be reachable by other people in your
org. The one exception is a private devbox you created: its shortcut sets
ForwardAgent yes so tools on it, like git, can act as you while you are
connected.
To change this for a single connection, pass the options yourself:
ControlPath=none is needed because ssh can reuse one underlying connection
for several sessions. A session that joins a reused connection keeps whatever
forwarding that connection started with, and your option is silently ignored.
ControlPath=none opens a fresh connection so the option takes effect. If
your config keeps connections open with ControlPersist, close a shared one
with ssh -O exit <name>.sail; the box can reach your ssh-agent until that
connection closes, not just until you disconnect.
The SSH server persists across sleep and resume. An open SSH session drops when
the Sailbox sleeps, but reconnecting with ssh <name>.sail wakes it and uses
the same host key.
Inspect endpoints
Look up one listener when you know the guest port, or list all published ports for a Sailbox:host and
port.
Add or remove ports at runtime
You don’t have to declare every port at create time.expose publishes a new
port on a running Sailbox and unexpose removes one, with no guest restart.
The listener returned by expose carries the resolved endpoint but an
"unknown" route status: the response confirms configuration, not
reachability. wait_for_listener confirms the route is live. The
HTTP API exposes the same two operations if you are not
using an SDK.
allowlist to what you
pass, so pass the whole list every time. Passing none clears the restriction
and reopens the port. Use it to tighten or relax a live port. Unexposing a
raw-TCP port stops serving it, so it no longer counts against your org’s
raw-TCP endpoint limit. Its public host:port stays owned by your org. Sail
may reassign an idle address to another of your Sailboxes; it is never given
to another org. If the address has not been reassigned, re-exposing the same
guest port reclaims it exactly. Otherwise the re-expose allocates a new
address, so read the endpoint from the response instead of assuming the old
one. A stale client that dials an old raw-TCP address may therefore reach a
different Sailbox in your org, and never another org’s. A raw-TCP guest port
can’t be repurposed to HTTP; use a different guest port. HTTP ports carry no
such reservation and are released on unexpose.
expose and unexpose work on a paused or sleeping Sailbox without waking it; a
later resume serves the new listener.
From the CLI:
Access controls
To restrict which sources may connect, passallowlist, as below. An entry that
reads as an address or a range matches source IPs on HTTP and TCP listeners.
Every other entry is a Sail app name, which admits authenticated traffic from
Sailboxes in that app and is supported on HTTP listeners only. An app name
cannot read as an address or a range, and cannot contain a /. An address
must not carry an IPv6 zone, such as fe80::1%eth0, which names an interface
on one machine rather than a source.
allowlist
means any source may connect.
For HTTP requests from one Sailbox to an app-name allowlisted listener, include
the SDK-provided source headers. Inside the calling Sailbox, the Python SDK
reads its own identity:
"tcp" listeners: a raw-TCP allowlist must contain only addresses
and ranges.
Exposing a well-known unauthenticated service port, such as Postgres, MySQL, or
Redis, as raw TCP without an explicit allowlist is rejected. Set source
restrictions, or use the all-sources allowlist to confirm you want it publicly
reachable:
Sleeping services
Sleeping Sailboxes wake on network ingress. If you callsleep() on a Sailbox
with exposed listeners, the next inbound HTTP, WebSocket, or TCP connection
wakes the VM before forwarding traffic to the guest process.
pause() instead when you want to preserve VM state without waking on
network traffic.
Ports and cleanup
Ports must be unique within a Sailbox and between1 and 65535. Ports 10000,
10001, 15001, and 15002 are reserved by Sail. Port 22 is the SSH port
and cannot be exposed as HTTP; expose it as raw TCP instead.
Each org can hold a limited number (32) of concurrent raw-TCP endpoints. The
limit counts actively-exposed endpoints, so unexpose frees a slot. An idle
host:port stays owned by your org, even after the Sailbox that used it
terminates. Sail may reassign it to another of your Sailboxes; another org
never receives it. Contact us to raise your limit if you need more concurrent
endpoints.
Custom domains
An HTTP listener can also answer on a hostname you own, such asapp.example.com, with a TLS certificate that Sail obtains and renews for
you. See Custom domains.