Skip to main content

Fadebox 1.4

The 1.4 line: fadebox/fadebox:1.4 follows its newest release, and the 1.4 docs describe every release on it. Moving between releases is covered in Upgrading.

1.4.5 — 2026-10-07​

This release makes the editors for environment variables and injected files easier to read and harder to get wrong. Nothing about how Fadebox deploys changes.

Environment variables are edited in a code editor. A service's overrides, an environment's shared variables and an instance's variables used to be plain text boxes. Keys and comments are now coloured, and typing {{ offers the placeholders you can use there, including the environment's own services. A line the deploy would ignore, a key set twice and an unusual variable name are flagged under their line. A line that overrides a value from the template or the shared variables says which value it replaces, and the inherited variables left alone are listed under the editor. An instance's variables take only literal values, so a {{ there is flagged before you save.

Injected files are highlighted by type. The file editor used to highlight YAML only. It now also highlights JSON, SQL, XML, TOML, shell scripts, env- and ini-style config and nginx config, and marks placeholders in all of them. See the spec editor for how a file's type is told. The catalog shows an entry's Compose and files with the same highlighting, and the file editor now uses the height of its drawer.

Upgrade notes. None.

The fadebox/fadebox:1.4 image follows this release; pull it.

1.4.4 — 2026-10-06​

This release fixes a leak in the MCP endpoint that could take a whole installation down. It also corrects what some assistant tools tell an agent about your data.

Heavy MCP use no longer exhausts the database connections. Some tool calls kept a database connection after they had answered. The most common was get_instance_logs for a service with no container yet, which is what an agent does while it watches a deploy come up. Each such call kept its connection for good. Once enough of them had done so, every request to Fadebox failed with Unable to acquire JDBC Connection until Fadebox was restarted, the web interface and the ingress included. Every tool call now hands its connection back when it answers.

Tool descriptions say what deleting and moving do to data. delete_instance told the agent it removed the instance's volumes. On a static runtime it keeps them, and reset_instance is what wipes an instance's data. On an elastic runtime, deleting an instance or moving it to another runtime destroys its machine, disk included. The descriptions now say so, and move_instance is marked destructive, so a client asks you before it moves an instance.

Stateless MCP requests without clientInfo are accepted. The protocol makes it optional, and a request that left it out used to fail.

Upgrade notes. None.

The fadebox/fadebox:1.4 image follows this release; pull it.

1.4.3 — 2026-10-05​

This release is a hardening pass that came out of a review of 1.4. Most of it changes nothing you will notice. It closes ways a project, an account or a page served on an instance could reach further than it should, and fixes places where Fadebox reported a failure badly or left something behind. The most significant fixes are below. The rest are smaller corrections across the server, the web interface and the CLI.

A page on an instance can no longer act as the person viewing it. Instances usually share a site with Fadebox (fadebox.example.com and *.envs.example.com), so the browser sent a visitor's Fadebox session along with requests that a page on an instance made. Such a page could deploy or reset an instance, or approve an OAuth consent, as whoever opened it. Fadebox now refuses a change that carries a session cookie unless it comes from Fadebox's own pages, and no other page may show Fadebox in a frame. API keys, OAuth tokens, the CLI and MCP clients send no session cookie and are not affected.

A private image stays with the projects that can pull it. An image already on a runtime could be deployed by any project that named it, so a project without a registry login could run another project's private image. When a project holds a login for an image's registry, each project that deploys the image now pulls it first. If the registry refuses that project, its deploy fails instead of using the copy already on the runtime.

Deleting an environment or a project no longer leaves instances running for nobody. Such a delete used to leave the instances' containers running and free their URLs while the ingress still routed them. It is now refused with instances_have_containers (409) while any instance under it still has containers, and the refusal names the instances to stop first. Deleting a single instance already followed this rule. The web interface also asks before it deletes an instance or removes a service. Both used to happen on one click.

