Linux – Forward X11 over an SSH connection to container’s host

alpine-linuxdockerx11-forwarding

I'd like to run a containerized GUI application from a remote machine.

I don't want to solve this problem by adding an ssh host to the container because

  • I already have access to the host machine over SSH
  • It adds unnecessary overhead
  • It makes the container non-portable between remote and local use

I can already successfully run GUI apps on the host, but not from within the container. These are the steps I've taken so far:

Host

  • xauth + (not for long term, but useful for eliminating possible problems)
  • docker-user with uid 501000 on host == docker-user with uid 1000 in container via namespace feature
  • .Xauthority file copied to docker-user home folder

Dockerfile

  • Based on alpine
  • Installs xauth and, for testing purposes, xterm
  • Creates docker-user with proper uid/gid

docker-compose

  • Environment variable DISPLAY forwarded in
  • Volume /home/docker-user/:/home/docker-user/:ro to provide .Xauthority cookie
  • Volume /tmp/.X11-unix:/tmp/.X11-unix:ro to provide X11 socket access
  • Runs command su - docker-user -c "export DISPLAY=$DISPLAY && xterm"
    • su used to run as docker-user
    • DISPLAY forwarded into su context

Unfortunately, this is not yet enough. While xterm on the host OS connects to my local X server without issue, xterm in the container says Xt error: Can't open display: localhost:10.0.

I've confirmed that "localhost:10.0" is correct, localhost exists in the container's /etc/hosts, and the cookie and socket are making it through with the right permissions.

What else could possibly be going wrong?

Best Answer

It looks like you're doing all of the same stuff I'm doing EXCEPT you're sharing the .Xauthority at the time of container creation. That means if you ever ssh -X into your machine after creating the container the .Xauthority will not be valid anymore. You can't ssh -X from another terminal into the same machine and go back and use the .Xauthority, ssh -X changes the .Xauthority every time for the most recent terminal. I've only got it to work by copying the .Xauthority every time I ssh -X into my machine and try and share the screen with my container.

note: I'm sharing a device and a machine id because I was forwarding a webcam output

1.Create the container and tell xhost to allow forwarding from container id:

sudo docker run -it -d \
    --net=host \
    --env="DISPLAY" \
    --env="QT_X11_NO_MITSHM=1" \
    --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
    --device="/dev/video0:/dev/video0" \
    --volume="/path/to/your/sharedDockerFiles:/root/sharedDockerFiles" \
    --volume="/etc/machine-id:/etc/machine-id" \
    yourdockerrepo/image:tag \
    bash
export containerId=$(docker ps -l -q)
sudo xhost +local:`sudo docker inspect --format='{{ .Config.Hostname }}' $containerId`
sudo docker start $containerId

2.Copy .Xauthority from host home to sharedDockerFiles directory:

sudo cp ~/.Xauthority /path/to/your/sharedDockerFiles

3.Start and attach your container

4.Copy the .Xauthority in your shared folder to your container home

sudo cp /root/sharedDockerFiles/.Xauthority ~/

5.(necessary once): Edit container's /etc/ssh/ssh_config under Host * to include:

   ForwardX11 yes
   X11Forwarding yes

6.Restart your container and reattach and run GUI app

7.If you still have problems, make sure $DISPLAY variable in the container is the same as the host's

echo $DISPLAY #do this in the container
exit
echo $DISPLAY #do this in the host, should be the same as container's
#if they aren't equal, start container and:
export DISPLAY= #put the output of your host's $DISPLAY variable here
Related Question