A couple of tricks with the secure shell
Posted by prhlava on Thu 7 Sep 2006 at 15:08
One can do a lot more with ssh than use it for remote terminal session. Here we'll show how to copy files using ssh, use ssh as part of a pipe, vnc or samba forwarding via ssh and mounting filesystems using ssh (fuse + sshfs)
(Several of these subjects have been covered upon this site before.)
- Sebastian Broekhoven
- pointed to obvious method of file copying over ssh - the scp command. http://www.thenetwork.nl
- Hardik Dalwadi
- showed the simple method of taking advantage of log-in without password (section 6.1). http://www.biostat.jhsph.edu/bit/nopassword.html
the version with pictures
The scp can be used to copy file(s) between two remote ssh server machines and copy files from local to remote or from remote to local.
It has options to (for more see the man page):
- turn on ssh compression (-C)
- preserve mode, access time and modification time (-p)
- do recursive copy (-r)
# scp -r mydir user@remote-box:
To copy in the opposite direction do
# scp -r user@remote-box:mydir .
Symlinks to directories are followed (not copied as symlinks) - in the result of the copy, symlink to directory will be a directory (named after the symlink's name).
The ssh works well as a part of the pipe. This can be used to transfer files directly over ssh. In combination with tar, multiple files can be transferred easily.
# cat myfile | ssh user@server "cat > myfile"
This transfers a local file "myfile" to the server. The location of the resulting file is the home directory of the "user".
The first "cat" command simply outputs the contents of "myfile" to stdout, the stdout gets piped to the local part of the ssh session and transferred to stdin of the shell on the server. The second "cat" command (runs on the server) outputs the transferred stdin to stdout. The stdout gets redirected to the "myfile" file on the server (one can choose a different name for the resulting file as required). After the transfer is complete, the ssh exits and user is left in the local terminal window.
If different location is required for the resulting file on the server, two options are available: specifying a full path for the file or changing to the desired directory before running the "cat" command (i.e. running two commands in sequence on the server):
# cat myfile | ssh user@server "cat > ~/backups/myfile"
# cat myfile | ssh user@server "cd ~/backups; cat > myfile"
To transfer in the opposite direction (from remote to local), the pipe is reversed:
# ssh user@server "cat myfile" > myfile
or from a different location:
# ssh user@server "cd ~/backups; cat myfile" > myfile
The simple option is to create an archive file (e.g. using tar) of files required for transfer, transfer the archive as single file and then unarchive the transferred archive on the server. But tar has an ability to create archive to stdout and read archive from stdin. This can be used in combination with ssh to transfer multiple files.
Transferring a directory (from local to remote):
# tar -c -f - mydir | ssh user@server "cat | tar -x -f -"
The first "tar" command creates archive to stdout using the contents of "mydir" directory. The stdout gets piped to ssh. On the server, the "cat" command copies stdin to stdout and the stdout gets piped to "tar". The "tar" reads the archive from stdin and extracts the content of the archive to user's home directory.
To extract the archive on the server to a different location, change the directory before executing "cat | tar" pipe:
# tar -c -f - mydir | ssh user@server "cd ~/backups; cat | tar -x -f -"
It is not a law to unarchive on the remote side. When creating backups of local files, one can keep them in tar archive on the server:
# tar -c -f - mydir | ssh user@server "cd ~/backups; cat > mydir.tar"
To transfer the files the other direction (from remote to local), the pipe is again reversed:
# ssh user@server "tar -c -f - mydir" | tar -x -f -
Again, one can keep the local archive of remote files instead of unarchiving:
# ssh user@server "tar -c -f - mydir" > mydir.tar
It is possible to create compressed archives directly by tar.
To transfer files in "mydir" directory, while compressing the archive (= less network traffic):
# tar -cz -f - mydir | ssh user@server "cat | tar -xz -f -"
To transfer files in "mydir" directory to a remote compressed archive:
# tar -cz -f - mydir | ssh user@server "cat > mydir.tar.gz"
The ssh has an ability to forward TCP ports. It can make a remote port appear on a local network interface (or vice versa). Once this forwarding (or tunnel) is set up a program can connect to the local port and use the remote service as if it was local.
If SAMBA and ssh servers run on the same machine, it is possible to tunnel SAMBA over ssh. This is done in two steps: setting up the tunnel and then mounting the SAMBA share over the tunnel.
# ssh -L 9999:localhost:139 user@server
The above command forwards remote port 139 (the SAMBA service) on the remote "localhost" network interface to local port 9999 on the local "localhost" network interface (the local TCP ports are always open on the "localhost" network interface by ssh).
The ssh allows forwarding of local privileged TCP ports (anything below number 1025) only when run as the superuser (root). The local port 9999 (above 1024) is used to allow a non-superuser to set up the the tunnel. It is a good idea to make sure that no local service is listening on forwarded local port (localhost:9999 in this case) before setting up the tunnel. Any unused and unprivileged port on "localhost" network interface can be used instead of port 9999.
One problem is that the SAMBA name resolution works over UDP and the ssh cannot forward that, The trick is to tell the "smbmount" command to connect to the specific network interface and TCP port directly, without using SAMBA name resolution (see "man smbmount" for more information).
To mount over the ssh tunnel, run in a new shell window (replacing [mount-point] and [username] with relevant values):
# smbmount //localhost/share [mount-point] -o username=[username],ip=localhost,port=9999
The //localhost would be normally a NET-BIOS name of the SAMBA server, but in this case the option "ip=" overrides it (no name resolution is used), the "smbmount" connects directly to local "localhost" network interface on port 9999.
It is a good idea to unmount the local SAMBA mount point ("smbumount" command) before closing the ssh session running the tunnel.
To connect from workstation1 to workstation2 using the server as a proxy:
# ssh -t user@server "ssh user@workstation2"
The command will ask for the password twice, the first time for server and the second time for workstation2. The X window forwarding also works given the correct configuration of all nodes in the chain.
This is not much different than tunneling samba. The VNC usually uses TCP port 5900 and this can be forwarded. This method also works if multiple "hops" are in place. The example setup will allow user to connect to the existing X11 session on linux desktop from a linux VNC viewer over ssh.
- install x11vnc server on the linux box
- create .x11vncrc in the user's home directory (the example allows
connecting multiple times and only uses localhost interface on the
linux machine). Example content of .x11vncrc file (replace [my-password]
with actual password later used in VNC client connection):
- install TightVNC under windows
- install copssh under windows (putty should work as well)
- start a ssh tunnel from windows:
# ssh -L 5900:localhost:5900 [user]@[linux-box]
- start the ThightVNC viewer (on the windows box) and ask it to connect to the localhost, port 5900
- supply the password (configured in .x11vncrc on the linux box)
on the windows box:
# ssh -L 5900:localhost:5900 [user]@[server]
then, on the [server] machine:
# ssh -L 5900:localhost:5900 [user]@[linux-box]
This will create 2 tunnels: one between the windows and the server, second between the server and the linux-box - effectively having port 5900 forwarded from the linux-box to the windows box where server acts as a packet forwarder... After this, one uses the TightVNC viewer as previously (connecting to the localhost, port 5900, on the windows box).
There is a way to make mount of remote file system location over ssh. The sshfs is a file system built on top of ssh protocol, it uses fuse (support for file systems in user space) to function.
How to make this work under debian sarge:
- change /etc/apt/sources.list to point to www.backports.org
- get the libfuse-dev and fuse-utils from backports
- get the source for sshfs from http://fuse.sourceforge.net/sshfs.html
- build the sshfs from source
- install the sshfs
- enable fuse support in the kernel ("files systems" -> "file system in user space support")
- to mount the remote location over ssh:
# sshfs hostname:/path [mount-point]
- to unmount the file system:
# fusermount -u [mount-point]
This way, ssh will not ask for the password - handy for doing periodic automated backups (no need to store password in a script).
On the client (logged in as user which will use the key):
- # ssh-keygen -t dsa
Transfer the id_dsa.pub to the user's ~/.ssh directory on the server, then on the server (in the user's ~/.ssh directory):
- # chmod 0600 id_dsa.pub
- # cat id_dsa.pub > authorized_keys
For example, one often needs to log in to three servers "red", "green" and "blue".
- create a simple script called "ssh-to-server" and put it in
ssh `basename $0` $*
- create symlinks with names of the servers:
# cd /usr/local/sbin
# chmod 0755 ssh-to-server
# ln -s ssh-to-server red
# ln -s ssh-to-server green
# ln -s ssh-to-server blue