Accounts, keys and connected applications.

  • Settings → API Keys now lists your connected applications: the MCP clients and other OAuth applications you have approved. You can revoke any of them there. The consent page now leads with the host it will send you back to.
  • On the Free tier, reactivating an account now counts against the user cap, as creating one does.
  • A service account that holds API keys but has no role in any project can no longer be given a role in another project, and only administrators manage such accounts.
  • The CLI sends a context's token only to that context's server. A --url or FADEBOX_URL that pointed elsewhere used to receive it. Such an override now needs its own token.

Runtimes.

  • A runtime given only part of its TLS material (CA certificate, client certificate, client key) was connected to without TLS, and nothing said so. Creating or updating one is now refused with runtime_tls_incomplete, which names what is missing.
  • When a runtime's Docker daemon cannot be reached, Fadebox now answers runtime_unreachable (503) and names the runtime. It used to fail with a 500, which sent the web interface to its error page.
  • Image reclaim's minimum age now counts from when Fadebox first saw an image, not from when the image was built. A deploy's images are also held from before its pull, so a freshly pulled image can no longer be reclaimed from under a deploy.

Upgrade notes.

  • No migration, and no setting you have to add, with one exception. Users may open Fadebox over plain http:// on an address other than localhost, through a proxy that does not pass the original Host on. If they do, set FADEBOX_PUBLIC_URL to that address, or every change made from the web interface is refused. Over https, or through a proxy that keeps the Host or forwards it, there is nothing to do. See Reverse proxy.
  • Fadebox can no longer be embedded in a frame on another page.
  • A script that deletes an environment or a project has to stop its instances first.
  • A remote runtime saved earlier with only part of its TLS material is still connected to without TLS until you complete the set or clear it. Check your remote runtimes.
  • The shipped compose file no longer publishes Postgres on the host's port 5432. An existing installation keeps its own compose file. If you take the new one, reach the database through the container: docker compose exec db psql -U fadebox fadebox.
  • Update the CLI to get its token fix; see Install.

The fadebox/fadebox:1.4 image follows this release; pull it.

1.4.2 — 2026-10-01​

This release closes the gaps in one rule 1.4.1 introduced: a published port cannot sit on the same host as a gated instance's URLs. 1.4.1 checked the rule just before a deploy started, and three cases got past that check. Each is now refused like the rest, with ingress_host_port_conflict (409).

Two deploys at the same moment. A gated deploy and a deploy that publishes a port on the same host could each pass the check before the other was recorded, and both landed. The rule is now checked again as each deploy is recorded, one at a time per host, so the later of the two is refused.

A redeploy that closes the gate. The URLs an instance already had stayed marked open until its redeploy finished, and a port deployed in that window landed beside them. An instance now counts as gated from the moment a deploy with its gate closed starts. A gate closed while a deploy is already under way counts too: it refuses a neighbour's port until that deploy ends, although the gate itself still waits for the next deploy, as before.

An elastic instance whose gate was closed while its machine started. Its deploy had been checked with the gate open, and nothing looked at its front's published ports again. They are now checked once the machine is ready, before any container starts. If a port is there, the instance ends in ERROR with the refusal's message, and its machine is stopped.

See Gated instances and published ports.

Upgrade notes. None: no migration, no setting, nothing new on the API, and the CLI is unchanged. If one of these cases let a port land beside a gated instance on 1.4.1, the two are still there after the upgrade, and the next deploy of either one is refused. Move one of them to another runtime, drop the port, or open the gate.

The fadebox/fadebox:1.4 image follows this release; pull it.

1.4.1 — 2026-09-30​

This release narrows who a gated instance lets in, from anyone with a Fadebox account to the people in its project. It also closes several ways a sign-in could reach the wrong place, and fixes about forty places where two copies of the same rule had drifted apart. Most of those rules now live in one place, so they cannot drift again.

A gate says who gets in, not just whether you sign in. Require sign-in was on or off, and a gated instance let in anyone with a Fadebox account. An instance's Access is now one of three levels:

  • Open: anyone who can reach the URL.
  • Members: the project's members, meaning anyone with a role in it, and administrators.
  • Creator: the instance's creator while they are a member of the project, the project's editors, and administrators.

