Home » How to forward X over SSH to run graphics applications remotely?

How to forward X over SSH to run graphics applications remotely?


X11 forwarding needs to be enabled on both the client side and the server side.

On the client side, the -X (capital X) option to ssh enables X11 forwarding, and you can make this the default (for all connections or for a specific connection) with ForwardX11 yes in ~/.ssh/config.

On the server side, X11Forwarding yes must be specified in /etc/ssh/sshd_config. Note that the default is no forwarding (some distributions turn it on in their default /etc/ssh/sshd_config), and that the user cannot override this setting.

The xauth program must be installed on the server side. If there are any X11 programs there, it’s very likely that xauth will be there. In the unlikely case xauth was installed in a nonstandard location, it can be called through ~/.ssh/rc (on the server!).

Note that you do not need to set any environment variables on the server. DISPLAY and XAUTHORITY will automatically be set to their proper values. If you run ssh and DISPLAY is not set, it means ssh is not forwarding the X11 connection.

To confirm that ssh is forwarding X11, check for a line containing Requesting X11 forwarding in the output of ssh -v -X. Note that the server won’t reply either way, a security precaution of hiding details from potential attackers.

To get X11 forwarding working over SSH, you’ll need three things in place:

  1. Your client must be set up to forward X11.
  2. Your server must be set up to allow X11 forwarding.
  3. Your server must be able to set up X11 authentication.

If you have both #1 and #2 in place but are missing #3, then you’ll end up with an empty DISPLAY environment variable.

Soup-to-nuts, here is how to get X11 forwarding working:

  1. On your server, make sure /etc/ssh/sshd_config contains:

    X11Forwarding yes
    X11DisplayOffset 10

    You may need to SIGHUP sshd so it picks up these changes.

    cat /var/run/sshd.pid | xargs kill -1
  2. On your server, make sure you have xauth installed.

    belden@skretting:~$ which xauth

    If you do not have xauth installed, you will run into the empty DISPLAY environment variable problem.

  3. On your client, connect to your server. Be certain to tell ssh to allow X11 forwarding. I prefer

    belden@skretting:~$ ssh -X blyman@the-server

but you may like

    belden@skretting:~$ ssh -o ForwardX11=yes blyman@the-server

or you can set this up in your ~/.ssh/config.

I was running into this empty DISPLAY environment variable earlier today when ssh’ing into a new server that I do not administer. Tracking down the missing xauth part was a bit fun. Here is what I did, and what you can do too.

On my local workstation, where I am an administrator, I verified that /etc/ssh/sshd_config was set up to forward X11. When I ssh -X back in to localhost, I do get my DISPLAY set correctly.

