Running a browser carries inherent risk. Just about every website runs arbitrary
sandboxes are good, with Firefox vulnerabilities going for up to $100,000 USD,
vulnerabilities are not unheard of and additionally some browser “features” can be used
maliciously such as CSRF on local services, and DNS rebinding attacks.
This post will explain how to run a sandboxed browser and common actions such as
installing addons and keeping bookmarks.
While Docker is not typically used as a desktop application sandbox, it can be
used as one without too much difficulty past initial setup. Firejail and Bubblewrap can
be used instead, but they lack advanced features of Docker such as manual state saving
(commiting), the extensibility of Docker volumes and the ability to easily install
particular software versions and forks. Docker is also older than Firejail and is
battle tested from enterprise use.
By default, Docker has no way of creating a window on your desktop. To do this,
it needs to either hook into the host’s x11/Wayland socket, make a second socket, or use
VNC. Each option has trade-offs. I will review each:
- Hooking into primary host socket
- This option is the most seamless, windows will feel pretty much like normal
- This option is insecure, especially under x11
- Under Wayland, things are more restricted.
- Not intended for remote use.
- Doesn’t work well with Windows or Mac as host
Hooking into secondary host socket
Most complicated option
More secure than using primary host socket, but less secure than VNC.
Not intended for remote use.
- Doesn’t work well with Windows or Mac as host
- Simplest option.
- Works remotely, even from a phone
- Host and workstation agnostic
- Most secure option (when a good password is set).
- VNC is not a secure protocol, see VNC section
This article uses the VNC option, due to the security and pure
independence of the host system.
Build the following Dockerfile using $ docker build -t firefox .
FROM ubuntu:latest # we could probably use a lighter os, but firefox dependencies make it not matter much
RUN apt-get update
RUN apt-get install -y x11vnc xvfb firefox \
openbox # Openbox is optional, one could use i3 or forego entirely
RUN adduser user # It would be poor practice to run a browser as root, even in a container
RUN mkdir /home/user/.vnc
# We generate the password for VNC during image build time, which would normally be poor practice, however this makes it easier to keep
# a bookmark in a VNC client. Do not publish the image anywhere or reuse it, be sure to rebuild each time
# If the container will be used locally and there are no other users or services that could access it, this line can be omitted
RUN bash -c 'PASSWD=$(head -c 20 /dev/urandom | base64); echo "VNC Password: $PASSWD"; x11vnc -storepasswd $PASSWD /home/user/.vnc/passwd'
# Finish setting up user
RUN chown -R user /home/user/
# Set so that when xterm launches on login, it will launch Firefox
RUN bash -c 'echo "firefox" >> /home/user/.bashrc'
Build and Run
Build the image with $ docker build -t firefox .
Docker container behavior and security can depend heavily on what run
arguments are specified for a container. Docker-compose is used partly for removing
the headache of that, but I regard it as unnecessary for this purpose.
This is the run command:
$ docker run –rm –cap-drop=ALL -p 127.0.0.1:5900:5900 -e HOME=/home/user/ firefox x11vnc -forever -create -usepw
The 127.0.0.1: can be omitted to bind to 0.0.0.0 or changed to bind to a private network.
-usepw can be omitted if the password generation line was. (local single user system only)
If SSH tunneling for a secure connection to the server is desired, still bind to localhost.
–rm can be omitted if the container should retain data after exiting, however
there should be little reason to do this, as if browser history/data is desired,
volumes or mounts should be used instead. You can use –volume with the Firefox
profile directory. Volumes and mounts are not recommended, as they would create
an avenue for malware (such as malicious addons) to persist. I discuss how to persist addons and bookmarks later.
Docker is a good way to use Tor Browser if a full-virtualisation solution
is not desired.
The process for using Tor Browser is very similar, it just has different
dependencies in the install.
See the Dockerfile and associated entryptoint script here.
Connecting with VNC
VNC is not a secure protocol. It is not encrypted and the password protection is mediocre at best.
This example uses Vinagre on Fedora.
To use Vinagre with a locally running container, it is very simple.
Just enter 127.0.0.1 into the host input after pressing connect, then press
connect again. You will be prompted for a password if one is configured.
If used remotely, VNC should be tunneled over SSH, a VPN, or another secure method.
In this example, I use SSH tunneling to the host system running the container.
(local username same as remote)
The process is the same, however I recommend that public key SSH login be used.
For slightly more security, make the remote user for tunneling be
The only difference is that the remote host’s IP/domain is specified in the
tunneling option. Localhost is still used as the IP to connect to.
To install addons permanently (or make bookmarks), one could either use
Firefox sync, add them during image build, or install them normally and commit
the Docker container. I recommend the container commit method.
To do this, run the container without –rm. Install the Firefox addons, and exit
the container. Then, commit the container with $ docker commit
By using Docker as a sandbox, we can isolate Firefox from private services and
mitigate the impacts of compromise. I recommend launching fresh containers for
each general “purpose”, such as one for social media, and one for work, and so on.