Someone signed in but not admitted lands on a page that names the project and says whom to ask. An environment's New instances setting picks the level its instances start at. A change between Members and Creator applies to new sign-ins at once; a session admitted before it lasts until its cookie expires, which for a gated instance is now at most an hour. Opening or closing the gate still applies on the instance's next deploy, as before.

Raising the level stays with whoever may operate the instance. Lowering it takes the editor role, and so does creating an instance below its environment's default. In the CLI, --gate open|members|creator works on instance create and up. instance gate <slug> closes an instance to its project's members, or to its creator with --creator. --gated, --ungated and instance ungate work as before; neither instance gate nor --gated lowers a gate already set to Creator. An administrator gets through every gate, and when the level would have refused them, the admission is audited as ingress.admin_admitted. A pipeline's access token (fadebox instance token) passes the same check, so a deployer who is neither the creator nor an editor gets no token for a Creator instance. See Requiring a sign-in and Letting a pipeline through.

Sign-ins stay where they were meant to go.

  • The sign-in cookie of a gated instance is now tied to that instance. A new instance that takes over a deleted one's address no longer accepts the old one's cookies.
  • The redirect back after signing in only goes to the scheme and port the ingress actually serves the instance on.
  • A published port can no longer sit on the same host as a gated instance. A browser sends the sign-in cookie to every port of the host, so such a port would receive it. On a static runtime, a deploy that would put a published port, fixed or picked by Docker, on the same host as a gated instance's URLs is refused with ingress_host_port_conflict, whichever of the two comes second. Closing the gate of an instance whose own services publish a port, or creating one closed, is refused the same way. The refusal never names another project's instance, nor its service or port. An elastic runtime's own machines are not affected. See Gated instances and published ports.
  • Accounts are looked up unambiguously. Restoring a session, and changing your own password, find the account by its username only. A username that happened to equal another account's email could reach that account's roles or password. Signing in by email works only when one account has that address. Linking an OIDC sign-in by verified email does the same, and refuses an address that only deactivated accounts hold. A new OIDC account's username never takes another account's email. See Account linking.

Security updates in the platform. Quarkus moves to 3.40.1. It brings Hibernate ORM 7.4.9, fixing CVE-2026-77874 (Fadebox never calls the affected HQL JSON functions), and a fix for security path matching on wildcard permissions. Its Elytron fixes CVE-2026-19611 by changing how passwords are normalized before they are hashed; see the upgrade notes. A proxy named by hostname in QUARKUS_HTTP_PROXY_TRUSTED_PROXIES no longer leaks a network socket on every request.

The CLI:

  • It prints the server's message instead of the raw JSON of the error.
  • Usage mistakes exit with 2, as documented. That includes malformed --tag, --var and --link values, which no longer print a Java class name.
  • --wait polls over one connection instead of opening a new one each time.
  • Expiry times print in your shell's time zone.
  • template list says when it stopped at the server's page limit.
  • instance token no longer blames the runtime for an instance that needs no token.
  • A malformed server URL says Invalid server URL instead of printing a Java exception.
  • instance get lines up its Not applied value with the other fields.

The web interface:

  • A refusal to extend or move an instance reads correctly, with the right way through.
  • Project API keys show how long they have left and flag an expired one, as personal keys already did.
  • ⌘K no longer lists administrator pages to people who are not administrators.
  • The environment composer no longer submits a runtime that was disabled while the form was open.
  • The dashboard and machine views follow the 12- or 24-hour clock setting.
  • Relative times read the same everywhere ("3 minutes ago").
  • Every audit action can be filtered on.
  • A new template's slug is checked like every other slug.
  • A provisioner field renders the same on the account and profile forms: a list of options as a choice, a secret hidden, even when it offers options.
  • A git reference with spaces around its file or JSON path shows the path trimmed, the way the server reads it.
  • A template with one service no longer offers a one-option Service picker for its files.
  • A refused environment delete says what failed, with the server's reason beneath.
  • When creating an environment fails partway, the project list still counts the environment that was created.

