I run a full Linux desktop in Docker just because I can


Like me, you’ve probably heard the unofficial rule of Docker: it’s for lightweight, headless servers and command-line applications, not for graphical interfaces. Most of us follow this rule for good reason—CLI is what Docker was built for. But what happens when you break the rules?

I decided to do something out of the ordinary. My goal was to run a full-fledged Linux desktop inside a container. I don’t want just a shell; I want a fully functional GUI that exists where it’s not supposed to. This is what happened when I tried.

Why am I doing this anyway?

It’s only a little bit crazy

So why would anyone go to all this trouble to run Linux? After all, we could simply use VirtualBox or even dual-boot Linux alongside Windows. My answer is simple: curiosity and the desire for a challenge.

I’ve been interested in Docker for some time, and while I have had experience with full-stack web development, not much in the world of Docker and containerization. I wanted to experiment with things and learn by doing them, so this project was the answer.

From the start, I knew this wouldn’t be easy. I expected that a day, maybe two days at most, would be enough to get a graphical Linux system up and running. But the reality of the challenge was quite the opposite. The obstacles I faced over the next four days were completely unexpected and far more complex than I could have ever anticipated, stretching my patience well beyond what I had prepared for.

Before diving into the technical details, here’s some context.

This entire experiment took place on a Windows 10 PC, driven by a specific question: what if you could have the best of both worlds? The idea of a full Linux environment running inside a Docker container, side-by-side with my standard Windows applications, was too intriguing to pass up. No reboots, no separate partitions—just a seamless, containerized Linux desktop.

So, first I had to get my lab ready. This meant installing Docker and setting up WSL. With the groundwork laid, I refreshed my Docker basics and read its documentation. With this, my initial preparation was complete; now, it was time to put theory into practice.

Running my Docker container

I tried doing this the hard way

Docker window showing failure to start a container

My first attempt to run a Linux desktop in Docker was, in hindsight, a rookie mistake out of overconfidence. I decided to build a custom image from scratch. If you are new to Docker, an image is a self-contained package of everything an application needs to run. So that once you have created an image, it will run the same everywhere, regardless of the hardware or operating system.

I made another error right from the start: I relied heavily on an AI tool to generate the code for my custom image.

Here’s the hard-earned lesson: If you don’t understand the technology, don’t copy-paste code just like I did. I spent hours debugging errors with no clear path forward, brute-forcing my way through a mess of code I didn’t understand.

After wasting an entire day on this unproductive path, I finally gave up and switched tactics. My new approach was simple: I’d use a pre-built image from Docker Hub. Think of Docker Hub as an “app store” for container images, filled with solutions created and shared by other developers. It was a much-needed adjustment and finally allowed the real work to begin.

First Ray of Light: The Good Things and the Bad Things

After my failed custom image attempt, I found a promising XFCE-based Debian image on Docker Hub. I downloaded it in minutes and, with a few commands, launched it. When I opened the URL, I was greeted by a fully functional Linux desktop, running right in my browser. The pure geek joy of seeing a complete OS served from inside a Docker container was a feeling I won’t forget. It worked!

The usability was surprisingly decent. LibreOffice and GIMP worked fine, although there was a bit of a lag. I would estimate about 70% of native performance, but still very usable. Firefox launched, too, and I even tried YouTube. That’s when I hit the first major hurdle: the colors were dull and washed out. A quick check confirmed my suspicion: the browser was using software rendering. My GPU was sitting idle.

There was another problem I noticed: Flatpak didn’t work. Any attempt to install an app from Flatpak failed with errors, so I had to resort to Debian packages. Despite these limitations, seeing a complete Linux desktop running in my browser, served directly from Docker, was a massive win.

Tweaking and learning

Couldn’t help myself

After a few minutes with XFCE, I decided to switch things up and try GNOME as my desktop environment. Big mistake! It took hours of troubleshooting and error-fixing to get it running, and when it finally launched, it was slow and resource-hungry. In the end, I swallowed my pride and reverted to XFCE, and told myself, XFCE may not be flashy, but it’s far more responsive. So let’s lean towards practicality.

