Deploy Air-Gapped using Docker Compose
Anchore Enterprise can run in an air-gapped environment with no outbound internet access. The only air-gapped-specific work is getting the container images onto the air-gapped network: you pull and build them on an internet-connected system, then move them across. Once the images are in place, deployment follows the standard Docker Compose procedure.
Prerequisites
- Low side (internet-facing) — the Docker static binary, used only to pull, build, and save images.
- High side (air-gapped) — Docker Engine/CE and a Docker Compose that supports at least v2 of the Compose configuration format, used to run Anchore Enterprise.
Detailed sizing and other requirements are in Requirements.
anchore-db image installs pg_cron, which requires APT access. If APT resources are not reachable on your network, work with Anchore Customer Success for alternatives.Prepare the Images (low side)
Download the current Docker Compose file and the database Dockerfile:
curl -sSfL https://docs.anchore.com/current/docs/deployment/docker_compose/docker-compose.yaml > docker-compose.yaml curl -sSfL https://docs.anchore.com/current/docs/deployment/docker_compose/Dockerfile.anchore-db > Dockerfile.anchore-dbPull the Anchore Enterprise images and build the database image:
docker pull docker.io/anchore/enterprise:v6.0.0 docker pull docker.io/anchore/enterprise-ui:v6.0.0 docker pull docker.io/redis:7.4.6 docker build -f Dockerfile.anchore-db -t anchore:db .
Move the Images to the High Side
Choose one of the following. A private container registry is the recommended path; use a local image tarball only if no registry is available on the air-gapped network.
Option 1: Private Container Registry (Recommended)
Re-tag the images for your private registry, replacing
<registry>with your registry domain (for example,core.harbor.domain):docker tag docker.io/anchore/enterprise:v6.0.0 <registry>/anchore/enterprise:v6.0.0 docker tag docker.io/anchore/enterprise-ui:v6.0.0 <registry>/anchore/enterprise-ui:v6.0.0 docker tag docker.io/redis:7.4.6 <registry>/redis:7.4.6 docker tag anchore:db <registry>/anchore:dbIf the registry is only reachable from the high side, save the tagged images and transfer them across (along with
docker-compose.yaml,Dockerfile.anchore-db, and yourlicense.yaml), then load them on the high side:# Low side docker save -o anchore-airgap-images.tar \ <registry>/anchore/enterprise:v6.0.0 \ <registry>/anchore/enterprise-ui:v6.0.0 \ <registry>/redis:7.4.6 \ <registry>/anchore:db # High side docker load -i anchore-airgap-images.tarPush the images to your private registry from a system that can reach it:
docker push <registry>/anchore/enterprise:v6.0.0 docker push <registry>/anchore/enterprise-ui:v6.0.0 docker push <registry>/redis:7.4.6 docker push <registry>/anchore:db
Option 2: Local Image Tarball
Save the images to a single archive:
docker save -o anchore-airgap-images.tar \ docker.io/anchore/enterprise:v6.0.0 \ docker.io/anchore/enterprise-ui:v6.0.0 \ docker.io/redis:7.4.6 \ anchore:dbTransfer the archive — along with
docker-compose.yaml,Dockerfile.anchore-db, and yourlicense.yaml— to the high side, then load it:docker load -i anchore-airgap-images.tar docker images
Deploy on the High Side
Besides the images, the air-gapped host needs your docker-compose.yaml and license.yaml in the working directory. You downloaded the Compose file on the low side in Prepare the Images; if you have not already copied it and the license across with the images, do so now. The database is deployed from the pre-built anchore:db image you moved, so there is nothing to build here. Configure the deployment as described in Step 4: Configure Secrets, with two additional air-gapped-specific changes:
Point every image: line at your air-gapped images instead of Docker Hub. Use your private-registry tags for Option 1, or the local names you loaded for Option 2. The enterprise image is referenced by many services (api, catalog, analyzer, policy-engine, and others), so update every instance. The anchore-db service builds its image from the Dockerfile by default, so replace its build: section with a reference to the anchore:db image you built and moved earlier.
For example, the api service ships referencing Docker Hub, and anchore-db builds its image locally:
api:
image: docker.io/anchore/enterprise:v6.0.0
anchore-db:
build:
context: .
dockerfile: Dockerfile.anchore-db
Using a private registry (Option 1), change them to your registry tags:
api:
image: <registry>/anchore/enterprise:v6.0.0
anchore-db:
image: <registry>/anchore:db
Using local images loaded from the tarball (Option 2), reference the local image names instead:
api:
image: anchore/enterprise:v6.0.0
anchore-db:
image: anchore:db
build: section (the context and dockerfile lines) from the anchore-db service when you add its image: line. The database image was already built and moved, so there is no need to build it again on the air-gapped host.Configure the deployment for air-gapped feed handling. Because the deployment cannot reach the Anchore Data Service, you must disable the Data Syncer’s automatic feed sync and then download and import feed bundles manually with AnchoreCTL. Both steps are described in Air-Gapped Feed Configuration.
Once the edits are complete, start the stack as described in Step 5: Start the Deployment.
Last modified June 17, 2026