Deploy and templates:

  • A Compose export of a template with no main service now matches what the deploy runs. It no longer points depends_on at a service the file does not declare, or fails outright. It also refuses container names that differ only in case, as the deploy does.
  • Retagging an image pinned by digest (app@sha256:…) now works. A {{git:…}} image tag whose file path contains / no longer breaks the retag.
  • Template validation warns about network and volume settings Fadebox does not apply: a volume driver or its options, a non-bridge network, network aliases. It never refuses them.
  • A deploy onto a disabled runtime is refused with runtime_unavailable, naming the runtimes you can use, as create and move already were.
  • An image named DOCKER.IO/… goes through the registry mirror as Docker Hub, in any letter case.
  • FADEBOX_PUBLIC_URL may carry surrounding spaces or a trailing slash.
  • A server whose JVM runs in a Turkish locale reads service_healthy correctly.
  • Template validation no longer warns that an image is unpinned when its tag is a {{git:…}} placeholder whose file path contains /.
  • A truncated log's marker writes its size with a decimal point, whatever the server's locale.

The API:

  • A page far past the end of a listing is empty, with the real total, instead of wrapping around to the first page or failing.
  • The audit listing falls back to newest first for a ?sort= field it does not know, and breaks ties newest first under occurredAt,desc as well.

Elastic runtimes:

  • Test connection reports a refused account with the same sentence the machines page shows, instead of "failed unexpectedly (NullPointerException)".
  • An empty optional field in the account form is left out instead of stored and refused later.
  • A refused stop whose instance is wanted running again is no longer flagged Refused. Retrying it no longer shortens the instance's start timeout.
  • FADEBOX_RUNTIME_USAGE_SWEEP_INTERVAL in the short form (2m) now also sizes each pass, as PT2M always did.

SSO and the assistant:

  • An email_verified claim sent as the string "true" now counts for account linking, as it already did for required claims.
  • The built-in authorization server for MCP clients names itself on every authorization response, including refusals, and says so in its metadata (RFC 9207).
  • GET /api/me shows the email for API-key and OAuth sessions.
  • The assistant's resolve_git_value offers a {{git:…}} placeholder only when a deploy can read it.

Upgrade notes.

  • A gated instance now admits only its project's members. One migration, V025, turns every gated instance, and every environment whose new instances start gated, into Members; nothing becomes Creator. A colleague who opened a gated URL without a role in its project is refused after the upgrade: give them viewer on the project, or a group that has it (see Who gets which role). The old on/off columns are kept in step, so going back to 1.4.0 keeps every closed gate closed.
  • Visitors of gated instances sign in again once, after each instance's next deploy. Their browser does it for them if they are signed in to Fadebox.
  • Behind a reverse proxy, if the proxy serves the ingress on another port and the runtime's Public port is not set, the redirect back after signing in is refused. The message names the address to set. See Custom ports and reverse proxies.
  • A published port beside a gated instance on the same static runtime makes the next deploy of either one refused. Move one of them to another runtime, drop the port, or open the gate.
  • Some local passwords need a reset. A password set on 1.4.0 or earlier that contains a character the old normalization rewrote no longer signs in: superscripts such as ², µ, º, or the fullwidth letters some input methods type. An administrator resets it (see Passwords); failed attempts count toward the login lockout until then. Plain ASCII and ordinary accented letters (ö, é) are unaffected, and so are OIDC accounts and API keys.
  • Signing in by an email two accounts share no longer works; sign in by username.
  • The CLI. Download it again from the upgraded server for the gate levels and the fixed error output. A 1.4.0 CLI keeps working. Scripts that read instance get's text find Gate: open|members|creator where they found Gated: yes/no; -o json only gains fields.
  • On the API, instances carry gate (OPEN, MEMBERS or CREATOR) beside gated, and environments carry instanceGate beside gatedInstances. gated: true from an older client means at least members and never lowers a gate. New refusals: instance_gate_restricted (403), instance_access_denied (403) and ingress_host_port_conflict (409). A deploy onto a disabled runtime answers runtime_unavailable.

