Note 1: Even though it’s mid-2018, this post is still about the X Window System. Things still are in the transition phase towards Wayland, and things might get better or different over time.
Note 2: This post is not about displaying a graphical window of a program running on a remote machine on the local machine (like VNC or X forwarding). It is about running a remote program and displaying its graphical window on the remote machine itself, as if it had been directly started by a user sitting in front of the remote display. One obvious use case for the solution to this problem would be a remote graphics rendering farm, where programs must make use of the GPU hardware acceleration of the machine they’re running on.
Note that graphical programs started via Xvfb or via X login sessions on fake/software displays (started by some VNC servers) will not use GPU hardware acceleration. The project VirtualGL might be a viable solution too, but I haven’t looked into that yet.
Some experiments on localhost
I’m going to explore the behavior of localhost relative to our problem first. You’ll need to be logged in to an X graphical environment with monitor attached.
The trivial case: No SSH login session
Running a local program with a graphical window from a local terminal on a local machine is trivial when you are logged into the graphical environment: For example, in a terminal, simply type
glxgears and it will run and display with GPU hardware acceleration.
With SSH login session to the same user
Things become a bit more interesting when you use SSH to connect to your current user on localhost. Let’s say your local username is “me”. Try
ssh me@localhost glxgears
It will output:
Error: couldn't open display (null)
This can be fixed by setting the
DISPLAY variable to the same value that is set for the non-SSH session:
Glxgears will run at this point.
With SSH login session to another user
Things become even more interesting when you SSH into some other local user on localhost, called “other” below.
ssh other@localhost glxgears
You will get the message:
Error: couldn't open display (null)
Trying to export
DISPLAY as before won’t help us now:
You will receive the message:
No protocol specified Error: couldn't open display :0
This is now a permission problem. There are two solutions for it:
Solution 1: Relax permissions vIA XHOST PROGRAM
To allow non-networked connections to the X server, you can run (as user “me” which is currently using the X environment):
xhost + local:
DISPLAY=:0 glxgears will start working as user “other”.
For security reasons, you should undo what you just did:
xhost - local:
xhost are not permanent across reboots.
Solution 2: via Xauthority file
If you don’t want or can’t use the
xhost program, there is a second way (which I like better because it only involves files and file permissions):
User “me” has an environment variable env | grep XAUTHORITY
(I’m using the
gdm display manager. The path could be different in your case.)
This file contains a secret which is readable only for user “me”, for security reasons. As a quick test, make this file available world-readable in
cp /run/user/1000/gdm/Xauthority /tmp/xauthority_me chmod a+r /tmp/xauthority_me
Then, as user “other”:
DISPLAY=:0 XAUTHORITY=/tmp/xauthority_me glxgears
Glxgears will run again.
To make sure that we are using hardware acceleration, run
XAUTHORITY=/tmp/xauthority_me DISPLAY=:0 glxinfo | grep Device
This prints for me:
Device: Mesa DRI Intel(R) HD Graphics 630 (Kaby Lake GT2) (0x5912)
Make sure you remove /tmp/xauthority_me after this test.
Note that the
Xauthority file is different after each reboot. But it should be trivial to make it available to other users in a secure way if done properly.
Application on remote machine
If you were able to make things work on the local machine, the same steps should work on a remote machine, too. To clarify, the remote machine needs:
- A real X login session active (you will likely need to set up auto-login in your display manager if the machine is not accessible).
- A real monitor attached. Modern graphics cards and/or BIOSes simply shut down the GPU to save power when there is no real device attached to the HDMI port. This is is not Linux or driver specific. Instead of real monitors, you probably want to use “HDMI emulator” hardware plugs – they are cheap-ish and small. Otherwise, the graphical window might not even get painted into the graphics memory. The usual symptom is a black screen when using VNC.
If you SSH-login into the remote machine, as the user that is currently logged in to the X graphical environment, you can just set the
DISPLAY environment variable when running a program, and the program should show on the screen.
If you SSH-login into the remote machine, as a user that is not currently logged in to the X graphical environment, but some other user is, you can set both
XAUTHORITY environment variables as explained further above, and the program should show up on the screen.