Spitfire

Version: 0.56.0This documentation is for Spitfire 0.56.0.

Installation, updates and backups

This page covers installing Spitfire on Docker, Kubernetes or Windows (Docker Desktop), creating the first admin, updating, rolling back, backing up and uninstalling. Installing runners in remote locations is a separate topic: Runners and locations.

What it is for

The installer (install.sh, on Windows install.ps1) does all of this with one command:

  • Downloads the release's installer bundle (install.sh, uninstall.sh, Compose/Kubernetes files; no source code) from spitfire.tr/download, checks its SHA-256 and unpacks it into ~/spitfire.
  • Pulls the image from Docker Hub: usespitfire/spitfire:<VERSION> (public, amd64 + arm64). Go and Node are not needed.
  • Starts Postgres, the controller (web UI + API) and the runners.
  • Generates the secrets (SPITFIRE_SECRET_KEY, SPITFIRE_JWT_SECRET, the setup code…) once and keeps them as they are on every later run.
  • Prints the UI address and the setup code for the first admin at the end.

Running the same command again is an update.

When to use it

  • At the first installation.
  • When a new release is out (the blue "Spitfire X is out" banner in the UI).
  • To change the controller's port, the number of runners or the proxy (run it again with the option).
  • When an update went wrong (--rollback).
  • When support asks for a support bundle and the UI does not open (--support-bundle).

Requirements

Installation Needs
Docker (Linux/macOS) Docker Engine (Linux) or Docker Desktop (macOS), the Docker Compose v2 plugin, curl. The installing user must reach the Docker daemon (on Linux: be in the docker group).
Kubernetes The above plus kubectl and an active context. Nodes pull the image from Docker Hub (internet access needed; otherwise --build --registry).
Windows Docker Desktop, Windows PowerShell 5.1 or PowerShell 7, tar.exe (ships with Windows 10 1803 and later).
Remote runner server Only Docker; on Linux without Docker a systemd service, on Windows without Docker a Windows service. See Runners.

