Monday, May 20, 2013

X11 Forwarding over SSH: run remote graphical app and display locally

In the modern networked environment, we often wish to run an application on a remote host while we are comfortably logged in on our local computer.

Assuming both machines are Linux-based, and the application runs on the graphical X desktop, the following approaches come to mind:

  • VNC
  • X11 forwarding over SSH

This article focuses only on X11 forwarding. X11 forwarding over SSH enables you to run a remote X app and display it locally, with traffic between the 2 hosts encrypted by SSH.

For X11 forwarding over SSH to work, both the SSH client and SSH server must be properly configured.

X11 forwarding must be enabled on The SSH server side. This is the machine where the application resides. To enable the feature, make sure the X11 configuration file /etc/ssh/sshd_config on the server contains this line:

X11Forwarding yes

If you edit the said file, you need to restart the sshd daemon for the change to take effect.

On Debian or Ubuntu systems, you restart the SSH daemon like this:

$ sudo service ssh restart
[ ok ] Restarting OpenBSD Secure Shell server: sshd.
$

On the ssh client side, you need to run SSH command with the proper parameters. For instance, suppose you want to run the xclock application on the remote SSH server and have it displayed back on the local client.

$ ssh -fX peter@192.168.1.112 xclock 
peter@192.168.1.112's password: 
$

The -X parameter allows an one-off X11 forwarding session.

The -f parameter instructs the SSH client to go to the background just before xclock is run.

If you want to permanently enable X11 forwarding for an user, insert this line in the user's own ~/.ssh/config file on the local host.

ForwardX11 yes 

With X11 forwarding permanently enabled for the client, you can leave out the -X parameter:

$ ssh -f peter@192.168.1.112 xclock 
peter@192.168.1.112's password: 
$

If X11 forwarding is not enabled on the SSH server, any attempt to tunnel X11 will fail with the following error message:

$ ssh -X peter@192.168.1.112 xclock 
peter@192.168.1.112's password: 
X11 forwarding request failed on channel 0
Error: Can't open display: 
$
If X11 forwarding is properly enabled on the server side, you will see a nice looking clock displayed on your local screen.

Thursday, May 2, 2013

Forcing pseudo terminal on ssh command execution

You already know how to execute a command on a remote computer via ssh.

The syntax is like this:

$ ssh peter@192.168.1.112 

This will work if the command is simply piping output, for example, ls.

If the command is "screen-based" in that it interprets user input, you may get an error. The following shows what happens when you ssh to run such programs (e.g., top, emacs, screen).

$ ssh peter@192.168.1.112 top
peter@192.168.1.112's password: 
TERM environment variable not set.
$ ssh peter@192.168.1.112 emacs
peter@192.168.1.112's password: 
emacs: standard input is not a tty
$ ssh peter@192.168.1.112 screen
peter@192.168.1.112's password: 
Must be connected to a terminal.

Here is a high-level explanation of what is happening behind the scene.

When you run ssh without a command just to login, a pseudo tty is automatically allocated. But if you specify a command to execute on the ssh command line, by default, ssh does not allocate a pseudo tty. You need to force it to allocate one if you want to run commands such as top or screen. This you do by giving the -t parameter to ssh.

$ ssh -t peter@192.168.1.112 top
peter@192.168.1.112's password: 
top - 11:09:46 up 133 days, 13:44,  5 users,  load average: 0.00, 0.00, 0.00
Tasks: 201 total,   1 running, 200 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.2%sy,  0.0%ni, 99.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1938896k total,  1466144k used,   472752k free,   592508k buffers
Swap:        0k total,        0k used,        0k free,   508120k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
22176 peter     20   0  2856 1296  984 R  0.3  0.1   0:00.07 top
    1 root      20   0  3944  572  332 S  0.0  0.0   0:02.80 init
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.17 kthreadd
    3 root      RT   0     0    0    0 S  0.0  0.0   0:09.22 migration/0
    4 root      20   0     0    0    0 S  0.0  0.0 406:20.92 ksoftirqd/0
    5 root      RT   0     0    0    0 S  0.0  0.0   0:00.03 migration/0