With my new focus on performance, I decided to revisit my first attempt: building a custom image from scratch. This time, I studied the Dockerfile of the pre-built image I had used previously. I wanted to understand exactly what was going on under the hood, and I wanted to see if I could improve the performance myself. I experimented with a few new configurations, specifically trying to use xrdp instead of the noVNC forwarding method, to see if a different protocol would offer a smoother experience. But I didn’t see any difference with xrdp.

To replicate, create a file with the name “dockerfile”, paste the code, and run it.

FROM ubuntu:jammy-20230425


RUN apt update && \
    DEBIAN_FRONTEND=noninteractive apt install -y \
        cinnamon locales sudo \
        tigervnc-standalone-server tigervnc-common \
        virtualgl mesa-utils mesa-vulkan-drivers \
        dbus-x11 xterm wget && \
    locale-gen en_US.UTF-8 && \
    update-locale LANG=en_US.UTF-8

# Create user
# Enter the below username and passoword in xrdp login screen
ARG USER=user
ARG PASS=1234
RUN useradd -m $USER -p $(openssl passwd $PASS) && \
    usermod -aG sudo $USER && \
    chsh -s /bin/bash $USER

# Environment for Cinnamon
RUN echo "#!/bin/sh\n\
export XDG_SESSION_DESKTOP=cinnamon\n\
export XDG_SESSION_TYPE=x11\n\
export XDG_CURRENT_DESKTOP=X-Cinnamon\n\
export LIBGL_ALWAYS_INDIRECT=0\n\
exec cinnamon-session" > /home/$USER/.xinitrc && \
    chown $USER:$USER /home/$USER/.xinitrc && chmod +x /home/$USER/.xinitrc

# Setup VNC password
RUN mkdir -p /home/$USER/.vnc && \
    echo $PASS | vncpasswd -f > /home/$USER/.vnc/passwd && \
    chmod 0600 /home/$USER/.vnc/passwd && \
    chown -R $USER:$USER /home/$USER/.vnc

# Start script
RUN echo "#!/bin/bash\n\
export DISPLAY=:1\n\
Xvnc :1 -geometry 1920x1080 -depth 24 -SecurityTypes VncAuth -rfbport 5901 -localhost no &\n\
sleep 2\n\
sudo -u $USER startx &\n\
tail -f /dev/null" > /start && chmod +x /start

EXPOSE 5901

CMD ["/start"]

Exploring Docker Hub

This is how I should’ve done it from the start

If all of this sounds like too much work, there’s good news. You don’t have to build your own image to get started or deal with errors. My research led me to two fantastic, ready-to-use solutions that offer a much more streamlined experience.

  • Webtop by LinuxServer.io: This is a great open-source option that provides a variety of Linux desktop flavors pre-packaged as Docker images. It uses noVNC to deliver the desktop straight to your browser, and the setup is straightforward.
  • Kasm Workspaces: This is another open-source option for personal use.

The good thing about these images is that they have everything pre-configured, especially Webtop. You simply pull the Docker image and run it. Once the container is running, you can access your Linux by entering the URL. I found the performance to be much better than anything I had tried previously, and, importantly, had audio pass-through, which I didn’t find with Kasm images.

To run Webtop, open Windows CMD and paste this code

docker run -d ^
--name webtop-xfce ^
-e PUID=1000 ^
-e PGID=1000 ^
-e TZ=Etc/UTC ^
-p 3000:3000 ^
--shm-size=1gb ^
lscr.io/linuxserver/webtop:latest

I discovered a few unexpected perks

There are some benefits to this silly setup

What started as a fun project to learn Docker and experiment with Linux containers ended up revealing some surprisingly useful features along the way. The biggest discovery, and my personal “aha!” moment, was realizing the power of remote desktop access.

When I saw a full Linux desktop running in my browser, I had a wild idea: what if I accessed it from a less powerful device? I grabbed my Chromebook—a humble machine with an Intel Celeron processor—opened the URL, and there it was: the full power of my main PC, streaming on my Chromebook. Suddenly, I wasn’t chained to my desk. I could continue working from the couch, or anywhere else in the house. My low-powered Chromebook became a high-performance window into my desktop, all thanks to a container.

For the best experience, use a wired Ethernet connection or a fast 5 GHz Wi-Fi network.

Apart from this, I could see several other benefits:

  • Disposable Sandboxes: I could test and break things in a Linux environment without any fear of messing up my main OS. A perfect playground for risky experiments.
  • Private Browsing: I can spin up a new container, use a web browser, and then delete the entire environment with a single click, leaving no trace behind.
  • Dedicated Workspaces: I can create custom Linux images tailored to specific tasks—a distraction-free writing environment, a coding setup with all my dev tools pre-installed.

This flexibility opened up possibilities I hadn’t even considered when starting the project.

What’s next?

My unfinished experiments

Terminal showing errors when installing Flatpak

While I had seen for myself that running a Linux desktop in Docker is possible, my journey isn’t over. There were a few experiments I wanted to do, but didn’t have time for it:

  • Flatpak and Snap Store: I’d love to figure out how to get these app stores working inside the container to expand the software library.
  • Gaming: Without the GPU passthrough, this wouldn’t be possible, but I’m curious to figure out a solution for this.
  • Further Optimization: I want to continue tweaking the setup to see if I can squeeze out even better performance and reduce the input lag.

Why is it difficult to run Linux in Docker?

The challenges

So, now that I have understood that running a full desktop environment inside a container and expecting it to behave like a normal desktop on Windows is possible but painful, fragile, and much more cumbersome than running a VM. The primary reasons for these are:

  • Containers are not isolated Operating Systems: Docker containers share the host kernel. This is what makes them lightweight and great for single services. Whereas desktop environments expect system services like (systemd, logind, udev, DBus) and device access to be available. Containers don’t provide that by default.
  • No built-in display servers: Linux GUIs need a compositor/display server (X11 or Wayland). A container does not provide one, so we have to do that ourselves.
  • GPU access: Containers don’t virtualize GPUs by default, so you must pass device nodes into the container. And on Windows, there’s an additional WSL layer to cross.

Was it worth the trouble?

Absolutely. This was a fun and deeply rewarding project. I learned a ton about the inner workings of Docker and Linux, and there’s a special kind of satisfaction that comes from troubleshooting for hours and finally seeing your work pay off.

So, would I recommend it? Yes, especially if you’re curious and are looking for a quirky weekend project. But even if you’re not, the practical benefits I discovered—like remote desktop access, disposable sandboxes, and dedicated workspaces—make this far more than an experiment. I can see practical use cases here.

Although the unofficial rules of Docker are there for a reason, sometimes the most valuable lessons are found by breaking them. So, fire up your terminal, grab a pre-built image (or be brave and build your own!), and see the magic for yourself. You might also find a few unexpected perks along the way.



Source link

Leave a Reply

Subscribe to Our Newsletter

Get our latest articles delivered straight to your inbox. No spam, we promise.

Recent Reviews


Disney+ is embracing the Dark Side, as Star Wars: Maul – Shadow Lord is about to emerge on the service. Before The Mandalorian brought Star Wars into live-action television, the franchise was thriving in animated form, thanks to the initial success of Star Wars: The Clone Wars. Among the many new twists that the series introduced, one of the most notable developments was the return of Darth Maul after his apparent death in Star Wars: The Phantom Menace.

Now, after several series that have developed the character from a terrifying figure to a tragic Sisyphean antagonist, Maul – Shadow Lord will throw the character into a fight against the tyranny of the Empire, leading to tense chases and surprise alliances:

What is Star Wars: Maul – Shadow Lord?

The former Sith Lord returns

Star Wars: Maul – Shadow Lord is set on the newly introduced world of Janix, a planet on the Mid Rim of the galaxy far, far away that has been unbothered by the still young Galactic Empire in the wake of the Clone Wars. While the planet’s Tactical Defense Force keeps the population in check, the planet has become host to individuals looking to avoid Imperial interests, either out of fear for their lives or to rebuild in the shadows.

Following his usurping of Mandalore and escape from Republic custody in The Clone Wars season 7, Maul is attempting to rebuild the Shadow Collective crime syndicate with what remains of his forces, including fellow Dathomirian Zabraks and Mandalorian supercommandos. As Maul’s operations become too much for the TDF to handle, the Empire establishes a foothold on Janix. While grappling with Stormtroopers and Inquisitors, Maul must make an uneasy alliance with a young Jedi on the run if he wants to initiate his plan for revenge.

Who is in Star Wars: Maul – Shadow Lord?

An Oscar nominee joins the cast

Star Wars: Maul – Shadow Lord sees Sam Witwer reprise the role of the former Sith Lord-turned-crime lord from his appearances across Star Wars: The Clone Wars and Star Wars: Rebels. Fellow Rebels stars Vanessa Marshall and Steve Blum join him as the Mandalorian Rook Kast and Zabrak fighter Icarus. Meanwhile, Gideon Adlon takes on the role of the young Twilek Padawan Devon Izara, while Dennis Haysbert’s Master Eeko-Dio Daki hopes to guide her in the Dark Times.

Meanwhile, Oscar-nominee Wagner Moura will provide the voice of TDF captain Brander Lawson, with Richard Ayoade voicing his partner Two-Boots, and Charlie Bushnell voicing his son, Rylee. Chris Diamantopoulos and Stephen Stanton will voice crime lords Looti Vario and Marg Krim, David W. Collins will voice Spybot, and A.J. LoCascio will voice Marrok, the Inquisitor first introduced in Ahsoka.

Subscription with ads

Yes, the Disney Basic plan

Simultaneous streams

Up to 4


When does Star Wars: Maul – Shadow Lord take place?

Stuck between two familiar events

Devon is imprisoned in in Star Wars_ Maul - Shadow Lord. Credit: Lucasfilm

Star Wars: Maul – Shadow Lord is set during the Dark Times, the period of the Star Wars franchise between Revenge of the Sith and A New Hope where the Empire was expanding its power over the galaxy, with those who opposed them choosing to lurk in the shadow. This period has been explored in The Bad Batch, Star Wars Rebels, Obi-Wan Kenobi, Andor, and the Star Wars: Jedi video game franchise, as well as briefly explored in select episodes of the Tales of the Jedi, Tales of the Empire, and Tales of the Underworld anthology series.

Some TV show characters with the Andor logo in the background.


Finished Andor? Stream These Star Wars Shows and Movies Next

The Star Wars universe has plenty to watch to keep the Force flowing now that Andor’s finished.

In the trailer itself, Maul and Devon are seen facing Stormtroopers wearing TK armor, an early version of Stormtrooper armor that was introduced in The Bad Batch season 1. This means that the Empire is still in a time of transition from the Galactic Republic to the forces that we see closer to the Star Wars Original Trilogy. As such, Maul – Shadow Lord events are likely happening concurrently with the events of The Bad Batch’s later two seasons.

Maul – Shadow Lord can finally explain the final years of the Sith Lord’s life

Time to explore new horizons

Maul ignites half of his lightsaber in in Star Wars_ Maul - Shadow Lord. Credit: Lucasfilm

While The Clone Wars successfully resurrected Maul and Rebels would give him a fitting end, there is still a large portion of his story left unexplored. While it is unclear whether the series will receive multiple seasons, the show will explore how he rearranged his forces from the Shadow Collective into Crimson Dawn, the faction first introduced in Solo: A Star Wars Story. Paul Bettany’s Dryden Vos did feature as a cameo in The Clone Wars’s final season, but the arc largely focused on Maul’s Mandalorian forces over his other agents. As such, Maul – Shadow Lord can complete his turn from a man well-aware of Smith’s schemes into his own fully-fledged criminal mastermind.

Furthermore, the presence of Devon in Maul’s story is allowing Lucasfilm to dust off long-scrapped plans. Prior to the Disney acquisition, a Darth Maul-focused game was in development that saw Maul paired with Darth Talon, another red-skinned Twilek, at the behest of George Lucas himself, as the pair took on the galaxy. While Devon may not be a direct adaptation of Talon in the existing canon, Witwer has teased that the series will finally adapt several unused concepts for Maul to screen, and Devon’s visual similarities to Talon could suggest that the series will fulfill one of Lucas’s final ideas for the franchise.

When will Star Wars: Maul – Shadow Lord stream?

Two-episode premiere coming soon

Maul in hiding in in Star Wars_ Maul - Shadow Lord. Credit: Lucasfilm

Star Wars: Maul – Shadow Lord will arrive on Disney+ on April 6th with a two-episode premiere. The series will then release two new episodes every Monday, culminating in the finale on May 4. While one of the shorter Star Wars series, Maul’s long-awaited 10-part story will finally give fans a glimpse into the mind of one of the Dark Side’s most terrifying warriors.



Source link