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.
This article is over a year old but was reviewed on July 30, 2026 — the content is still accurate.

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

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
DISPLAYenvironment variable, so it knows which X display to draw on. - The host's
/tmp/.X11-unixsocket is mounted into the container, which is the actual channel X11 applications use to talk to the display server. xhost +local:dockergrants 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.

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.

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.

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.