The fadebox/fadebox:1.4 image follows this release; pull it. No setting is new or required.

1.4.0 — 2026-09-27​

This release is about where an instance runs. Until now every instance shared a Docker host an admin had built beforehand. An instance can now get a virtual machine of its own, made when it deploys and switched off when it stops. Beside that, the sign-in gate moves from the runtime to the instance, and an OIDC provider can say who may sign in through it.

Elastic runtimes: a machine per instance, on Google Compute Engine. An elastic runtime holds a cloud account instead of a Docker host. Deploying an instance onto it creates a machine at the provider and deploys onto that machine once it is ready. Stopping the instance switches the machine off and keeps its disk, so the next deploy starts with the images already pulled. A reset keeps the machine and wipes the volumes, and deleting or moving the instance destroys the machine. While the machine comes up the instance reads PROVISIONING, which survives a restart of Fadebox, and a machine log narrates the boot step by step: on the card, in the log pane, and in fadebox instance up --wait. The first deploy is minutes rather than seconds, and the concepts page weighs that before anything else.

  • Sizes are the admin's. A runtime offers named machine profiles (machine type, disk, spot or not, a public address or none), one of them the default. An environment can name one as its Machine profile.
  • Machines need no image of your own. A profile boots the published Fadebox runtime image unless it names another. The image contract and a reference Packer template are in the setup guide for an image you build yourself.
  • Each machine is locked down at boot. It gets a certificate authority of its own for its Docker daemon, a host firewall that admits only Fadebox and the front, and no route from containers to the metadata service. Once the machine is ready, the boot document, which holds that CA's key, is removed from the provider's metadata.
  • Instance URLs come from a front. A machine has no DNS name and no certificate, so its instance URLs are served by a front: a static runtime with an ingress domain and the managed ingress stack. The front forwards each hostname to the machine over mutual TLS. The runtime form can create the front and install its stack on the spot.
  • Admins can see and clean up what is billing. The machines view lists every machine, what it is doing and what needs attention. A pass compares the rows with what the cloud account actually holds, and a machine Fadebox lost track of can be reclaimed from there. Stopped-machine retention, set per runtime, gives up a disk nobody came back for, and the instance card counts down to it. fadebox runtime machines lists the machines too.
  • Every tier has it. A runtime counts as one runtime, and its machines are bounded by the per-runtime instance cap. On Free the front can be the disabled local.

See Elastic runtimes and Setting up an elastic runtime, whose Compute Engine section lists the one-time prerequisites in the project.

The sign-in gate belongs to the instance. Require Fadebox sign-in used to be a switch on the runtime, so every instance on a host was either behind a sign-in or open. Each instance now has its own Require sign-in: the internal tool can be closed and the customer demo beside it open. An environment's Instances require sign-in sets what new instances start as. Whoever may operate an instance can change it afterwards, from the card's More menu or with fadebox instance gate / ungate, and instance up --gated gates before it deploys. A change applies on the next deploy, and until then the card and instance list show what is in force (open → gated). Changes are audited as instance.gate_changed. See Requiring a sign-in.

An OIDC provider can say who may sign in. A provider now takes required claims: rules on the ID token, such as a Google Workspace domain (hd), an email suffix, an Entra tenant (tid) or a group, that are checked before any account is created or linked. A rule on email also requires email_verified. Someone the rules refuse lands back on the sign-in page with a message, and the refusal is audited as user.login_refused, naming the claim and never its value. See Required claims.

