GNS3 + Docker: Internet modem container

Goal: Deploy internet modem for GNS3 topology using Docker container. The container uses iptables to perform NAT (masquerading) and dnsmasq as DHCP server for LAN interfaces.

Used Docker images:

GNS3 host preparation : This is performed on GNS3 linux host

From GNS3 host console, create a tap interface (tap0) and put it along with the physical interface (eth0) in a bridge (ex: ovsbr0):

ip tuntap add dev tap0 mode tap user <username>

sudo ovs-vsctl add-br ovsbr0

sudo ovs-vsctl add-port ovsbr0 tap0

You can use either linux bridge (brctl command) or OpenVswitch bridge (ovs-vsctl command)

sudo ovs-vsctl show


Bridge “ovsbr0”

Port “tap0”

Interface “tap0”

Port “ovsbr0”

Interface “ovsbr0”

type: internal

Port “eth0”

Interface “eth0”

ovs_version: “2.3.0”

Remove ip address from eth0 (or release dhcp parameters) then reconfigure IP address and default gateway (or request dhcp) for the ovs bridge ovsbr0

Import containers

1- Create a new docker template in GNS3. Create new docker template: Edit > Preferences > Docker > Docker containers and then “New”.

Choose “New image” option and the name ajnouri/internet

Screenshot - 170716 - 18:49:03

Accept all default parameters.

2- Create a new docker template in GNS3. Create new docker template: Edit > Preferences > Docker > Docker containers and then “New”.

Choose “New image” option and the name gns3/openvswitch

Screenshot - 170716 - 18:49:12

Set the number of interfaces to eight and accept default parameters with “next” until “finish”.

3- Same for end host container. From GNS3, create new docker template Edit > Preferences > Docker > Docker containers and then “New”.

Choose “New image” option and the name gns3/endhost.

Screenshot - 170716 - 18:49:21

Next you can choose a template name for the container, in this case I renamed it as “dvpc”.

Accept default parameters with “next” until “finish”.

GNS3 Topology

Insert a cloud to the topology and map it to tap0

Screenshot - 170716 - 18:49:31

Build the below topology

Screenshot - 170716 - 18:49:40

Configure containers network interfaces:

Internet container ajnouri/Internet-1

Screenshot - 170716 - 18:50:33

End host container dvpc-1

Screenshot - 170716 - 18:50:49

The WAN interface of the Internet container should have been assigned an IP and gateway from your physical network (connected to internet).

Start the script from /data directory

You will be asked to set the LAN and WAN interfaces as well as the IP range for dhcp clients connected to LAN interface, then the script will start dnsmasq and set iptables for NAT (masquerade)

ajnouri/internet-1 console

Screenshot - 170716 - 18:51:15

ajnouri/dvpc-1 console

Screenshot - 170716 - 18:51:37

Other dhcp parameters assigned to the client are taken from Internet device WAN interface DHCP parameters.

Connectivity check


Let’s have fun! Now that we have internet connectivity, install a text-based browser package on the end host container


Start elinks and browse Internet


For more comfortable browsing experience, you can use the image gns3/webterm.

Create a new Docker template


Choose vnc as the console type to allow GUI browsing of Firefox


And keep the remaining default parameters.

Insert the image and connect it to the topology as follow:


Set the container interface for dhcp client


Start the stopped containers and console (vnc) to Webterm container.

(gns3/openvswitch doesn’t need any configuration)


You should get this







Routing between Docker containers using GNS3.

The idea is to route (IPv4 and IPv6) between Dockers containers using GNS3 and use them as end-hosts instead of Virtual Machines.

Containers use only the resources necessary for the application they run. They use an image of the host file system and can share the same environment (binaries and libraries).

In the other hand, virtual machines require entire OS’s, with reserved RAM and disk space.

Virtual machines vs Docker containers

Virtual machines vs Docker containers


If you are not familiar with Docker, I urge you to take a look at the below excellent short introduction and some additional explanation from Docker site. :



As for now, Docker has limited networking functionalities. This is where pipework comes to the rescue. Pipework allows more advanced networking settings like adding new interfaces, IP’s from a different subnets and set gateways and many more…

To be able to route between the containers using your own GNS3 topology (the sky the limit!), pipework allows to create a new interface inside a running container, connect it to a host bridge interface, give it an IP/mask in any subnet you want and set a default gateway pointing to a device in GNS3. Consequently all egress traffic from the container is routed to your GNS3 topology.


