Skip to main content

mac 通过 sshfs 挂载远程 Linux 文件系统

· 9 min read

面对 mac 中浏览/下载/上传文件到远程linux服务器这个需求,无论是在终端中使用 sftp 交互命令, 还是使用一些 sftp 客户端(如 Termius,transmit),都有或者或那的不方便。 最大的问题是其不能很好地和本地文件系统融合,例如 Termius 无法通过拖拽的方式将文件拷贝到本地, 也无法通过 command + c/v 进行文件拷贝等等。 其他的需求就似乎更难满足了,像查看远程的 pdf 或者图片文件也显得比较麻烦(先下载到本地,在打开), 更别说类似于finder里面的"快速查看"功能来浏览远程文件或者显示简介了。

因此,或许我们可以将远程的文件挂载到本地目录,但是 mac 系统本身只提供了 SMB/CIFS、NFS、FTP、AFP 等服务连接, 似乎不能很好地满足需求(如果你是远程服务器等管理员的话,也可以配置linux 的 nfs 服务)。
通过一番探索,发现 sshfs 可以实现这个的需求。 本文后续内容主要就是一点关于 mac 上 sshfs 的配置步骤与使用方法的。

安装 OSXFUSE

brew cask install osxfuse # 3.11.0

另外,从 brew cask info osxfuse 的信息来看,需要重启系统才能生效。

You must reboot for the installation of osxfuse to take effect.

遂重启系统。安装完成后,在系统的偏好设置里面,就可以看到 FUSE 扩展的图标及信息了。 fuse-ext-in-system-preferenece

brew 安装 sshfs(放弃)

然后使用 brew 安装 sshfs。

$ brew info sshfs
sshfs: stable 2.10 (bottled)
File system client based on SSH File Transfer Protocol
https://osxfuse.github.io/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/sshfs.rb
License: GPL-2.0
==> Dependencies
Build: autoconf ✘, automake ✘, libtool ✘, pkg-config ✔
Required: glib ✘
==> Requirements
Required: osxfuse ✔
==> Analytics
install: 4,788 (30 days), 13,409 (90 days), 70,551 (365 days)
install-on-request: 3,947 (30 days), 10,897 (90 days), 56,706 (365 days)
build-error: 0 (30 days)
$ brew install sshfs
Updating Homebrew...
==> Downloading https://homebrew.bintray.com/bottles/gdbm-1.18.1_1.catalina.bottle.tar.gz
==> Downloading https://www.openssl.org/source/openssl-1.1.1g.tar.gz
==> Downloading https://homebrew.bintray.com/bottles/readline-8.0.4.catalina.bottle.tar.gz
==> Downloading https://homebrew.bintray.com/bottles/sqlite-3.32.3.catalina.bottle.tar.gz
==> Downloading https://homebrew.bintray.com/bottles/xz-5.2.5.catalina.bottle.tar.gz
==> Downloading https://files.pythonhosted.org/packages/2f/8e/38259f4a44944a92068d5ff77230511a4c685604b47a81318f9e5cf2
==> Downloading https://files.pythonhosted.org/packages/08/25/f204a6138dade2f6757b4ae99bc3994aac28a5602c97ddb2a35e0e22
==> Downloading https://files.pythonhosted.org/packages/75/28/521c6dc7fef23a68368efefdcd682f5b3d1d58c2b90b06dc1d0b805b
==> Downloading https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tar.xz

这一堆下载都是什么鬼啊,感觉下载的东西挺多的。果断停止用 brew 安装。 而且 brew 上的版本似乎很老了(现在最新版都 3.7.0 了)。 这么多依赖,还不如自己源码编译呢。

另外有意思都是,sshfs 在github有两个仓库,一个是 https://github.com/libfuse/sshfs, 另一个是 https://github.com/osxfuse/sshfs。 后者似乎没有维护了,好像仓库迁移到前者继续开发了。

通过一番折腾,发现brew 中 sshfs 版本是比较老的,但其也是有原因的。 从这几 issue 来看,osxfuse 一直用的 libfuse 2.x:

目前最新的 3.x 版本的sshfs,需要 libfuse 3.x;2.x 版本的sshfs,需要 libfuse 2.x 依赖。 如果我们在 mac 上安装 3.x 的 sshfs 则会出现 libfuse 库不兼容的问题。 所以,由于 osxfuse 中使用的 libfuse 低版本缘故,我们只能安装 2.x 的 sshfs。

例如,安装 osxfuse 后,如果编译 3.x 的 sshfs 则会出现 API 对不上的编译错误:

cache.c:456:46: error: too many arguments to function call, expected 2, have 3
int err = cache.next_oper->rename(from, to, flags);
~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~
cache.c:475:47: error: too many arguments to function call, expected 2, have 3
int err = cache.next_oper->chmod(path, mode, fi);
~~~~~~~~~~~~~~~~~~~~~~ ^~
cache.c:484:51: error: too many arguments to function call, expected 3, have 4
int err = cache.next_oper->chown(path, uid, gid, fi);
~~~~~~~~~~~~~~~~~~~~~~ ^~
cache.c:493:47: error: too many arguments to function call, expected 2, have 3
int err = cache.next_oper->utimens(path, tv, fi);