When the installer finds something missing it stops with an ERROR: line followed by a Fix: line; read that first. The installer speaks English or Turkish depending on the system locale (LANG); SPITFIRE_LANG=en or SPITFIRE_LANG=tr forces one (for example curl -fsSL https://spitfire.sh | SPITFIRE_LANG=en bash -s -- docker).

Installing with Docker

  1. Check that Docker runs: docker info must return without an error.

  2. Run the install command:

    bash
    curl -fsSL https://spitfire.sh | bash -s -- docker

    This installs Postgres + controller + 2 runners on one machine. For another release write SPITFIRE_VERSION=0.5.3, for another folder SPITFIRE_DIR=/opt/spitfire (both before bash):

    bash
    curl -fsSL https://spitfire.sh | SPITFIRE_DIR=/opt/spitfire bash -s -- docker

    https://spitfire.sh is the short address of https://spitfire.tr/install.sh (on Windows https://spitfire.sh/ps = https://spitfire.tr/install.ps1); both serve the same script, so a proxy or firewall that only allows spitfire.tr can use the long form.

  3. The installation ends with the line Installation complete. Open in your browser: http://.... Copy the Setup code: XXXX-XXXX-XXXX line right below it.

  4. Open the address in your browser and continue with First sign-in and setup code.

Default ports: UI and API 8470, gRPC (TLS) for remote runners 8471. To change them:

bash
~/spitfire/install.sh docker --port 8480 --grpc-port 8481 --runners 4

Demo target

If you have no system to test yet, or want to get to know the tool first, run the installer with --demo (Windows: -Demo):

bash
curl -fsSL https://spitfire.sh | bash -s -- docker --demo

A small HTTP API is installed next to Spitfire (/health, /api/items, /api/items/{id} and /ocpp/{id} for OCPP). Only the local runners reach it; no port is published. On Tests → From a template the HTTP and OCPP templates start on it, so you can create a test and run it at once. To move to your own system, change the address in the template or in the editor. The setting is kept on later installs (updates); to remove it, ~/spitfire/install.sh docker --no-demo. There is no demo target on Kubernetes.

Installing on Kubernetes

  1. Check that you are on the right cluster with kubectl config current-context.

  2. Run the install command:

    bash
    curl -fsSL https://spitfire.sh | bash -s -- kubernetes

    The default namespace is spitfire, the context is the current one. Change them with --namespace NS and --context C.

  3. By default the UI opens on NodePort 30470 (change with --node-port N; --service-type LoadBalancer or ClusterIP are also possible). If this machine cannot open the UI through the NodePort, the installer starts a kubectl port-forward in the background (deploy/kubernetes/.port-forward.pid).

  4. Copy the setup code from the output and open the address.

Security settings of the Kubernetes installation: pods run as non-root with a read-only root filesystem, no capabilities and the RuntimeDefault seccomp profile. NetworkPolicies (where the CNI enforces them) let only the controller reach Postgres and only this installation's runners reach the plaintext runner port (8475). Stopping the controller stops active runs and stores their results first (up to 30 s; the pod gets 45 s).

Common Kubernetes options:

Option Meaning
--namespace NS, --context C Target (default spitfire, current-context)
--service-type T NodePort (default), LoadBalancer, ClusterIP
--node-port N UI NodePort (default 30470)
--storage-class SC, --storage-size S Postgres PVC (default: the cluster default, 5Gi)
--local-port N Local port for the port-forward fallback
--runners N Number of always-on runners
--on-demand-runners N Runners started as pods during a run (see Runners)
--build --registry REG Builds the image from source and pushes it to your registry
Note

An image built with --build is loaded directly into kind, minikube, k3d and Docker Desktop; other clusters need --build --registry REG. --build only works in the source tree; the bundle from spitfire.tr carries no source code.

With Helm

For clusters managed with Helm, Argo CD or Flux there is a chart. It installs the same pieces with the same security settings and names (spitfire-controller, spitfire-secrets…):

bash
helm repo add spitfire https://spitfire.sh/helm
helm install spitfire spitfire/spitfire -n spitfire --create-namespace

https://spitfire.sh/helm is the short address of https://spitfire.tr/download/helm; the chart packages themselves come from spitfire.tr, so behind a proxy or firewall allow spitfire.tr (or add the long address).

The install notes print how to open the UI and how to read the setup code. Common values:

Value Meaning
controller.service.type ClusterIP (default; with an ingress or port-forward), NodePort, LoadBalancer
ingress.enabled, ingress.host, ingress.className, ingress.tls The UI behind your ingress controller
controller.grpcPublicAddr host:8471 that runners in other locations dial
runners.replicas, runners.location Always-on runners (default 2, local)
onDemandRunners.max Runners started as pods during a run (0: off)
postgres.enabled, externalDatabase.existingSecret Postgres in the cluster, or your own (a Secret with the DSN)
secrets.existingSecret Bring the installation's keys yourself instead of generated ones
admin.email, admin.password, license.key The first admin and a license key (both optional)
proxy.httpsProxy, proxy.noProxy Outbound proxy for the controller

The installation's keys are generated on the first install, kept on every upgrade and left in place by helm uninstall, as is the database volume; back up the spitfire-secrets Secret. Update with helm repo update spitfire && helm upgrade spitfire spitfire/spitfire -n spitfire --reuse-values; the Version card shows this command on a Helm installation.

Installing on Windows

  1. Start Docker Desktop.

  2. In PowerShell:

    powershell
    irm https://spitfire.sh/ps | iex

    This installs in docker mode; the bundle is unpacked into %USERPROFILE%\spitfire (change it with $env:SPITFIRE_DIR, pick a release with $env:SPITFIRE_VERSION).

  3. To pass options, call the script as a scriptblock:

    powershell
    & ([scriptblock]::Create((irm https://spitfire.sh/ps))) docker -Port 8480 -GrpcPort 8481 -Runners 4

The install.ps1 options mean the same as those of install.sh: -Runners N, -Location NAME, -Version V, -Image IMAGE, -AdminEmail/-AdminPassword, -Port N, -GrpcPort N, -GrpcPublicAddr H:P, -NoBackup, -Rollback, -SupportBundle, -Yes, -Help.

To install only a runner on a Windows server without Docker, use the command on the Windows tab of the key dialog on the Runners page: Runners.

Installer options

~/spitfire/install.sh --help lists them all. The most used:

Option Meaning
--port 8480 --grpc-port 8481 Docker: UI and runner ports (default 8470/8471)
--runners N Number of local runners (default 2)
--location NAME Location of the local runners (default local; a-z 0-9 - _ .)
--demo / --no-demo Docker: install / remove the demo target
--grpc-public-addr HOST:PORT The address runners in other locations dial (shown in the UI's command; on Docker the LAN IP by default)
--version V Pull another release from Docker Hub
--image IMAGE Use a specific ready-made image
--offline FILE Install or update from an offline bundle, without internet (Updating without internet)
--admin-email E --admin-password P Create the first admin during installation (password at least 8 characters)
--no-backup Do not back up the database when updating
--rollback [DUMP] Roll the last update back
--support-bundle Installs nothing; prepares a support bundle (zip)
-y, --yes Do not ask for confirmation

First sign-in and setup code

On the first visit the UI shows the Create the first admin screen. It appears only once, while there are no users at all.

The Create the first admin screen: Setup code, Name, Email, Password and Confirm password fieldsThe Create the first admin screen: Setup code, Name, Email, Password and Confirm password fields

  1. Paste the XXXX-XXXX-XXXX code printed at the end of the installation into Setup code.
  2. Enter Name, Email and Password (at least 8 characters), and repeat it in Confirm password.
  3. Click Create admin and sign in.

The new account is the installation admin: installation settings such as the license, users, SSO and system events belong to this role only. The code stops working once the first admin exists.

Lost the code? (It stays valid until the first admin exists and is never regenerated.)

  • Docker: grep SPITFIRE_SETUP_CODE ~/spitfire/deploy/docker/.env

  • Kubernetes: kubectl -n spitfire get secret spitfire-secrets -o jsonpath='{.data.SPITFIRE_SETUP_CODE}' | base64 -d

  • The setup_code= line in the controller log:

    bash
    docker compose -p spitfire -f deploy/docker/docker-compose.yml logs controller | grep -i setup
    kubectl -n spitfire logs deploy/spitfire-controller | grep -i setup
  • Running the install command again shows it again (the code does not change).

To create the first admin during installation without the code: install.sh docker --admin-email admin@example.com --admin-password '...' (Windows: -AdminEmail/-AdminPassword).

Warning

Do not share the setup code with anyone but the person installing. Whoever uses it first becomes the installation's admin.

After signing in, the next step is usually the license: License.

Updating

How you notice a new release

Once a day the controller asks spitfire.tr whether there is a newer release (it sends only its own version). If there is, admins see the Spitfire X is out banner at the top of every page:

  • What's new and how to update opens the release notes and the update command for this installation (separately for Linux/macOS Docker, Windows PowerShell, Kubernetes and runner servers in other locations).
  • Hide for this release closes the banner for that release. A Security update banner (red) cannot be hidden; it shows again on every visit.

The Version and updates card on the License page shows the installed version, the installation type, the last check's result, the Outbound proxy and the Update command; Check now checks without waiting.

The Version and updates card on the License page: installed version, installation type, update check and the Check now buttonThe Version and updates card on the License page: installed version, installation type, update check and the Check now button

Updating step by step

  1. Make sure no run is in progress (the update restarts the controller).

  2. On the server the controller is installed on, run the same command as at installation:

    bash
    curl -fsSL https://spitfire.sh | bash -s -- docker
    curl -fsSL https://spitfire.sh | bash -s -- kubernetes --context C --namespace NS

    On Windows: irm https://spitfire.sh/ps | iex.

  3. The script unpacks the latest bundle into the same folder and pulls the image. Generated keys (deploy/docker/.env or the spitfire-secrets Secret) and data are kept.

  4. If the version changes, the database is first dumped to ~/spitfire/backups/*.dump (the newest 5 are kept; --no-backup skips it).

  5. Update the runners in other locations too: Runners → Updating runners. The Runners page marks runners on another release than the controller with a yellow older release tag.

Rolling back

If an update goes wrong:

bash
~/spitfire/install.sh docker --rollback          # Kubernetes: install.sh kubernetes --rollback

On Windows .\install.ps1 -Rollback. The script first dumps the current database, restores the newest dump under backups/ (or the file you give: --rollback backups/<file>.dump) and returns to the release that took that dump. Changes made after the dump are lost. Without a terminal it needs --yes.

Updating without internet

On installations that cannot reach the internet, such as banks or closed networks, the controller cannot learn about a new release itself. When the update check is off (SPITFIRE_UPDATE_CHECK=off) or its last attempt failed, and the installed release is more than 60 days old, admins see a This release is N days old note at the top of the page. The installed release's date is also on the License → Version and updates card. There are three ways; pick the one that fits your network.

a) Temporary internet access

  1. For the time of the update, allow HTTPS (443) from the controller server (on Kubernetes, the nodes too) to:
    • spitfire.sh, spitfire.tr: the install script, bundles, releases.json, the Helm chart
    • Docker Hub: registry-1.docker.io, auth.docker.io, production.cloudflare.docker.com, docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com (image layers), hub.docker.com (the release check of a Kubernetes install)
  2. In the UI, press Check now on the License → Version and updates card; the new release and its notes show up. With the check off (SPITFIRE_UPDATE_CHECK=off) skip this step; the latest release is on usespitfire.com/release-notes.
  3. Run the update command the card shows (Updating step by step); the database is dumped first.
  4. Close the access again.

If you go out through a proxy, run the command with HTTPS_PROXY set: Installing behind a proxy.

b) Internal registry mirror (Harbor, Artifactory, Nexus)

Pull the image on a machine with internet access and push it to your internal registry (or use your registry's Docker Hub proxy cache):

bash
docker pull usespitfire/spitfire:0.33.0
docker tag usespitfire/spitfire:0.33.0 harbor.example.local/spitfire/spitfire:0.33.0
docker push harbor.example.local/spitfire/spitfire:0.33.0

Then unpack the installer bundle (spitfire-0.33.0.tar.gz, listed at usespitfire.com/install) into the install folder and run the installer with that image:

bash
tar -xzf spitfire-0.33.0.tar.gz -C ~/spitfire
~/spitfire/install.sh docker --image harbor.example.local/spitfire/spitfire:0.33.0
~/spitfire/install.sh kubernetes --image harbor.example.local/spitfire/spitfire:0.33.0

With Helm: helm upgrade spitfire ./spitfire-0.33.0.tgz -n spitfire --reuse-values --set image.repository=harbor.example.local/spitfire/spitfire --set image.tag=0.33.0. A new installation also needs the Postgres image in the mirror: push postgres:16 the same way and give --postgres-image harbor.example.local/spitfire/postgres:16 (Helm: --set postgres.image=…); the image given is kept on later runs.

c) Offline bundle (--offline)

Every release publishes one bundle per platform: spitfire-offline-<version>-linux-amd64.tar.gz and …-linux-arm64.tar.gz (listed with their .sha256 at usespitfire.com/install). It holds the Spitfire image and the Postgres image installations use (postgres:16; docker save for that platform), the installer bundle, the Helm chart, the signed releases.json and a signed SHA256SUMS of all of it. A first installation works from the bundle alone; nothing is downloaded.

  1. Download the bundle on a machine with internet access and copy it to the controller server the way your organisation moves files in (approved USB media, a file transfer server, scp through a jump host). A bundle is a few hundred MB; keep three times its size free on the install folder's disk.

  2. For a first installation, unpack the bundle's installer files first (an update skips this):

    bash
    mkdir -p ~/spitfire && tar -xzf spitfire-offline-0.33.0-linux-amd64.tar.gz -C ~/spitfire spitfire-0.33.0.tar.gz
    tar -xzf ~/spitfire/spitfire-0.33.0.tar.gz -C ~/spitfire && rm ~/spitfire/spitfire-0.33.0.tar.gz
  3. Run it with the installer in the install folder:

    bash
    ~/spitfire/install.sh docker --offline spitfire-offline-0.33.0-linux-amd64.tar.gz
    ~/spitfire/install.sh kubernetes --offline spitfire-offline-0.33.0-linux-amd64.tar.gz --registry harbor.example.local/spitfire

The script never reaches the internet. It first checks the SHA256SUMS signature with the Spitfire release key written into it (OpenSSL 3, Ed25519) and every file against the list; if the signature does not hold, it stops without touching anything. Then it loads the image with docker load, unpacks the new release's installer files into the folder (deploy/*/.env is kept) and installs with --image. If the Postgres image is not on this machine it loads that too (if it is, it is left alone: an update does not change the running database's image): if the version changes the database is dumped first, and --rollback works as usual. On Kubernetes --registry is required, because the cluster cannot see images on this machine: the image is pushed to your internal registry as REG/spitfire:<version> (docker login first); the Postgres image is pushed as REG/postgres:16 and the installation uses it. With Helm, the chart is the bundle's helm/spitfire-<version>.tgz: --set image.repository=REG/spitfire --set image.tag=<version> --set postgres.image=REG/postgres:16. Runner servers update from the same bundle: install.sh runner --offline <bundle>.

Without OpenSSL 3 on the server (e.g. RHEL 8) the script cannot check the signature and refuses the bundle. Then give the bundle's .sha256 value listed at usespitfire.com/install: --offline-sha256 <value>. You can also verify the bundle by hand (on a machine with OpenSSL 3):

bash
mkdir bundle && tar -xzf spitfire-offline-0.33.0-linux-amd64.tar.gz -C bundle && cd bundle
{ printf 'spitfire-offline-v1\n'; cat SHA256SUMS; } > signed.txt
openssl base64 -d -A -in SHA256SUMS.sig -out SHA256SUMS.bin
openssl pkeyutl -verify -rawin -pubin -inkey spitfire-release.pub.pem -in signed.txt -sigfile SHA256SUMS.bin
sha256sum -c SHA256SUMS

spitfire-release.pub.pem is Spitfire's release key (also in the bundle's README.txt):

text
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAE7pSZPzN3PgBdeCyFwRvfMP2EWlKt87gSgRu84qu5Io=
-----END PUBLIC KEY-----
Note

--offline comes with this release's install.sh. On an older installation, the first time, unpack the bundle's spitfire-<version>.tar.gz into the install folder (tar -xzf … -C ~/spitfire), then run the command above. Windows (install.ps1) has no --offline: verify the bundle on a Linux machine, load it with docker load -i spitfire-image.tar and run .\install.ps1 docker -Image usespitfire/spitfire:<version>. For Postgres, also run docker load -i postgres-image.tar.

Serving the release list on your network

So that the controller still shows new releases in the UI, put the bundle's releases.json and releases.json.sig on an internal web server and give the controller SPITFIRE_UPDATE_FEED=https://intranet.example.local/spitfire/releases.json (the .sig must be at the same address plus .sig). The list is signed; if it is altered on the mirror the controller refuses it. Replace both files with every new bundle.

Installing behind a proxy

Behind a corporate HTTPS proxy, run the install command with HTTPS_PROXY (and if needed HTTP_PROXY, NO_PROXY) set:

bash
export HTTPS_PROXY=http://proxy.example.com:3128
export NO_PROXY=.example.local
curl -fsSL https://spitfire.sh | bash -s -- docker

The script passes these values on to the controller (Docker: deploy/docker/.env; Kubernetes: the spitfire-proxy Secret). The controller makes the update check, webhooks and SSO calls through this proxy. The installation's own names (localhost, postgres, controller…) are added to NO_PROXY automatically. Add the names of an SSO provider or webhook targets on your internal network to NO_PROXY yourself. If a later run gives no proxy, the earlier setting is kept.

On an installation without internet access, turn the update check off: SPITFIRE_UPDATE_CHECK=off on the controller, and follow the release notes on usespitfire.com/release-notes. If you use your own mirror, give it with SPITFIRE_UPDATE_FEED; the mirror must also carry releases.json.sig. Ways to update: Updating without internet.

Backups and SPITFIRE_SECRET_KEY

Spitfire's data lives in Postgres; connection secrets are encrypted with SPITFIRE_SECRET_KEY. Back up both.

A full backup in one file (the database and the installation's keys, encrypted with a passphrase you choose):

bash
cd ~/spitfire
./install.sh docker --backup spitfire-2026-10-10.sfbak        # Kubernetes: ./install.sh kubernetes --backup …

It asks for a passphrase (at least 12 characters), or takes it from SPITFIRE_BACKUP_PASSPHRASE for a scheduled job. Keep the passphrase apart from the file: without it the backup cannot be opened. To restore, on this machine or a new one, install Spitfire first and then:

bash
./install.sh docker --restore spitfire-2026-10-10.sfbak

The current database is backed up first (backups/), then the backup's data and keys replace it and the services restart; sign in with the backup's users. A backup of a newer Spitfire is refused on an older installation (update it first). The target keeps its own Postgres password.

Or by hand:

  1. Keys: on Docker the ~/spitfire/deploy/docker/.env file, on Kubernetes the spitfire-secrets Secret. Copy it to a safe place (such as a password vault).
  2. Database: updates take ~/spitfire/backups/*.dump automatically when the version changes; restore them with pg_restore. For regular backups, add this folder or the Postgres volume to your own backup system.
Warning

If SPITFIRE_SECRET_KEY is lost, stored connection secrets (database, Kafka… passwords) cannot be read; you have to enter them all again. The TLS identity the controller presents to runners is also stored encrypted with this key.

Ports and network

Port For Who must reach it
8470 (Docker; NodePort 30470 on Kubernetes) Web UI and REST API Users, CI pipelines
8471 gRPC endpoint remote runners connect to, TLS Runner servers in other locations (inbound TCP)
8475 Plaintext gRPC for runners on the same machine/cluster Only the installation's own runners; never published
8472 (optional) Mock services (turned on with SPITFIRE_MOCK_ADDR) The system under test

Runners connect out to the controller; no inbound port is needed on a runner server.

With a reverse proxy (ingress, nginx) in front of the UI, the client address is taken from X-Forwarded-For only when the request comes from loopback or a private network. Declare a proxy on a public address (a cloud load balancer, Cloudflare) in SPITFIRE_TRUSTED_PROXIES (comma-separated CIDRs); otherwise the audit log and the sign-in limits see the proxy's address. When users reach Spitfire directly from the same private network (no proxy in between), set SPITFIRE_TRUST_PRIVATE_NETWORKS=false: then only loopback and the proxies in SPITFIRE_TRUSTED_PROXIES may set the client address, so a user cannot choose the address they appear from in the audit log and the sign-in limits.

Sign-in is throttled: one client address may try 30 times at once, then once every 2 s; an account accepts 10 wrong passwords, then one a minute. When many users sit behind one proxy/NAT, raise the first limit with SPITFIRE_SIGNIN_BURST.

Link-local and cloud metadata addresses (169.254.0.0/16 such as 169.254.169.254, fe80::/10, fd00:ec2::254, 100.100.100.200) are never reached: not by the controller's own requests (webhooks, imports from a URL, observability and connection tests, Try it, GraphQL schema reading) and not by test steps (HTTP, GraphQL, SSE, WebSocket, MQTT 5, browser, a custom SQS endpoint). Such a request fails with link-local and cloud metadata addresses are not allowed. localhost and private addresses (10.x, 172.16–31.x, 192.168.x) are not affected. If a system you test really lives on a link-local address, set SPITFIRE_ALLOW_LINK_LOCAL=1 on the runners (and on the controller for Try it); the controller's own requests stay protected. Test steps also open only http/https addresses (ws/wss for WebSocket), even when the address comes from a variable; a browser step never opens file:// pages.

TLS and runner pin basics

  • Port 8471 is always TLS. The controller creates its own identity on first start and stores it in the database (encrypted with SPITFIRE_SECRET_KEY).
  • A remote runner verifies the controller by the pin of that key (sha256:…). The pin and the ready-made install command are in the key dialog on the Runners page. The pin is required because connection secrets travel to runners over this channel.
  • To use your own certificate, give the controller SPITFIRE_GRPC_TLS_CERT and SPITFIRE_GRPC_TLS_KEY; runners then verify with --tls (system CAs) or --ca <PEM file> instead of a pin.
  • The controller address remote runners see is set at installation with --grpc-public-addr HOST:PORT or with SPITFIRE_GRPC_PUBLIC_ADDR.

Details: Runners → TLS pin and certificates.

Uninstalling

bash
~/spitfire/uninstall.sh docker
~/spitfire/uninstall.sh kubernetes --context C --namespace NS
~/spitfire/uninstall.sh runner          # remote runners installed with install.sh runner

Windows: .\uninstall.ps1 docker or .\uninstall.ps1 runner.

By default the data (Postgres volume / PVC) and the generated keys (.env / spitfire-secrets) are kept; a later install.sh brings everything back. To delete everything, add --purge (Windows: -Purge).

Warning

--purge deletes the database and SPITFIRE_SECRET_KEY; it cannot be undone. Take a backup first.

Common problems

Symptom: ERROR: Cannot reach the Docker daemon. Cause: Docker is not running, or your user is not in the docker group. Fix: Start Docker Desktop or sudo systemctl start docker; add your user to the docker group and log in again.

Symptom: ERROR: Docker Compose not found. Cause: The Compose v2 plugin is not installed. Fix: Install the Docker Compose v2 plugin (https://docs.docker.com/compose/install/).

Symptom: ERROR: Port 8470 is used by another application. Cause: Another service on the machine uses that port. Fix: Pick another port: install.sh docker --port 8480 --grpc-port 8481.

Symptom: ERROR: Could not pull the image: usespitfire/spitfire:... Cause: The machine cannot reach Docker Hub, or the version is wrong. Fix: Try internet access with docker pull; behind a proxy, configure the Docker daemon's proxy; check the version number.

Symptom: The setup screen says "Wrong setup code". Cause: The code was copied incompletely, or it belongs to another installation. Fix: Copy it again from the .env file or the controller log (First sign-in and setup code).

Symptom: The sign-in page opens instead of the setup screen, saying "Setup is already complete". Cause: The first admin already exists (perhaps through --admin-email). Fix: Sign in with that account. If its password is unknown, use spitfire-controller reset-password on the server: Users and access.

Symptom: ERROR: The controller was not ready within 180 s. Cause: The controller failed while starting (database, missing setting…). Fix: Read the log with docker compose -p spitfire -f deploy/docker/docker-compose.yml logs -f controller; if you cannot solve it, prepare a support bundle with ./install.sh --support-bundle (Troubleshooting).

Symptom: The Version and updates card shows Check failed. Cause: The controller cannot reach spitfire.tr. Fix: Behind a proxy, run the install command again with HTTPS_PROXY set; without internet access set SPITFIRE_UPDATE_CHECK=off.

Symptom: After a reinstall, saved connections no longer work; secrets cannot be read or Test fails. Cause: SPITFIRE_SECRET_KEY changed (e.g. .env was deleted and the installation redone). Fix: Put back the .env you backed up and run the installer again; without a backup, enter the secrets again.