ssh进阶用法

基本的ssh操作

ssh登录与ssh配置文件

使用ssh可以从一台设备登录到另一台已开启sshd服务的远程设备。
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ ssh yukari@172.28.24.152
The authenticity of host '172.28.24.152 (172.28.24.152)' can't be established.
ECDSA key fingerprint is SHA256:YSCMU48vJ8btRmdqgWLz8/VhMR3xjUIQn64K4MX/EgE.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Password:
yukari@SALICYLIC:~$ ‎

ssh_config是存储OpenSSH配置信息的文本文件,用户个人的ssh_config配置储存在~/.ssh/config下。一条合法的配置格式如下

复制代码
Host salic
  HostName 172.28.24.152
  User yukari

其中Host表示配置名,HostName表示远程设备地址,User表示登录的用户名。

~/.ssh/config中添加上述配置后,可以通过设定的配置名进行更为简便的登录:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ vim ~/.ssh/config
Host salic
  HostName 172.28.24.152
  User yukari
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
coli@DESKTOP-J45M1NUM:~$ ssh salic
Password:
yukari@SALICYLIC:~$ ‎

ssh密钥登陆

除了使用密码进行登录身份验证之外,OpenSSH还支持通过密钥完成登录身份验证。

一对ssh密钥由私钥和公钥两个文件组成,它们是两段不同的复杂随机文本。一段数据由公钥加密后可以由其对应的私钥解密还原,而在没有私钥的情况下,仅根据公钥和密文的来推断加密前的数据被认为是不可实现的。因此,密钥可被用于身份验证:用户在服务器端和客户端分别存储公钥和私钥,需要身份验证时,服务器端将一段加密后的文本发送到客户端,客户端将通过私钥将密文解密后发回服务器端,如果服务器端收到的文本与加密前的文本一致,那么用户身份得以验证。

利用ssh-keygen可以生成一组全新的ssh密钥:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/coli/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/coli/.ssh/id_rsa
Your public key has been saved in /home/coli/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:NNxg9U2L1+XdtcxDVOxfobNrQ5Qf/IBwubrCaSJHUQY coli@DESKTOP-J45M1NUM
The key's randomart image is:
+---[RSA 3072]----+
|      E.o..  .o+=|
|       ooo..o++=B|
|       o+ .oooB**|
|      .. .  o*.o+|
|       .S  .. +.=|
|      .   .  o .o|
|     . . . .. .  |
|    . o = .  +   |
|     o o .  . .  |
+----[SHA256]-----+
coli@DESKTOP-J45M1NUM:~$ ls ~/.ssh
$ ls -al ~/.ssh
total 8
drwx------ 1 coli coli 4096 Mar  3 08:43 .
drwxr-xr-x 1 coli coli 4096 Mar  3 08:43 ..
-rw------- 1 coli coli  474 Mar 21 19:50 config
-rw------- 1 coli coli 2602 Mar 21 20:01 id_rsa
-rw------- 1 coli coli  565 Mar 21 20:01 id_rsa.pub
-rw-r--r-- 1 coli coli  222 Mar 21 19:48 known_hosts
coli@DESKTOP-J45M1NUM:~$ ‎

其中/home/coli/.ssh/id_rsa指定了生成的密钥文件的储存位置,passphrase是私钥口令,每次使用私钥登录前都需要输入此口令以启用私钥,相当于给私钥再设置一个密码。

按照其默认配置(全部留空)生成的私钥文件储存在/home/coli/.ssh/id_rsa,公钥文件储存在/home/coli/.ssh/id_rsa.pub

要通过密钥登录到远程设备,还需要将公钥复制到远程设备的~/.ssh/authorized_keys下,可以通过scp将文件传输到远程设备:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ scp ~/.ssh/id_rsa.pub salic:~/.ssh/id_rsa.pub
Password:
id_rsa.pub                                                         100% 565   264.4KB/s   00:00
coli@DESKTOP-J45M1NUM:~$ ssh salic
Password:
yukari@SALICYLIC:~$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
yukari@SALICYLIC:~$ logout
Connection to 172.28.24.152 closed.
coli@DESKTOP-J45M1NUM:~$ ssh salic
yukari@SALICYLIC:~$ ‎

配置成功后,你即可通过密钥验证的方式直接登录到远程设备,而不需要输入密码。

