Linux Fu: Simple SSH File Sharing

If you have more than one Linux computer, you probably use ssh all the time. It is a great tool, but I’ve always found one thing about it strange. Despite having file transfer capabilities in the form of scp and sftp, there is no way to move a file back or forth between the local and remote hosts without starting a new program on the local machine or logging in from the remote machine back to the local machine.

That last bit is a real problem since you often access a server from behind a firewall or a NAT router with an ephemeral IP address, so it can’t reconnect to you anyway. It would be nice to hit the escape character, select a local or remote file, and teleport it across the  interface, all from inside a single ssh session.

I didn’t quite get to that goal, but I did get pretty close. I’ll show you a script that can automatically mount a remote directory on the local machine. You’ll need sshfs on the local machine, but no changes on the remote machine where you may not be able to install software. With a little more work, and if your client has an ssh server running, you can mount a local directory on the remote machine, too. You won’t need to worry about your IP address or port blocking. If you can log into the remote machine, you are good.

Combined, this got me me very close to my goal. I can be working in a shell on either side and have access to read or write files on the other side. I just have to set it up carefully.

Wait… Is that Cheating?

You might say this is cheating because you are really using two ssh connections — one for the file system mount and another to log in. That’s true. However, if you have ssh set up properly, you’ll only authenticate once, and it won’t be as much overhead as two separate connections.

In addition, the script hides the details so from a user’s point of view, you connect (almost) the same as usual and it just works.

About SSHFS

The sshfs program is a user-space file system (FUSE), which means that it’s a user-space layer over the underlying file system. In this case, the underlying file system is an ssh server that can do sftp. This lets you access a file on the remote machine as if it were on the real filesystem on the local machine. If you haven’t used it, it works quite well.

If you have a login set up for a machine myserver, you simply run sshfs myserver:/home/admin ~/mounts/myserver from the local machine.

Now the /home/admin directory on the remote machine will appear at ~/mounts/myserver on the local machine.

There are some options you can use. For example, it is useful to allow the file system to reconnect a broken connection. Read the man page for more.

Because sshfs uses the remotely mounted version of the file, all changes made show up on the remote machine, but once you’ve shut sshfs down, you’ve got nothing on the local box. Let’s fix that.

Before The Script

Before I get into the script, there is a little setup on the client that you could customize if you like. I create a directory ~/remote and then create a subdirectory for each of my remote computers. For example ~/remote/fileserver and ~/remote/lab.

The script is called sshmount and it takes all the same arguments as ssh. To make life easier, you should have your details in the ~/.ssh/config file for the remote host so that you can use a simple name. For example, lab might be something like this:

Host lab
Hostname lab.wd5gnr-dyn.net
Port 444
User alw
ForwardX11 yes
ForwardX11Trusted yes
TCPKeepAlive yes
Compression yes
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p

Thiat isn’t strictly necessary, but then you get a nice ~/remote/lab directory and not ~/remote/alw@lab.wd5gnr-dyn.net:444 which is annoying to use. There’s nothing magic about any of these parameters but the ControlMaster and ControlPath do make multiple connections more economical which is important in this case.

You’ll also want to set up logging in automatically using a certificate if you haven’t already. We did a post on this for the Raspberry Pi, but it really applies to any ssh setup.

The Script

The script has a split personality. If you call it via a link to sshunmount it will unmount the directory associated with the named remote host. If you call it as anything else (usually sshmount), it will do three things:

  1. It checks for a directory under ~/remote that matches the remote host name (e.g., lab). If it fails to find it, it prints an error message and continues to execute ssh.
  2. If the directory exists, the script examines the list of mounted file systems to see if it is already mounted. If it is, the script just continues with ssh.
  3. If the directory is not mounted, the script calls sshfs and then proceeds with ssh.

You can find the script on GitHub, but here’s the gist of it (less some comments);


#!/bin/bash

if [ "$1" == "" ]
then
echo Usage: sshmount host [ssh_options] - Mount remote home folder on ~/remote/host and log in
echo or: sshunmount host - Remove mount from ~/remote/host
exit 1
fi

# if called as sshunmount...
if [ $(basename "$0") == sshunmount ]
then
echo Unmounting... 1>&2
fusermount -u "$HOME/remote/$1"
exit $?
fi

# normal call...
if [ -d "$HOME/remote/$1" ] # does directory exist?
then
if mount | grep "$HOME/remote/$1 " # already mounted?
then
echo Already mounted 1>&2
else
sshfs -o reconnect $1: $HOME/remote/$1 # mount
fi
else
echo No remote directory ~/remote/$1 exists 1>&2
fi
ssh $@ # do log in

This gives us half of what I wanted. My local machine has a direct mapping of the remote file system while I’m logged into the system. But getting the local directory mapped to the remote machine is a bit harder.

Reversing the Process

