将 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 表示同步更新,如果不使用此选项,那么将导致两端同步有时延。
要在这里说清楚的是:
- 本地一旦挂载,那么原目录会被覆盖,本地上的文件会“消失”掉,替换成挂载后的目录。
- 当卸载挂载点后,原本的文件会被恢复。
使用 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 成功地挂载。
实时文件传输的举例
-
列出本地文件
列出本地目录中的文件:
╰─>$ ls /data/local-dir/
remote-test.txt
查看此时本地文件内容:
╰─>$ cat /data/local-dir/remote-test.txt
Hello, world!
说明同步成功。
-
在本地创建新文件
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
-
修改本地内容
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!
-
修改本地的时间戳
修改前的时间戳:
$ 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
-
修改远程文件测试本地是否同步更新
远程:
[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/
卸载后的影响
-
本地:
╰─>$ ls /data/local-dir/
本地里面没有任何东西。
-
远程:
[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 一致。
生成无密码的密钥对
无密码访问的首位步骤是在本地生成无密码密钥对:
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_sshfs 和 id_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 目录及其下文件的属主和属组,属主要求与登录用户相同。而属组也要和登录用户相同。
设置服务器允许密钥登录
vi /etc/ssh/sshd_config,修改以下的配置选项:
-
如果不需要密码登录,就把以下一行设置为 no:
PasswordAuthentication no
否则,默认值 yes。
-
取消下面几行的注释:
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
复制客户端的配置内容
如果你是 Ubuntu 操作系统,那么可以拷贝客户端配置文件到任意地方。这里是 /data/ 目录下:
# /data 目录在上文已经使用过
cp /etc/ssh/ssh_config /data
修改 /data/ssh_config
-
如果 SSH 服务器的端口不是默认值 22,那么就要设置它。
首先要解开注释:
Port {PORT}
以实际端口号代替 {PORT}。
-
解开其中一个 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 值
当前用户的 uid 和 gid 均可由 id 命令得到,或者在文件 /etc/passwd 和 /etc/group 中。
Linux 下 id 命令的用法
id 得到当前登录用户的属主和属组 id;
id root 得到系统 root 用户的属主和属组 id;
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。