Skip to main content

Air-gapped installation

Written by Aron Day

Use this when the target server has no internet access. You run the air-gapped bundle builder on a connected machine, then carry the resulting bundle to the offline server.

The offline server must still meet all the prerequisites except outbound connectivity — it needs no internet access at all.

Build host requirements

The connected machine that builds the bundle needs:

  • An amd64 Linux host with several gigabytes of free disk space in the output directory — the bundle contains every container image.

  • curl, Docker Engine (daemon running and usable by the current user), ORAS, sha256sum, tar, unzip, and zip.

  • Outbound HTTPS (TLS 1.2 or later) to sh.3b.dev and oci.tines.com. github.com is needed only if the builder has to install ORAS itself.

The builder contacts no other endpoints and never changes the host without asking first, so this list is everything a provisioning team needs to prepare an approved build host in advance.

Step 1 — Produce the bundle on a connected machine

On the connected machine, run the builder as a user with access to Docker:

bash -c "$(curl --proto '=https' --tlsv1.2 -fsSL https://sh.3b.dev/airgapped.sh)"

If your security process requires reviewing scripts before they run, download the script, inspect it, and run your reviewed copy — its header comment states exactly which endpoints it contacts and how credentials are handled:

curl --proto '=https' --tlsv1.2 -fsSLO https://sh.3b.dev/airgapped.sh
less airgapped.sh
bash airgapped.sh

Provide the version, tenant name, and API key when prompted. The script downloads the release files and container images, then creates 3b-self-hosted-<version>.zip in the current directory and prints its full path and SHA256 checksum.

The builder reports whether each dependency is available before doing anything else. If anything is missing, it asks whether to install it and defaults to no. You can explicitly allow it to install the missing packages through apt, dnf, or yum; before installing ORAS, it checks connectivity to github.com, then downloads the official release and verifies its pinned SHA256 checksum. On managed systems, answer no and have your administrator install the approved packages instead. For approved non-interactive installation, set DEPENDENCY_ACTION=y.

The builder also verifies that Docker is usable by the current user, and exits with instructions if it isn’t — common right after installing Docker, when the user is not yet in the docker group. Have an administrator grant access (for example usermod -aG docker <user>), log in again, and re-run the builder.

As part of its host checks, the builder verifies TLS connectivity to oci.tines.com after satisfying its dependencies and before requesting registry credentials. A connectivity failure exits without beginning the bundle download.

This zip contains setup.sh, the Helm chart, the bundled k3s and Helm binaries, the configuration template, and all the container images, so the offline server needs nothing from the network.

The credentials are held in temporary login configurations while the images are downloaded, then deleted. They are not included in the bundle.

To run the builder non-interactively, provide its inputs as environment variables:

VERSION=v2.0.0 \
  REGISTRY_USERNAME=your-tenant \
  REGISTRY_PASSWORD=your-api-key \
  bash -c "$(curl --proto '=https' --tlsv1.2 -fsSL https://sh.3b.dev/airgapped.sh)"

When scripting, load REGISTRY_PASSWORD from your secret manager or a protected file rather than typing the API key inline, so it stays out of your shell history. Interactive runs are unaffected — the prompt does not echo the key.

Step 2 — Move the bundle to the offline server

Copy the zip to the air-gapped server by whatever means you use (USB, SCP, internal file transfer, etc.).

Step 3 — Install on the offline server

On the offline server, extract the bundle into /opt/3b and run the installer. Both steps need root, because they write to /opt:

sudo unzip 3b-self-hosted-v2.0.0.zip -d /opt/3b && cd /opt/3b
sudo bash setup.sh

(Replace the filename with your actual version.) From here, setup.sh asks the same configuration questions as the standard install, then installs k3s, imports the bundled images, and deploys everything. Because the images are already in the bundle, there is no registry download.

Continue with verifying the install.

Updating an air-gapped server

To move to a new version, build the new version’s bundle on a connected machine (step 1), copy it over, change VERSION in /opt/3b/.env, replace the previous chart, images, and bundled tools, and re-run setup.sh:

sudo rm -rf /opt/3b/chart /opt/3b/images /opt/3b/bundled
sudo unzip -o 3b-self-hosted-<new-version>.zip -d /opt/3b
cd /opt/3b && sudo bash setup.sh

Your configuration and secrets in /opt/3b/.env are preserved — extracting the bundle never overwrites an existing .env. See updating the single-server install.

Did this answer your question?