A sample on how to run docker containers that can display GUI elements without external commands or xhost safety concerns:
git clone https://github.com/pabsan-0/docker-painless-guis docker-guitest
cd docker-guitest
docker compose build
docker compose run guitest
Once inside of the container, run the following:
firefox: should not run if you're root, but simply dosu gumbyand try again as usernautilus: should run out of the box as either userrootorgumby.
For more details, continue reading. Else, just copy the templates and continue your proj.
The docker compose file in this gist is basically running this command:
docker run
--[*extra-args]
--volume /tmp/.X11-unix:/tmp/.X11-unix:rw # See https://unix.stackexchange.com/a/196680
--volume $XAUTHORITY:$XAUTHORITY # Shared xauth token
--env QT_X11_NO_MITSHM=1 # Helps sometimes with weird apps
--env DISPLAY=$DISPLAY # The display to use
--env XAUTHORITY=$XAUTHORITY # Where to find xauth token
Your host machine has a default access list to your X server. Run xhost to see it, something like this should pop out by default:
access control enabled, only authorized clients can connect
SI:localuser:your_user_name
Common external xhost mods to achieve X server access are laid below, though take note actively using these commands is typically unsafe:
xhost +: grants access to anyone, the unsafest option of allxhost +local:root: grants access to any local connections.xhost +SI:localuser:root: grants acces to the root user of your machine. Though I cannot make any promise, it looks way safer than the abovexhost +SI:localuser:your_user_name: grants acces to current user of your machine. This option is enabled by default
Docker connections are generally local, though you may encounter non-local xhost needs when sharing GUIs over SSH or similar, though such scenarios are left outside the scope of this gist.
Better than allowing external connections through xhost is sharing an X server access token with your docker containers through volumes through $XAUTHORITY, however there are some user-level related limitations with this.
The $XAUTHORITY env variable we are sharing should be a user-id-dependent path (notice the 1000) and looks like:
user@ubuntu20.04:~$ echo $XAUTHORITY
/run/user/1000/gdm/Xauthority
Some internet results use the variable $XAUTH rather than $XAUTHORITY. Check if $XAUTH is defined in your host's shell. It wasn't in mine, so my guess is this depends on your OS version.
Build the default image with docker compose build and try the following examples if you like for a walkthrough of different scenarios.
We will be running two graphical applications for these:
firefox: standard web browser. Has some root-related issues sometimesnautilus: standard file explorer which should always work in a healthy environment
Here's a refresher for some commands we'll be using:
- Switch to a different user
gumbyin a subshell:su gumby - Come back from a subshell to previous user: just press
^D - See user ids and a bit more:
cat /etc/group
By default, Ubuntu 20.04 gives each non-root user an ID starting at 1000. If your host's user ID is not 1000, you'll probably get different outcomes in thes examples. The ID of root should be 0.
Build and run the default docker compose run guitest, which is passing all run arguments seen above including the $XAUTHORITY token as a volume plus an env variable telling its location. You'll log in as root by default:
- As
root: We cannot runfirefoxbecause there is a XAUTHORITY in place for an user other thanrootand the access to the xserver is limited by thefirefoxapplication. You can runnautilus, though, which has noroot$XAUTHORITYrestrictions. - As
gumby: Switching to an usersu gumbywith the same user id than our host's user (first user in ubuntu defaults to 1000) does allowfirefoxto run, as well as nautilus. - As
gumby2: Switching to a different usersu gumby2with a different user id will forbid us from using the token at$XAUTHORITYand no GUI will be displayed for neither application.
Make sure your xhost looks like this (default value), then run docker compose run guitest_noxauth, which is not passing a $XAUTHORITY token.
access control enabled, only authorized clients can connect
SI:localuser:your_user_name
- As
root: No display is found to run any of the apps. - As
gumby: Both apps will work because this user's ID presumably matches your host's (since ubuntu first users usually default to ID=1000). - As
gumby2: No display is found to run any of the apps because this user does not match the authorised ID.
You can see the user ids by running cat /etc/groups.
Run xhost + and make sure your xhost looks like this, then run docker compose run guitest_noxauth, which is not passing a $XAUTHORITY token.
access control disabled, clients can connect from any host
SI:localuser:your_user_name
- As
root: bothfirefoxandnautiluswill run. Firefox does not find any issue withrootbecause it is no longer using a$XAUTHORITYtoken meant for a different user id. - As
gumby: bothfirefoxandnautiluswill run. Everyone is whitelisted (though by defaultgumbyis allowed through the user id 1000). - As
gumby2: bothfirefoxandnautiluswill run. Everyone is whitelisted.
Revert to the default safety by running xhost -.
Run xhost +SI:localuser:root and make sure your xhost looks like this, then run docker compose run guitest_noxauth, which is not passing a $XAUTHORITY token.
access control enabled, only authorized clients can connect
SI:localuser:root
SI:localuser:your_user_name
- As
root: bothfirefoxandnautiluswill run. - As
gumby: bothfirefoxandnautiluswill run. - As
gumby2: neitherfirefoxnornautiluswill run. Gumby2 is not whitelisted byxhostand a display will not be found.
Revert to default by running xhost -SI:localuser:root.
Here's a truth table with a summary of the above
Generated with tablesgenerator.com
| User | ID | App | $XAUTHORITY | xhost +SI:localuser:user (default) | xhost + | xhost +SI:localuser:root |
|---|---|---|---|---|---|---|
| root | 0 | firefox | ✖ | ✖ | ✔ | ✔ |
| nautilus | ✔ | ✖ | ✔ | ✔ | ||
| gumby | 1000 | firefox | ✔ | ✔ | ✔ | ✔ |
| nautilus | ✔ | ✔ | ✔ | ✔ | ||
| gumby2 | 1001 | firefox | ✖ | ✖ | ✔ | ✖ |
| nautilus | ✖ | ✖ | ✔ | ✖ |