The ingress stack reports whether it is reaching Fadebox. Every managed ingress stack now asks Fadebox for the routes of the elastic runtimes it fronts, and a stack that fronts nothing gets an empty answer. Fadebox works out where the stack should call from FADEBOX_PUBLIC_URL, or from the runtime's daemon when that is unset. Where it can tell that the address it worked out cannot work, it refuses to install or update the stack rather than leave it broken. This covers a containerized Fadebox with a remote daemon, a loopback address, and Fadebox listening on loopback only. Where it cannot tell in advance, the runtime's Ingress dialog shows whether the stack is polling (OK, Waiting or Stale). The dialog also says why an instance there cannot require a sign-in, and what fixes it. A container of another installation holding one of the stack's names is now refused with ingress_stack_foreign (409) instead of an error. See How the stack reaches Fadebox.

The instance card leads with one action. The card shows the one action its state calls for: Deploy, Redeploy, Stop or Cancel. Reset, Extend, Describe, overrides, Move, the verdict, sharing, the sign-in gate and Delete sit behind More. An action you may not use stays in the menu, greyed out, and names whom to ask.

The CLI reads states it does not know. A CLI shows a state its release does not know as unknown and waits through it instead of failing. That only helps with the next new state: PROVISIONING arrived in this release, so a 1.3 CLI fails on elastic instances. See the upgrade notes.

Upgrade notes. Eleven migrations run on start, V014 to V024. Most of them only add the elastic-runtime tables and columns, and every runtime you have stays a static one. Three change what you will see:

  • Sign-in gates. The per-runtime sign-in switch becomes each instance's own (V014, V024). Every instance on a runtime that required a sign-in stays gated. Instances require sign-in is turned on for every environment whose project could deploy onto such a runtime, whatever instances it has now. Where new instances should start open, an editor turns it off. The runtime switch is gone: an API call that still sends ingressAuth: true for a runtime is refused with a 400 rather than leaving the runtime open. Turning the gate on for an instance is refused without FADEBOX_PUBLIC_URL, as the gate always needed it.
  • Managed ingress stacks. Every managed ingress stack shows outdated once, because each stack now polls Fadebox; press Update in each runtime's Ingress dialog. The pinned traefik:v3.7 and tecnativa/docker-socket-proxy:v0.5.0 images are unchanged. If Fadebox runs in a container and a static runtime's daemon is remote (tcp://), or Fadebox listens on a loopback address only, set FADEBOX_PUBLIC_URL first to an address the runtime's host can reach. Until it is set, Update is refused and the dialog says why. If you publish Fadebox on a FADEBOX_PORT other than 8080, set FADEBOX_PUBLIC_URL too, or the stack's poll reads Stale.
  • The CLI. Download the CLI again from the upgraded server: a 1.3 CLI fails on the PROVISIONING state of instances on elastic runtimes (see Download the CLI again).

In the compose file, change the image line to fadebox/fadebox:1.4. The installation file gains only a comment on the ports line, and no variable is new or required. The new settings are the seven FADEBOX_MACHINE_* cadences, FADEBOX_EGRESS_ECHO_URL and FADEBOX_MACHINES_GCP_DEFAULT_IMAGE, all under Elastic machines. Their defaults cost one query per pass on an installation without an elastic runtime.

For API clients:

  • Runtimes carry placement (STATIC or ELASTIC) and, on an elastic one, an elastic block. GET /api/provisioners lists the providers this build carries (gcp). PUT/DELETE /api/runtimes/{name}/profiles/{profile} define the sizes. GET /api/runtimes/{name}/machines, …/machines/findings, POST …/machines/reconcile, …/machines/reclaim and …/machines/{machine}/retry are the fleet.
  • The ingress stack status carries applyRefused, poll and gateUnavailable.
  • Instances gain the PROVISIONING status, gated, a machine block and machineExpiredAt. PUT …/instances/{slug}/gate changes the gate, and GET …/instances/{slug}/machine/log reads the machine log.
  • Environments gain gatedInstances and machineProfile.
  • OIDC providers gain requiredClaims.

A client that fails on an instance status it does not know has to learn PROVISIONING before it meets an elastic runtime.