This runbook runs the production Overture tile generator and static viewer on Docker Desktop for Windows. The Overture GeoParquet source is an internal S3-compatible service, and all runtime images come from an Artifactory registry inside the disconnected network. Nothing in this workflow builds an image or requires a public registry.
The deployment uses compose.windows-airgap.yml. Run every command below from PowerShell in the repository root.
internal S3 GeoParquet
-> one-shot tile-generator container
-> Docker named volumes for PMTiles and preserved GeoParquet
-> one-shot PMTiles publisher
-> same S3 bucket under pmtiles/release/<release>/
-> one-shot catalog container
-> Docker named volumes for catalogs and viewer configuration
-> read-only nginx viewer plus browser-accessible S3 HTTP gateway
-> browser on the Windows host
Only tiles-generator and publish-pmtiles receive the S3 credentials. The
catalog and viewer containers have no S3 credentials. The browser reads PMTiles
through an internal HTTP endpoint because browsers cannot read s3:// URLs
directly. The viewer continues to serve preserved GeoParquet downloads locally.
Use Docker Desktop in Linux-container mode with a current Docker Compose v2.
Allocate enough Docker Desktop CPU, memory, and virtual-disk capacity for the
selected Overture themes. Whole-world base, buildings, and transportation
runs can be large; run one theme at a time and monitor free space.
The air-gapped Artifactory must contain these Linux images:
- The production Overture viewer image built from
Dockerfile.viewer. - The production tile-generator image built from
airgap/tile-generator/Dockerfile. - A production Node 20 image used only for the one-shot catalog job. A mirrored
node:20-alpineimage is sufficient because the catalog script uses only Node built-ins.
Use immutable release tags or, preferably, digest-pinned Artifactory references. The tile-generator and catalog images must match the CPU architecture selected in Docker Desktop. The production images must already trust the internal Artifactory and S3 certificate authorities; do not disable TLS verification.
Confirm Docker Desktop and Compose are available:
docker version
docker compose versionCreate .env.windows-airgap in the repository root. It contains both deployment
settings and the S3 credentials. Replace every example value with the
deployment's actual value:
VIEWER_IMAGE=artifactory.airgap.example/overture/overture-explorer-airgap:1.0.0
TILES_IMAGE=artifactory.airgap.example/overture/overture-tiles-airgap:1.0.0
CATALOG_IMAGE=artifactory.airgap.example/dockerhub/library/node:20-alpine
OVERTURE_RELEASE=2026-04-15.0
S3_BUCKET=overture-source
SOURCE_RELEASE_PREFIX=release
PMTILES_RELEASE_PREFIX=pmtiles/release
S3_ENDPOINT_URL=https://s3.airgap.example
S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=replace-with-s3-access-key
AWS_SECRET_ACCESS_KEY='replace-with-s3-secret-key'
PMTILES_HTTP_BASE=https://s3-gateway.airgap.example/overture-source/pmtiles/release/2026-04-15.0/
THEME=places
BBOX=
PRESERVE_PARQUET=true
DOWNLOAD_MIN_ZOOM=15
VIEWER_PORT=8088
OUTPUT_VOLUME_PREFIX=overture-2026-04-15-0The Compose stack constructs both S3 paths from the same S3_BUCKET:
s3://<bucket>/<source-release-prefix>/<release>/theme=<theme>/type=<type>/<file>.parquet
s3://<bucket>/<pmtiles-release-prefix>/<release>/<theme>.pmtiles
For example:
s3://overture-source/release/2026-04-15.0/theme=places/type=place/part-00000.parquet
s3://overture-source/pmtiles/release/2026-04-15.0/places.pmtiles
Do not include leading or trailing slashes in SOURCE_RELEASE_PREFIX or
PMTILES_RELEASE_PREFIX. PMTILES_HTTP_BASE is the browser-accessible URL for
the generated release directory and must refer to the same objects as the
s3://.../pmtiles/release/<release>/ path. It may be an S3 HTTP endpoint or an
internal reverse proxy, but it must allow browser GET and HEAD, byte-range
requests, and CORS from the viewer origin. Avoid expiring presigned URLs in the
static catalog.
BBOX is min_lon,min_lat,max_lon,max_lat. Set BBOX= for a whole-world run.
Use a different OUTPUT_VOLUME_PREFIX for each release or independently managed
deployment so that outputs cannot be mixed accidentally.
If the S3 service runs directly on the Windows host, use an endpoint such as
https://host.docker.internal:<port>. Do not use localhost: inside the
generator container it means the container itself.
Use single quotes for a secret containing $, #, spaces, or other characters
that Docker Compose could otherwise interpret. The quotes delimit the dotenv
value and are not passed to S3.
.env.windows-airgap is excluded by the repository's .gitignore. Confirm that
before adding or committing files:
git check-ignore .env.windows-airgap
git status --shortThe first command must print .env.windows-airgap, and the second must not list
it. Restrict the file's Windows ACL to the operator and required administrator
accounts. Do not paste or print the file in tickets, logs, or deployment records.
The Compose stack loads it only into the one-shot tiles-generator and
publish-pmtiles services; the catalog and viewer services do not use this env
file.
The S3 identity needs ListBucket and GetObject on the configured source
prefix. It also needs ListBucket, GetObject, and PutObject on only the
pmtiles/release/<release>/ output prefix. It does not need permission to modify
the source GeoParquet objects.
Authenticate only to the internal registry. Do not place the registry password
in .env.windows-airgap. config --images prints only resolved image names;
avoid an unrestricted docker compose config because its rendered output can
include environment values:
docker login artifactory.airgap.example
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml --profile generate config --images
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml --profile generate pullInspect the resolved images and record their immutable digests in the deployment log:
docker image inspect artifactory.airgap.example/overture/overture-explorer-airgap:1.0.0 --format '{{json .RepoDigests}} {{.Os}}/{{.Architecture}}'
docker image inspect artifactory.airgap.example/overture/overture-tiles-airgap:1.0.0 --format '{{json .RepoDigests}} {{.Os}}/{{.Architecture}}'
docker image inspect artifactory.airgap.example/dockerhub/library/node:20-alpine --format '{{json .RepoDigests}} {{.Os}}/{{.Architecture}}'All three images must report linux/<Docker Desktop architecture>. Once the
images are present locally, generation and viewing do not require Artifactory to
remain reachable.
Test credentials, endpoint, region, certificate trust, and the expected object layout before starting an expensive generation run:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml --profile generate run --rm --entrypoint /bin/bash tiles-generator -euc 's5cmd ls "${SOURCE_PATH%/}/theme=${THEME}/type=*/*.parquet"'Do not continue unless this returns one or more parquet objects. If the S3
appliance does not support that wildcard form, use s5cmd ls successively on
the theme prefix and a known exact object key.
Generate the theme configured by THEME:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml --profile generate run --rm tiles-generatorTo generate several themes with the same release and bounding box, run them sequentially:
$Themes = @("base", "buildings", "places", "divisions", "transportation", "addresses")
foreach ($Theme in $Themes) {
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml --profile generate run --rm -e "THEME=$Theme" tiles-generator
if ($LASTEXITCODE -ne 0) { throw "Tile generation failed for $Theme" }
}Each successful run writes:
tiles/<release>/<theme>.pmtiles
data/release/<release>/theme=<theme>/type=<type>/<file>.parquet
The PMTiles file is initially local. The publisher uploads it to the configured path in the same S3 bucket before the viewer starts.
The generator downloads the selected theme from S3 into its temporary container storage before processing it. Ensure Docker Desktop has enough free virtual-disk space for both temporary input and persistent output. Removing the one-shot container after success releases its temporary layer; the named output volumes remain.
Start the viewer only after at least one theme has completed:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml up -d viewerCompose first runs the one-shot publish-pmtiles service, which synchronizes all
locally generated PMTiles for the release to
s3://<bucket>/pmtiles/release/<release>/. The one-shot catalog service then
discovers the available PMTiles and parquet files, writes S3 HTTP PMTiles links
into the STAC catalogs, creates the download manifest and release-matched
viewer-config.json, and exits. The viewer starts only if both jobs succeed.
Open:
http://localhost:8088
Use the configured VIEWER_PORT instead of 8088 if it was changed.
After generating another theme, rerun the catalog and recreate the viewer so the new theme is listed:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml run --rm publish-pmtiles
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml run --rm catalog
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml up -d --force-recreate viewerCheck container state and logs:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml ps -a
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml logs publish-pmtiles catalog viewerProbe the runtime configuration, root catalog, release manifest, uploaded PMTiles object, and PMTiles range support:
curl.exe -fsS http://localhost:8088/config/viewer-config.json
curl.exe -fsS http://localhost:8088/catalog/catalog.json
curl.exe -fsS http://localhost:8088/catalog/2026-04-15.0/manifest.geojson
curl.exe -fsS -D - --range 0-1023 -o NUL https://s3-gateway.airgap.example/overture-source/pmtiles/release/2026-04-15.0/places.pmtilesReplace the port, release, and theme in those URLs with the configured values.
The final request should print HTTP 206 Partial Content in its response
headers. In the browser, confirm that the map loads with
the network disconnected from all public services and that visible-layer
downloads return data from /data/release/<release>/.
Stop the viewer while retaining every generated object:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml downRestart it later with:
docker compose --env-file .env.windows-airgap -f compose.windows-airgap.yml up -d viewerThe named volumes are persistent workstation data inside Docker Desktop. Back
them up according to the deployment's recovery requirements. Do not use
docker compose down --volumes unless permanent deletion of all generated
PMTiles, GeoParquet, catalogs, and runtime configuration is intended.
If Artifactory pulls fail:
- Confirm the three image references are fully qualified internal names.
- Confirm Docker Desktop trusts the Artifactory CA and the operator is logged in.
- Confirm the image architecture matches Docker Desktop.
If S3 access fails:
- Confirm the endpoint is reachable from a Linux container, not only Windows.
- Do not use
localhostfor a service running on the Windows host; usehost.docker.internal. - Confirm the S3 certificate chain is trusted by the production generator image.
- Confirm the region, read/write access policies, both release prefixes, and object-key case.
- Re-run the exact-prefix check from section 6.
If PMTiles publishing or browser loading fails:
- Run
publish-pmtilesdirectly and confirms5cmd lsreports the uploaded key. - Confirm
PMTILES_HTTP_BASEmaps to the same bucket and release prefix. - Confirm the HTTP endpoint supports anonymous or gateway-authorized browser reads without exposing the S3 write credentials.
- Confirm CORS permits the viewer origin and byte-range requests return
206.
If generation is killed or Docker Desktop runs out of space:
- Increase Docker Desktop memory and virtual-disk capacity.
- Generate one theme at a time and use a bounded
BBOXfirst. - Inspect Docker Desktop disk usage before retrying.
If the viewer is blank:
- Confirm the catalog job completed successfully.
- Confirm the requested release and theme exist in the named volumes.
- Fetch the catalog and PMTiles URLs from section 9 directly.
- Confirm PMTiles responses support byte ranges.
- Use immutable, verified production image digests from internal Artifactory.
- Give the S3 identity read-only access to the source prefix and write access only to the generated PMTiles prefix.
- Keep secret values out of Compose, logs, the viewer, and deployment records.
- Protect
.env.windows-airgapwith Windows ACLs and rotate it according to site policy. - Keep TLS verification enabled for Artifactory and S3.
- Validate that browser developer tools show no public-network requests.
- Retain deployment records for image digests, release, BBOX, generated themes, catalog timestamp, and validation results.