需要注意的是,只有在.ssh文件夹和密钥文件访问权限配置正确的情况下,密钥认证才能正确进行。具体说来,本地和远程的.ssh文件夹应当拥有700 rwx------(仅本人用户可读写访问)权限,而本地的私钥文件则应当拥有600 rw-------(仅本人用户可读写)权限。过于如果相应文件或文件夹的权限过于开放,那么ssh会禁用密钥验证。

默认情况下,OpenSSH会默认用~/.ssh下的id_rsa文件作为私钥尝试登录。如果你有多台远程设备,建议你分别使用不同的密钥对。要为不同的远程设备配置不同的密钥,你可以在~/.ssh/config中指定IdentityFile

复制代码
Host salic
  HostName 172.28.24.152
  User yukari
  IdentityFile ~/.ssh/salic.id_rsa

此后登录salic时ssh客户端将使用~/.ssh/salic.id_rsa为私钥进行身份验证。

ssh代理跳板与端口转发

ssh代理跳板

一些情况下,不是所有设备都能够直接访问:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ ssh yukari@172.28.24.104
ssh: connect to host 172.28.24.104 port 22: Resource temporarily unavailable
coli@DESKTOP-J45M1NUM:~$ ssh salic
yukari@SALICYLIC:~$ ssh yukari@172.28.24.104
Password:
yukari@CITRIC:~$ ‎

在这个例子中,你无法通过本地设备直接登录到远程设备172.28.24.104,而需要通过另一台设备中转。这可能是由于该设备仅允许来自特定网段的连接,而你的本地设备不在允许规则内;或者远程设备是一个局域网设备,且与你的本地设备不在同一个局域网内。通常,用于登录中转的设备被称为代理跳板(proxy jump)。

在这种情况下,你可以通过ssh选项-J指定ssh代理跳板,或者在配置文件中指定ProxyJump项:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ ssh -J salic yukari@172.28.24.104
Password:
yukari@CITRIC:~$ logout
Connection to 172.28.24.104 closed.
coli@DESKTOP-J45M1NUM:~$ vim ~/.ssh/config
Host salic
  HostName 172.28.24.152
  User yukari
  IdentityFile ~/.ssh/salic.id_rsa

Host citric
  HostName 172.28.24.104
  User yukari
  ProxyJump salic
~
~
~
~
~
~
~
~
~
coli@DESKTOP-J45M1NUM:~$ ssh citric
Password:
yukari@CITRIC:~$ ‎

同样,你可以在citric和本地分别配置公钥和私钥,从而实现免密码登录。

端口转发

不同的设备处于不同的网络环境,但ssh可以通过端口转发以实现不同设备之间的网络数据交换。

ssh的端口转发分为远程转发和本地转发两种类型,分别用可于远程设备访问本地网络服务和本地访问远程设备网络服务。

下面将介绍端口转发的几种常用场景。

远程转发------反向ssh

scp命令可以在本地设备和远程设备之间传递文件。很多时候,我们希望在远程设备的工作目录与本地设备的特定目录之间进行文件交换(下载文件)。但是在不少情况下,远程设备无法通过ip地址连接到本地,因此我们只能依靠在本地打开一个新的命令行来传递文件。然而,在本地使用scp时需要指定远程文件的绝对路径 ,很方便。ssh的远程转发可以帮我们解决这个问题。

远程转发的ssh命令行参数格式为-R remoteport:localhost:localport,ssh_config的配置格式为RemoteForward remoteport host:hostport

设置远程转发后,远程设备中所有发送到remoteport端口的数据将通过ssh隧道转发到本地的localport端口。

此时你只需要在本地开启sshd服务,即可在通过转发的端口建立反向的ssh通道,从而在远程设备上使用scp传输文件
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ mkdir ~/downloads/
coli@DESKTOP-J45M1NUM:~$ sudo service ssh start
[sudo] password for coli:
coli@DESKTOP-J45M1NUM:~$ ssh -R 22222:localhost:22 salic
yukari@SALICYLIC:~$ cd data
yukari@SALICYLIC:~/data$ scp -P 22222 output.jpg coli@localhost:~/downloads/
output.jpg                                                         100% 2465   463.2KB/s   00:00
yukari@SALICYLIC:~/data$ logout
Connection to 172.28.24.152 closed.
coli@DESKTOP-J45M1NUM:~$ ls ~/downloads/
output.jpg
coli@DESKTOP-J45M1NUM:~$ ‎

