SSHFS 教程:如何挂载远程目录及配置无密码访问

By | 最新修改:2025-04-26

前言

SSHFS(SSH File System)是一种通过 SSH 协议实现远程文件系统挂载的工具,允许用户像操作本地文件一样管理远程服务器上的文件,它基于 SFTP。本文详细介绍了 SSHFS 的安装、配置、使用方法,以及如何实现无密码认证和系统启动时自动挂载。

SSHFS-基于SFTP的远程文件系统同步工具


安装 SSHFS 客户端

Debian 系,像 Ubuntu

sudo apt-get install -y sshfs

RHEL 系,像 Rocky Linux,Fedora

在红帽系的衍生版中的安装有点儿麻烦,但是也不那么复杂。

以下适合 Red Hat Enterprice Linux 7/8/9,CentOS 7,CentOS Stream 9,Rocky Linux 8/9,Fedora 等等。

  1. 安装 EPEL 源:
    yum install -y epel-release
    
  2. 更换 EPEL 源为国内源(阿里云 EPEL 源)
    • RHEL 7 / CentOS 7
      curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
      
    • RHEL 8 / Rocky Linux 8

      这里不使用 EPEL

      dnf --enablerepo=powertools -y install fuse-sshfs
      
    • RHEL 9 / CentOS Stream 9 / Rocky Linux 9
      sed -e 's|^metalink=|#metalink=|g' \
          -e 's|^#baseurl=https\?://download.fedoraproject.org/pub/epel/|baseurl=https://mirrors.aliyun.com/epel/|g' \
          -e 's|^#baseurl=https\?://download.example/pub/epel/|baseurl=https://mirrors.aliyun.com/epel/|g' \
          -i.bak \
          /etc/yum.repos.d/epel{,-testing}.repo
      
  3. 刷新软件缓存及更新系统软件
    yum makecache
    yum update -y
    
  4. 安装
    yum install -y fuse3 fuse-sshfs
    

本文将以在 Rocky Linux 9 作为服务端,Ubuntu 24.04 作为客户端来演示如何挂载远程目录。

尽管本文的举例中仅涉及到上述两种操作系统,但是本文的教程仍然在其他 Linux 操作系统有效。


SSH 服务端启用 SFTP

将 SSH 配置文件(/etc/ssh/sshd_config)中的相关配置解开注释:

Subsystem       sftp    /usr/libexec/openssh/sftp-server

重启 SSHD:

systemctl restart sshd
# 查看 SSHD 状态
systemctl status -l sshd

使用

首先,在服务器创建目录 /tmp/remote-dir,在本地创建 /data/local-dir 作为本地客户端挂载点。

先在服务端创建一个文件

cat>/tmp/remote-dir/remote-test.txt<<EOF
Hello, world!
EOF

挂载

sshfs -o sshfs_sync root@192.168.1.108:/tmp/remote-dir/ /data/local-dir/

# 命令格式
sshfs -o sshfs_sync username@ipORdomain:/path/to/remote/source/dir/ /path/to/local/mount/point/dir/

其中 -o sshfs_sync 表示同步更新,如果不使用此选项,那么将导致两端同步有时延。

要在这里说清楚的是:

  1. 本地一旦挂载,那么原目录会被覆盖,本地上的文件会“消失”掉,替换成挂载后的目录。
  2. 当卸载挂载点后,原本的文件会被恢复。

使用 df 命令查看挂载效果

╰─>$ /usr/bin/df -h|grep local-dir

root@192.168.1.108:/tmp/remote-dir/   64G  2.1G   62G   4% /data/local-dir

若出现类似于上面执行结果表示 SSHFS 成功地挂载。