If you want to experiment with having a local directory mounted on the server, you can do that too if you have an ssh server running on the local machine. Of course, if your local machine is visible to the host and accessible, that’s trivial. Just run sshfs on the remote machine and mount a directory from the local machine. But in many cases, you won’t have an accessible route from the remote machine through whatever firewalls and routers you are behind, especially on something like a laptop that doesn’t stay in one place.

There is still an answer though. It requires two things. First, you need to add an extra argument when you call sshmount (you could edit the file if you wanted to always do this):


sshmount MyServer -R 5555:localhost:22

Then after you are on the host, run


sshfs -p 5555 localhost:/home/me ~/local

The -R option creates a socket on the remote machine at 5555 (which, obviously, needs to be otherwise unused) and maps it back to us on port 22. Assuming there is an ssh server on port 22, this will allow the server to log back into our local machine over the same connection. No need to know our IP address or have an open port.

The sshfs command, which you could put in your startup files, maps your local /home/me directory to the remote server’s ~/local directory. If you log in locally too, there are several SSH_ environment variables you could use to tell if you are starting up remotely, for example $SSH_CLIENT or $SSH_TTY.

Of course, you’ll need to change the hosts and directories and port numbers to suit your environment. But once set up, you can have folders on both machines visible to the other. No, I haven’t tried circularly mounting the same directories. That might create a black hole.

Be Careful Out There

You still should probably be careful going in both directions. Tools that scan the whole file system, for example, could easily get confused. I also wish I had a better answer to cleanly disconnect the server’s file share when you log out of the last session.

However, for now, the system works well and it is an easy way to share files from within an ssh session without much work. Another answer might be to just keep directories synchronized and use those directories for transfers. Want more stupid ssh tricks? We got ’em.

28 thoughts on “Linux Fu: Simple SSH File Sharing

  1. SSH with scripting is one of most complex and powerful tools in linux. I used to use it with tunnelling to run screens from a remote UltraSPARC on my linux desktop. Very nice article on shares.

  2. When connecting to a linux machine from a mac you need to do some name encoding conversion if you’re using characters outside ascii. It took me quite a whille to figure out the fix.

    `sshfs -p 22 user@host:/dir/ -o allow_other -ovolname=Linux -o modules=iconv,from_code=UTF-8,to_code=UTF-8-MAC`

    1. Silk idea.

      But I think the smart creators of SSH already have such thing implemented.

      > How?

      I don’t know. I make this reply for getting the discussion further with the hope it yields a solutions.

      For feeding the discussion: Type `~.`, tilde dot, at client side closes the connection. Perhaps is `~`, tilde, also used to preamble a file transfer

  3. sshfs, smbfs, pre-shared keys, fuse, and the automounter let you put together a real simple way to access the filesystems of every system within your network segment. Read only.
    This setup even properly handles seeking within files so you can do cool things liked tail -f on massive log files, on hundreds of machines, at the same time. Can be rather processor intensive at that level due to all the encryption happening, but on a trusted network segment you can turn that down or even disable that if desired.
    Simply awesome.

      1. Until you blindly trust rsync never gets it wrong but incremental updates detemines no changes are needed even though they are.
        Now your systems are no longer in sync but rsync claims otherwise. Especially annoying when relying on a cron’d rsync.

      2. I’m not so sure about sshfs being abandoned. I had to recompile it on Gentoo a few months ago because they changed how some of the options worked and updated it to work with the new(er) FUSE system. I had updated my Ubuntu system and then found my Gentoo system couldn’t automount as it had before and had to update sshfs to get it to work as expected.

    1. I actually got about the same performance out of sshfs as I ever did out of NFS. I had to switch to NFS for a short time while updating my Gentoo system to get it compatible with one of my Ubuntu systems and I noticed no great difference in performance. The biggest bottleneck was my network.

    1. I use rclone for this purpose also. I have ~/cloud and then mount points in there for Google, NextCloud, and all my remote machines. I have to put an echo in my profile though reminding me that when it fails, run rclone config to redo the credentials.

  4. “I also wish I had a better answer to cleanly disconnect the server’s file share when you log out of the last session.”

    I have a script for per-project encrypted directories. It mounts the directory, starts a new instance of graphical terminal with “gnome-terminal –disable-factory” and after that exits, it unmounts. That way the directory is automatically unmounted when I close the whole terminal window, but I can still have multiple tabs inside the window and close and open them as I want.

  5. You should learn about escape code in SSH. Typically type “Enter then ‘~’ and ‘?’.
    This allow modifying SSH environment dynamically and thus open a port for forwarding transfers.
    Thus, the sequence is
    Enter
    ‘~’
    Ctrl+Z
    scp myFile me@host
    password
    fg

  6. I have been using sshfs for years in place of NFS as I prefer the improved security and flexibility. One thing I added to my mount script is a line like:
    ssh-add -l|grep -q || ssh-add

    Where is the signature for your key. This may or may not be necessary depending on how your ssh-agent is invoked for your particular DE.

Leave a Reply to Al Williams Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.