A Docker-based remote browser platform for automation, testing, debugging, and browser infrastructure.
Run Chromium, Firefox, Edge, or WebKit in disposable Linux containers, driven over VNC and CDP — for Eggplant Functional, Playwright, Selenium, or just watching a browser run somewhere that isn't your laptop.
Replace
OWNER/REPOin the badge URL above once this is pushed to GitHub.
| Engine | BROWSER= |
Source | Included by default? |
|---|---|---|---|
| Chromium | chromium |
Debian package | ✅ always |
| Firefox ESR | firefox |
Debian package | opt-in: INCLUDE_FIREFOX=true |
| Microsoft Edge | edge |
Microsoft's apt repository | opt-in: INCLUDE_EDGE=true |
| WebKit | webkit |
Playwright's MiniBrowser | opt-in: INCLUDE_WEBKIT=true |
- One command to scale, any engine —
browser.cmd start 10 firefoxgets 10 isolated Firefox containers with sequential ports, no manualdocker-compose.ymlediting. - Disposable by default — fresh profile every container start;
SESSION_MODE=persistentopts in to cookies/logins surviving a restart. - Real automation, not just visual checks — Chromium/Edge containers
publish a CDP port; Playwright's
connectOverCDP()or Selenium'sdebugger_addressdrive the exact browser you're watching over VNC. - Watchable two ways — a VNC port for Eggplant/any VNC client, plus a noVNC web portal for anyone with just a browser.
- Deterministic rendering — fixed resolution, fixed zoom, first-run dialogs pre-suppressed, so reference images stay valid across runs.
- Health-checked and resource-capped — Docker-native health checks per container, CPU/memory limits so one runaway instance can't starve the rest.
flowchart LR
CMD["browser.cmd\n(farm manager)"] -->|"docker run -e BROWSER=... x N"| C["Container rb-N\nXvfb + Openbox + <engine>\n+ x11vnc + noVNC"]
EGG["Eggplant Functional /\nany VNC client"] -->|VNC 5900+N| C
WEB["Any web browser"] -->|HTTP 6080+N| C
AUTO["Playwright / Selenium"] -.->|"CDP 9200+N\n(chromium/edge only)"| C
Full breakdown of every layer and the design decisions behind them:
docs/architecture.md. Per-engine capability
matrix: docs/browsers.md.
git clone <this-repo-url> && cd "RemoteBrowser v2.0"
browser.cmd build # builds Chromium (default engine), a few minutes the first time
browser.cmd start 1 # start one container
browser.cmd list # get its VNC/noVNC connection detailsOpen http://localhost:6081/vnc.html in any browser to watch it, or point a
VNC client (or Eggplant) at localhost:5901. Point Playwright at
http://localhost:9201 (see Playwright) to drive it.
browser.cmd stop # tear everything down when you're doneThat's the whole loop. Everything past this point is reference material for when you need more than one container, a different engine, or persistence.
Not yet captured. This section is structured so real screenshots drop in without any doc changes — see
assets/README.mdfor exactly what to capture and the expected filenames. No mock/fabricated images are included.
Image-based UI test tools compare screenshots pixel-for-pixel. A browser running directly on a tester's machine is a moving target — window size drifts, zoom changes, profile state piles up, and you can't run more than one at a time without them fighting over the screen. Cross-browser coverage makes it worse: Chromium, Firefox, Edge, and WebKit all render slightly differently, and getting a clean, isolated instance of each running side by side is its own infrastructure problem. Remote Browser Kit solves this by running one engine per disposable container, exposed purely as a VNC framebuffer at a fixed resolution — recycle a container for a byte-for-byte clean browser, run more containers for parallelism.
| Remote Browser Kit | Manual/local browser | Headless-only automation | Commercial cloud grid | |
|---|---|---|---|---|
| Cost | Free, self-hosted | Free | Free | Paid, per-minute/seat |
| Watchable while automating | ✅ VNC + noVNC | ✅ it's right there | ❌ invisible by design | |
| Disposable, reproducible state | ✅ fresh profile every start | ❌ profile drift over time | ✅ (already stateless) | ✅ |
| Multi-engine on one platform | ✅ Chromium/Firefox/Edge/WebKit | ✅ | ||
| Runs on infrastructure you control | ✅ | ✅ | ✅ | ❌ vendor's cloud |
| Native VNC support (Eggplant, etc.) | ✅ | ✅ | ❌ | |
| Setup cost | Docker + one script | none | some | account + billing |
Who this is for: QA/test engineers who need one-to-many disposable, cross-browser targets on a machine running Docker Desktop, and automation engineers who'd rather watch Playwright/Selenium drive a real container than debug a headless run blind.
- Playwright — attach
connectOverCDP()to a running, watchable Chromium/Edge container instead of a headless instance you can't see. - Selenium — same CDP port, via
debugger_address. - Eggplant Functional — every
container is already a VNC SUT;
browser.cmd listprints the connection table. - Manual/exploratory testing — open noVNC in any browser, no VNC client install required, click around like it's a normal desktop.
- Remote debugging — reproduce a user-reported bug in a clean, disposable browser you (or a teammate) can watch live, without touching your own machine's browser state.
- CI —
examples/ci-pipeline.ps1shows the build → start → wait-healthy → test → always-tear-down shape for a pipeline step.
| Tool | Download |
|---|---|
| Docker Desktop (Windows) | https://www.docker.com/products/docker-desktop |
| Git (optional, for cloning) | https://git-scm.com/download/win |
Make sure Docker Desktop is running (whale icon in the system tray) before continuing.
RemoteBrowser v2.0\
│
├── browser.cmd ← the only file you run day to day
├── env ← the only file you edit day to day
├── docker-compose.yml ← builds the image only, never used at runtime
├── Dockerfile ← the container image recipe (Chromium always; Firefox/Edge/WebKit opt-in build args)
├── README.md
├── LICENSE
├── SECURITY.md
│
├── config\ ← baked into the image at build time
│ ├── chromium-prefs.json (shared by Chromium and Edge)
│ ├── firefox-prefs.js
│ ├── openbox-rc.xml
│ └── logrotate.conf
│
├── scripts\ ← baked into the image at build time
│ ├── start.sh (browser-agnostic orchestration)
│ ├── healthcheck.sh
│ └── browsers\ (one launcher per engine)
│ ├── chromium.sh
│ ├── firefox.sh
│ ├── edge.sh
│ └── webkit.sh
│
├── docs\ ← architecture, browsers, usage, config, dev, security, troubleshooting, FAQ
├── examples\ ← per-browser quick starts, Eggplant, CI pipeline, Playwright/Selenium automation
├── tests\ ← smoke test (per engine) + browser validation test
├── assets\ ← real screenshots (once captured — see assets/README.md)
└── .github\ ← CI workflow, issue/PR templates, release notes config
browser.cmd buildBuilds Chromium only by default — a few minutes on the first build. To add
Firefox, Edge, and/or WebKit, set the matching INCLUDE_FIREFOX /
INCLUDE_EDGE / INCLUDE_WEBKIT flag(s) to true in env before
building (each one adds real time and image size — see the build matrix in
docs/browsers.md). Cached by default; re-run after
changing Dockerfile, scripts/**, or config/*. Use browser.cmd build clean to force a from-scratch --no-cache rebuild.
browser.cmd build Build the image (cached)
browser.cmd build clean Build from scratch (--no-cache)
browser.cmd start <N> [browser] Start N containers (chromium|firefox|edge|webkit)
browser.cmd stop Stop and remove all containers
browser.cmd restart <N> [browser] Stop all, then start N fresh ones
browser.cmd status Show running containers with ports
browser.cmd list Show Eggplant SUT connection table
browser.cmd logs <N> See live logs for container N
browser.cmd shell <N> Open a terminal inside container N
browser.cmd health Check health of all containers
Port rule: 5900 + N for VNC, 6080 + N for noVNC, 9200 + N for the CDP
automation port (Chromium/Edge only). rb-1 → 5901/6081/9201.
browser.cmd list always shows the VNC/noVNC table.
Full walkthrough (multi-instance farms, watching a container, resetting mid
test-run, persistent sessions): docs/usage.md.
Never run docker compose up — that only builds the image, it doesn't
set the ports/mounts/env that browser.cmd does. Always use browser.cmd.
browser.cmd build installs Chromium only by default. Enable additional
engines by setting flags in env before building:
| Combination | env settings |
|---|---|
| Chromium only (default) | (nothing to set) |
| Chromium + Firefox | INCLUDE_FIREFOX=true |
| Chromium + Edge | INCLUDE_EDGE=true |
| Chromium + WebKit | INCLUDE_WEBKIT=true |
| All four browsers | all three flags true |
Full build matrix with equivalent raw docker build --build-arg commands:
docs/browsers.md.
BROWSER picks which of the installed engines a container runs. Set it in
env for a farm-wide default, or override per batch:
browser.cmd start 5 # 5 containers, using env's BROWSER (default: chromium)
browser.cmd start 3 firefox # 3 Firefox containers, this batch only (needs INCLUDE_FIREFOX=true at build time)
browser.cmd start 2 edge
browser.cmd start 1 webkitRejected client-side by browser.cmd and again inside the container by
scripts/start.sh — both if the value isn't one of the four known engines,
and if it wasn't actually built into the image (clear error either way,
telling you which build flag to flip). Full capability matrix (what each
engine does and doesn't support — kiosk mode, zoom, CDP automation):
docs/browsers.md.
# in env:
SESSION_MODE=persistent
Each container's profile is bind-mounted at profiles/rb-N/<browser>/ on
the host, namespaced per engine so switching BROWSER on the same instance
number never mixes profiles. Default (fresh) wipes the profile on every
container start. Details: docs/usage.md.
Every container publishes VNC (5900+N) and a noVNC web portal
(6080+N), bound to 127.0.0.1 on the host by default — see
docs/security.md before widening that.
| Field | Value |
|---|---|
| Type | VNC |
| Host | localhost |
| Port | 5900 + N (5901 for rb-1, 5902 for rb-2, …) |
| Password | whatever VNC_PASS is set to in env |
Full worked example: examples/eggplant-sut.md.
Chromium and Edge containers publish a CDP port (9200+N); Playwright can
connectOverCDP() to the exact browser you're watching over VNC instead of
launching its own headless instance. Firefox/WebKit aren't supported this
way — see why in the example. Full walkthrough with runnable Node.js and
Python code: examples/playwright-automation.md.
Same CDP port, via Selenium 4's debugger_address option (Chromium/Edge
only). Full walkthrough: examples/selenium-automation.md.
examples/eggplant-sut.md— configuring a 3-browser farm and wiring it into Eggplant as SUTsexamples/browser-quickstarts.md— per-engine build/start commands and gotchas (Chromium, Firefox, Edge, WebKit)examples/playwright-automation.md,examples/selenium-automation.md— attaching automation frameworks to a running containerexamples/ci-pipeline.ps1— driving a farm from a Windows CI pipeline (build → start → wait-healthy → test → always tear down)examples/custom-single-container.md— running one container with a differentSTART_URL/browser combo than the rest of the farm
Day-to-day settings live in env — browser.cmd loads it
automatically and it overrides the script's built-in defaults:
BROWSER=chromium
START_URL=https://your-app-url.com/
VNC_PASS=your-password-here
BROWSER_MODE=normal
SCREEN_WIDTH=1920
SCREEN_HEIGHT=1080
SESSION_MODE=fresh
Keep BROWSER_ZOOM=1.0 and the resolution at 1920x1080 (or whatever
you captured reference images at) — changing either after capturing Eggplant
images breaks image matching.
Full variable reference, per-engine flag rationale, and security notes:
docs/configuration.md.
Nothing to compile — this is a Dockerfile, browser launcher scripts, a
startup/healthcheck script, one batch script, and static config. See
docs/development.md for the local iteration loop,
linting, and what does/doesn't require a rebuild.
bash tests/smoke-test.sh # chromium (default)
bash tests/smoke-test.sh firefox
bash tests/browser-validation.sh # confirms bad BROWSER values are rejectedBuilds the image if needed, boots a throwaway container for the given
engine, waits for it to report healthy, confirms noVNC/VNC respond and the
right browser process is running, tears it down. Testing an engine other
than chromium requires an image built with the matching INCLUDE_* flag
(see Build options). CI builds once with every flag
enabled and runs the smoke test as a 4-way matrix on every push. There's no
application code to unit test — see
tests/README.md for what is and isn't covered.
This is a tool for disposable browsers on a machine you control, not a
hardened multi-tenant service — the defaults reflect that. In short: ports
are bound to 127.0.0.1 only by default, VNC_PASS=changeme is a
placeholder you must change before wider exposure, real secrets belong in
an untracked .env/.env.local override rather than the committed env
template, and third-party package sources (Microsoft's apt repo for Edge,
Playwright's CDN for WebKit) are pinned by key/checksum rather than
trusted blindly. Vulnerability reporting process: SECURITY.md.
Full operational security picture, including container isolation and
credential-handling guidance: docs/security.md.
Quick hits — full guide at docs/troubleshooting.md.
| Symptom | Check |
|---|---|
| "Connection refused" in Eggplant | Used browser.cmd start, not docker compose up? Port is 5900+N, not 5900? browser.cmd status shows it running? |
browser.cmd is not recognized |
Run it from inside the RemoteBrowser v2.0 folder. |
| Black screen over VNC | browser.cmd logs <N> — look for [ERROR]/[HEALTH] FAIL lines. |
browser.cmd build fails on Edge/WebKit layers |
Check outbound access to packages.microsoft.com and Playwright's browser CDN — see docs/troubleshooting.md. |
| Kiosk/fullscreen/zoom "doesn't work" | Check the capability matrix in docs/browsers.md — not every engine supports every mode. |
| Browsers | Minimum RAM |
|---|---|
| 1 | 2 GB |
| 5 | 6 GB |
| 10 | 10 GB |
| 20 | 18 GB |
- Native per-instance
START_URLoverride within a singlebrowser.cmd startbatch (today: manualdocker run, seeexamples/custom-single-container.md) - Linux/macOS-native control script (today:
browser.cmdis Windows-batch-only; the container itself is already cross-platform) - WebDriver/Marionette automation support for the Firefox container
(today: CDP automation is Chromium/Edge-only — see
docs/browsers.md) - Optional non-loopback bind for teams running the farm on a shared host behind their own reverse proxy/VPN
- Real screenshots/GIF in
assets/(structure is ready — seeassets/README.md)
- Read
docs/architecture.md,docs/browsers.md, anddocs/development.mdfirst. - Run
bash tests/smoke-test.sh <browser>for whichever engine(s) your change affects (all four if it touches shared logic instart.sh), andbash tests/browser-validation.shif you touched validation. If you touchedscripts/*.shor theDockerfile, run ShellCheck/Hadolint locally (commands indocs/development.md) before opening a PR. - Fill out the PR template's test checklist honestly — there's no application test suite to fall back on, so manual verification is the real bar here.
- Adding a fifth browser engine? See "Adding a future browser" in
docs/browsers.mdfor the checklist.
MIT — this project is orchestration around other open-source
components (Debian, Chromium, Firefox, x11vnc, noVNC) plus Microsoft's and
Playwright's own distributions of Edge and WebKit; MIT keeps it maximally
easy to adopt into an internal test pipeline without copyleft or
patent-grant overhead. See docs/faq.md
for the full reasoning.
Built on Debian, Chromium, Firefox, Microsoft Edge, WebKit via Playwright, Xvfb, Openbox, x11vnc, noVNC/websockify, and tini.
| File | What it does | What to edit |
|---|---|---|
browser.cmd |
Farm manager CLI — start/stop/scale containers, assign ports, validate BROWSER, load env |
Nothing, normally — see docs/development.md if you're adding a subcommand |
env |
Runtime configuration for every container | This — day to day |
docker-compose.yml |
Defines the build (remote-browser-kit:1.0); not used at runtime |
Nothing |
Dockerfile |
Image recipe — Debian + Xvfb + Openbox + Chromium (always) + Firefox/Edge/WebKit (opt-in build args) + x11vnc + noVNC, non-root browser user |
Only to add a system package or a new engine, then browser.cmd build |
scripts/start.sh |
Browser-agnostic container entrypoint — validates BROWSER, starts every service in order, dispatches to the right launcher |
Nothing, normally |
scripts/browsers/*.sh |
Per-engine launch flags and profile seeding | Here, if you're changing one engine's behavior |
scripts/healthcheck.sh |
Docker health check, runs every 20s | Nothing |
config/chromium-prefs.json |
Default profile template — Chromium and Edge | Download behavior only; keep default_zoom_level: 0 |
config/firefox-prefs.js |
Default profile template — Firefox | Same idea, Firefox user.js syntax |
config/openbox-rc.xml |
Window manager config — maximize, no decorations | Nothing |
config/logrotate.conf |
Log rotation for /logs |
Retention period only |