编译 sshfs

从 sshfs 仓库主页上文档(2.10.0)来看,编译 sshfs 需要用到一个叫 meson 到构建工具 和 ninja(ninja 我倒是很熟悉,也经常用)。并依赖与 glib 和 osxfuse。

安装 meson

我准备用 brew 安装下 meson,看了下依赖信息,这玩意儿似乎不怎么合理啊。

$ brew info meson
meson: stable 0.55.0 (bottled), HEAD
Fast and user friendly build system
https://mesonbuild.com/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/meson.rb
License: Apache-2.0
==> Dependencies
Required: ninja ✔, python@3.8 ✘
==> Options
--HEAD
Install HEAD version
==> Analytics
install: 15,161 (30 days), 43,572 (90 days), 162,570 (365 days)
install-on-request: 4,042 (30 days), 10,587 (90 days), 29,641 (365 days)
build-error: 0 (30 days)

mac 系统已经预装有了 python 3.7.3 了,竟然还需要我安装一个 python 3.8 的依赖, 而且meson 官房文档上面也只要求 python3,其他 python3 的版本又不是不能用。

于是又放弃用 brew 安装了 meson,遂决定从源码来。去 https://github.com/mesonbuild/meson 下载最新的 release 代码(v0.55.0),并配合文档食用。

Installation from source Requirements: git Meson can be run directly from the cloned git repository.

发现直接执行源码中的 python3 脚本就行了,甚喜。 直接下载代码,解压就可以用了。

wget https://github.com/mesonbuild/meson/releases/download/0.55.0/meson-0.55.0.tar.gz
tar zxvf meson-0.55.0.tar.gz

ninja

另外,还需要安装ninja。由于我已经安装过了 ninja 了,如果没有安装 ninja 的话,可以用 brew 安装一下:

brew install ninja

glib

文档:https://developer.gnome.org/glib/stable/glib-building.html

glib依赖与 pcre, gettext, Python 3.5 or newe, pkg-config, libiconv (mac 系统已经提供了)

# 安装依赖,用完可删
brew install pcre gettext pkg-config
wget https://github.com/GNOME/glib/archive/2.65.1.tar.gz
tar zxvf 2.65.1.tar.gz
cd glib-2.65.1
meson --prefix=$HOME/.local/develop/glib/2.65.1 _build
ninja -C _build
ninja -C _build install
export PKG_CONFIG_PATH=$HOME/.local/develop/glib/2.65.1/lib/pkgconfig

编译 sshfs

至此,编译 sshfs 的相关工具或库就准备好了。 下面下载 sshfs 并依据github README 文档进行编译:

wget https://github.com/libfuse/sshfs/archive/sshfs-2.10.0.tar.gz
tar zxvf sshfs-2.10.0.tar.gz
cd sshfs-2.10.0
../../meson/0.55.0/meson.py build
ninja -C build

编译如果出现下面的 cp 命令错误:

ninja: Entering directory `build'
[1/3] Generating test_scripts with a custom command
FAILED: test/conftest.py test/pytest.ini test/test_sshfs.py test/util.py
cp -fPu --preserve=mode ../test/conftest.py ../test/pytest.ini ../test/test_sshfs.py ../test/util.py /Users/genshen/.local/develop/sshfs/sshfs-sshfs-2.10/build/test
cp: illegal option -- u
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file ... target_directory
[2/3] Linking target test/wrong_command
ld: warning: directory not found for option '-L/Users/genshen/.local/lib'
[3/3] Linking target sshfs
ld: warning: directory not found for option '-L/Users/genshen/.local/lib'
ninja: build stopped: subcommand failed.

可以修改 build 下面的 build.ninja 文件,找到出错的那一条cp命令,将cp命令的参数仅保留-fP即可。

顺利的话,在 build 目录下,会生成一个叫 sshfs 的可执行文件,将其拷到 PATH 环境变量指定的目录下面,就可以用了。

使用 sshfs

我们先在本地建一个目录,然后用 sshfs 挂载远程目录:

mkdir -p local_dir/local_dir
cd local_dir
sshfs -C docker@docker.hpcer.dev:/home/docker ./local_dir/

mac 上首次使用 sshfs 命令,会被系统的安全阻止,需要前往 偏好设置->安全与隐私->通用 中进行允许。 security-allow-for-osxfuse 挂载成功后,就可以开始在 finder 里面直接访问与操作远程linux系统上的文件了。 sshfs-mounted

用完卸载文件系统的话,在 BSD 和 OS-X,可以鼠标右键挂载的文件系统->推出 或者使用 umount 命令:

umount ./local_dir

另外,还有几个可能会提升效率的使用方式:

  1. 配置远程服务器公钥和私钥,实现免密码访问。
  2. 在 finder 的偏好设置中的通用,勾选在桌面上显示"已连接的服务器",这样就可以快速访问了。