{"id":14483492,"url":"https://github.com/c0b/chrome-in-docker","last_synced_at":"2025-07-30T00:31:34.851Z","repository":{"id":201656347,"uuid":"65653441","full_name":"c0b/chrome-in-docker","owner":"c0b","description":"run Google Chrome in container (as a perfect headless browser)","archived":false,"fork":false,"pushed_at":"2016-08-14T07:44:57.000Z","size":5,"stargazers_count":219,"open_issues_count":4,"forks_count":34,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-09-04T00:06:06.488Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/c0b0/chrome-stable/","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c0b.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-08-14T06:33:30.000Z","updated_at":"2024-08-17T12:27:37.000Z","dependencies_parsed_at":"2024-03-07T17:00:35.729Z","dependency_job_id":null,"html_url":"https://github.com/c0b/chrome-in-docker","commit_stats":null,"previous_names":["c0b/chrome-in-docker"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0b%2Fchrome-in-docker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0b%2Fchrome-in-docker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0b%2Fchrome-in-docker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0b%2Fchrome-in-docker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c0b","download_url":"https://codeload.github.com/c0b/chrome-in-docker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228061806,"owners_count":17863374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-03T00:01:48.611Z","updated_at":"2024-12-04T07:11:54.608Z","avatar_url":"https://github.com/c0b.png","language":"Shell","readme":"\n# google-chrome in docker\n\n*Need to test some latest Chrome version's features?* but hestitant to\nupgrade your main browser to unstable? this chrome-in-docker project can help you\n\n## Features\n\n- It downloads a google-chrome Linux version from chrome channels, either\n  stable, or beta, or developer version; install and pack into a docker\n  container, that can run on anywhere you have docker daemon;\n  https://www.chromium.org/getting-involved/dev-channel#TOC-Linux\n\n- It turns google-chrome into a headless browser, can be used together\n  with Selenium with chrome webdriver, or with Chrome's native Remote\n  Debugging Protocol you can program with\n  https://developer.chrome.com/devtools/docs/debugger-protocol\n  https://github.com/cyrus-and/chrome-remote-interface\n  that makes it a better headless browser than PhantomJS or SlimerJS,\n  better programability in my opinion;\n  while if need debugging, you have a VNC session to see the actual browser,\n  and do whatever you want, or you can even use it as your everyday main browser.\n\n# Usage\n\nYou may either just pull my prebuilt docker image at https://hub.docker.com/r/c0b0/chrome-stable/\n\n    $ docker pull c0b0/chrome-stable\n    $ docker run -it --rm c0b0/chrome-stable /opt/google/chrome/google-chrome --version\n    Google Chrome 52.0.2743.116\n\nOr build it locally with Dockerfile here\n\n    $ docker build -t chrome-stable:20160813 .\n\nCheck what Chrome version is builtin, and tag a version:\n\n    $ docker run -it --rm chrome-stable:20160813 /opt/google/chrome/google-chrome --version\n    Google Chrome 52.0.2743.116\n    $ docker tag chrome-stable:20160813 chrome-stable:52.0.2743.116\n\nThe extra `get-latest-chrome.sh` script here is to get latest versions of\nChrome Stable, Beta, or Unstable version, for testing some latest features,\nhere you may modify the Dockerfile to build a different image with each one,\nwhile, since the beta and unstable versions are changing fast, may be updating\nevery week or every day, you don't have to rebuild docker images everyday,\nwith this `get-latest-chrome.sh` and local volume bind, you can run a different\ncontainer with the same image; that way, within a relatively longer time range\nyou don't have to rebuild the base docker image; the reasons of a same base image\ncan be reused is dependencies of the different channels (stable, beta, or -dev)\nare most probably the same, or changing much less often; anyway, if there is\nany problem that stable can run but unstable cannot, you may always have a no-cache\nrebuild: by `docker build --pull --no-cache ...` to force pull latest ubuntu base\nand latest Chrome binary packages.\n\n    $ ./get-latest-chrome.sh\n    [... downloading latest Chrome and extracting to ./opt ...]\n\nYou may test run it one time first to check what's exact version of each Chrome channel:\n\n    $ docker run -it --rm -v $PWD/opt:/opt:ro chrome:20160813 \\\n                             /opt/google/chrome-unstable/google-chrome-unstable --version\n    Google Chrome 54.0.2824.0 dev\n\n    $ docker run -it --rm -v $PWD/opt:/opt:ro chrome:20160813 \\\n                             /opt/google/chrome-beta/google-chrome-beta --version\n    Google Chrome 53.0.2785.57 beta\n\n    $ docker run -it --rm -v $PWD/opt:/opt:ro chrome:20160813 \\\n                             /opt/google/chrome/google-chrome --version\n    Google Chrome 52.0.2743.116\n\nThen run 3 different containers with the same base docker image:\n\n```console\n$ docker run -dt \\\n             --name Chrome-dev-54.0.2824.0 \\\n             -h chrome-dev-54.local \\\n             -v $PWD/opt:/opt:ro \\\n             -e CHROME=/opt/google/chrome-unstable/google-chrome-unstable \\\n         chrome:20160813\n56417156ffea4a55642cfa59cf5e9758a2be144144b2df39e91aa9265f098b75\n$ docker run -dt \\\n             --name Chrome-beta-53.0.2785.57 \\\n             -h chrome-beta-53.local \\\n             -v $PWD/opt:/opt:ro \\\n             -e CHROME=/opt/google/chrome-beta/google-chrome-beta \\\n         chrome:20160813\nd5b784cbe9ac7d3a52b43c7fb6918b28366c8b939293b10fb9b1808de7b46e2e\n$ docker run -dt \\\n             --name Chrome-stable-52.0.2743.116 \\\n             -h chrome-beta-52.local \\\n             -v $PWD/opt:/opt:ro \\\n             chrome:20160813\n35974a5247cf8650da25d03d9f279749ae4cf1e5b0c57349af1d511b8ac99545\n\n$ docker ps -a\nCONTAINER ID  IMAGE            COMMAND      CREATED  STATUS  PORTS  NAMES\n35974a5247cf  chrome:20160813  \"/entry.sh\"  ...                     Chrome-stable-52.0.2743.116\nd5b784cbe9ac  chrome:20160813  \"/entry.sh\"  ...                     Chrome-beta-53.0.2785.57\n56417156ffea  chrome:20160813  \"/entry.sh\"  ...                     Chrome-dev-54.0.2824.0\n```\n\nTo connect the chrome in docker, you may either use port mappings, let it call proper\niptables to set up proper mappings; or use inspect to find out the ip addresses\nof each container:\n\n    $ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' Chrome-dev-54.0.2824.0\n    172.18.0.4\n\nThat means the chrome browser's Chrome Debugging Protocol can be accessed by `172.18.0.4:9222`\n\n    $ curl -s 172.18.0.4:9222/json/version\n    {\n       \"Browser\": \"Chrome/54.0.2824.0\",\n       \"Protocol-Version\": \"1.1\",\n       \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2824.0 Safari/537.36\",\n       \"WebKit-Version\": \"537.36 (@facabd3224aecbcab4bea9daadad31c67488d78c)\"\n    }\n\nOr, if you use docker port mapping, like:\n\n```console\n         #  this one is not using any local volume binding on /opt, so it's using the builtin Chrome at build time,\n$ docker run -dt \\\n             --name Chrome-stable-builtin-52.0.2743.116 \\\n             -h chrome-stable-52.local \\\n             -p 9222:9222 \\\n         chrome:20160813\ne9a3738f2d642e5d1a4dd895750d1a09ddece3dd187c82309ade99e1b4123027\n$ docker ps -a\nCONTAINER ID  IMAGE            COMMAND      CREATED        STATUS         PORTS                     NAMES\ne9a3738f2d64  chrome:20160813  \"/entry.sh\"  3 seconds ago  Up 3 seconds   0.0.0.0:9222-\u003e9222/tcp   Chrome-stable-builtin-52.0.2743.116\n\n        # by inspect we know we can access this container by 172.18.0.2:9222\n$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' Chrome-stable-builtin-52.0.2743.116\n172.18.0.2\n$ curl -s 172.18.0.2:9222/json/version\n{\n   \"Browser\": \"Chrome/52.0.2743.116\",\n   \"Protocol-Version\": \"1.1\",\n   \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36\",\n   \"WebKit-Version\": \"537.36 (@9115ecad1cae66fd5fe52bd9120af643384fd6f3)\"\n}\n        # by above port mapping, this container can also be accessed by 0.0.0.0:9222; if it's from localhost Linux, \n$ curl -s localhost:9222/json/version\n{\n   \"Browser\": \"Chrome/52.0.2743.116\",\n   \"Protocol-Version\": \"1.1\",\n   \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36\",\n   \"WebKit-Version\": \"537.36 (@9115ecad1cae66fd5fe52bd9120af643384fd6f3)\"\n}\n```\n\nYou may try https://github.com/cyrus-and/chrome-har-capturer with more har capturing commands\nlike `chrome-har-capturer -t 172.18.0.2 urls...`\n\n## Debugging\n\nVNC session listens default on the container's 5900 port, if you figured out the container's\nIP address (by above inspect command), an VNC session can be opened by your favorite\nVNC client connect to this ip address, or you may use another `-p localport:5900`\nto set up another port forwarding to be able to use it from a 3rd computer.\n\n## Env variables to customize\n\n1. the default VNC password is `hola`; you may pass additional env var to docker run\n   by `-e VNC_PASSWORD=xxx` to change to use a different VNC password;\n2. the default CHROME is `/opt/google/chrome/google-chrome`, if you use local\n   volume bind to have different chrome versions, you may pass additional env var\n   by `-e CHROME=/path/to/chrome or chromium`\n\n# Design\n\n## Docker Image Build Time\n\n1. The Dockerfile defined process of where as start, it's starting from latest\n\n2. Ubuntu as base image, then install VNC and some network utilties like curl and socat,\nxvfb, x11vnc as Graphic layer for Chrome graphical output, xterm as debugging term window\nsupervisor as processes manager, sudo also for debugging, not technically required.\n\n3. Then add Google-Chrome's apt source and install google-chrome-stable version,\nand it will handle all runtime dependencies by Chrome;\nThis static version will be packed as part of the docker image, when you're not\nusing local volume bind, this version will be used. It depends how often do you\nrebuild, but with above `./get-latest-chrome.sh` script, you don't have to rebuild\nvery often.\n\n3. Then add a regular user at 1000:100 for improved security and run all services\nunder this regular user; sudo can be used for debugging.\nCopying supervisord.conf as definition of process structure; and entry.sh as\ncontainer entrypoint.\n\n## Container Spawn\nAt container spawn time (`docker run ...`), it starts from the entrypoint `entry.sh`\nthere it handles default VNC password `hola`, and check CHROME environment,\nset it default to the stable version `/opt/google/chrome/google-chrome`;\n\nThen it exec to supervisord to spawn more processes defined in `supervisord.conf`\n\n## Process Management\n\nSupervisord is the process manager, it spawns 4 processes:\n\n1. Xvfb ... as X server\n2. x11vnc ... as VNC on top of X Server\n3. fluxbox as window manager, this is technically not required,\n   any X11 application can directly run on X server, but with a window\n   manager, it's easier for debugging, when need to move window, resize,\n   maximize, and minimize, etc.\n4. xterm, same for debugging\n5. start chrome from CHROME environment variable, with `--remote-debugging-port=19222`\n   to enable Remote Debugging Protocol\n4. socat, as a forwarding channel, chrome can only listen on local loopback\n   interface (127.0.0.1); hence not accepting any request from outside\n   so a tcp forwarding tool like socat is necessary here.\n\nSupervisord will respawn any managed processes if it crashed.\n\nIdeally here should define dependencies between the processes, but due to\nhttps://github.com/Supervisor/supervisor/issues/122 it lacks such feature.\n\n# Some further improvements\n\n- [ ] Chromium nightly https://download-chromium.appspot.com/\n- [ ] VNC in browser, see https://github.com/fcwu/docker-ubuntu-vnc-desktop\n      have an openbox version, or lxde, an lightweight also full featured\n      Ubuntu desktop\n- [ ] setup iptables instead of socat\n- [ ] find replacement of supervisord, need a lightweight mananger also has\n      dependencies management. But sysvinit, upstart, or systemd is too heavy.","funding_links":[],"categories":["Shell","Virtualization"],"sub_categories":["Containers"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc0b%2Fchrome-in-docker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc0b%2Fchrome-in-docker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc0b%2Fchrome-in-docker/lists"}