实时文件传输的举例

  1. 列出本地文件

    列出本地目录中的文件:

    ╰─>$ ls /data/local-dir/
    remote-test.txt
    

    查看此时本地文件内容:

    ╰─>$ cat /data/local-dir/remote-test.txt
    Hello, world!
    

    说明同步成功。

  2. 在本地创建新文件

    cat>/data/local-dir/local-test.txt<<EOF
    This is a local test file
    EOF
    

    同步后,远程的内容如下:

    [root@localhost ~]# cat /tmp/remote-dir/local-test.txt
    This is a local test file
    
  3. 修改本地内容
    cat>/data/local-dir/remote-test.txt<<EOF
    This file has been modified!
    EOF
    

    远程内容:

    [root@localhost ~]# cat /tmp/remote-dir/remote-test.txt
    This file has been modified!
    
  4. 修改本地的时间戳

    修改前的时间戳:

    $ stat /data/local-dir/local-test.txt
    
    File: /data/local-dir/local-test.txt
    Size: 26 Blocks: 8 IO Block: 4096 regular file
    Device: 0,52 Inode: 4 Links: 1
    Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
    Access: 2025-04-25 17:03:55.000000000 +0800
    Modify: 2025-04-25 17:03:55.000000000 +0800
    Change: 2025-04-25 17:03:55.000000000 +0800
    Birth: -
    

    修改时间戳:

    touch /data/local-dir/local-test.txt
    

    修改后的时间戳:

    ╰─>$ stat /data/local-dir/local-test.txt
    
    File: /data/local-dir/local-test.txt
    Size: 26              Blocks: 8          IO Block: 4096   regular file
    Device: 0,52    Inode: 4           Links: 1
    Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 2025-04-25 17:08:48.000000000 +0800
    Modify: 2025-04-25 17:08:48.000000000 +0800
    Change: 2025-04-25 17:08:48.000000000 +0800
    Birth: -
    

    此时远程的时间戳:

    [root@localhost ~]# stat /tmp/remote-dir/local-test.txt
    
    File: /tmp/remote-dir/local-test.txt
    Size: 26              Blocks: 8          IO Block: 4096   regular file
    Device: fd00h/64768d    Inode: 68159792    Links: 1
    Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
    Context: unconfined_u:object_r:user_tmp_t:s0
    Access: 2025-04-25 17:08:48.000000000 +0800
    Modify: 2025-04-25 17:08:48.000000000 +0800
    Change: 2025-04-25 17:08:48.479923470 +0800
    Birth: 2025-04-25 16:59:18.966515040 +0800
    
  5. 修改远程文件测试本地是否同步更新

    远程:

    [root@localhost ~]# echo 'ok' > /tmp/remote-dir/
    local-test.txt   remote-test.txt
    [root@localhost ~]# echo 'ok' > /tmp/remote-dir/remote-test.txt
    [root@localhost ~]# cat /tmp/remote-dir/remote-test.txt
    ok
    

    本地:

    ╰─>$ cat /data/local-dir/remote-test.txt
    
    ok
    

经以上实验可知,只要任意一端有任何修改,两边都会同步修改。


卸载

进行卸载操作

fusermount -u /data/local-dir

# 命令格式
fusermount -u /path/to/local/mount/point/dir/

fusermount -u 指定的一定是绝对路径。

若无输出,表明卸载成功。

此时运行 df 命令:

╰─>$ /usr/bin/df -h|grep local-dir

df 命令输出内容经过滤后并无任何内容输出,表示卸载成功!

出现错误“Device or resource busy”,强制卸载

如果执行上一个命令出现以下错误:

fusermount: failed to unmount. Device or resource busy

那么此时需要强制卸载:

# 这是强制卸载,在上一个命令失效的时候使用
sudo umount -l /path/to/local/mount/point/dir/

卸载后的影响

  1. 本地:
    ╰─>$ ls /data/local-dir/
    

    本地里面没有任何东西。

  2. 远程:

    [root@localhost ~]# ls /tmp/remote-dir/
    local-test.txt  remote-test.txt
    

综上所述,卸载操作对远程没有影响的同时还保持着卸载前的样子。


无密码远程访问

本文前面挂载时需要输入密码,然而,有些使用场景中不能输入密码,比如在系统启动时自动挂载。此时便要使用 SSH 密钥,并且是无密码的密钥。

实现 SSHFS 的无密码访问与 SSH 一样,可通过 -F 参数指定地一个 ssh_config 文件,同时此 ssh_config 里面指定无密码的 SSH 私钥。不同的是,SSH 有个 -i 参数可指定私钥,然而 SSHFS 客户端没有这个参数。

无密码访问还有一个步骤是在服务器上部署无密码密钥的公钥,这和 SSH 一致。

生成无密码的 SSH 密钥对

无密码访问的首位步骤是在本地生成无密码密钥对:

mkdir ~/.ssh
cd ~/.ssh/
ssh-keygen -t ed25519 -f id_ed25519_no_pwd_for_sshfs

当需要输入密码时,不输入任何东西,直接回车确定:

╰─>$ ssh-keygen -t ed25519 -f id_ed25519_no_pwd_for_sshfs

Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_ed25519_no_pwd_for_sshfs
Your public key has been saved in id_ed25519_no_pwd_for_sshfs.pub
The key fingerprint is:
SHA256:JlW4pjyu1emNPZE/qcb7A9AMyyz9T/IpsP/1dlr6oYA istrue@dev-pc
The key's randomart image is:
+--[ED25519 256]--+
|         ..      |
|        o.       |
|       +.*       |
|      ..O o      |
|     ..+So .     |
|      ++..B .    |
|     ...oE X o...|
|     ....+= X..++|
|    ..  oo*Bo+o++|
+----[SHA256]-----+

得到 id_ed25519_no_pwd_for_sshfsid_ed25519_no_pwd_for_sshfs.pub 两个密钥,前者是私钥,后者是公钥,公钥部署在服务器端,私钥用来访问部署着对应公钥的服务器。

复制公钥到服务器

登录服务器,然后:

${HOME} 指的是当前用户家目录,可修改为其他免密登录用户(/home/username)。

cat /path/to/id_ed25519_no_pwd_for_sshfs.pub >> ${HOME}/.ssh/authorized_keys

如果该服务器首次使用公钥登录,需要更改相关权限设置:

chmod 700 ${HOME}/.ssh
chmod 600 ${HOME}/.ssh/authorized_keys

若是目录不存在,请创建一下。

