Skip to content

Remote access

On your own machine spwn asks for nothing: it’s bound to 127.0.0.1, and anything that can reach the port can already do anything you can. Bind it anywhere else and it requires an account, so you can open it from another machine, a container or a cluster.

spwn decides from the address it binds, unless you tell it otherwise:

You run Accounts
spwn (binds 127.0.0.1) Off
spwn serve --host 0.0.0.0 (or any non-loopback address) On
spwn serve --auth On, even on localhost
spwn serve --no-auth Off, even on 0.0.0.0

The flags win over the SPWN_AUTH environment variable, which wins over the bind. SPWN_AUTH takes off, on (or local), proxy or oidc.

Use --no-auth only when you have your own gate in front: anyone who can reach the port gets a shell.

The first time spwn boots with accounts on and none exist yet, it prints a one-time link:

spwn has no account yet. Open this to make the first one:
http://localhost:4317/?setup=…

Open it, choose a username and password, and you’re signed in. The link stops working the moment that account exists. If the logs have rolled, the same token is in setup-token in spwn’s data folder (mode 0600), and it’s removed once used. Set SPWN_SETUP_TOKEN to choose the token yourself instead of having one minted.

In the Docker and Helm deployments, find it with logs … | grep -A3 'no account yet' (see Install).

Sessions last 12 hours. Settings → Account changes your password, which signs out every other device, and has Sign out everywhere.

Put an Ingress, nginx or any reverse proxy in front of spwn and set SPWN_PUBLIC_URL to the URL people actually visit:

Terminal window
SPWN_PUBLIC_URL=https://spwn.example.com spwn serve --host 0.0.0.0 --no-open

It does three things:

  • Origin checks. spwn refuses cross-origin requests that change state, WebSocket handshakes and everything under /ide. A proxy that rewrites the Host header to its upstream’s name makes every request look cross-origin, and you get 403s with no obvious cause. With SPWN_PUBLIC_URL set, the Origin is compared against it instead.
  • Secure cookies. The proxy terminates TLS, so spwn can’t see it. An https:// public URL is what marks the session cookie Secure.
  • Links. It’s the base of the setup link and, in OIDC mode, the redirect URI.

In the Helm chart it’s auth.publicUrl.

A git client or CI job can’t sign in through a browser. Create an access token in Settings → Account instead. Its secret (spwn_pat_…) is shown once. Send it as Authorization: Bearer <token>, or as the password in HTTP Basic with any username, which is what git does:

Terminal window
git clone http://me:spwn_pat_…@spwn.example.com/git/<project-name>

spwn serves a read-only git endpoint at /git/<project>, by a project’s name or id. Tokens work in every mode, and revoking one takes effect at once.

If you already have an identity provider, spwn can use it instead of its own passwords. Both modes need an image built with the enterprise feature (docker build -f deploy/Dockerfile --build-arg CARGO_FEATURES=enterprise .). The default build refuses them at startup, by name, rather than falling back to a password prompt.

proxy trusts an identity header set by whatever authenticates in front of spwn: oauth2-proxy, Pomerium, an ingress auth-url, Cloudflare Access, IAP, Teleport. Prefer it when you have one: your proxy already handles MFA and group rules.

  • SPWN_AUTH_PROXY_HEADER (required): the header, e.g. X-Auth-Request-Email.
  • SPWN_AUTH_PROXY_FROM: comma-separated addresses or CIDR ranges allowed to assert it. Empty means any peer.

spwn doesn’t re-check the header, so it’s worth exactly what the path it came over is worth. Set SPWN_AUTH_PROXY_FROM and a NetworkPolicy, so nothing can reach spwn without going through the proxy. Accounts are created the first time the proxy lets someone through.

oidc runs the OpenID Connect flow itself (authorization code with PKCE), for a setup with an identity provider and nothing doing forward-auth:

  • SPWN_OIDC_ISSUER, SPWN_OIDC_CLIENT_ID (required), and SPWN_PUBLIC_URL (required).
  • SPWN_OIDC_CLIENT_SECRET or SPWN_OIDC_CLIENT_SECRET_FILE.
  • SPWN_OIDC_SCOPES (default email,profile; openid is always sent).
  • SPWN_OIDC_AUTO_PROVISION=1 to give anyone the provider admits an account. Without it, a sign-in must match an existing account by name.

Register <SPWN_PUBLIC_URL>/api/auth/oidc/callback with the provider. Accounts are keyed on the provider’s issuer and subject, not the email.

The Helm chart sets all of these from its auth: values. See deploy/charts/spwn and design/011 for the reasoning.