Forcing DISPLAY to get unset was not too hard. I just needed to watch what sshd and ssh were doing to get it set correctly. Here is the full output of everything I did along the way.

    blyman@skretting:~$ mkdir ~/dummy-sshd
    blyman@skretting:~$ cp -r /etc/ssh/* ~/dummy-sshd/
    cp: cannot open `/etc/ssh/ssh_host_dsa_key' for reading: Permission denied
    cp: cannot open `/etc/ssh/ssh_host_rsa_key' for reading: Permission denied

Instead of using sudo to force copying my ssh_host_{dsa,rsa}_key files into place, I used ssh-keygen to create dummy ones for myself.

    blyman@skretting:~$ ssh-keygen -t rsa -f ~/dummy-sshd/ssh_host_rsa_key
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /home/blyman/dummy-sshd/ssh_host_rsa_key.
    Your public key has been saved in /home/blyman/dummy-sshd/ssh_host_rsa_key.pub.

Rinse-and-repeate with -t dsa:

    blyman@skretting:~$ ssh-keygen -t dsa -f ~/dummy-sshd/ssh_host_dsa_key
    # I bet you can visually copy-paste the above output down here

Edit ~/dummy-sshd/sshd_config to point to the correct new ssh_host key files.

    # before
    blyman@skretting:~$ grep ssh_host /home/blyman/dummy-sshd/sshd_config 
    HostKey /etc/ssh/ssh_host_rsa_key
    HostKey /etc/ssh/ssh_host_dsa_key

    # after
    blyman@skretting:~$ grep ssh_host /home/blyman/dummy-sshd/sshd_config 
    HostKey /home/blyman/dummy-sshd/ssh_host_rsa_key
    HostKey /home/blyman/dummy-sshd/ssh_host_dsa_key

Fire up sshd on a new port in non-detach mode:

    blyman@skretting:~$ sshd -p 50505 -f ~/dummy-sshd/sshd_config -d
    sshd re-exec requires execution with an absolute path

Whoops, better correct that path:

    blyman@skretting:~$ /usr/sbin/sshd -p 50505 -f ~/dummy-sshd/sshd_config -d
    debug1: sshd version OpenSSH_5.5p1 Debian-4ubuntu6
    debug1: read PEM private key done: type RSA
    debug1: Checking blacklist file /usr/share/ssh/blacklist.RSA-2048
    debug1: Checking blacklist file /etc/ssh/blacklist.RSA-2048
    debug1: private host key: #0 type 1 RSA
    debug1: read PEM private key done: type DSA
    debug1: Checking blacklist file /usr/share/ssh/blacklist.DSA-1024
    debug1: Checking blacklist file /etc/ssh/blacklist.DSA-1024
    debug1: private host key: #1 type 2 DSA
    debug1: setgroups() failed: Operation not permitted
    debug1: rexec_argv[0]='/usr/sbin/sshd'
    debug1: rexec_argv[1]='-p'
    debug1: rexec_argv[2]='50505'
    debug1: rexec_argv[3]='-f'
    debug1: rexec_argv[4]='/home/blyman/dummy-sshd/sshd_config'
    debug1: rexec_argv[5]='-d'
    Set /proc/self/oom_adj from 0 to -17
    debug1: Bind to port 50505 on
    Server listening on port 50505.
    debug1: Bind to port 50505 on ::.
    Server listening on :: port 50505.

Pop a new terminal and ssh into localhost on port 50505:

    blyman@skretting:~$ ssh -p 50505 localhost
    The authenticity of host '[localhost]:50505 ([::1]:50505)' can't be established.
    RSA key fingerprint is 81:36:a5:ff:a3:5a:45:a6:90:d3:cc:54:6b:52:d0:61.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '[localhost]:50505' (RSA) to the list of known hosts.
    Linux skretting 2.6.35-32-generic #67-Ubuntu SMP Mon Mar 5 19:39:49 UTC 2012 x86_64 GNU/Linux
    Ubuntu 10.10
    Welcome to Ubuntu!
     * Documentation:  https://help.ubuntu.com/
    1 package can be updated.
    0 updates are security updates.
    Last login: Thu Aug 16 15:41:58 2012 from
      SSH_CLIENT=::1 43599 50505
      SSH_CONNECTION=::1 43599 ::1 50505
    Running /usr/bin/xauth remove unix:10.0
    /usr/bin/xauth add unix:10.0 MIT-MAGIC-COOKIE-1 79aa9275ced418dd445d9798b115d393

Look at the last three lines there. I fortuitously had DISPLAY set, and had those two nice-looking lines from /usr/bin/xauth.

From there it was child’s play to move aside my /usr/bin/xauth to /usr/bin/xauth.old, disconnect from ssh and stop the sshd, then launch sshd and ssh back in to localhost.

When /usr/bin/xauth was gone, I did not see DISPLAY reflected in my environment.

There is nothing brilliant going on here. Mostly I got lucky in choosing a sane approach to try reproducing this on my local machine.

Make sure that:

  • You’ve xauth installed on the server (see: xauth info/xauth list).
  • On the server your /etc/ssh/sshd_config file have these lines:

    X11Forwarding yes
    X11DisplayOffset 10
    X11UseLocalhost no
  • On the client side your ~/.ssh/config file have these lines:

    Host *
      ForwardAgent yes
      ForwardX11 yes
  • On the client side, you’ve X server installed (e.g. macOS: XQuartz; Windows: Xming).

Then to do X11 forwarding using SSH, you need to add -X to your ssh command, e.g.

ssh -v -X user@host

then verify that your DISPLAY is not empty by:


If it is, then having verbose parameter for ssh (-v), check for any warnings, e.g.

debug1: No xauth program.
Warning: untrusted X11 forwarding setup failed: xauth key data not generated

In case you’ve got untrusted X11 as shown above, then try -Y flag instead (if you trust the host):

ssh -v -Y user@host

See: What does “Warning: untrusted X11 forwarding setup failed: xauth key data not generated” mean when ssh’ing with -X?

In case you’ve warning: No xauth data, you may try to generate a new .Xauthority file, e.g.

xauth generate :0 . trusted
xauth list

See: Create/rebuild a new .Xauthority file

If you’ve got a different warnings than above, follow the further clues.

Related Solutions

Extract file from docker image?

You can extract files from an image with the following commands: docker create $image # returns container ID docker cp $container_id:$source_path $destination_path docker rm $container_id According to the docker create documentation, this doesn't run the...

Transfer files using scp: permission denied

Your commands are trying to put the new Document to the root (/) of your machine. What you want to do is to transfer them to your home directory (since you have no permissions to write to /). If path to your home is something like /home/erez try the following:...

What’s the purpose of DH Parameters?

What exactly is the purpose of these DH Parameters? These parameters define how OpenSSL performs the Diffie-Hellman (DH) key-exchange. As you stated correctly they include a field prime p and a generator g. The purpose of the availability to customize these...

How to rsync multiple source folders

You can pass multiple source arguments. rsync -a /etc/fstab /home/user/download bkp This creates bkp/fstab and bkp/download, like the separate commands you gave. It may be desirable to preserve the source structure instead. To do this, use / as the source and...

Benefits of Structured Logging vs basic logging

There are two fundamental advances with the structured approach that can't be emulated using text logs without (sometimes extreme levels of) additional effort. Event Types When you write two events with log4net like: log.Debug("Disk quota {0} exceeded by user...

Interfaces vs Types in TypeScript

2019 Update The current answers and the official documentation are outdated. And for those new to TypeScript, the terminology used isn't clear without examples. Below is a list of up-to-date differences. 1. Objects / Functions Both can be used to describe the...

Get total as you type with added column (append) using jQuery

One issue if that the newly-added column id's are missing the id number. If you look at the id, it only shows "price-", when it should probably be "price-2-1", since the original ones are "price-1", and the original ones should probably be something like...

Determining if a file is a hard link or symbolic link?

Jim's answer explains how to test for a symlink: by using test's -L test. But testing for a "hard link" is, well, strictly speaking not what you want. Hard links work because of how Unix handles files: each file is represented by a single inode. Then a single...

How to restrict a Google search to results of a specific language?

You can do that using the advanced search options: http://www.googleguide.com/sharpening_queries.html I also found this, which might work for you: http://www.searchenginejournal.com/how-to-see-google-search-results-for-other-locations/25203/ Just wanted to add...

Random map generation

Among the many other related questions on the site, there's an often linked article for map generation: Polygonal Map Generation for Games you can glean some good strategies from that article, but it can't really be used as is. While not a tutorial, there's an...

How to prettyprint a JSON file?

The json module already implements some basic pretty printing in the dump and dumps functions, with the indent parameter that specifies how many spaces to indent by: >>> import json >>> >>> your_json = '["foo", {"bar":["baz", null,...

How can I avoid the battery charging when connected via USB?

I have an Android 4.0.3 phone without root access so can't test any of this but let me point you to /sys/class/power_supply/battery/ which gives some info/control over charging issues. In particular there is charging_enabled which gives the current state (0 not...

How to transform given dataset in python? [closed]

From your expected result, it appears that each "group" is based on contiguous id values. For this, you can use the compare-cumsum-groupby pattern, and then use agg to get the min and max values. # Sample data. df = pd.DataFrame( {'id': [1, 2, 2, 2, 2, 2, 1, 1,...

Output of the following C++ Program [closed]

It works exactly like this non-recursive translation: int func_0() { return 2; } int func_1() { return 3; } int func_2() { return func_1() + func_0(); } // Returns 3 + 2 = 5 int func_3() { return func_2() + func_1(); } // Returns 5 + 3 = 8 int func_4() { return...

Making a circle out of . (periods) [closed]

Here's the maths and even an example program in C: http://pixwiki.bafsoft.com/mags/5/articles/circle/sincos.htm (link no longer exists). And position: absolute, left and top will let you draw: http://www.w3.org/TR/CSS2/visuren.html#choose-position Any further...

Should I use a code converter (Python to C++)?

Generally it's an awful way to write code, and does not guarantee that it will be any faster. Things which are simple and fast in one language can be complex and slow in another. You're better off either learning how to write fast Python code or learning C++...

tkinter: cannot concatenate ‘str’ and ‘float’ objects

This one line is more than enough to cause the problem: text="რეგულარი >> "+2.23+ 'GEL' 2.23 is a floating-point value; 'GEL' is a string. What does it mean to add an arithmetic value and a string of letters? If you want the string label 'რეგულარი...