Install in an air-gapped environment
Install, update, and support Dreadnode on a disconnected cluster — prerequisites, the procedure for each install path, and support-bundle transfer.
sudo ./dreadnode install --license license.yaml --airgap-bundle dreadnode.airgapOn Embedded Cluster that flag is the whole difference. Everything else on this page is about the two things you need before it will run: a license entitled to download air-gap bundles, and a release that has one built.
Before you begin
Section titled “Before you begin”Air gap is not a switch you flip on an existing license. Two things have to be in place, and both come from us:
Air-gap download on your license. The entitlement differs by install path — Embedded Cluster and KOTS use one, the Helm CLI uses another. Tell us which path you’re installing and we’ll enable the right one.
A release with a built bundle. Bundles are built per release, per channel. A version that shipped before your entitlement existed has no bundle until it’s rebuilt. Name the version you intend to install so we can confirm its bundle exists before you plan the transfer.
Reach out to us to arrange both. Your path’s normal requirements still apply — VM requirements for Embedded Cluster, cluster requirements otherwise. Air gap changes how images arrive, not what the platform needs to run.
On the KOTS existing-cluster and Helm CLI paths, download the support-bundle binary before you cross the boundary and carry it in alongside the release bundle. It’s how you collect diagnostics for us later, it isn’t part of the air-gap bundle, and there’s no way to fetch it once you’re disconnected. Embedded Cluster installs it on control plane nodes for you, so that path doesn’t need this.
curl -L https://github.com/replicatedhq/troubleshoot/releases/latest/download/support-bundle_linux_amd64.tar.gz \ | tar xzvf -sudo mv ./support-bundle /usr/local/bin/kubectl-support_bundlePick your path
Section titled “Pick your path”| Path | Bundle | Ingress | Image handling |
|---|---|---|---|
| Embedded Cluster | Yes — includes k0s, Traefik, and the Admin Console | Included | Automatic, into an in-cluster registry |
| Existing cluster with KOTS | Yes | You supply it | KOTS re-tags and pushes to your registry |
| Helm CLI | No — bundles are a KOTS feature | You supply it | You mirror images yourself |
Embedded Cluster is the shortest path and the one to choose unless you already run a cluster you must deploy into.
Embedded Cluster
Section titled “Embedded Cluster”Embedded Cluster’s air-gap bundle carries the infrastructure as well as the application: k0s, the Admin Console, Traefik, and every platform image. During installation it stands up a registry inside the cluster to hold the application images, and preloads the infrastructure images and Helm charts onto each node.
1. Download the bundle on a machine with internet access.
curl -f 'https://replicated.app/embedded/dreadnode/stable?airgap=true' \ -H 'Authorization: <license-id>' -o dreadnode.tgzYour license ID is the licenseID: field inside your license file. For Beta releases,
replace stable with beta.
2. Extract it and confirm the bundle is there.
tar -xvzf dreadnode.tgzls dreadnode.airgap3. Transfer all three files to the target machine, then install.
sudo ./dreadnode install --license license.yaml --airgap-bundle dreadnode.airgapThe installer prompts for an Admin Console password, runs its host preflight checks, and prints the Admin Console URL on port 30000. Installation takes longer than an online install — it loads every image from the bundle before the application starts.
4. Configure and deploy through the Admin Console. From here the flow matches an
online install: open the console, complete the config screen, and click Deploy. See
Configure via the Admin Console
for what each group covers, and
Build a ConfigValues file if
you’d rather supply configuration on the command line with --config-values.
Existing cluster with KOTS
Section titled “Existing cluster with KOTS”Installing into a cluster you already run needs an image registry inside the network that KOTS can push to. KOTS rewrites every image reference in the application to read from that registry, then re-tags and pushes the images from the bundle into it. You supply two sets of registry credentials: read-write ones to push with, which KOTS does not store, and read-only ones the cluster keeps for pulling.
The application expects a single namespace in that registry, and most registries need the namespace to exist before anything can be pushed into it. Amazon ECR is the exception — it doesn’t use namespaces.
You’ll need the application bundle for your version from us, plus the KOTS Admin Console
bundle (kotsadm.tar.gz) from the
kots releases page. Its version has to
match your kots CLI — check with kubectl kots version — and be compatible with the
application bundle. Push the Admin Console images first, then install:
kubectl kots admin-console push-images ./kotsadm.tar.gz <registry-host> \ --registry-username <rw-username> \ --registry-password <rw-password>
kubectl kots install dreadnode \ --kotsadm-registry <registry-host> \ --registry-username <ro-username> \ --registry-password <ro-password>Then open the Admin Console, upload your license and the .airgap application bundle,
complete the config screen, and deploy. Replicated’s
air gap installation in existing clusters
covers the registry compatibility requirements and the full prompt-by-prompt sequence.
This path does not bring an ingress controller — see Ingress outside Embedded Cluster.
Helm CLI
Section titled “Helm CLI”Replicated does not build air-gap bundles for Helm CLI installs; bundles are a KOTS feature. An air-gapped Helm install means you mirror the platform images into your own registry and install the chart against that mirror. We provide the image list and the pull, tag, and push commands for your target version — ask us for them alongside the entitlement, since the list changes release to release.
Once your images are mirrored, point the chart at your registry:
global: domain: dreadnode.example.com imageRegistry: registry.internal.example.com imagePullSecrets: - name: mirror-pull-secret airgapped: true
replicated: isAirgap: trueglobal.imageRegistry replaces the registry host on every image the chart renders and
leaves the repository path untouched, so mirror each image to the same path under your own
host. The chart refuses to install if you set it without global.imagePullSecrets, because
every workload would otherwise fail to pull. Create that Secret before you install.
Ingress outside Embedded Cluster
Section titled “Ingress outside Embedded Cluster”Traefik ships only as an Embedded Cluster extension. On the KOTS existing-cluster and Helm
CLI paths you supply your own ingress controller — and in an air-gapped network, you mirror
its images too. The chart emits standard networking.k8s.io/v1 Ingress resources and does
not install a controller.
Set global.ingress.className if your controller isn’t the cluster default. Traefik is
what we test against; other controllers work in principle but may need controller-specific
annotations via global.ingress.annotations.
Updates
Section titled “Updates”Air-gapped updates carry a new bundle in and deploy it from the Admin Console. Migrations are forward-only and rollback stays disabled — see Upgrades for what runs during an upgrade and how recovery works.
On Embedded Cluster, download the new version with the same curl command you used to
install, extract it, and check for the .airgap file as before. Then either upload it from
the command line:
./dreadnode update --airgap-bundle dreadnode.airgapOr use Version history → Upload new version in the Admin Console and choose the
.airgap file. Either way the version becomes available but is not live: click Deploy
next to it, review the config and preflight screens, and confirm.
On an existing cluster with KOTS, upload the new .airgap bundle through the Admin
Console the same way.
Support bundles and telemetry
Section titled “Support bundles and telemetry”A support bundle is how anything gets out of an air-gapped install — including the instance telemetry we’d otherwise receive continuously.
Generate one from the Admin Console under Troubleshoot, or with the support-bundle binary you carried in during setup. See Support bundles for both commands. If you didn’t stage that binary, there’s no way to install it from inside the enclave, and the Admin Console is your only route.
Then transfer the archive out of the enclave the same way you carried the bundle in, and send it to us. Review the contents first if your environment requires it — the bundle collects logs, cluster state, and the telemetry Secrets.
What still reaches the network
Section titled “What still reaches the network”An air-gapped install has no outbound path, and the platform doesn’t need one. Two things are worth knowing when you plan a network review.
The outbound endpoints an online install
uses go unused: images come from the bundle or your mirror, and the SDK stops calling out
once air-gap mode is on. On the Helm CLI path that last part depends on you setting
replicated.isAirgap: true — until you do, the SDK keeps trying.
Marking the deployment air-gapped turns off the features that can only reach a public host, so configuration left over from a connected install doesn’t produce outbound attempts. That covers GitHub and Google authentication — use OpenID Connect against an identity provider inside your network instead — along with the Linear and HackerOne integrations and the model catalog.
Services you point somewhere yourself are a different case, and the platform leaves them alone: E2B sandboxes, external SMTP, and Logfire reach whatever you configure. See Optional external services. E2B runs sandboxes in E2B’s cloud and cannot work without outbound access; leave the sandbox provider on its default to keep execution inside your cluster.
Features that need outbound access
Section titled “Features that need outbound access”Most of the platform works the same disconnected as connected. The features that need a public host are switched off when the deployment is marked air-gapped, rather than left to fail in front of a user:
| Feature | Why it needs the network | Disconnected behaviour |
|---|---|---|
| Analytics → Notebook | Its Python kernel is a WebAssembly runtime the browser downloads from a public CDN when the notebook opens | The tab is hidden. Analytics → Query covers the same project data |
| Web-search result icons | Site icons come from a public favicon service | Results show a generic icon |
| Agent web search | The web_search tool answers from a search provider, and the hosted one needs a public API | The tool reports that search is unavailable. Point it at an internal provider to restore it |
| GitHub and Google sign-in | Both authenticate against the provider’s own public endpoints | Neither appears on the sign-in page. Use OpenID Connect or local passwords |
| Linear and HackerOne | Both submit findings to a fixed vendor API | Neither can be selected. Webhook connections still work — see below |
| Model pricing and limits | Cost, context window, and capability metadata come from a public model catalog | Served from a copy shipped in the release. Accurate as of that release |
Agent web search deserves a note. An agent’s web_search tool normally answers from the
hosted search backend, which reaches a public API. Disconnected, that backend is
unavailable, and the tool is barred from falling back to a public search engine — so the
call returns no results and says why, rather than reaching out and failing. Tasks written
against a connected deployment that assume search works will still run; their searches
come back empty with the reason in the tool’s warnings.
If you run a search provider inside your network, you can give the tool a real backend. A
provider you have pointed at your own host is not restricted — only the one that needs no
credentials and answers from a public engine is. Set the provider’s credentials and
internal URL through
config.sandboxExtraEnv, along with
DREADNODE_WEB_SEARCH_MODE: auto to let the tool use it.
An agent can still reach a URL a task hands it. The fetch and web_extract tools connect
to whatever the task or model asks for, which is what makes them useful against services
inside your enclave, and they are not gated by this setting. Restricting where an agent may
connect is your network’s job, not a product toggle.
Model pricing deserves a note. Disconnected, the platform reads cost and context data from a catalog bundled into the image rather than fetching a current one, so a model released after your version won’t be in it. Deployments you configure with explicit pricing are unaffected — that pricing is what the platform bills against. If you add a model the bundled catalog doesn’t recognize, set its costs on the deployment.
Findings can still leave the deployment through a webhook connection, which posts to whatever URL you give it. Point it at a ticketing system inside your network to keep the submission workflow intact.
Embedded Cluster and KOTS detect air-gapped installs and set this for you. On the Helm CLI
path nothing can detect it, so set global.airgapped: true yourself — the same division of
labour as replicated.isAirgap.
Left unset on a disconnected deployment, neither feature breaks loudly. The notebook sits on Initializing Python… and never finishes, and result icons silently fail to load. If you are seeing either, this value is the first thing to check.
Fonts are served by the platform itself and need no configuration. Earlier versions loaded them from a public font service on every page load, which failed in a disconnected network and left the interface in a fallback typeface.
Documentation
Section titled “Documentation”This documentation ships inside the release. The dreadnode-docs workload serves the pages
for the version you installed at /docs on the platform’s own hostname, and every help
link in the application points there, so a reader on an isolated network gets the same
docs as a connected one — including the API and CLI reference and full-text search, which
run entirely in the browser. Nothing in the bundled copy fetches from a public host.
Two things the public site has are left out, because they are indexes of absolute URLs
and the hostname is not known when the release is built: the sitemap, and the llms.txt
exports on the homepage.
The bundled copy is on by default and needs no configuration. Turning it off in favour of another documentation site, and the routing it needs under your own ingress, are covered in Configure → Documentation.
Agent capabilities and their tools
Section titled “Agent capabilities and their tools”Capabilities are how agents get their tooling, and each one can declare system packages, Python packages, and setup scripts that the sandbox runs when it starts. Disconnected, none of that is fetched: the runtime image already contains everything the capabilities shipped with the release declare, so each step finds its work already done.
A deployment marked air-gapped goes further and installs without network access at all, rather than relying on those steps to be quiet. Python packages resolve from what is already installed and the local cache. System packages are not requested — if one is missing, the deployment reports it as an unmet prerequisite instead of contacting a package archive it cannot reach. A request that cannot succeed is not made.
Setup scripts still run, because a capability whose tools are present has to keep working. Their contents are the capability author’s responsibility, so a script that reaches for something it does not already have will fail. That failure is bounded and reported rather than left to hang, and it is recorded distinctly from an ordinary install error, so a network review can tell the difference between a capability that could not install and one that tried to reach a public host.
A capability whose prerequisites are missing loads with those tools marked unavailable. The agent is told, so it asks you rather than calling tools that cannot work.
Two tools are the exception, because we do not redistribute them.
Caido backs the web-security capability’s proxy tooling. The capability talks to a Caido
instance over the network rather than driving a local binary, so run Caido somewhere inside
your network and point the sandbox at it by setting CAIDO_URL. Until you do, the
capability loads but its proxy tools cannot connect, and the agent is told the tool is
unavailable rather than discovering it mid-task.
Burp Suite is optional for the same capability. Supply the Community or Professional jar
at /opt/burp/burpsuite.jar in a runtime image derived from ours if you want it. A Java
runtime is already included, so nothing else is needed.
The browser automation tool downloads its browser on first use and cannot do that disconnected. The rest of the capability is unaffected.
Pointing sandboxes at services inside your network
Section titled “Pointing sandboxes at services inside your network”config.sandboxExtraEnv sets environment variables on every sandbox. Use it for the
endpoints above, and for internal package mirrors if you run them:
dreadnode-api: config: sandboxExtraEnv: CAIDO_URL: http://caido.internal.svc.cluster.local:8080 UV_INDEX_URL: https://nexus.internal/repository/pypi/simple PIP_INDEX_URL: https://nexus.internal/repository/pypi/simple HF_ENDPOINT: https://huggingface.internalMirrors are optional. Everything the built-in capabilities need is already in the image, and these are only useful if you have added capabilities of your own that declare dependencies we do not ship. The variables are the standard ones each tool already understands, so anything a resolver or client reads from its environment works here.
Variables the platform sets for the sandbox itself, such as its server address and credentials, cannot be overridden this way. Setting one stops the API at startup with a message naming it, rather than accepting a value that would be ignored.
Set up the platform
Section titled “Set up the platform”Installation is not a finished deployment. Continue with the post-install steps, which are the same on every path:
- First admin account — sign in and claim platform ownership
- First model deployment — every model picker stays empty until you add one
- Connect clients — point the TUI, CLI, and SDK at your deployment
Your Hub starts empty, and an air-gapped instance can’t pull from ours. See Loading Hub content for the export-and-carry flow that populates it.