Changelog
Released 10 October 2026: release notes and files on GitHub.
A harder Spawner: environments kept from the cloud’s metadata and the server’s services, source repositories chosen by admins, Traefik 3.7 and releases you can verify. And its documentation, now on https://spawner.run.
- Environments no longer reach the cloud’s metadata or the server’s services: the code of a branch could read the credentials of the server from the metadata service of its cloud (AWS, GCP, Azure, Hetzner, OVH…), or call a service listening on the server. A new
spawner-firewallcontainer loads rules for every container of Docker’s bridge networks: the metadata addresses are refused, but for DNS, and the server answers on DNS, HTTP and HTTPS only. The installer also has Docker load them before it starts, so that they hold from boot on: after an update from the dashboard, runinstall.sh --upgradeonce on the server for that part. - Source repositories are chosen by admins: the other sources of
spawner.yamlmust come from repositories listed in the project (Projects, Edit, “Source repositories”);spawner uprefuses the others before sending anything. A branch could otherwise make Spawner clone any repository its deploy keys reach, or an address of the internal network. The upgrade lists for each project the repositories its live environments already use. - Traefik 3.7: Traefik 3.5, which no longer gets security fixes, gives way to 3.7; upgrading Spawner pulls it. Traefik 3.7 embeds lego v5, which dropped the DNS providers azure (use azuredns), dnspod, googledomains, cloudxns, brandit, iwantmyname and iij (use iijdpf): a server set up with one of them switches before upgrading. Request headers whose name holds a character other than a letter, a digit or a dash (
X_Spawner_Preview,X.Forwarded.For) no longer reach applications, so an application that reads headers the PHP or CGI way cannot be handed one that Traefik removes or sets. - What you download can be verified: the images,
install.shand the CLI bundle of a release carry build provenance attestations (gh attestation verify install.sh -R Flosk6/Spawner). Theinstall.shof a release names the digest of its image, and updates from the dashboard read it there: both run the image the release built, whatever its tag points to later. Postgres and Traefik are pinned by digest. - Terminals and log streams close when their access goes: deactivating a user, changing their role or revoking a token now closes the terminals and the streams of logs they had open, at once, and an expired token’s within 30 seconds.
- Uploads stop at their first limit: an archive is read as a stream that stops at the first file, byte or decompressed byte over the limits, so that a compression bomb costs no more than a legitimate archive; a person has 5 deploys of uploaded code waiting to start at most.
- A harder installation:
- The installer no longer makes a token of the installation with every scope (
SPAWNER_BOOTSTRAP_TOKEN) unless given one; installations that have one keep it until you empty its line in.env. - It refuses a version older than the installed one (its database only migrates forward;
--allow-downgradeafter restoring a backup), a data directory other than the installation’s, and system directories; it never makes new secrets over an installation that lost them, never upgrades without a backup (it starts Postgres for it), writes.envanddns.envin one move, keeps a trailing=of their values, and no longer shows the DNS credentials typed. - The data directory is mode 700, rendered compose files and logs are readable by Spawner only, Traefik runs without capabilities but binding ports, Postgres and Traefik have memory limits, Spawner’s code belongs to root, and Prisma’s telemetry is off. A local install over HTTP warns that it serves every interface; the development stack listens on 127.0.0.1.
- git reaches GitHub, GitLab and Bitbucket with the host keys they publish, even the first time.
- The installer no longer makes a token of the installation with every scope (
- The installer warns below 4 GiB of memory, where no environment starts with the default settings, and names the settings to lower. It accepts an
/opt/spawnerholding only.envanddns.env, as when restoring on a new server. - Smaller hardening:
- Previews: a cookie a preview sets under the name of Spawner’s no longer locks its visitors out; share links opened on public URLs never reach the application; the waiting page of a public URL no longer says why its environment failed; logging out takes the preview cookie off the browser; the cache of preview hosts is bounded.
- The dashboard’s page has a Content-Security-Policy that runs its own scripts only; every answer carries
Referrer-Policy, and over HTTPSStrict-Transport-Security. - Accounts: passkeys must verify their user (a PIN, a fingerprint); names are unique, whatever their case; renames and linked GitHub accounts are audited, and every audit event records the address of its request; the CLI approval page says when and from where the login started. Removing someone from the GitHub organization does not deactivate them in Spawner: do it on the Team page.
- Compose: an environment has 4 CPUs and 4096 processes to share between its services (
SPAWNER_ENV_CPUS,SPAWNER_ENV_PIDS), as it has its memory, and no service gets raw sockets (NET_RAW). A file asking more CPUs or processes than that is refused. - Uploads: links are followed through the links they lead to once extracted.
- CLI:
spawner loginopens http and https URLs only; untracked.env-*,.npmrc, private keys and*.pemfiles stay home like.envfiles; a Dockerfile is read only when it is a regular file of 1 MiB at most; the MCP server fences what comes from the environment and tells the model to read it as data.
- The documentation moves to https://spawner.run, with new pages: a quickstart from a fresh server to a first environment; previews for pull requests from GitHub Actions and GitLab CI; the two example projects; troubleshooting. Also new: every key of
spawner.yamland the codes of a refused.spawner/, what an application needs to run behind Spawner, every option, variable and error code of the CLI and what each MCP tool takes and returns, VS Code with GitHub Copilot, Gemini CLI and Devin Desktop for agents, and what Spawner does not do. - Corrections to the documentation: the minimum memory is 4 GiB, not 2; the compose policy listed
platformunderbuildas allowed, which Spawner refuses; services withoutmem_limitshare what is left of the environment’s memory, up to 512 MiB each; public URLs (auth: none) never wake a sleeping environment; with GitHub login set to an organization, its members get an account at their first login, without an invitation;admin.js invitelinks last 24 hours; the Dockerfile example of “Dockerfiles that share their layers” builds again; removing Spawner and the local install download the installer from the release, as upgrades do. spawner initlinksspawner.yamlto https://spawner.run/docs/manifest/ instead of an outdated branch of the repository, and the instructions it writes for coding agents say what to do on exit code 6. The dashboard’s Docs button opens https://spawner.run/docs/.spawner loginsays a 90-day token expires in 90d, not 89d 24h.- The MCP server is listed on the official MCP Registry as
io.github.Flosk6/spawner, and spawner-cli on npm links to https://spawner.run. Release pages say what Spawner is, give the install and upgrade commands apart, and show how to check the files againstSHA256SUMS.
Upgrading from 2.1.0: update from the dashboard or with install.sh --upgrade, then run install.sh --upgrade once on the server, so that Docker loads the firewall rules of the environments before it starts any container (an update from the dashboard installs the firewall container, not Docker’s part). Before upgrading, a server set up with a DNS provider that lego v5 dropped switches to another one (see Traefik 3.7 above). The upgrade lists, for each project, the repositories its live environments already take sources from; new ones need an admin. An installation from 2.1 or before keeps its bootstrap token until you empty its line in /opt/spawner/.env.
Released 9 October 2026: release notes and files on GitHub.
A new dashboard, and patched dependencies.
- A new dashboard: a sidebar with breadcrumbs, dense tables, one status badge everywhere, environment pages with their services as cards (memory of each), a lifecycle card, and jobs that show the phase they are at or failed in. Search everything with Ctrl+K (Cmd+K on a Mac). Every page works on a phone.
- Light and dark themes that hold, or the system’s: the dark theme no longer has buttons, menus and banners you could not read, and the page no longer flashes light before it turns dark. The waiting page of sleeping environments follows the same colors.
- The dashboard loads no font from another site any more: they are bundled.
- Patched dependencies: the packages Dependabot flagged, among them protobufjs (code execution, through dockerode) and proxy-addr (IP spoofing through trusted subnets, used by Express).
Released 8 October 2026: release notes and files on GitHub.
A rewrite of Spawner: preview environments for every branch, for teams and the coding agents working for them, on a server of your own. Nothing carries over from 1.x: install 2.0 on a fresh server.
- Environments from Docker Compose: a project describes its environment in
.spawner/(a manifest and a compose file), checked against a security policy before anything runs. Environments come from a branch, a tag, a commit, or an uploaded worktree with its uncommitted changes, from one or several repositories. - The
spawnerCLI and its MCP server, for people and coding agents:upfrom a worktree,execin a service, logs with an error filter, URLs with a preview token, share links;--jsoneverywhere and stable exit codes.npm install -g spawner-cli. - Access without passwords: invitation links and passkeys, optional GitHub login, roles, personal tokens with scopes, a device flow for the CLI. Previews are protected: teammates pass with their session, agents with a short token, guests with a share link, and the applications never see what opens the other previews. Everything goes to an audit trail.
- Supervision: CPU and memory of every container over 30 days, disk per environment, a timeline of crashes, out-of-memory kills and jobs, crash loop alerts, logs kept 7 days after a deletion, terminals with limits and recordings.
- Lifecycle and density: environments sleep after 2 hours without activity and wake up on the next visit, expire after 72 hours, and count against a quota per person; Spawner refuses an environment beyond the server’s capacity, removes replaced images and the code a build no longer needs, and cleans up what deleted environments leave, nothing else.
- One-command install:
install.shsets up Docker, a wildcard certificate through your DNS provider (or one per host), and the stack from the images on GHCR; it upgrades (with a database backup) and uninstalls too. - Updates from the dashboard: Spawner sees new versions and updates itself in one click, backing its database up first and going back to the previous version if the new one does not start.
- Examples and documentation: Node.js with PostgreSQL, and Laravel, Next.js and MySQL; guides for installing, agents, security, operations and density.
Spawner is now licensed under Apache-2.0; the release candidates up to 2.0.0-rc.2 were published under AGPL-3.0.
Upgrading from 2.0.0-rc.1 or rc.2, which have security issues fixed here: run install.sh --upgrade, then redeploy or delete the environments created with them. Compose files now need service names, network aliases and hostnames that are lowercase DNS labels without dots, not starting with spawner or spn-, and no IPv6 network; and the CLI asks for the device code to be typed in the dashboard. Guests who opened a share link before the upgrade open it again.