要注意的是 .ssh 目录及其下文件的属主和属组,属主要求与登录用户相同。而属组也要和登录用户相同。

设置 SSH 服务器允许密钥登录

vi /etc/ssh/sshd_config,修改以下的配置选项:

  1. 如果不需要密码登录,就把以下一行设置为 no
    PasswordAuthentication no
    

    否则,默认值 yes

  2. 取消下面几行的注释:

    HostKey /etc/ssh/ssh_host_rsa_key
    HostKey /etc/ssh/ssh_host_ecdsa_key
    HostKey /etc/ssh/ssh_host_ed25519_key
    PubkeyAuthentication yes
    AuthorizedKeysFile      .ssh/authorized_keys
    

修改完成,重启 SSH 服务器进程:

systemctl restart sshd
# 查看 SSHD 状态
systemctl status -l sshd

复制 SSH 客户端的配置内容

如果你是 Ubuntu 操作系统,那么可以拷贝客户端配置文件到任意地方。这里是 /data/ 目录下:

# /data 目录在上文已经使用过
cp /etc/ssh/ssh_config /data

修改 /data/ssh_config

  1. 如果 SSH 服务器的端口不是默认值 22,那么就要设置它。

    首先要解开注释:

    Port {PORT}
    

    以实际端口号代替 {PORT}

  2. 解开其中一个 IdentityFile 的注释,然后设置成上文中生成的私钥路径(绝对路径,不能是相对路径):

    IdentityFile ~/.ssh/id_ed25519_no_pwd_for_sshfs
    

将无密码密钥应用到 SSHFS

sshfs 命令的 -F 参数指定 ssh_config 的路径:

sshfs -o sshfs_sync -F /data/ssh_config root@192.168.1.108:/tmp/remote-dir/ /data/local-dir/

-F 指定的一定要是绝对路径。

-o sshfs_sync 是“同步写入”的意思。

此处不输出任何内容表示挂载成功。

运行 df 命令检查挂载是否有效:

╰─>$ /usr/bin/df -h|grep local-dir

root@192.168.1.108:/tmp/remote-dir/   64G  2.1G   62G   4% /data/local-dir

指定本地同步目录的属主和属组

sshfs -o sshfs_sync -o uid=1000 -o gid=1000 -F /data/ssh_config root@192.168.1.108:/tmp/remote-dir/ /data/local-dir/

uid 表示用户的 id 值;
gid 表示用户的属组 id。

获取系统用户的 id 值

当前用户的 uidgid 均可由 id 命令得到,或者在文件 /etc/passwd/etc/group 中。

Linux 下 id 命令的用法

  1. id 得到当前登录用户的属主和属组 id;
  2. id root 得到系统 root 用户的属主和属组 id;
  3. id username 得到普通用户 username 的属主和属组的 id。

系统启动自动挂载

将以下内容放进文件系统表(/etc/fstab)中从而让 SSHFS 随系统启动而挂载:

sudo bash -c "echo 'root@192.168.1.108:/tmp/remote-dir/ /data/local-dir/ fuse.sshfs delay_connect,_netdev,user,idmap=user,transform_symlinks,identityfile=/data/id_ed25519_no_pwd_for_sshfs,default_permissions,uid=1000,gid=1000 0 0'>>/etc/fstab"

上面的 Bash 语句解析如下:

sudo bash -c "echo '<remote username>@<remote address>:<remote dir> <local dir> fuse.sshfs delay_connect,_netdev,user,idmap=user,transform_symlinks,identityfile=<ssh private key path>,default_permissions,uid=<local file user id>,gid=<local file group id> 0 0'>>/etc/fstab"

<remote username>:SSH 登录用户名;
<remote address>:SSH 地址,可以是 IP 地址,也可以是域名;
<remote dir>:远程绝对路径;
<local dir>:挂载点路径;
<ssh private key path>:SSH 私钥路径;
<local file user id>:本地用户 id,即本地挂载点的属主 id;
<local file group id>:本地用户属主 id,即本地挂载点的属组 id。


总结

本文详细介绍了 SSHFS 的安装、配置和使用方法,包括在 Debian/Ubuntu 和 RHEL 系系统中的安装步骤,如何启用 SFTP 服务,以及通过 SSHFS 挂载远程目录到本地的操作指南。此外,还提供了无密码访问的实现方式(SSH 密钥对)、指定本地目录权限的技巧,以及系统启动时自动挂载的配置方法,并为每个步骤提供了实用场景示例和常见问题讲解。

SSHFS 目前有一个令笔者不喜欢的地方,就是不能在服务器端自动地改变远程文件的属主和属组,这在一些场景下很不方便。

远程和本地文件的同步可能有稍许的延迟,只要配置是正确的,那么请稍等一下便会同步起来。


程序知路

鉴于本人的相关知识储备以及能力有限,本博客的观点和描述如有错漏或是有考虑不周到的地方还请多多包涵,欢迎互相探讨,一起学习,共同进步。

本文章可以转载,但是需要说明来源出处!

本文使用的部分图片来源于网上,若是侵权,请与本文作者联系删除: admin@icxzl.com