# WebDesigner: Configuring a node to run containerized Chrome

Dockerfile Dockerfile.linux-linux Dockerfile.macos-linux Dockerfile.windows Dockerfile.windows-linux Dockerfile.windows-windows

**Status:** Development / validation. Do not enable for production until the acceptance checklist in the implementation progress log (`<span class="editor-theme-code">documentation/BrowserManager/design/containerized-browser-pool-implementation-progress.md</span>`) is complete.

## Overview

DSServer can run Chrome sessions inside disposable Docker containers instead of a local browser profile. Each session leases a container from a pool; when the session ends the container's Chrome process and lease directory are cleaned up and the container is reused. Local browser profiles keep working through the existing manager path — containerized Chrome is an additional profile (`<span class="editor-theme-code">ChromeContainerized</span>`), not a replacement.

Source lives in `<span class="editor-theme-code">DSServer/container-browser/</span>` (Dockerfiles, shared `<span class="editor-theme-code">browser-supervisor.py</span>`, baked `<span class="editor-theme-code">extensions/</span>`, host guides under `<span class="editor-theme-code">guides/</span>`, and `<span class="editor-theme-code">global.json</span>` examples under `<span class="editor-theme-code">config/</span>`). Installed AIQ packages use the **release-matched container-browser bundle** shipped with that release (see [Installed AIQ package vs. source checkout](https://appvance.atlassian.net/wiki/spaces/EN/pages/5542674435/WebDesigner+Configuring+a+node+to+run+containerized+Chrome#Installed-AIQ-package-vs.-source-checkout "#Installed-AIQ-package-vs.-source-checkout")).

### Key concepts

- **The container OS selects the image, not the host OS.** A Mac or a Windows 11 machine in Linux-container mode runs the Linux image. There is no native macOS container mode.
- **Two images:** Linux (`<span class="editor-theme-code">appvance/ds-chrome:local</span>`, Debian bookworm + Google Chrome stable, **linux/amd64**) and Windows (`<span class="editor-theme-code">appvance/ds-chrome-windows:local</span>`, Windows Server 2025 LTSC + Chrome for Testing + embeddable Python). Tags are distinct, so building one never overwrites the other.
- **Headless only.** Neither image starts a visible desktop browser window.
- **A new manager per session;** only the container pool registry is shared.
- **No persistent state.** No bind mounts, no persistent profiles. Linux uses tmpfs on a read-only root filesystem; Windows uses the container's disposable writable layer. Idle containers run no Chrome process.
- **DSServer and Docker on the same host.** Every recipe assumes this. A remote Docker daemon, rootless Docker, or a custom network needs a separate address and CDP routing review.
- **Docker access is root/admin-equivalent.** The account DSServer runs as must be able to use the Docker CLI against the configured context; restrict that access to trusted operators.

## Validation status

<table id="bkmrk-scenariostatuswindow" style="margin: 24px 0px 0px; border-collapse: collapse; width: 760px; border: 1px solid rgb(221, 222, 225); table-layout: fixed; font-size: 1em; height: 1px;"><colgroup><col></col><col></col></colgroup><tbody><tr style="box-sizing: border-box; height: 46.4219px;"><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Scenario

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Status

</th></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows 11 / Docker Desktop, Linux containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">VALIDATED Live DSServer MCP sessions (navigation, click, page queries, proxy injection, shutdown, container reuse); 2–10 container stress test, 11th-session rejection, 4 replacements

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows 11 / Docker Desktop, Windows containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">VALIDATED Live Apple flow, 10-container stress, 4 same-container Chrome PID replacements, 20-second exhaustion retry

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">macOS Apple Silicon / Docker Desktop, Linux containers (amd64 emulation)

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">VALIDATED <span style="color: rgb(41, 42, 46); background-color: rgba(5, 21, 36, 0.06);">Sep 29, 2026</span>, Chrome 154.0.8037.57: image load/inspect, standalone supervisor checks, pool startup, proxy probe, MCP discovery, navigation, stop and reuse; 10 concurrent sessions on 10 sites; replacement batches at 10–12 concurrency; 30 starts/navigations and 32 stops. **Not** a completed 100-session soak.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows Server 2025, Windows containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">RECIPE ONLY Not yet build/live tested

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Native Linux, Docker Engine

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">RECIPE ONLY Not yet build/live tested

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Broader action parity / production rollout

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">PENDING

</td></tr></tbody></table>

The macOS concurrency run exposed a race between explicit stop and the browser watcher: both removed the same JVM shutdown hook, throwing a `<span class="editor-theme-code">NullPointerException</span>` and leaving stale session inventory. The lifecycle code now claims and clears the hook atomically; the post-fix run was clean.

Evidence: `<span class="editor-theme-code">documentation/BrowserManager/evidence/containerized-chrome-apple-2026-09-23/</span>` and `<span class="editor-theme-code">containerized-chrome-windows-2026-09-24/</span>`.

## Step 1 — Pick the recipe for your node

<table id="bkmrk-dsserver-hostdocker-" style="margin: 24px 0px 0px; border-collapse: collapse; width: 760px; border: 1px solid rgb(221, 222, 225); table-layout: fixed; font-size: 1em; height: 1px;"><colgroup><col></col><col></col><col></col><col></col><col></col><col></col></colgroup><tbody><tr style="box-sizing: border-box; height: 73.8438px;"><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">DSServer host

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Docker engine mode

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Dockerfile

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">`<span class="editor-theme-code">global.json</span>` example

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Docker host key

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Guide

</th></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows 11

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Linux containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Dockerfile.windows-linux</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">config/windows11-dual.json</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">dockerHosts.desktop</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">guides/windows-11.md</span>`

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows 11

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Dockerfile.windows-windows</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">config/windows11-dual.json</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">dockerHosts.desktop</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">guides/windows-11.md</span>`

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows Server 2025

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Dockerfile.windows-windows</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">config/windows-server-2025-windows.json</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">dockerHosts.server</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">guides/windows-server-2025.md</span>`

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">macOS

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Linux containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Dockerfile.macos-linux</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">config/macos-linux.json</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">dockerHosts.desktop</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">guides/macos.md</span>`

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Linux

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Linux containers

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Dockerfile.linux-linux</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">config/linux-linux.json</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">dockerHosts.engine</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">guides/linux.md</span>`

</td></tr></tbody></table>

The named Dockerfiles make each host/engine combination explicit. `<span class="editor-theme-code">Dockerfile</span>` (Linux) and `<span class="editor-theme-code">Dockerfile.windows</span>` remain canonical; the three Linux recipes produce the same `<span class="editor-theme-code">appvance/ds-chrome:local</span>` image, and `<span class="editor-theme-code">Dockerfile.windows-windows</span>` mirrors `<span class="editor-theme-code">Dockerfile.windows</span>`. If you change a canonical file, keep the named copies aligned.

### Installed AIQ package vs. source checkout

- **Source checkout (development):** build from the repository root with `<span class="editor-theme-code">DSServer/container-browser</span>` as the build context, and edit `<span class="editor-theme-code">DSServer/config/global.json</span>`.
- **Installed, released AIQ package:** do **not** rebuild DSServer, replace its JAR, run Maven, or mix container-browser files from another AIQ version. Use the container-browser bundle shipped with the installed release (Dockerfiles, `<span class="editor-theme-code">browser-supervisor.py</span>`, `<span class="editor-theme-code">config/*.json</span>`, and helper scripts such as `<span class="editor-theme-code">verify-macos.sh</span>`). Edit `<span class="editor-theme-code"><AIQ-install>/config/global.json</span>` and restart with the package's normal launcher. If the bundle wasn't included, get it from the same release's artifacts, not an arbitrary checkout.

## Step 2 — Common configuration (global.json)

Each example file in `<span class="editor-theme-code">config/</span>` contains a complete **root-level** `<span class="editor-theme-code">containerBrowsers</span>` **object**. Copy **only that object** into `<span class="editor-theme-code">global.json</span>`, replacing any previous `<span class="editor-theme-code">containerBrowsers</span>` object and keeping every other property. If the installed configuration already has the object, update it in place.

Required edits before starting DSServer:

1. `<span class="editor-theme-code">ownerId</span>` — stable across restarts and unique to one DSServer deployment. On startup DSServer removes labeled containers belonging to this owner and pool before accepting leases; two running servers sharing an `<span class="editor-theme-code">ownerId</span>` would delete each other's containers.
2. `<span class="editor-theme-code">dockerHosts.<name>.context</span>` — set to the output of `<span class="editor-theme-code">docker context show</span>` (check `<span class="editor-theme-code">docker context ls</span>` too). The adapter uses the configured context explicitly for every Docker call and does not inherit the shell's current context. Common values: `<span class="editor-theme-code">default</span>`, `<span class="editor-theme-code">desktop-linux</span>` (Docker Desktop on Mac).
3. `<span class="editor-theme-code">network.dsProxyHost</span>` — the address containers use to reach DSServer's HTTP proxy (port typically **9090**):
    - Docker Desktop (Windows 11, macOS): `<span class="editor-theme-code">host.docker.internal</span>`
    - Linux Docker Engine: the `<span class="editor-theme-code">bridge</span>` network gateway (replaces `<span class="editor-theme-code">REPLACE-WITH-DOCKER-BRIDGE-GATEWAY-IPV4</span>`)
    - Windows Server 2025: the `<span class="editor-theme-code">nat</span>` network gateway (replaces `<span class="editor-theme-code">REPLACE-WITH-HOST-NAT-IPV4</span>`). Native Docker on Windows Server has no `<span class="editor-theme-code">host.docker.internal</span>`.
4. **Pool size (**`<span class="editor-theme-code">minSize</span>` **/** `<span class="editor-theme-code">maxSize</span>`**)** — examples start 2 warm containers and allow up to 20 (Linux) or 10 (Windows). The maximum is a ceiling, not a recommendation; size it for host memory and CPU.

### Configuration reference

<table id="bkmrk-settingnotesenabledf" style="margin: 24px 0px 0px; border-collapse: collapse; width: 760px; border: 1px solid rgb(221, 222, 225); table-layout: fixed; font-size: 1em; height: 1px;"><colgroup><col></col><col></col></colgroup><tbody><tr style="box-sizing: border-box; height: 46.4219px;"><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Setting

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Notes

</th></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">enabled</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">false</span>` (or omitting `<span class="editor-theme-code">containerBrowsers</span>`) disables the feature explicitly.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">ownerId</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Stable, unique per deployment.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">dockerHosts.<name>.context</span>` **or** explicit endpoint

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Choose one. An explicit TCP endpoint **requires** `<span class="editor-theme-code">tls</span>` with CA, client certificate, and key paths and is rejected without them.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">apiVersion</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">"auto"</span>` uses normal Docker CLI/server negotiation. A numeric value sets `<span class="editor-theme-code">DOCKER_API_VERSION</span>` only for commands this adapter launches.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">network.dsProxyHost</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Container-reachable address of DSServer's HTTP proxy (see above).

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">runtime.platform</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Linux pools: keep `<span class="editor-theme-code">linux/amd64</span>` — the image uses Google's amd64 Chrome package. Do not simply change it on arm64 hosts.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">runtime.isolation</span>` (Windows pool)

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">process</span>` by default; change to `<span class="editor-theme-code">hyperv</span>` if the host needs Hyper-V isolation (change the image build flag too).

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">minSize</span>` / `<span class="editor-theme-code">maxSize</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Warm containers / ceiling.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Image / `<span class="editor-theme-code">allowUnpinnedImage</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">The mutable `<span class="editor-theme-code">:local</span>` tag with `<span class="editor-theme-code">allowUnpinnedImage: true</span>` is development only. Production must pin an approved image digest.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">acquireRetryIntervalMs</span>` / `<span class="editor-theme-code">acquireRetryCount</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Example `<span class="editor-theme-code">5000</span>` / `<span class="editor-theme-code">4</span>` → a session start waits up to 20 s for a free lease. A released lease wakes waiters immediately. On deadline, startup fails with `<span class="editor-theme-code">POOL_EXHAUSTED</span>` and no session is retained.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">acquireTimeoutMs</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Legacy, still supported, cannot be combined with the retry settings above.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">cdpAdvertisedHost</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Linux pool: host DSServer uses to reach the published CDP port; must be reachable from DSServer.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">cdpContainerPort</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Supervisor CDP relay port inside the container (9222). Chrome itself listens on the next port (9223), bound to container loopback.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">extensionList</span>` (profile option)

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Comma-separated IDs of extensions baked into the image under `<span class="editor-theme-code">extensions/<id>/</span>`. Host extension directories are not copied at session time.

</td></tr></tbody></table>

## Step 3 — Host-specific setup

### Linux host (Docker Engine, Linux containers)

Assumes **rootful** Docker Engine on a Linux/amd64 host, the standard `<span class="editor-theme-code">bridge</span>` network, and DSServer on the same host.

1. Install Docker Engine per the official instructions for your distribution and start the daemon. Give the DSServer service account access to the daemon (socket/group access is root-equivalent — restrict to trusted operators). Confirm:  
    `<span class="editor-theme-code">docker info --format '{{.OSType}}'    </span>`*`<em class="editor-theme-code editor-theme-italic"># must print: linux</em>`*  
    `<span class="editor-theme-code">docker context show</span>`
2. Build from the repository root:  
    `<span class="editor-theme-code">docker build --platform linux/amd64 -f DSServer/container-browser/Dockerfile.linux-linux -t appvance/ds-chrome:local DSServer/container-browser</span>`
3. Find the bridge gateway and subnet:  
    `<span class="editor-theme-code">docker network inspect bridge --format '{{(index .IPAM.Config 0).Gateway}}'</span>`  
    `<span class="editor-theme-code">docker network inspect bridge --format '{{(index .IPAM.Config 0).Subnet}}'</span>`
4. Copy `<span class="editor-theme-code">containerBrowsers</span>` from `<span class="editor-theme-code">config/linux-linux.json</span>`; set `<span class="editor-theme-code">ownerId</span>`, `<span class="editor-theme-code">dockerHosts.engine.context</span>`, and replace `<span class="editor-theme-code">REPLACE-WITH-DOCKER-BRIDGE-GATEWAY-IPV4</span>` with the gateway.
5. Make DSServer's HTTP proxy listen on an interface reachable through that gateway (typically 9090) and allow inbound traffic **only from the bridge subnet**. `<span class="editor-theme-code">127.0.0.1</span>` inside a container is not the host.
6. Start DSServer; verify one session navigates, close it, start a replacement. CDP is published only to host loopback, so DSServer must run on this host.

**arm64 Linux hosts:** don't just change `<span class="editor-theme-code">runtime.platform</span>`. Use a compatible, validated browser image or explicitly accept and test amd64 emulation.

### Windows 11 (Docker Desktop, Linux and/or Windows containers)

Docker Desktop runs one engine mode at a time. `<span class="editor-theme-code">config/windows11-dual.json</span>` defines both pools; DSServer registers only the one matching the active engine **at startup**, so switching modes requires a DSServer restart.

1. **Prepare Docker Desktop.** Supported Windows 11 build with hardware virtualization enabled. Install Docker Desktop **for all users** — the per-user install does not support Windows containers. Windows container mode requires a Pro/Enterprise edition. For the `<span class="editor-theme-code">ltsc2025</span>` image with process isolation the host build must be compatible with Windows Server 2025 images (check Microsoft's version compatibility matrix).
2. **Build the Linux image.** Select *Linux containers* in the Docker tray menu, confirm `<span class="editor-theme-code">docker info --format '{{.OSType}}'</span>` prints `<span class="editor-theme-code">linux</span>`, then:  
    `<span class="editor-theme-code">docker build --platform linux/amd64 -f DSServer/container-browser/Dockerfile.windows-linux -t appvance/ds-chrome:local DSServer/container-browser</span>`
3. **Build the Windows image.** Switch to *Windows containers*, confirm the OS type prints `<span class="editor-theme-code">windows</span>`, test host/image compatibility first, then build:  
    `<span class="editor-theme-code">docker run --rm --isolation=process mcr.microsoft.com/windows/server:ltsc2025 cmd /</span>`c ver  
    `<span class="editor-theme-code">docker build --isolation=process -f DSServer/container-browser/Dockerfile.windows-windows -t appvance/ds-chrome-windows:local DSServer/container-browser</span>`  
    If process isolation isn't supported, review Hyper-V isolation requirements and change **both** the build flag and the Windows pool's `<span class="editor-theme-code">runtime.isolation</span>` to `<span class="editor-theme-code">hyperv</span>`. For build-only DNS problems add `<span class="editor-theme-code">--build-arg BUILD_DNS=<working-DNS-IP></span>`.
4. **Configure DSServer.** Copy `<span class="editor-theme-code">containerBrowsers</span>` from `<span class="editor-theme-code">config/windows11-dual.json</span>`; set `<span class="editor-theme-code">ownerId</span>`; set `<span class="editor-theme-code">dockerHosts.desktop.context</span>` (change from `<span class="editor-theme-code">default</span>` if needed). The DSServer process account must be able to run the Docker CLI — typically membership in `<span class="editor-theme-code">docker-users</span>`, followed by sign-out/sign-in.
5. **Proxy.** DSServer's proxy must be reachable at `<span class="editor-theme-code">host.docker.internal:9090</span>` from containers: listen on a container-reachable interface and add a Windows Firewall rule allowing **only the Docker private subnet** to that port.
6. **Start** DSServer after selecting the engine mode. Verify one session, stop it, start a second to check reuse before increasing load. Lower `<span class="editor-theme-code">minSize</span>`/`<span class="editor-theme-code">maxSize</span>` on a smaller workstation.

### Windows Server 2025 (native Docker, Windows containers)

Use a **Windows Server 2025** host. Docker Desktop is not supported on Windows Server; install a native Windows-container runtime (Docker CE/Moby). This recipe provides no Linux containers — those need a separate Linux Docker host and a reviewed remote-network design.

1. Install updates; make sure the host can reach Microsoft Container Registry, Chrome for Testing downloads, and Python downloads during the image build. Reserve disk and memory for the Windows base image and the pool.
2. Set up the container host per Microsoft's Windows Server container-host guide. In elevated PowerShell (review the script and your org policy first — it enables container features and may reboot):  
    `<span class="editor-theme-code">New-Item -ItemType Directory -Force C:\setup | Out-Null</span>`  
    `<span class="editor-theme-code">Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1 -OutFile C:\setup\install-docker-ce.</span>`ps1  
    `<span class="editor-theme-code">powershell.exe -ExecutionPolicy Bypass -File C:\setup\install-docker-ce.ps1</span>`
3. After reboot, verify:  
    `<span class="editor-theme-code">Get-Service</span>` docker  
    docker context show  
    `<span class="editor-theme-code">docker info --format '{{.OSType}}'    </span>`*`<em class="editor-theme-code editor-theme-italic"># must print: windows</em>`*  
    `<span class="editor-theme-code">docker run --rm --isolation=process mcr.microsoft.com/windows/server:ltsc2025 cmd /c ver</span>`
4. Build from the repository root:  
    `<span class="editor-theme-code">docker build --isolation=process -f DSServer/container-browser/Dockerfile.windows-windows -t appvance/ds-chrome-windows:local DSServer/container-browser</span>`
5. Copy `<span class="editor-theme-code">containerBrowsers</span>` from `<span class="editor-theme-code">config/windows-server-2025-windows.json</span>`; set `<span class="editor-theme-code">ownerId</span>` and `<span class="editor-theme-code">dockerHosts.server.context</span>` (if not `<span class="editor-theme-code">default</span>`). Run DSServer under an account authorized for the Docker daemon with `<span class="editor-theme-code">docker</span>` on `<span class="editor-theme-code">PATH</span>`.
6. Find the NAT gateway and subnet:  
    `<span class="editor-theme-code">(docker network inspect nat | ConvertFrom-Json)[0].IPAM.Config | Select-Object Subnet,Gateway</span>`  
    Replace `<span class="editor-theme-code">REPLACE-WITH-HOST-NAT-IPV4</span>` in `<span class="editor-theme-code">network.dsProxyHost</span>` with the **Gateway**. DSServer's proxy must listen on that interface, and Windows Firewall must allow the **Subnet** to the proxy port (typically 9090). Do not open it publicly.
7. Start DSServer; verify one session, stop, start a replacement before growing the pool. CDP is only on each container's private NAT IPv4 and is never published.

### macOS (Docker Desktop, Linux containers)

Docker Desktop runs Linux containers in a VM. On **Apple Silicon** the linux/amd64 image runs under emulation — slower and heavier than an x86-64 Linux host. This procedure targets an **installed AIQ package** with its release-matched container-browser bundle.

1. **Verify Docker Desktop.**  
    `<span class="editor-theme-code">docker context show                                  </span>`*`<em class="editor-theme-code editor-theme-italic"># record it, commonly desktop-linux</em>`*  
    `<span class="editor-theme-code">docker info --format '{{.OSType}}/{{.Architecture}}' </span>`*`<em class="editor-theme-code editor-theme-italic"># OS must be linux</em>`*  
    `<span class="editor-theme-code">docker</span>` version  
    `<span class="editor-theme-code">uname -m                                             </span>`*`<em class="editor-theme-code editor-theme-italic"># arm64 on Apple Silicon (expected)</em>`*  
    On Apple Silicon, install Rosetta if `<span class="editor-theme-code">arch -x86_64 /usr/bin/true</span>` fails (`<span class="editor-theme-code">softwareupdate --install-rosetta</span>`), then in Docker Desktop **Settings → General** select the Apple Virtualization framework and enable *Use Rosetta for x86\_64/amd64 emulation on Apple Silicon*.
2. **Build and inspect.**  
    `<span class="editor-theme-code">cd <container-browser-bundle></span>`  
    `<span class="editor-theme-code">docker build --platform linux/amd64 -f Dockerfile.macos-linux -t appvance/ds-chrome:local .</span>`  
    `<span class="editor-theme-code">docker image inspect appvance/ds-chrome:local --format '{{.Os}}/{{.Architecture}}'   </span>`*`<em class="editor-theme-code editor-theme-italic"># must print linux/amd64</em>`*
3. **Smoke-test the image** before involving DSServer:  
    `<span class="editor-theme-code">docker run -d --name ds-chrome-macos-smoke --platform linux/amd64 -p 127.0</span>`.0.1::9222 appvance/ds-chrome:local  
    `<span class="editor-theme-code">docker exec ds-chrome-macos-smoke python3 /opt/appvance/browser-supervisor.py status     </span>`*`<em class="editor-theme-code editor-theme-italic"># idle</em>`*  
    `<span class="editor-theme-code">docker exec ds-chrome-macos-smoke python3 /opt/appvance/browser-supervisor.py manifest   </span>`*`<em class="editor-theme-code editor-theme-italic"># JSON: protocol, /usr/bin/google-chrome, Chrome version</em>`*  
    `<span class="editor-theme-code">docker rm -f ds-chrome-macos-smoke</span>`
4. **Configure.** Merge `<span class="editor-theme-code">containerBrowsers</span>` from the bundle's `<span class="editor-theme-code">config/macos-linux.json</span>` into `<span class="editor-theme-code"><AIQ-install>/config/global.json</span>`. Set `<span class="editor-theme-code">ownerId</span>` and `<span class="editor-theme-code">dockerHosts.desktop.context</span>`; keep `<span class="editor-theme-code">runtime.platform: linux/amd64</span>` and `<span class="editor-theme-code">dsProxyHost: host.docker.internal</span>`. On Apple Silicon start small (e.g. `<span class="editor-theme-code">minSize: 2</span>`, `<span class="editor-theme-code">maxSize: 10</span>`) and grow only after measuring memory, CPU, launch latency, and CDP responsiveness.
5. **Restart AIQ.** Start Docker Desktop first, stop AIQ with the installation's normal procedure, then start it again (e.g. `<span class="editor-theme-code">cd <AIQ-install> && ./startds.sh</span>`). Do not run Maven or a replacement JAR.
6. Verify using Step 4, including `<span class="editor-theme-code">verify-macos.sh</span>`.

## Step 4 — Verify

### Startup logs

In `<span class="editor-theme-code">OutputLogs/ds3output0.txt</span>` (installed package), confirm `<span class="editor-theme-code">Container pool engine ready</span>` for the matching pool, `<span class="editor-theme-code">Container pool warmed</span>` for the warm containers, and that the `<span class="editor-theme-code">ChromeContainerized</span>` profile is loaded. A configured pool for the other engine OS being hidden is expected (e.g. the Windows pool on a Linux engine).

### Proxy and pool connectivity

`<span class="editor-theme-code">curl -i --max-time 5 http://127.0.0.1:9090/          </span>`*`<em class="editor-theme-code editor-theme-italic"># any HTTP response (even 404) = proxy listening</em>`*  
`<span class="editor-theme-code">docker ps --filter 'label=appvance.ds.container-pool=chrome-linux'</span>`  
`<span class="editor-theme-code">docker exec <container-id> python3 /opt/appvance/browser-supervisor.py status        </span>`*`<em class="editor-theme-code editor-theme-italic"># warm containers: idle</em>`*  
`<span class="editor-theme-code">docker exec <container-id> python3 /opt/appvance/browser-supervisor.py probe-proxy host.docker.internal 9090   </span>`*`<em class="editor-theme-code editor-theme-italic"># must print: reachable</em>`*

On Linux / Windows Server use your `<span class="editor-theme-code">dsProxyHost</span>` (bridge or NAT gateway) instead of `<span class="editor-theme-code">host.docker.internal</span>`. The commands use Linux image paths; adjust for the Windows image.

### Lease, cleanup and reuse

1. Select `<span class="editor-theme-code">ChromeContainerized</span>`, start a session, navigate to a simple page. The leased container's `<span class="editor-theme-code">status</span>` must start with `<span class="editor-theme-code">running:</span>`.
2. Stop the session; the container returns to `<span class="editor-theme-code">idle</span>`.
3. Start a replacement session and navigate again — this proves cleanup and reuse, not just first launch.

For concurrency testing, keep one or two spare pool slots and replace sessions in small batches (start replacements first, then stop the old ones) to avoid pool exhaustion. Use bounded navigation retries for external sites and record session readiness separately from page success.

### macOS packaged verifier (verify-macos.sh)

Shipped in the release bundle; it does not change AIQ configuration. It creates one disposable container with DSServer's settings, checks both network directions, and removes it on exit.

`<span class="editor-theme-code">cd <container-browser-bundle></span>`  
`<span class="editor-theme-code">chmod</span>` +x verify-macos.sh  
`<span class="editor-theme-code">./verify-macos.sh --aiq-install <AIQ-install>                         </span>`*`<em class="editor-theme-code editor-theme-italic"># infrastructure checks</em>`*  
`<span class="editor-theme-code">./verify-macos.sh --aiq-install <AIQ-install> --observe-session 180   </span>`*`<em class="editor-theme-code editor-theme-italic"># start ChromeContainerized from the UI when prompted</em>`*  
`<span class="editor-theme-code">./verify-macos.sh --aiq-install <AIQ-install> --mcp                   </span>`*`<em class="editor-theme-code editor-theme-italic"># only if loopback MCP is already enabled</em>`*  
`<span class="editor-theme-code">AIQ_MCP_TOKEN='<token>' ./verify-macos.sh --aiq-install <AIQ-install> --mcp   </span>`*`<em class="editor-theme-code editor-theme-italic"># bearer token kept off the command line</em>`*

Observed-session checks walk the full route: container → `<span class="editor-theme-code">host.docker.internal:9090</span>`; Chrome launched with `<span class="editor-theme-code">--proxy-server</span>`; Chrome CDP on 9223 inside the container; supervisor relay on 9222; 9222 published to a dynamic host-loopback port; host reaches `<span class="editor-theme-code">/json/version</span>` through it. The script never enables MCP or edits `<span class="editor-theme-code">mcp.json</span>`.

## Troubleshooting

### Session closes unexpectedly

- **Closes immediately** → usually a proxy or Chrome-start failure.
- **Closes after ~130 seconds** → CDP route problem: DSServer closes a browser when its native connector can't attach within that window.

### First verifier failure → likely fault

<table id="bkmrk-first-failurelikely-" style="margin: 24px 0px 0px; border-collapse: collapse; width: 760px; border: 1px solid rgb(221, 222, 225); table-layout: fixed; font-size: 1em; height: 1px;"><colgroup><col></col><col></col></colgroup><tbody><tr style="box-sizing: border-box; height: 46.4219px;"><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">First failure

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Likely fault

</th></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">DSServer proxy is not accepting host connections</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Proxy disabled, not listening, or on a different port.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">container cannot reach DSServer proxy</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Docker can't route `<span class="editor-theme-code">dsProxyHost</span>` to the proxy, or a firewall is blocking it.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Chrome CDP does not respond ... 9223</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Chrome failed or exited inside the image.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">container CDP relay does not respond ... 9222</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Supervisor/relay missing, incompatible, or failed.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">Docker did not publish ... 9222</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Pool container created without the dynamic loopback mapping, or AIQ is using a different Docker context.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">host cannot reach Chrome CDP through the published port</span>`

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Docker Desktop host-loopback forwarding failed or was blocked.

</td></tr></tbody></table>

If every route check passes but sessions still close, compare the installed DSServer and container-browser bundle versions and inspect the lifecycle errors from `<span class="editor-theme-code">OutputLogs</span>`. Send support the full verifier output starting at the first `<span class="editor-theme-code">FAIL</span>` line.

### GPU process launch failed: error\_code=1002 (macOS)

Emitted after Chrome starts when a GPU child-process launch fails. It is **not** a DSServer proxy error. On Apple Silicon, first check the amd64 emulation path:

`<span class="editor-theme-code">cd <container-browser-bundle></span>`  
`<span class="editor-theme-code">./diagnose-macos-gpu.sh --aiq-install <AIQ-install> > macos-gpu-diagnostic.txt 2>&1</span>`

The redacted report records host, Docker Desktop version, virtualization backend, Rosetta status, context, engine resources, image identity, Chrome version, and a three-mode Chrome launch matrix. Attach it with the `<span class="editor-theme-code">verify-macos.sh</span>` output.

- `<span class="editor-theme-code">rosetta_host_translation</span>` and `<span class="editor-theme-code">docker_vmm_rosetta</span>` should both be `<span class="editor-theme-code">true</span>`; otherwise fix Rosetta (macOS step 1), restart Docker Desktop, then restart AIQ so pool containers are recreated.
- If `<span class="editor-theme-code">current</span>` fails but `<span class="editor-theme-code">no-software-rasterizer</span>` succeeds, the failure is in Chrome's graphics path. **As a temporary diagnostic only**, add the options below to the `<span class="editor-theme-code">ChromeContainerized</span>` profile, restart AIQ, and retry one session. This disables WebGL/software GPU rendering and can change application behaviour — not a production default.
- If every mode shows `<span class="editor-theme-code">qemu</span>`, `<span class="editor-theme-code">SIGTRAP</span>`, zygote, or network-service crashes, fix Docker Desktop's amd64 emulation, not AIQ proxy settings.

`<span class="editor-theme-code">{"name": "disable-gpu", "value": "true"},</span>`  
`<span class="editor-theme-code">{"name": "experimentalDS3", "value": "--disable-software-rasterizer"}</span>`

Reference working Apple Silicon host (comparison values, not minimums)

### Other common issues

<table id="bkmrk-symptomlikely-cause-" style="margin: 24px 0px 0px; border-collapse: collapse; width: 760px; border: 1px solid rgb(221, 222, 225); table-layout: fixed; font-size: 1em; height: 1px;"><colgroup><col></col><col></col></colgroup><tbody><tr style="box-sizing: border-box; height: 46.4219px;"><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Symptom

</th><th class="align-left" style="background-color: rgb(240, 241, 242); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 0px; text-align: left; vertical-align: top; box-sizing: border-box; min-width: 48px; font-weight: 400; position: relative;">Likely cause / fix

</th></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">ChromeContainerized</span>` profile missing

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Docker unreachable at startup, wrong context, or pool OS doesn't match engine mode. Check `<span class="editor-theme-code">docker context show</span>`, fix config, restart DSServer.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">POOL_EXHAUSTED</span>` on session start

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">All leases busy for the full retry window (~20 s default). Increase pool size (if memory allows) or retry settings; keep spare slots during batch replacement.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows build fails downloading Chrome/Python

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">--build-arg BUILD_DNS=<working-DNS-IP></span>`.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows container won't start with process isolation

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Host build incompatible with `<span class="editor-theme-code">ltsc2025</span>` — check Microsoft's matrix, or switch build flag and `<span class="editor-theme-code">runtime.isolation</span>` to `<span class="editor-theme-code">hyperv</span>`.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Windows containers unavailable on Windows 11

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Docker Desktop installed per-user, or Home edition. Reinstall for all users on Pro/Enterprise.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">DSServer can't run Docker on Windows 11

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Service account not in `<span class="editor-theme-code">docker-users</span>` (sign out/in after adding).

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Config rejected for TCP endpoint

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">tls</span>` CA/cert/key paths missing.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Config rejected for acquire settings

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">`<span class="editor-theme-code">acquireTimeoutMs</span>` combined with the retry settings — use one style.

</td></tr><tr style="box-sizing: border-box;"><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Containers disappear when another server starts

</td><td class="align-left" style="background-color: rgb(255, 255, 255); border-width: 1px 0px 0px 1px; border-style: solid; border-color: rgb(221, 222, 225); border-image: none; padding: 8px; text-align: left; box-sizing: border-box; min-width: 48px; font-weight: 400; vertical-align: top;">Two DSServer deployments share an `<span class="editor-theme-code">ownerId</span>`.

</td></tr></tbody></table>

## Production checklist (not yet complete)

Pin an approved image digest; set `<span class="editor-theme-code">allowUnpinnedImage</span>` to `<span class="editor-theme-code">false</span>`

Size the pool for host memory and CPU

Unique, stable `<span class="editor-theme-code">ownerId</span>` per deployment

Docker daemon access restricted to the DSServer account and trusted operators

Proxy firewall rules limited to the Docker private subnet; CDP never public; mTLS and a private CDP route for any remote Docker host

Release-matched container-browser bundle for installed packages

Acceptance checklist in the implementation progress log complete

## References

- `<span class="editor-theme-code">DSServer/container-browser/README.md</span>` and `<span class="editor-theme-code">guides/</span>` (`<span class="editor-theme-code">linux.md</span>`, `<span class="editor-theme-code">macos.md</span>`, `<span class="editor-theme-code">windows-11.md</span>`, `<span class="editor-theme-code">windows-server-2025.md</span>`)
- Config examples: `<span class="editor-theme-code">DSServer/container-browser/config/</span>`
- Implementation progress log: `<span class="editor-theme-code">documentation/BrowserManager/design/containerized-browser-pool-implementation-progress.md</span>`
- [Install Docker Engine](https://docs.docker.com/engine/install/)
- [Linux post-installation steps for Docker Engine](https://docs.docker.com/engine/install/linux-postinstall/)
- [Install Docker Desktop on Windows](https://docs.docker.com/desktop/setup/install/windows-install/)
- [Install Docker Desktop on Mac](https://docs.docker.com/desktop/setup/install/mac-install/)
- [Change your Docker Desktop settings](https://docs.docker.com/desktop/settings-and-maintenance/settings/)
- [Explore networking how-tos on Docker Desktop](https://docs.docker.com/desktop/features/networking/networking-how-tos/)
- [Prepare Windows operating system containers](https://learn.microsoft.com/en-us/virtualization/windowscontainers/quick-start/set-up-environment)
- [Windows container version compatibility](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility)
- [Windows container networking](https://learn.microsoft.com/en-us/virtualization/windowscontainers/container-networking/architecture)