This picture was taken by my Rolleiflex Automat II

A Very Basic Browser-Sync Development Environment Based on Docker

Chun Ming Wang


The purpose is to set up a very basic environment based on Docker for me to play HTML, CSS and Javascript like Codepen or plunkr. However, embedding images in these site is cumbersome.

The requirement is: 1. browser should automatically refresh when HTML, CSS and Javascript files change, 2. being able to use images in the html file, 3. I want to keep my own machine minimal , that is I don’t want install node.js and browser-sync locally.

The first step is to build a docker image with browser-sync install. The following Dockerfile should do.

FROM node:lts-alpine
RUN apk update && apk upgrade
#install browser-sync
RUN npm install -g browser-sync

The most important line is RUN npm install -g browser-sync which installs browser-sync globally.

In the directory where the Dockerfile resides, using following command to create the image. Note the trailing dot which is necessary.

docker build -t="your-own-image-tag" .

The option t designates the tag of the newly created image. Now the image is ready.

To run the container, use the following command.

docker run -it --rm \
-v $(pwd):/app \
-p 3000:3000 \
-p 3001:3001 \
your-own-image-tag \
browser-sync start \
--server \
--files \"*.html, *.js, *.css,css/*.css, js/*.js\" \
--no-open false

A complicated command, um…! Explanation is necessary for me, because I definitely forget some day.

-it tells docker to run this container interactively with a terminal.

-rm tells docker to delete this container after the container is stopped.

-v binds a host directory to a directory in the container. The format is host-directory:directory-in-container. With this option, files in the host and in the container are actually the same copy. Changes of the files synchronize.

-p 3000:3000 tells docker to map the port 3000 (the first 3000 before the column :) of the host to the port 3000 (the second 3000 after the column :) of the container. Browser-sync uses port 3000 to serve the site as default.

-p 3001:3001 tells docker to map the port 3001 (the first 3001 before the column :) of the host to the port 3001 (the second 3001 after the column :) of the container. Browser-sync uses port 3001 to provide a UI to manage its options.

your-own-image-tag is the image tag that is just created.

browser-sync start is the command to be executed after the container is initiated.

--server tells browser-sync to start a static server for basic HTML/JS/CSS websites.

— files \"*.html, *.js, *.css, *.jpg,css/*.css, js/*.js, img/*.jpg\" tells browser-sync to watch all files with extension of html, js, css, jpg; also watch the files in directories css, js, andimg with the same extension. In short, this option tells browser-sync to watch all static files in current working directory and sub-directories. \ is for escaping.

--no-open false tells browser-sync not to open a browser because it is run in a environment without a browser.

Now a very simple server that serves static files runs, and I can see the following image. I can simple right click the link to open the website.

message emitted by browser-sync

For convenience, I store the command which runs the container in a shell script named start-browser-sync in my home directory. Make the script executable with the following command.

chmod +x start-browser-sync

Now I can use this simple web server with one command. Make a directory with a index.html with the following content.

<!DOCTYPE html>
<title>Browser-Sync Test</title>
<h1>Browser-Sync works in root</h1>

Then cd to this directory, use the shell script with the command,


A simple static web server is now running, and it watches all changes I make.

Another way to run the command is to use alias. Just copy and paste following code. Don’t forget the escaping character \. This annoys me for months.

alias serve="docker run -it --rm \\
-v \$(pwd):/app \\
-p 3000:3000 -p 3001:3001 \\
cmwang/browser-sync browser-sync start \\
--server --files \"*.html, *.js, *.css,css/*.css, js/*.js\" \\
--no-open false"