VS Code Running in a Docker Container with X11 Forwarding

I recently wrote a post about running GUI applications in a Docker Desktop container in Linux. This is more challenging than it should be because I use Docker Desktop instead of the Docker Engine. You can read about it here.

The post got the bones of what I wanted in place, but my final goal was to run VS Code in a container and forward the X11 display from the container to the host. Why, you might ask? For a couple of reasons. First, I wanted to see how to do it, and second, to combine with my Claude in a container post so I could add the Claude Code extension to VS Code.

The steps are mostly the same as the previous post (see link above), but I’ve included them for completeness.

The big difference is the Dockerfile, the Microsoft application repository and VS Code are added.

The Dockerfile

Here it is -

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get upgrade -y 

RUN apt-get install -y \
    x11-apps \
    x11-utils \
    x11-xserver-utils \
    dbus-x11 \
    at-spi2-core \
    gedit \
    fonts-dejavu-core \
    fonts-liberation \
    adwaita-icon-theme \
    gnome-themes-extra \
    wget \
    curl \
    gpg \
    sudo \
    && rm -rf /var/lib/apt/lists/*

# Install VS Code from the Microsoft repository
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /usr/share/keyrings/microsoft.gpg && \
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list && \
    apt-get update && \
    apt-get install -y code && \
    rm -rf /var/lib/apt/lists/*

# Add a user named bryan, it's better not to run VS Code as root (the password is also bryan)
RUN useradd -m -s /bin/bash bryan && \
    echo "bryan:bryan" | chpasswd && \
    usermod -aG sudo bryan

USER bryan
WORKDIR /home/bryan

# Alias the code command to add two options
RUN echo "alias code='code --disable-gpu --no-sandbox'" >> /home/bryan/.bashrc

CMD ["/bin/bash"]

Build the image with -

docker build -t x11_local_vscode .

xhost

In a terminal, run this command -

xhost +local:

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.

socat

What? socat?

This is the thing that solves the problem that is unique to Docker Desktop. It allows you to forward TCP connections to Linux sockets allowing the X11 display from the container to reach the host.

You probably need to install it. I didn’t have it, and I’ve been using Linux for a long time. On Ubuntu, you can install it with -

sudo apt install socat

Now run it with this -

socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:/tmp/.X11-unix/X0

  • TCP-LISTEN:6000 - listen for TCP connections on port 6000, which is the default port for X11.
  • reuseaddr - allows the socket to be reused, which is useful if you need to restart the socat command.
  • fork - allows multiple connections to be handled simultaneously.
  • 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.

Keep this terminal open.

Run the Container

Finally, run the container with this command -

docker run -it --rm \
    --add-host=host.docker.internal:host-gateway \
    -e DISPLAY=host.docker.internal:0 \
    --ipc=host \
    --name x11_local_vscode \
    x11_local_vscode
  • --add-host=host.docker.internal:host-gateway - adds a host entry for host.docker.internal, 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.
  • -e DISPLAY=host.docker.internal:0 - sets the DISPLAY environment variable in the container to point to the X11 server on the host. The :0 part is the display number, which is usually 0 for the first display.
  • --ipc=host - allows the container to share the IPC namespace with the host, some GTK/GL apps require this.
  • --name x11_local_vscode - this is the container name.
  • x11_local_vscode - the name of the image to run.

Running VS Code

Here it is, after all the work.

In the container, run code ., but remember, this is an alias of code --disable-gpu --no-sandbox. It will start and send the display to your host.

Conclusion

Once I figured out how to forward xeyes, adding VS Code wasn’t too difficult, but there were still some challenges. I hope this helps you.

It works!
It works!
comments powered by Disqus

Related