How to Run Selenium Grid with Docker
Run Selenium Grid in Docker, choose the right topology, connect browser containers, check sessions, and troubleshoot ports, capacity, and access.
Selenium Grid runs in Docker in two related ways: you can run the Grid service itself in a container, or configure Grid to start each browser session in its own Docker container. For a local setup or quick CI check, start with a single Standalone container. Use Hub and Node when you need one endpoint across multiple machines or want to add browser capacity. Use Distributed mode when you need to deploy Grid components independently.
The examples below use the official Selenium Docker images and a versioned tag. Check the current docker-selenium README for updated full tags before pinning a production image. The examples here use tag 4.48.0-20260905, shown in the project README at the time of writing. Pin matching tags across Hub and Nodes.
1. Choose a Grid topology
| Topology | Good fit | What runs | Operational notes |
|---|---|---|---|
| Standalone | Local development, quick pre-push suites, simple CI | All Grid components in one process/container | One machine and one endpoint, typically http://localhost:4444. |
| Hub and Node | Several machines or elastic browser capacity | A Hub entry point and one or more Nodes | Nodes can be added or removed. Hub and Nodes need HTTP and Event Bus network paths. |
| Distributed | Larger or more controlled installations | Router, Distributor, Session Map, New Session Queue, Event Bus, and Nodes as separate components | More components and ports to deploy, monitor, and secure independently. |
Selenium describes Standalone as the easiest mode. Start there unless you need multiple machines, separate component ownership, or more capacity than a single container can provide. See the Selenium Grid getting started guide for topology details.
2. Run a Standalone Grid container
This is the shortest path to a working Grid. Docker publishes port 4444 for the Grid UI and WebDriver endpoint. The optional 7900 port serves the noVNC browser viewer. Shared memory is set to 2 GB, following the Docker Selenium project recommendation for browser containers.
docker run -d --name selenium \
-p 4444:4444 \
-p 7900:7900 \
--shm-size="2g" \
selenium/standalone-firefox:4.48.0-20260905
Open http://localhost:4444 for the Grid UI. To inspect the browser session visually, use http://localhost:7900/?autoconnect=1&resize=scale&password=secret. The noVNC viewer is optional; omit the port mapping when you do not need it.
Stop and remove the container with:
docker rm -f selenium
To use Chrome, replace the image with selenium/standalone-chrome:4.48.0-20260905. For an all-browser standalone image, the project documents selenium/standalone-all-browsers:4.48.0-20260905; it is larger and browser availability can vary by CPU architecture. Match the image tag to your Grid release and architecture.
3. Run Hub and Nodes with Docker
Hub and Nodes make a single Grid URL available across multiple browser containers. Put them on a Docker network so they can resolve one another by container name. The Hub publishes 4444 for clients and UI, plus Event Bus ports 4442 and 4443 for Node registration and communication.
docker network create grid
docker run -d --name selenium-hub --net grid \
-p 4442-4444:4442-4444 \
selenium/hub:4.48.0-20260905
docker run -d --name chrome --net grid \
-e SE_EVENT_BUS_HOST=selenium-hub \
--shm-size="2g" \
selenium/node-chrome:4.48.0-20260905
docker run -d --name firefox --net grid \
-e SE_EVENT_BUS_HOST=selenium-hub \
--shm-size="2g" \
selenium/node-firefox:4.48.0-20260905
Clients connect to http://localhost:4444. Nodes do not need host port publication when they communicate with the Hub over the shared Docker network on their internal network. If Nodes run on other machines, route the Hub Event Bus ports 4442 and 4443 and each Node’s configured port between those machines; also ensure advertised hostnames resolve from both sides. Do not assume publishing only 4444 is sufficient for remote Hub and Node communication.
For Compose, the official project maintains versioned examples such as docker-compose-v3.yml. Use that maintained file rather than an old copied Compose recipe, and inspect its port mappings and image tags before adapting it. Start and stop with docker compose up -d and docker compose down.
4. Configure Grid to create browser containers
The previous pattern runs browser Nodes as long-lived containers. In Docker-backed session mode, a Selenium Node asks the Docker daemon to create a browser container for each requested session. Its configuration needs three things: automatic driver detection disabled, image-to-capability stereotypes, and a reachable Docker daemon endpoint.
Save this as docker.toml and adapt the image tags and stereotypes to the browser images you intend to run. This shows the current TOML shape documented by Selenium; the versions in the upstream syntax example are illustrative, so use actual compatible images and capability versions for your deployment.
[node]
detect-drivers = false
max-sessions = 4
[docker]
configs = [
"selenium/standalone-chrome:4.48.0-20260905", "{\"browserName\": \"chrome\"}",
"selenium/standalone-firefox:4.48.0-20260905", "{\"browserName\": \"firefox\"}"
]
url = "http://host.docker.internal:2375"
The configs array pairs each image reference with JSON describing the capabilities it can satisfy. The requested session capabilities must match a configured stereotype, such as {"browserName":"chrome"}. Add a browser version or platform capability only when the corresponding image can truthfully satisfy it.
The daemon URL is deployment-specific. The sample uses host.docker.internal, which some Docker installations provide for reaching the host from a container. On Linux or remote hosts, configure a reachable daemon address using your platform’s networking setup. Selenium’s Docker configuration documentation says this mode requires the Docker daemon to be exposed through HTTP/TCP. Protect that daemon endpoint: an unauthenticated remote Docker API is a powerful control interface.
Mount the configuration and Docker socket into the Selenium service container. This local socket example grants the container substantial control over Docker on the host; run it only in a trusted environment and restrict access to the service.
docker run --rm --name selenium-docker \
-p 4444:4444 \
--shm-size="2g" \
-v "$PWD/docker.toml:/opt/selenium/docker.toml:ro" \
-v /var/run/docker.sock:/var/run/docker.sock \
selenium/standalone-docker:4.48.0-20260905
Set the TOML daemon URL to the endpoint your container can actually reach. The official docker-selenium examples also show mounting /var/run/docker.sock for this pattern. Review the TOML options and Docker Selenium README for image-specific setup and current variables.
5. Connect a WebDriver client and create a session
Once Grid is reachable, a RemoteWebDriver client sends browser capabilities to its endpoint. Here is a minimal Python example using Selenium’s Python package:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new")
driver = webdriver.Remote(
command_executor="http://localhost:4444",
options=options,
)
try:
driver.get("https://example.com")
print(driver.title)
finally:
driver.quit()
Install the client with python -m pip install selenium. For a Firefox session, use FirefoxOptions() and request browserName: firefox. In a CI container on the same Docker network, use the Hub service name, for example http://selenium-hub:4444, rather than localhost.
Do not expose the browser’s debugging or VNC ports to untrusted networks. For repeatable tests, set explicit timeouts in the test client and always call quit() so sessions are cleaned up if an assertion or navigation fails.
6. Which ports does Selenium Grid need?
| Topology/component | Documented default port(s) | Purpose |
|---|---|---|
| Standalone / Hub / Router | 4444 | Grid UI and WebDriver HTTP endpoint. |
| Hub Event Bus | 4442, 4443 | Node and Grid component event communication. |
| Node | 5555 by default in common Node configuration | Hub reaches a Node over HTTP to confirm and manage it; configured Node ports can differ. |
| Distributed Event Bus | 4442, 4443, 5557 | Publish, subscribe, and Event Bus service ports. |
| Distributed New Session Queue | 5559 | Queues session requests for the Distributor. |
| Optional noVNC viewer | 7900 | Visual debugging for Docker Selenium browser containers. |
Distributed mode also has separately configured Session Map, Distributor, Router, and Node endpoints. Consult the official component port defaults for the specific roles you deploy. Publish only ports required by clients and peer components, and ensure the hostnames the components advertise are reachable across the relevant networks.
7. Check whether Grid is ready
Check container state and logs first:
docker ps
docker logs --tail=100 selenium-hub
Then request the Grid status endpoint:
curl --fail --silent http://localhost:4444/status
Read the returned value.ready field and inspect registered Nodes, slots, and active sessions. The Grid UI at http://localhost:4444 provides the same operational view. A running container alone does not prove that a Node registered or that a requested browser stereotype is available.
8. Size parallel capacity from measurements
Grid can run parallel sessions when it has available matching slots. Actual concurrency depends on the number of Nodes, each Node’s configured maximum sessions, browser workload, CPU and memory limits, and the kinds of pages under test. Selenium gives 1 CPU and 1 GB RAM per browser as a reference starting point, not a universal sizing rule. Measure your own suite and environment.
- Start with a low session limit and representative test pages.
- Watch queued requests, available slots, session duration, CPU, memory, and container restarts.
- Increase Node count or session limits in small steps, comparing throughput and failure rate.
- Keep enough memory and shared memory for the heaviest browser pages; a session that starts successfully can still fail under load.
For cost, account for the machines or CI runners that host the Grid, browser image storage and pulls, and the idle capacity held for parallel jobs. Containers reduce environment drift but do not remove the compute cost of running browsers. Scaling to the observed workload is more reliable than setting concurrency from a guess.
9. Secure the Grid and Docker daemon
Selenium warns that an unprotected Grid can expose its infrastructure, permit access to internal applications and files, or allow third parties to run custom binaries. Keep the client endpoint on a trusted network, apply firewall rules, and avoid publishing an unauthenticated Grid to the public internet. Where appropriate, configure Grid authentication and put network access controls around it.
Docker-backed sessions add a separate trust boundary: access to the Docker socket or a remote Docker API can allow control over containers on the host. Restrict which users and jobs can reach the Grid, avoid mounting the host socket into a broadly accessible service, and do not expose a daemon’s TCP endpoint without appropriate protection.
10. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Client gets connection refused on port 4444 | Container is stopped, still starting, or the port is not published/reachable. | Check docker ps, logs, host firewall, and -p 4444:4444. Poll /status until ready. |
| Hub UI loads but no Nodes appear | Wrong Event Bus hostname/ports, mismatched image versions, or Node cannot reach Hub. | Check SE_EVENT_BUS_HOST, shared network membership, matching tags, and ports 4442/4443. For remote Nodes, verify Node port reachability and advertised host. |
| New session says no matching capabilities or slot | Requested capabilities do not match a registered Node stereotype, or all slots are busy. | Inspect /status and the UI. Align browserName and version with the image mapping, or add a matching Node/slot. |
| Docker-backed Node cannot create browser container | Daemon URL is unreachable, socket is not mounted, or daemon permissions deny access. | From the Grid container, validate the configured daemon path and access. Ensure the TOML [docker] URL matches the actual socket or TCP endpoint. |
| Browser image pull fails | Tag is invalid, registry is unavailable, or the host architecture is unsupported. | Use a full tag published by the official project, verify architecture support and registry access, and pull the image manually to reveal the Docker error. |
| Browser crashes, hangs, or reports tab crashes | Insufficient memory/shared memory, heavy pages, or too many concurrent sessions. | Set appropriate --shm-size, reduce session concurrency, increase host resources, and observe container and Grid logs. |
| Works locally but fails from CI | localhost points at the CI test container, not the Grid service. |
Use the service/container hostname on the shared network and ensure CI waits for /status readiness. |
| A copied CLI option is rejected | Options change between Selenium releases or roles. | Run java -jar selenium-server.jar --config-help or the role-specific --help for the deployed release; use the CLI options reference. |
Or skip the browser setup
If your task is to capture a page image or PDF rather than interact with it through a browser test, ScreenshotNeo returns a screenshot or PDF from one GET request. Its API removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot and PDF tools. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
See the ScreenshotNeo API documentation for parameters and response details. Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
FAQ
Can Selenium Grid run browser tests in parallel?
Yes. Grid distributes new sessions to available matching slots. Parallel capacity is limited by registered slots and the resources available to those sessions.
Do I need Docker Compose?
No. docker run is enough for a single container or a small Hub and Node setup. Compose is useful when you want to keep several related services and their configuration together.
Should I use a container per test?
With ordinary Node containers, sessions share the Node’s browser environment. Docker-backed session mode creates browser containers on demand. Choose based on isolation needs and the added daemon configuration and permissions that per-session containers require.
Can Grid run on one machine?
Yes. Standalone is designed for one machine. Hub and Node can also run on one Docker host for development, though its main benefit is coordinating Nodes across machines.


