Part 2: Docker install and container build
This article is part 2 in a series about HTTP2 server push in NGINX. This article continues with the environment setup by describing how to install Docker and configure a Docker container running the NGINX web server with HTTP/2 and HTTPS in Ubuntu 18.
Check out these previous articles which describe setting up the environment and configuring NGINX web server for HTTP/2:
Now we are ready to install Docker and build a container running NGINX.
Follow the steps below to install Docker in Ubuntu 18 using the repository, or you can refer the official Docker Docs for other options.
Launch a new terminal window
First, make sure
sudo apt-get update
sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common
Add Docker’s GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Enter the below to get the latest stable docker repository:
sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"
Now we can install Docker with the following commands:
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io
Finally, verify the installation by running the
sudo docker run hello-world
hello-worldimage will not exist, so Docker will download it then run it. You should see something like the below:
Build and run the NGINX docker container
Now we are ready to build a docker container running NGINX web server.
Change into the
/docker-nginx/confdirectory and create a file named
dockerfilecontaining the below:
FROM nginx COPY ./html/ /usr/share/nginx/html COPY ./conf/nginx.conf /etc/nginx/conf.d/nginx.conf COPY ./ssl/ /etc/nginx/ssl
Some notes on what this means:
FROM nginxtells Docker we want to use the
- Next we tell docker to copy the local
/htmlsubdirectory into the container at location
nginx.confis copied into container location
ssl/directory containing the self-signed certificates is copied to container location
Keep in mind that making changes to any of the copied files after the container has been built will require a re-build of the container.
Change into the
/docker-nginxdirectory and enter the following to build the container:
sudo docker build -f conf/dockerfile -t nginx-http2 .
-foption tells Docker to use the
dockerfilecreated previously in the
-toption will tag the container with the name
nginximage does not exist, Docker will download it as part of the build.
Ensure you do not get any errors and all files are successfully copied to the container. A clean build will look similar to the screenshot below.
List the available docker images to verify the build completed successfully:
sudo docker images
If you have followed all the previous steps there should be 3 images listed:
If you have hit an error and need to delete an image before rebuilding, use the below command:
sudo docker rmi [image_name OR image_id]
Run the docker container:
sudo docker run -dit --name nginx-http -p 80:80 -p 443:443 nginx-http2
This will map container ports 80 and 443 to local ports 80 and 443.
Note: If there is an existing service running on local port 80 or port 443 you will get an error. Modify the command to use a free port and try again.
Now connect to a terminal within the running container:
sudo docker exec -it nginx-http /bin/bash
This will behave like a normal terminal. For example, you can change directories to
/usr/share/nginx/htmlwhere the webpage was copied and view the files:
cd /usr/share/nginx/html ls -l
Exit the terminal by entering the command exit and hitting
You should be able to access the NGINX web server on localhost port 443. Open Firefox and browse to
Since we are using a self-signed certificate you will get a warning: Your connection is not secure
Click Advanced then click Add Exception….
In the prompt click Confirm Security Exception.
If everything has worked you will see the NGINX welcome page.
Navigate to the webpage you created at
The docker container will contine to run in the background. You can stop the container with the following command:
sudo docker rm -f nginx-http
You can also start the container with output printed to stdout for debugging purposes:
sudo docker run -a STDOUT -it --name nginx-http -p 80:80 -p 443:443 nginx-http2
Refresh the webpage in Firefox and check the terminal for output.
You can see in the debugging output that HTTP/2 is being used.
Other ways to validate HTTP/2
There are a number of other ways to verify the webpage is using HTTP/2. Below are 2 examples.
Using Firefox to validate HTTP/2
Open Firefox and navigate to
Note: You can also explicity specify HTTP2 with the following URL, however this shouldn’t be neccessary:
In Firefox, open the Menu and select Web Developer > Network, or alternatively hit Ctrl + Shift + E.
To add the Protocol column, right-click one of the existing column headers (such as Status, Method or Domain) and select Protocol.
Now refresh the page to populate the Network activity details.
The Protocol should show as HTTP/2.0
Using curl to validate HTTP/2
Open a new terminal and enter the below
curl -I -k https://localhost/home.html
- -I option tells curl to fetch the HTTP headers only
- -k option tells curl to accept the self-signed SSL certificate
You should see the HTTP/2 header returned:
HTTP/2 200 server: nginx/1.15.8 date: Mon, 11 Feb 2019 08:03:46 GMT content-type: text/html content-length: 571 last-modified: Mon, 11 Feb 2019 04:55:09 GMT etag: "5c61002d-23b" accept-ranges: bytes
Verify HTTP/2 Server Push
At the time of writing (Firefox v65.0 64-bit) I was unable to find a way in Firefox to verify that server push is working. There are a few long-standing open bugs related to this:
Google Chrome to the rescue.
If you don’t already have Chrome installed in Ubuntu, download and install it from https://www.google.com/chrome/
Open Google Chrome
Enable the Developer tools by opening the menu and selecting More tools > Developer tools (or hit Ctrl + Shift + i)
Select the Network tab
You will get a security warning similar to Firefox. Again, this is because we used a self-signed certificate.
Click Advanced and then click Proceed to http2.localhost (unsafe)
The page will load and the Network tab will populate to indicate the network activity.
The Initiator column will indicate that the resources were pushed with
You can also add the Protocol column (same steps as in Firefox) which will show h2, which indicates HTTP/2 was used.
Congratulations for getting this far! There were quite a few steps involved but now we have successfully confirmed that NGINX is serving our website using HTTP/2 and server push.
Stay tuned for the next article which will describe how to capture and decrypt this HTTP/2 traffic using Wireshark.