GNS3 connection to Docker a container

GNS3 connection to Docker a container


How pipework connects exposes container network

How pipework connects exposes container network

Lab requirements:


sudo bash -c "curl\
 > /usr/local/bin/pipework"

For each container, we will generate docker image, run a container with an interactive terminal and set networking parameters (IP and default gateway).

To demonstrate docker flexibility, we will use 4 docker containers with 4 different subnets:



This is how containers are built for this lab:




Here is the general workflow for each container.

1- build image from Dockerfile (

An image is readonly.

sudo docker build -t <image-tag> .

Or (docker v1.5) sudo docker build -t <image-tag> <DockerfileLocation>

2- Run the built image:

Spawn and run a writable container with interactive console.

The parameters of this command may differ slightly for each GUI containers.

sudo docker run -t -i <image id from `sudo docker images`> /bin/bash

3- Set container networking:

Create host bridge interface and link to a new interface inside the container, assign to it an IP and a new default gateway.

sudo pipework <bridge> -i <int> <container if from `sudo docker ps`> <ip/mask>@<gateway-ip


To avoid manipulating image id’s and container id’s for each of the images and the containers, I use a bash script to build and run all containers automatically:


IMGLIST="$(sudo docker images | grep mybimage | awk '{ print $1; }')"
[[ $IMGLIST =~ "mybimage" ]] && sudo docker build -t mybimage -f phusion-dockerbase .
[[ $IMGLIST =~ "myapache" ]] && sudo docker build -t myapache -f apache-docker .
[[ $IMGLIST =~ "myfirefox" ]] && sudo docker build -t myfirefox -f firefox-docker .

BASE_I1="$(sudo docker images | grep mybimage | awk '{ print $3; }')"
lxterminal -e "sudo docker run -t -i --name baseimage1 $BASE_I1 /bin/bash"
sleep 2
BASE_C1="$(sudo docker ps | grep baseimage1 | awk '{ print $1; }')"
sudo pipework br4 -i eth1 $BASE_C1 

BASE_I2="$(sudo docker images | grep mybimage | awk '{ print $3; }')"
lxterminal -e "sudo docker run -t -i --name baseimage2 $BASE_I2 /bin/bash"
sleep 2
BASE_C2="$(sudo docker ps | grep baseimage2 | awk '{ print $1; }')"
sudo pipework br5 -i eth1 $BASE_C2 

APACHE_I1="$(sudo docker images | grep myapache | awk '{ print $3; }')"
lxterminal -t "Base apache" -e "sudo docker run -t -i --name apache1 $APACHE_I1 /bin/bash"
sleep 2
APACHE_C1="$(sudo docker ps | grep apache1 | awk '{ print $1; }')"
sudo pipework br6 -i eth1 $APACHE_C1 

lxterminal -t "Firefox" -e "sudo docker run -ti --name firefox1 --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix myfirefox"
sleep 2
FIREFOX_C1="$(sudo docker ps | grep firefox1 | awk '{ print $1; }')"
sudo pipework br7 -i eth1 $FIREFOX_C1


And we end up with the following conainers:

Containers, images and dependencies.

Containers, images and dependencies.



All you have to do is to bind a separate cloud to each bridge interface (br4,br5,br6 and br7) created by pipework, and then connect them to the appropriate segment in your topology.


Lab topology

Lab topology

Note that GNS3 topology is already configured for IPv6, so as soon as you start the routers, Docker containers will be assigned IPv6 addresses from the routers through SLAAC (Stateles Auto Configuration) which makes them reachable through IPv6.


Here is a video on how to launch the lab:


Cleaning up

To clean your host from all containers and images use the following bash script: which uses the below docker commands:

Stop running containers:

  • sudo docker stop <container id’s from `sudo docker ps`>

Remove the stopped container:

  • sudo docker rm <container id’s from `sudo docker ps -a`>

Remove the image:

  • sudo docker rmi <image id’s from `sudo docker images`>
sudo ./
Stopping all running containers...
Removing all stopped containers...
Erasing all images...
Make sure you are generating image from a Dockerfile
or have pushed your images to DockerHub.
*** Do you want to continue? No

I answered “No”, because I still need those images to spawn containers, you can answer “Yes” to the question if you don’t need the images anymore or if you need to change the images.




pipework for advanced Docker networking:

Running firefox inside Docker container:


3D model shipping container:

%d bloggers like this: