<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>X11 | no dogma blog</title><link>https://nodogmablog.bryanhogan.net/tag/x11/</link><atom:link href="https://nodogmablog.bryanhogan.net/tag/x11/index.xml" rel="self" type="application/rss+xml"/><description>X11</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><lastBuildDate>Mon, 29 Jun 2026 00:00:00 +0000</lastBuildDate><image><url>https://nodogmablog.bryanhogan.net/media/icon_hu9c23d68d4e9f1f9acfa8237e5c2ea674_3344_512x512_fill_lanczos_center_3.png</url><title>X11</title><link>https://nodogmablog.bryanhogan.net/tag/x11/</link></image><item><title>Docker Desktop Linux X11 Forwarding from Container to Host</title><link>https://nodogmablog.bryanhogan.net/2026/06/docker-desktop-linux-x11-forwarding-from-container-to-host/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://nodogmablog.bryanhogan.net/2026/06/docker-desktop-linux-x11-forwarding-from-container-to-host/</guid><description>&lt;p>Oh boy, this was much harder than I expected. I found guides and articles and blog posts on how to do this, but none of them worked for me.&lt;/p>
&lt;h3 id="what-i-wanted-to-do">What I wanted to do&lt;/h3>
&lt;p>I like running applications in containers; I wrote a post about running &lt;a href="https://nodogmablog.bryanhogan.net/2026/06/claude-code-in-a-container/">Claude Code in a container&lt;/a>. For a while, I&amp;rsquo;ve wanted to run GUI applications in a container and forward the X11 display from the container to the host.&lt;/p>
&lt;p>Why do this? Sometimes I don&amp;rsquo;t want to install an application on my host computer; it might be something I won&amp;rsquo;t use often, or it might be something I want to try out, or it could be something I&amp;rsquo;m a little concerned about and don&amp;rsquo;t want it to have access to my personal files (like Claude Code).&lt;/p>
&lt;h3 id="how-to-do-it">How to do it&lt;/h3>
&lt;p>There are a few steps.&lt;/p>
&lt;h4 id="the-dockerfile">The Dockerfile&lt;/h4>
&lt;p>It starts with a Dockerfile. I&amp;rsquo;m going to use &lt;code>ubuntu:24.04&lt;/code> as the base image, and install a few things including &lt;code>xeyes&lt;/code>, because that is like the &amp;ldquo;Hello World&amp;rdquo; of X11 applications. I also include &lt;code>gedit&lt;/code> because it is a nice, simple text editor that is a bit more complex than &lt;code>xeyes&lt;/code>.&lt;/p>
&lt;p>This is the Dockerfile -&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cfg" data-lang="cfg">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">FROM ubuntu:24.04&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888;font-style:italic"># avoid interactive prompts during package installation&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">ENV DEBIAN_FRONTEND&lt;/span>=&lt;span style="color:#5a2">noninteractive &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888;font-style:italic"># Update package lists and upgrade installed packages&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">RUN apt-get update &amp;amp;&amp;amp; apt-get upgrade -y &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888;font-style:italic"># install lots of stuff, some might not be necessary, you can tweak it to see what works&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">RUN apt-get install -y \ &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">x11-apps \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">x11-utils \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">x11-xserver-utils \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">dbus-x11 \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">at-spi2-core \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">gedit \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">fonts-dejavu-core \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">fonts-liberation \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">adwaita-icon-theme \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">gnome-themes-extra \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">wget \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">curl \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">gpg \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">sudo \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">&amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">CMD [&amp;#34;/bin/bash&amp;#34;]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Nothing too special or fancy here.&lt;/p>
&lt;h4 id="socat">socat&lt;/h4>
&lt;p>What? socat?&lt;/p>
&lt;p>This is the thing that solves the problem that is unique to Docker Desktop. It allows you to forward the X11 display from the container to the host.&lt;/p>
&lt;p>You probably need to install it. I didn&amp;rsquo;t have it, and I&amp;rsquo;ve been using Linux for a long time. On Ubuntu, you can install it with -&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cfg" data-lang="cfg">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">sudo apt install socat&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Now run it with this -
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cfg" data-lang="cfg">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:/tmp/.X11-unix/X0&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;ul>
&lt;li>TCP-LISTEN:6000 - listen for TCP connections on port 6000, which is the default port for X11.&lt;/li>
&lt;li>reuseaddr - allows the socket to be reused, which is useful if you need to restart the socat command.&lt;/li>
&lt;li>fork - allows multiple connections to be handled simultaneously.&lt;/li>
&lt;li>UNIX-CLIENT:/tmp/.X11-unix/X0 - this is the path to the X11 socket on the host, which is where the X11 server is listening for connections.&lt;/li>
&lt;/ul>
&lt;p>Keep this running in a terminal.&lt;/p>
&lt;h4 id="xhost">xhost&lt;/h4>
&lt;p>In another terminal, run this command -&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cfg" data-lang="cfg">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">xhost +local:&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>This allows any local user to connect to the X11 server. This is necessary for the container to be able to connect to the X11 server on the host.&lt;/p>
&lt;h4 id="run-the-container">Run the container&lt;/h4>
&lt;p>Finally, run the container with this command -&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cfg" data-lang="cfg">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">docker run -it --rm \&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">--add-host&lt;/span>=&lt;span style="color:#5a2">host.docker.internal:host-gateway \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5a2"> -e DISPLAY=host.docker.internal:0 \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5a2"> --ipc=host \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5a2"> --name x11_local \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5a2"> x11_local&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;ul>
&lt;li>&lt;code>--add-host=host.docker.internal:host-gateway&lt;/code> - adds a host entry for &lt;code>host.docker.internal&lt;/code>, which is the hostname that Docker Desktop uses to refer to the host machine. This is necessary for the container to be able to connect to the X11 server on the host.&lt;/li>
&lt;li>&lt;code>-e DISPLAY=host.docker.internal:0&lt;/code> - sets the &lt;code>DISPLAY&lt;/code> environment variable in the container to point to the X11 server on the host. The &lt;code>:0&lt;/code> part is the display number, which is usually 0 for the first display.&lt;/li>
&lt;li>&lt;code>--ipc=host&lt;/code> - allows the container to share the IPC namespace with the host, some GTK/GL apps require this.&lt;/li>
&lt;li>&lt;code>--name x11_local&lt;/code> - this is the container name.&lt;/li>
&lt;li>`x11_local&amp;rsquo; - the name of the image to run.&lt;/li>
&lt;/ul>
&lt;p>When you&amp;rsquo;re in the container, run &lt;code>xeyes&lt;/code> or &lt;code>gedit&lt;/code>, and you should see the application running on your host computer.&lt;/p>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;figure id="figure-it-works">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="It works!" srcset="
/2026/06/docker-desktop-linux-x11-forwarding-from-container-to-host/media/xeyes_x11_hu7771a971dc3e708f55afa7b675201dd7_95611_6146d708f9f824783e3bcb31dbc42565.webp 400w,
/2026/06/docker-desktop-linux-x11-forwarding-from-container-to-host/media/xeyes_x11_hu7771a971dc3e708f55afa7b675201dd7_95611_c595c203c98e00ed4d1f19662c6afc17.webp 760w,
/2026/06/docker-desktop-linux-x11-forwarding-from-container-to-host/media/xeyes_x11_hu7771a971dc3e708f55afa7b675201dd7_95611_1200x1200_fit_q75_h2_lanczos.webp 1200w"
src="https://nodogmablog.bryanhogan.net/2026/06/docker-desktop-linux-x11-forwarding-from-container-to-host/media/xeyes_x11_hu7771a971dc3e708f55afa7b675201dd7_95611_6146d708f9f824783e3bcb31dbc42565.webp"
width="760"
height="376"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
It works!
&lt;/figcaption>&lt;/figure></description></item></channel></rss>