Docker isn’t just for serve your code, appliactions. you can actually run a full desktop app inside it. In this project, I containerized Firefox with a virtual desktop and made it accessible through a browser using noVNC.
What this project does?
It creates a lightweight container that:
- Runs a minimal desktop environment (Fluxbox)
- Launches Firefox
- Serves a VNC display using x11vnc
- Exposes that desktop through noVNC (so you can open it in your web browser)
You can literally open Firefox running inside Docker, from your browser tab.
All using a single docker compose up.
How it works?
Here’s a quick breakdown of what happens inside the container:
Everything runs headlessly, there’s no physical display, but the combo of Xvfb + Fluxbox gives Firefox a virtual desktop.
🐋 Dockerfile Overview
FROM alpine:edge
RUN apk add --no-cache \
faenza-icon-theme \
firefox \
fluxbox \
xfce4 \
xvfb \
x11vnc \
novnc \
supervisor \
bash \
net-tools
# Install noVNC & websockify from source code
RUN apk add --no-cache git python3 py3-pip \
&& rm -rf /usr/share/novnc \
&& git clone https://github.com/novnc/noVNC.git /usr/share/novnc \
&& git clone https://github.com/novnc/websockify.git /usr/share/novnc/utils/websockify \
&& ln -sf /usr/share/novnc/vnc.html /usr/share/novnc/index.html
ENV DISPLAY=:1
ENV RESOLUTION=1920x1080x24
# Set vnc password
ARG VNC_PASS=dummypass
# Create vnc password file
RUN mkdir -p /root/.vnc && \
x11vnc -storepasswd "$VNC_PASS" /root/.vnc/passwd
COPY supervisord.conf /etc/supervisord.conf
EXPOSE 5900 6080
CMD ["supervisord", "-c", "/etc/supervisord.conf", "-n"]
📦 Docker Compose Setup
version: '3.8'
services:
vnc_firefox:
build: .
container_name: vnc_firefox
ports:
- "5901:5900" # VNC
- "6080:6080" # noVNC web UI
healthcheck:
test: ["CMD-SHELL", "netstat -tln | grep -q 6080 || exit 1"]
interval: 1m30s
timeout: 30s
retries: 5
start_period: 30s
Under the Hood (process supervision)
Everything is managed by supervisord, which runs:
Xvfb - virtual framebuffer display
x11vnc - provides VNC access
fluxbox - lightweight window manager (WM)
firefox - your GUI browser
novnc_proxy - web socket bridge
Example supervisord.conf:
# Supervisor main config
[supervisord]
nodaemon=true
logfile=/var/log/supervisord.log
pidfile=/var/run/supervisord.pid
childlogdir=/var/log
# XVirtual Framebuffer (Xvfb)
# Creates a virtual display environment (:1)
[program:xvfb]
command=/usr/bin/Xvfb :1 -screen 0 1920x1080x24
autostart=true
autorestart=true
priority=10
# x11vnc, VNC server
[program:x11vnc]
command=/usr/bin/x11vnc -display :1 -rfbauth /root/.vnc/passwd -forever -shared -rfbport 5900
autostart=true
autorestart=true
priority=20
# fluxbox, lightweight window manager
[program:fluxbox]
command=/usr/bin/fluxbox
environment=DISPLAY=":1"
autostart=true
autorestart=true
priority=30
# Runs firefox inside the Xvfb + Fluxbox environment
[program:firefox]
command=/usr/bin/firefox
environment=DISPLAY=":1"
autostart=true
autorestart=true
priority=40
# noVNC, WebSocket VNC Proxy
# Bridges VNC (port 5900) to a web interface (port 6080)
[program:novnc]
command=/usr/share/novnc/utils/novnc_proxy --vnc localhost:5900 --listen 6080
autostart=true
autorestart=true
priority=50
Our project structure should look likes this:
.
├── docker-compose.yml
├── Dockerfile
└── supervisord.conf
How to Run It?
1. Build & start the container:
$ docker compose up --build -d
2 Access it by using your browser or VNC client. Using dummypass as password:
- Using noVNC Web: http://localhost:6080
- Open any VNC viewer (e.g., RealVNC, TigerVNC, Remmina), then connect to: localhost:5901
What’s Next?
While this is mostly a fun experiment, it can be used for:
- Headless browser testing environments
- Remote browsing (isolated Firefox)
- Demonstrating GUI automation setups
NB: 😎 This post is part of my “Container Stuffs” open-source project on GitHub. Upcoming labs include:
- PostgreSQL master–replica setup
- Redis Sentinel cluster
- Multi-node Docker Swarm simulations
- and more to come!
danielcristho/container-stuffs
Conclusion
Docker is more than backend services you can literally containerize entire user experiences.
Projects like this prove that containers aren’t limited to APIs, databases, and background workers. With a bit of creativity, you can run full desktops, interactive UIs, browsers, automation toolchains, and even full development environments inside isolated, reproducible containers.
Running Firefox inside Docker with noVNC shows how:
- system-level components (Xvfb, window managers, VNC)
- web technologies (WebSockets, noVNC)
- and container orchestration (Docker + Compose) can blend together to create something both useful and fun.
Cheers, feel free to give me a feedback, and happy containerizing! 🐳







Top comments (0)