注意

端口没有用户认证机制,建立远程转发后,远程设备上的所有用户都能够访问到你所转发的端口,从而能够通过ssh试图访问你的本地设备。

远程转发------网络服务转发

考虑这样一种情况:你想在远程设备上使用pip安装一个python包,或者安装一个R包,但是你的远程设备没有连接到互联网,你该如何操作?

最简单的做法是将先文件下载到本地,然后通过scp传输到远程设备,最后离线安装。但这对于哪些拥有复杂依赖的包来说十分不方便。

幸运的是,通过ssh远程端口转发,我们可以让远程设备访问到本地的网络服务:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ sudo apt install squid
[sudo] password for coli:
Preparing to unpack .../4-ssl-cert_1.0.39_all.deb ...
Unpacking ssl-cert (1.0.39) ...
Selecting previously unselected package squid.
Preparing to unpack .../5-squid_4.10-1ubuntu1.5_amd64.deb ...
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
Unpacking squid (4.10-1ubuntu1.5) ...
Setting up squid-langpack (20191103-1) ...
Setting up ssl-cert (1.0.39) ...
Setting up libdbi-perl:amd64 (1.643-1ubuntu0.1) ...
Setting up libecap3:amd64 (1.0.1-3.2ubuntu1) ...
Setting up squid-common (4.10-1ubuntu1.5) ...
Setting up squid (4.10-1ubuntu1.5) ...
Setcap worked! /usr/lib/squid/pinger is not suid!
invoke-rc.d: could not determine current runlevel
Created symlink /etc/systemd/system/multi-user.target.wants/squid.service → /lib/systemd/system/squid.service.
invoke-rc.d: could not determine current runlevel
Processing triggers for ufw (0.36-6) ...
Processing triggers for systemd (245.4-4ubuntu3.11) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.2) ...
coli@DESKTOP-J45M1NUM:~$ sudo vim /etc/squid/squid.conf
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
include /etc/squid/conf.d/*

# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
#http_access allow localnet
http_access allow localhost

# And finally deny all other access to this proxy
#http_access deny all
http_access allow all

#  TAG: adapted_http_access
#       Allowing or Denying access based on defined access lists
#
#       Essentially identical to http_access, but runs after redirectors
coli@DESKTOP-J45M1NUM:~$ sudo service squid start
coli@DESKTOP-J45M1NUM:~$ ssh -R 3129:localhost:3128 salic
yukari@SALICYLIC:~$ export http_proxy=http://127.0.0.1:3128
yukari@SALICYLIC:~$ export https_proxy=http://127.0.0.1:3128
yukari@SALICYLIC:~$ curl www.baidu.com
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
yukari@SALICYLIC:~$ ‎

其中,squid是安装在本地的http代理客户端,它可以将所有发送到本地3128端口的http请求解析并转发给相应的目标。

ssh远程转发-R 3129:localhost:3128使得远程设备上所有发送到3129端口的数据转发到本地的3128端口,从而交给squid处理。

远程设备上所设置的环境变量http_proxyhttps_proxy能够让所有http和https网络请求发送给远程设备的3129端口,进而被转发到本地3128端口交由squid处理。

你也可以使用3129之外的其他端口,只需保证ssh转发的端口和http_proxy转发到的端口一致即可。

http_proxyhttps_proxy变量的设置是一次性的,仅适用于当前命令行。你可以将这两句话添加到~/.bashrc使得每次登录时自动设置这两个变量。

这里的ssh远程转发的命令行参数可以在ssh_config中设置为RemoteForward 3129 localhost:3128

如果你使用Windows下的OpenSSH客户端登录远程设备,那么你需要在Windows下安装squid或其他代理工具,并在ssh时指定对应的转发端口。

注意

端口没有用户认证机制,建立远程转发后,远程设备上的所有用户都能够访问到你所转发的端口,从而能够通过你的本地代理访问网络。

本地转发------访问远程设备网络

ssh允许本地设备监听远程设备端口(准确地说,是将远程设备的某些特定端口转发到本地的特定端口)。通过这种方法,你可以在本地访问远程设备的网络服务。

例如,python的http.server (python3)或SimpleHTTPServer (python2)模块可以提供非常简单的http服务,包括文件索引和下载功能。

而且操作异常简单:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

随后打开浏览器,访问http://localhost:8080,就可以看到类似这样的界面:
Directory listing for /

Directory listing for /


这里显示的就是本地~文件夹下的文件和文件夹,单击页面上的文件链接会下载文件。

如果用ssh本地转发连接到远程设备,并在远程设备开启http服务:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
127.0.0.1 - - [24/May/2022 20:58:27] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [24/May/2022 21:01:03] "GET /downloads/ HTTP/1.1" 200 -
^C
Keyboard interrupt received, exiting.
coli@DESKTOP-J45M1NUM:~$ ssh -L 8081:172.28.24.152:8080 salic
yukari@SALICYLIC:~$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

此时打开浏览器访问http://localhost:8081,就可以看到服务器上home文件夹的内容:
Directory listing for /

Directory listing for /


这里显示的是SALICYLIC远程服务器~文件夹下的文件和文件夹,单击页面上的文件链接即可从远程服务器上下载文件。

本地转发在ssh_config中的设置格式为LocalForward 8081 172.28.24.152:8080

sshfs:将远程存储挂载为文件系统

sftp是一种远程文件传输协议,能够利用ssh协议在本地和远程之间拷贝文件。较新的scp命令行程序就利用sftp协议传输文件。

利用命令行程序传输文件通常较为不便,一次只能传输一个完整的文件夹,或者需要单独指定每个文件的路径。

在远程和本地间选择性传输大量文件时,图形化的用户界面能够带来很大的方便。

WinSCP和FileZilla是常用的图形化文件管理工具,支持sftp远程文件传输协议,通常可以满足常规的文件传输需求。

这里我们介绍一种基于WSL和sshfs的、更加原生和易用的解决方案。

WSL是一种在Windows系统中运行Linux程序的方法,其中新版(WSL2)可以运行完整的Linux内核。sshfs是一种文件系统,它借助Linux内核的功能,将远程存储挂载为本地文件系统。结合Windows对WSL文件系统的支持,我们可以Windows的资源管理器下直接访问远程设备存储。

在使用之前,你需要先安装WSL,并确保WSL版本为2。
如果你一定要使用WSL1

不建议在WSL1下使用sshfs

由于sshfs需要用到Linux内核模块FUSE,而WSL1不支持Linux内核,所以WSL1原生不支持sshfs。

尽管你可以通过某些手段进行模拟,但是总的来说效果不佳。

sshfs的安装需要root权限
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ sudo apt install sshfs
[sudo] password for coli:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  sshfs
0 upgraded, 1 newly installed, 0 to remove and 80 not upgraded.
Need to get 43.5 kB of archives.
After this operation, 123 kB of additional disk space will be used.
Get:1 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal/universe amd64 sshfs amd64 3.6.0+repack+really2.10-0ubuntu1 [43.5 kB]
Fetched 43.5 kB in 1s (40.8 kB/s)
Selecting previously unselected package sshfs.
(Reading database ... 52945 files and directories currently installed.)
Preparing to unpack .../sshfs_3.6.0+repack+really2.10-0ubuntu1_amd64.deb ...
Unpacking sshfs (3.6.0+repack+really2.10-0ubuntu1) ...
Setting up sshfs (3.6.0+repack+really2.10-0ubuntu1) ...
Processing triggers for man-db (2.9.1-1) ...
coli@DESKTOP-J45M1NUM:~$ ‎

文件系统的挂载则不需要root权限。例如,如果要将远程设备salic的用户文件夹挂载到本地,只需要在WSL中执行:
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ mkdir ~/mnt
coli@DESKTOP-J45M1NUM:~$ sshfs salic:/home/yukari ~/mnt
coli@DESKTOP-J45M1NUM:~$ df
Filesystem           1K-blocks       Used  Available Use% Mounted on
/dev/sdc             263174212    4278568  245457488   2% /
none                   4031704         32    4031672   1% /mnt/wslg
none                   4031704          4    4031700   1% /mnt/wsl
tools                 83886076   57364804   26521272  69% /init
none                   4029656          0    4029656   0% /dev
none                   4031704          4    4031700   1% /run
none                   4031704          0    4031704   0% /run/lock
none                   4031704          0    4031704   0% /run/shm
none                   4031704          0    4031704   0% /run/user
tmpfs                  4031704          0    4031704   0% /sys/fs/cgroup
drivers               83886076   57364804   26521272  69% /usr/lib/wsl/drivers
lib                   83886076   57364804   26521272  69% /usr/lib/wsl/lib
none                   4031704         76    4031628   1% /mnt/wslg/versions.txt
none                   4031704         76    4031628   1% /mnt/wslg/doc
drvfs                 83886076   57364804   26521272  69% /mnt/c
drvfs                403832828  146119192  257713636  37% /mnt/d
salic:/home/yukari 14290771910 9655851976 4634919934  68% /home/coli/mnt
coli@DESKTOP-J45M1NUM:~$ ls -al ~/mnt
total 52
drwxr-xr-x  1 1003 1003  4096 Dec 28  2021 ./
drwxr-xr-x 14 coli coli  4096 Mar  3 08:43 ../
-rw-------  1 1003 1003  8432 Mar 21 22:20 .bash_history
-rw-r--r--  1 1003 1003   220 Dec 28  2021 .bash_logout
-rw-r--r--  1 1003 1003   807 Dec 28  2021 .bash_profile
drwxr-xr-x  1 1003 1003  4096 Feb 18 15:20 .config/
drwx------  1 1003 1003  4096 Mar 21 20:05 .ssh/
drwxrwxrwx  1 1003 1003  4096 Jan  9 15:30 software/
drwxrwxrwx  1 1003 1003  4096 Mar 15 11:34 data/
coli@DESKTOP-J45M1NUM:~$ ‎

可以看到远程设备上的存储已经被到挂载wsl文件系统的~/mnt[1]下,你可以像本地文件一样编辑、移动或删除其中的文件。

[1]sshfs仅支持将远程存储挂载到wsl文件系统下,不支持挂载到windows文件系统(即wsl中的/mnt/c等)下

但是,你现在还不能从Windows资源管理器中直接访问挂载的文件夹,因为Windows和WSL的用户权限不完全相同。要使Windows资源管理器能够直接访问挂载的文件夹,你还需要在挂载时添加参数-o allow_other
Ubuntu-22.04

复制代码
coli@DESKTOP-J45M1NUM:~$ umount ~/mnt
coli@DESKTOP-J45M1NUM:~$ sshfs -o allow_ohter -o follow_symlinks salic:/home/yukari ~/mnt
fusermount: option allow_other only allowed if 'user_allow_other' is set in /etc/fuse.conf
coli@DESKTOP-J45M1NUM:~$ sudo vi /etc/fuse.conf
# /etc/fuse.conf - Configuration file for Filesystem in Userspace (FUSE)

# Set the maximum number of FUSE mounts allowed to non-root users.
# The default is 1000.
#mount_max = 1000

# Allow non-root users to specify the allow_other or allow_root mount options.
user_allow_other
~
~
~
~
~
~
~
~
~
~
coli@DESKTOP-J45M1NUM:~$ sshfs -o allow_other salic:/home/yukari ~/mnt
coli@DESKTOP-J45M1NUM:~$ ‎

umount ~/mnt用于卸载先前挂载在~/mnt的远程文件夹;

只有在/etc/fuse.conf配置文件中取消注释最后一行#user_allow_other后,普通用户才能够启用-o allow_other选项,该文件的编辑需要root权限。

重新挂载后,你可以通过地址\\wsl.localhost\Ubuntu-22.04\home\coli\mnt在资源管理器中直接访问到远程存储,并像本地文件一样对远程文件进行新建、编辑、移动或删除[1]

[1]要使远程存储中的链接可用,还需要启用-o follow_symlinks选项,否则链接将显示为不可打开的文件而非文件夹。

于是,你就可以在Windows资源管理器内直接完成本地文件和远程文件的交换了。

不仅如此,你还可以直接使用Windows应用打开或编辑\\wsl.localhost\Ubuntu-22.04\home\coli\mnt下的远程文件,或者将文件下载或者保存到该路径,所有更改和创建都会直接应用到远程设备上。

远程数据访问

除了传输文件,ssh进行还可以用来直接传输数据。在本地运行ssh user@host command会在远程设备上执行command命令,并将结果输出到本地的标准输出。根据这一特性,我们可以在Rpython等应用程序中通过ssh命令来读取远程设备上的数据。这样可以避免在本地保留大量临时数据,并省去数据版本校对和同步的麻烦。
Ubuntu-22.04

复制代码
yukari@SALICYLIC:~/mydata$ cat data.csv
Tree,age,circumference
1,118,30
1,484,58
1,664,87
1,1004,115
1,1231,120
1,1372,142
1,1582,145
2,118,33
2,484,69
2,664,111
2,1004,156
2,1231,172
2,1372,203
2,1582,203
3,118,30
3,484,51
3,664,75
3,1004,108
3,1231,115
3,1372,139
3,1582,140
4,118,32
4,484,62
4,664,112
4,1004,167
4,1231,179
4,1372,209
4,1582,214
5,118,30
5,484,49
5,664,81
5,1004,125
5,1231,142
5,1372,174
5,1582,177
yukari@SALICYLIC:~/mydata$ ‎
复制代码
coli@DESKTOP-J45M1NUM:~$ ssh citric head -n 5 ~/mydata/data.csv
Tree,age,circumference
1,118,30
1,484,58
1,664,87
1,1004,115
coli@DESKTOP-J45M1NUM:~$ R --quiet
> library(data.table)
data.table 1.14.3 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
> fread(cmd="ssh citric cat ~/mydata/data.csv")
    Tree  age circumference
 1:    1  118            30
 2:    1  484            58
 3:    1  664            87
 4:    1 1004           115
 5:    1 1231           120
 6:    1 1372           142
 7:    1 1582           145
 8:    2  118            33
 9:    2  484            69
10:    2  664           111
11:    2 1004           156
12:    2 1231           172
13:    2 1372           203
14:    2 1582           203
15:    3  118            30
16:    3  484            51
17:    3  664            75
18:    3 1004           108
19:    3 1231           115
20:    3 1372           139
21:    3 1582           140
22:    4  118            32
23:    4  484            62
24:    4  664           112
25:    4 1004           167
26:    4 1231           179
27:    4 1372           209
28:    4 1582           214
29:    5  118            30
30:    5  484            49
31:    5  664            81
32:    5 1004           125
33:    5 1231           142
34:    5 1372           174
35:    5 1582           177
    Tree  age circumference
> q()squid
Save workspace image? [y/n/c]: n
coli@DESKTOP-J45M1NUM:~$ python
Python 3.9.7 (default, Sep 16 2021, 16:59:08)
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.run(['ssh', 'citric', 'cat ~/mydata/data.csv'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'Tree,age,circumference\n1,118,30\n1,484,58\n1,664,87\n1,1004,115\n1,1231,120\n1,1372,142\n1,1582,145\n2,118,33\n2,484,69\n2,664,111\n2,1004,156\n2,1231,172\n2,1372,203\n2,1582,203\n3,118,30\n3,484,51\n3,664,75\n3,1004,108\n3,1231,115\n3,1372,139\n3,1582,140\n4,118,32\n4,484,62\n4,664,112\n4,1004,167\n4,1231,179\n4,1372,209\n4,1582,214\n5,118,30\n5,484,49\n5,664,81\n5,1004,125\n5,1231,142\n5,1372,174\n5,1582,177\n'
>>> ‎

附录

ssh_config配置参考:~/.ssh/config

复制代码
Host salic
  HostName 172.28.24.152
  User yukari
  IdentityFile ~/.ssh/salic.id_rsa
  RemoteForward 3129 localhost:3128

Host citric
  HostName 172.28.24.104
  User yukari
  ProxyJump salic
  IdentityFile ~/.ssh/citric.id_rsa
  RemoteForward 3129 localhost:3128
  LocalForward 8081 172.28.24.104:8080

Host wsl wsl1.succinic wsl2.succinic
  User coli
  IdentityFile ~/.ssh/coli.id_rsa

Host wsl
  HostName localhost
  Port 2233

Host wsl1.succinic
  HostName 172.28.24.169

Host wsl2.succinic
  HostName localhost
  Port 2233
  HostKeyAlias wsl2.succinic
  ProxyJump wsl1.succinic

该配置文件记录了saliccitric两台远程设备,wsl1.succinicwsl2.succinic两个远程WSL子系统,以及一个本地WSL子系统的ssh配置。

HostKeyAlias的作用是,当HostName冲突(例如同为localhost)时,可以将其指定为两个不同的名称,避免指纹冲突。