In summary, if you run ssh with a command argument to execute on a remote server, and you see an error message that suggests a terminal is not configured, run it again with the -t parameter.

Monday, April 22, 2013

One-liner to shutdown remote host

To shutdown the local machine immediately, you execute this command as root or under sudo:
$ shutdown -h now

If it is a remote server that you want to shutdown, it could be slightly more involved.

You need to have root privileges to shutdown a machine. However, many systems are configured to block root from logging in remotely usingssh. So, you need to ssh in as a regular, non-root user, and pass the sudo command to shutdown host.

$ ssh -t peter@192.168.1.112 'sudo shutdown -h now'
peter@192.168.1.112's password: 
[sudo] password for peter: 
Broadcast message from root@tiger (pts/2) (Sat Apr 13 10:56:30 2013):

The system is going down for system halt NOW!
Connection to 192.168.1.112 closed.
$ 

Don't forget the -t sshparameter to "force pseudo-tty allocation". Without it, the above one-liner will fail with this message.

sudo: no tty present and no askpass program specified

Note that you will be prompted twice to type in your password. The first time is for ssh; the second, sudo.

To avoid typing the first password, set up password-less login. This is a topic by itself, and I won't go into it here.

To avoid the second, configure sudo to not prompt peter for his password when he issues a sudo command. This is done by editing the /etc/sudoers file.

$ visudo

Insert the following line to the file:

peter ALL=(ALL) NOPASSWD: ALL

The above line allows peter to sudo as anybody from any host and run any command without being authenticated. Only do this after you have considered its security ramifications. You have been forewarned.

Now run the one-liner again.

$ ssh -t peter@192.168.1.112 'sudo shutdown -h now'
peter@192.168.1.112's password: 

Broadcast message from root@tiger (pts/1) (Sat Apr 20 21:40:50 2013):

The system is going down for system halt NOW!
Connection to 192.168.1.112 closed.
The user is only prompted once, by ssh, to enter a password.

Friday, April 19, 2013

One-liner to copy text to a remote host

Occasionally, I want to copy a short line of text to a remote computer. For instance, I have an URL for some real cool web site which, for whatever reason, I want to send to a remote host. I can always put the text in a file, and transfer it via scp.

$ cat > coolurl.txt
http://really-cool-web-site/

$ scp coolurl.txt peter@192.168.1.112:

Or, you can use the following one-liner command:

$ echo 'http://really-cool-web-site/'|ssh peter@192.168.1.112 'cat >coolurl.txt'

The one-liner uses only simple commands such as echo, ssh and cat. It saves you the step of creating a new file on the local machine.

The text is saved to a file called coolurl.txt on the remote computer under your home directory.

Let me know your favourite way to accomplish the same thing.

Saturday, March 16, 2013

Identify available printer names

Some machines have access to more than one printer. Unless the default printer is the one you want, you need to know the name of the printer to use in the printer-related command. For instance, if you want to know the status of a printer, you execute the lpq command:

$ lpq
ml1640 is ready
no entries

ml1640 is the default printer for the machine. If you want a printer other than the default, the lpq command requires that you specify the printer name. Other commands such as lpr, and lprm behave the same way.

How do you find out the printer name that the Linux printing system will recognize?

$ lpstat -a
clp325w accepting requests since Tue 12 Mar 2013 09:42:07 PM PDT
ml1640 accepting requests since Sun 10 Mar 2013 09:22:33 PM PDT
scx3405 accepting requests since Sun 10 Mar 2013 09:24:00 PM PDT

Armed with the printer name scx3405, you simply run lpq again like this:

$ lpq -P scx3405
scx3405 is ready
no entries

If you run lpstat with the -s parameter, it will give even more information in the form of a status summary (including identifying the default printer):

$ lpstat -s
system default destination: ml1640
device for clp325w: ipp://192.168.1.22
device for ml1640: mfp:/dev/mfp4
device for scx3405: ipp://192.168.1.11

You can tell then ml1640, the default printer, is a local printer, and the rest are remote.

With lpstat, you can list the printer names that the Linux printing system can recognize.