Skip to main content

Docker - Run Graphical User Interfaces - Firefox, Chrome & GIMP

Unlock the power of Docker! A step-by-step guide to running Linux Graphical User Interfaces (GUIs) like Firefox, Chrome, and GIMP in Docker containers.

· 5 min read
View raw
Christophe
Markdown, WSL and Docker lover ~ Insatiable curious.
Cet article existe aussi en français — lire la version française.

This article is over a year old but was reviewed on July 30, 2026 — the content is still accurate.

Docker - Run Graphical User Interfaces - Firefox, Chrome & GIMP

⚡
TL;DR

This follow-up article shows how to build custom Docker images (starting with a minimal xeyes example) that run Linux GUI apps — Firefox, Chrome, GIMP — as native windows on the host, by sharing the DISPLAY environment variable and the /tmp/.X11-unix socket with the container and granting X server access via xhost +local:docker.

In my previous post, I've illustrated how to start Firefox or GIMP in a browser. This was the first part of this series about graphical user interfaces because, until very recently, I didn't know it was possible to run GUIs with Docker and that's just amazing.

`GUI` stands for `Graphical User Interface`

So, using Docker, we can start Firefox or GIMP or even ... Doom 2. And if a single application isn't enough, Start lubuntu Desktop in Docker gives you an entire desktop.

In this blog post, we'll create our own xeyes Docker image, then play with Firefox and Gimp.

A first look​

xeyes under Docker

Yes, it's true, it's useless, but wow! it's possible to run a GUI from a container and replicate the image in real time on our host machine. That's xeyes — a pair of eyes following your mouse cursor — running entirely inside a container, displayed as a native window.

Why it works​

  • The container shares the host's DISPLAY environment variable, so it knows which X display to draw on.
  • The host's /tmp/.X11-unix socket is mounted into the container, which is the actual channel X11 applications use to talk to the display server.
  • xhost +local:docker grants the Docker socket permission to connect to the host's X server in the first place — without it, the connection is refused.

Creating our own xeyes Docker image​

Let's start with something really geeky.

Go to a temporary folder (f.i. mkdir -p /tmp/xeyes && cd $_) and create a file called Dockerfile with this content:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y --no-install-recommends x11-apps && \
rm -rf /var/lib/apt/lists/*
CMD [ "xeyes" ]

This Dockerfile creates a container based on Ubuntu that installs X11 graphical applications, then cleans up the package manager cache to keep the image small. When you run this container, it launches the xeyes program, which is a simple graphical tool that displays a pair of eyes following your mouse cursor.

Now, create the image by docker build like this: docker build --tag cavo789/xeyes . (replace cavo789 by anything else like your pseudo).

Make sure you've a variable called DISPLAY. You can check this by running printenv | grep DISPLAY. If you don't have it, create the variable by running export DISPLAY=:0 in the console.

Now, run xhost +local:docker in your console. That command grants permission to connect to an X server using the Docker socket. This means that applications running within Docker containers can display their graphical user interface (GUI) on the host system. The expected result is this text: non-network local connections being added to access control list

Now, simply run a container and make sure to share the DISPLAY variable: docker run --rm --env DISPLAY=$DISPLAY --volume /tmp/.X11-unix:/tmp/.X11-unix cavo789/xeyes — you'll get the window shown above.

Creating our own Firefox Docker image​

So, once you've understood the very basic example of xeyes, you can think out-of-the-box: which GUI can I install using Docker?

Let's try Firefox... By using my favorite search engine, I've found this post: Install Official Firefox .deb in Dockerfile.

In a Dockerfile and with small changes, this gives us this:

# cspell:disable
FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install --no-install-recommends -y apt-utils ca-certificates curl gpg && \
rm -rf /var/lib/apt/lists/*
# https://jetthoughts.com/blog/install-official-firefox-deb-in-dockerfile-docker-devops/
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=tmpfs,target=/var/log \
# Create a directory to store APT repository keys, repository lists, and preferences if they don't exist
install -d -m 0755 /etc/apt/keyrings /etc/apt/preferences.d /etc/apt/sources.list.d > /dev/null && \
# Import the Mozilla APT repository signing key
curl -fsSL https://packages.mozilla.org/apt/repo-signing-key.gpg | \
gpg --dearmor --no-tty -o /etc/apt/keyrings/packages.mozilla.org.gpg > /dev/null && \
# Add the Mozilla APT repository to the APT sources list
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/packages.mozilla.org.gpg] https://packages.mozilla.org/apt mozilla main" | \
tee /etc/apt/sources.list.d/packages.mozilla.org.list > /dev/null && \
# Configure APT to prioritize packages from the Mozilla repository
echo "Package: *\nPin: origin packages.mozilla.org\nPin-Priority: 1000\n\n" | tee /etc/apt/preferences.d/mozilla > /dev/null && \
# Update your package list and install the Firefox .deb package
apt-get update -qq > /dev/null && \
DEBIAN_FRONTEND=noninteractive apt-get install -qq --no-install-recommends firefox > /dev/null && \
rm -rf /var/lib/apt/lists/*
CMD [ "firefox" ]

This Dockerfile creates a Ubuntu container with Firefox installed from Mozilla's official APT repository. It sets up the necessary keys and repository configuration to get Firefox directly from Mozilla, then installs it cleanly with caching optimizations to keep the image size down.

To build the image, please run the next command (and remember to replace cavo789 with your username): docker build --tag cavo789/firefox ..

And to start Firefox, just run docker run --rm -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY cavo789/firefox.

Running Firefox in a window

As you know, my OS is Windows 11 and I'm running Linux thanks to the amazing WSL2 technology. So, in short, here above, you can see I've started Firefox for Debian as a windowed application in my Windows.

The old MS-DOS developer in me continues to be amazed by this possibility.

Creating our own Chrome Docker image​

We can do the same with Chrome:

FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends wget \
&& wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
&& apt-get install -y ./google-chrome-stable_current_amd64.deb \
&& rm -rf /var/lib/apt/lists/*
CMD ["google-chrome", "--disable-dev-shm-usage", "--disable-gpu"]

This Dockerfile creates a Docker image based on Ubuntu and installs Google Chrome in it. It sets up a non-interactive environment to avoid prompts during installation, downloads Chrome, installs it, and cleans up temporary files to keep the image smaller. When the container runs, it launches Chrome with flags that disable some features for better compatibility in containerized environments.

Build the image using docker build --tag cavo789/chrome . then run it using docker run --rm -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY cavo789/chrome.

Running Chrome in a window

Creating our own GIMP Docker image​

Ok, now, I think you've understood how it works. So, very shortly, here is how to run GIMP for Linux in a Docker container:

FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --no-install-recommends -y gimp && rm -rf /var/lib/apt/lists/*
CMD [ "gimp" ]

This Dockerfile creates a container image based on Ubuntu that installs GIMP (an image editing application) and runs it by default when the container starts. It's a minimal setup that prevents interactive prompts during installation and cleans up package cache to keep the image size smaller.

Create the image by running docker build --tag cavo789/gimp ..

And to start GIMP, just run docker run --rm -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY cavo789/gimp.

Running GIMP for Linux in a Docker container

Conclusion​

Same recipe every time — share DISPLAY, mount /tmp/.X11-unix, docker run — and any Linux GUI app shows up as a native window on the host, whether it's a silly xeyes demo or a full browser or image editor. If a single application isn't enough and you'd rather have a whole desktop to play with, Start lubuntu Desktop in Docker is the next step.


Was this article helpful?
Did you try the steps in this article?