ssh -L 转发多个端口
ssh -L forward multiple ports
我目前正在 运行宁一堆:
sudo ssh -L PORT:IP:PORT root@IP
其中 IP 是安全机器的目标,PORT 代表我转发的端口。
这是因为我使用了很多没有此转发就无法访问的应用程序。执行此操作后,我可以通过 localhost:PORT
.
访问
现在主要问题出现了,我实际上有 4 个端口需要转发。
我的解决方案是打开 4 shells 并不断向后搜索我的历史记录以查找需要转发的确切端口等,然后 运行 这个命令 - 每个 shell(必须填写密码等)。
如果我能做这样的事情就好了:
sudo ssh -L PORT1+PORT2+PORT+3:IP:PORT+PORT2+PORT3 root@IP
那么这已经很有帮助了。
有没有办法让它更容易做到这一点?
-L
选项可以在同一命令中指定多次。每次都有不同的端口。 IE。 ssh -L localPort0:ip:remotePort0 -L localPort1:ip:remotePort1 ...
正是 NaN 回答的内容,您指定了多个 -L 参数。我一直这样做。下面是一个多端口转发的例子:
ssh remote-host -L 8822:REMOTE_IP_1:22 -L 9922:REMOTE_IP_2:22
注意:如果不指定localhost
,则与 -L localhost:8822:REMOTE_IP_1:22
相同。
有了这个,你现在可以(从另一个终端)做:
ssh localhost -p 8822
连接到 REMOTE_IP_1
端口 22
同样
ssh localhost -p 9922
连接到 REMOTE_IP_2
端口 22
当然,如果您有许多不同的 host/ports 要转发和转发给某些特定的人,没有什么能阻止您将其包装到脚本中或自动化它。
希望这对您有所帮助。
您可以使用以下 bash 函数(只需将其添加到您的 ~/.bashrc
):
function pfwd {
for i in ${@:2}
do
echo Forwarding port $i
ssh -N -L $i:localhost:$i &
done
}
用法示例:
pfwd hostname {6000..6009}
jbchichoko和yuval给出了可行的方案。但是 jbchichoko 的答案并不是一个灵活的函数答案,yuval 的答案打开的隧道不能被 ctrl+c
关闭,因为它在后台运行。我在下面给出解决这两个缺陷的解决方案:
在 ~/.bashrc
或 ~/.zshrc
中定义函数:
# fsshmap multiple ports
function fsshmap() {
echo -n "-L 1:127.0.0.1: " > $HOME/sh/sshports.txt
for ((i=(+1);i<;i++))
do
echo -n "-L 1$i:127.0.0.1:$i " >> $HOME/sh/sshports.txt
done
line=$(head -n 1 $HOME/sh/sshports.txt)
cline="ssh "" "$line
echo $cline
eval $cline
}
运行函数的一个例子:
fsshmap 6000 6010 hostname
这个例子的结果:
您可以像 hostname:6000~6009
一样访问 127.0.0.1:16000~16009
我开发了 loco 来帮助进行 ssh 转发。它可用于在相同端口的远程本地共享端口 5000 和 7000:
pip install loco
loco listen SSHINFO -r 5000 -r 7000
使用端口转发登录服务器的好处之一是便于使用 Jupyter Notebook。这个 link 提供了关于如何做到这一点的精彩描述。在这里我想做一些总结和扩展,供大家参考。
情况 1. 从名为 Host-A 的本地计算机(例如您自己的笔记本电脑)登录到名为 Host-B.
的远程工作计算机
ssh user@Host-B -L port_A:localhost:port_B
jupyter notebook --NotebookApp.token='' --no-browser --port=port_B
然后您可以打开浏览器并输入:http://localhost:port_A/ 在 Host-B 上完成您的工作,但会在 Host-A.
中看到它
情况 2. 从名为 Host-A 的本地计算机(例如您自己的笔记本电脑)登录到名为 Host-B 的远程登录计算机,然后从那里登录到名为 Host-C 的远程工作计算机].这通常是大学内大多数分析服务器的情况,可以通过使用两个 ssh -L
与 -t
连接来实现。
ssh -L port_A:localhost:port_B user@Host-B -t ssh -L port_B:localhost:port_C user@Host-C
jupyter notebook --NotebookApp.token='' --no-browser --port=port_C
然后您可以打开浏览器并输入:http://localhost:port_A/ 在 Host-C 上完成您的工作,但会在 Host-A.
中看到它
情况 3. 从名为 Host-A 的本地计算机(例如您自己的笔记本电脑)登录到名为 Host-B 的远程登录计算机,然后从那里登录到名为 Host-C 的远程工作计算机] 最后登录远程工作机器Host-D。通常情况并非如此,但有时可能会发生。它是情况 2 的扩展,相同的逻辑可以应用于更多机器。
ssh -L port_A:localhost:port_B user@Host-B -t ssh -L port_B:localhost:port_C user@Host-C -t ssh -L port_C:localhost:port_D user@Host-D
jupyter notebook --NotebookApp.token='' --no-browser --port=port_D
然后您可以打开浏览器并输入:http://localhost:port_A/ 以在 Host-D 上完成您的工作,但会在 Host-A.
中看到它
注意port_A、port_B、port_C、port_D可以是随机数,除了here列出的常用端口号。情况1中,port_A和port_B可以相同,以简化程序。
对于通过 同一主机转发多个端口的人 可以在他们的 ~/ .ssh/config
Host all-port-forwards
Hostname 10.122.0.3
User username
LocalForward PORT_1 IP:PORT_1
LocalForward PORT_2 IP:PORT_2
LocalForward PORT_3 IP:PORT_3
LocalForward PORT_4 IP:PORT_4
它变得简单 ssh all-port-forwards
了。
您可以使用此 zsh 功能(可能也适用于 bash)(将其放入 ~/.zshrc
):
ashL () {
local a=() i
for i in "$@[2,-1]"
do
a+=(-L "${i}:localhost:${i}")
done
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NT "" "$a[@]"
}
示例:
ashL db@114.39.161.24 6480 7690 7477
ashL db@114.39.161.24 {6000..6050} # Forwards the whole range. This is simply shell syntax sugar.
如果您想要一个在后台运行且易于终止的简单解决方案 - 使用控制套接字
# start
$ ssh -f -N -M -S $SOCKET -L localhost:9200:localhost:9200 $HOST
# stop
$ ssh -S $SOCKET -O exit $HOST
这是一个灵感来自 Yuval Atzmon 的解决方案。
它比最初的解决方案有一些好处:
- 首先它创建一个后台进程,而不是每个端口一个
- 它生成允许您关闭隧道的别名
- 它只绑定到 127.0.0.1 更安全
您可以将其用作:
- tnl your.remote.com 1234
- tnl your.remote.com {1234,1235}
- tnl your.remote.com {1234..1236}
最后用tnlkill
杀死他们。
function tnl {
TUNNEL="ssh -N "
echo Port forwarding for ports:
for i in ${@:2}
do
echo " - $i"
TUNNEL="$TUNNEL -L 127.0.0.1:$i:localhost:$i"
done
TUNNEL="$TUNNEL "
$TUNNEL &
PID=$!
alias tnlkill="kill $PID && unalias tnlkill"
}
在我的公司,我和我的团队成员都需要访问无法访问的“目标”服务器的 3 个端口,因此我创建了一个 永久隧道 (这是一个隧道可以 运行 在后台 无限期地,请参阅参数 -f
and -N
) 从可访问的服务器到目标服务器。在我执行的可达服务器的命令行上:
ssh root@reachableIP -f -N -L *:8822:targetIP:22 -L *:9006:targetIP:9006 -L *:9100:targetIP:9100
我使用的是用户 root
,但您自己的用户也可以。您将必须输入所选用户的密码(即使您已经与该用户连接到可访问的服务器)。
现在可访问机器的端口 8822 对应于目标机器的端口 22(对于 ssh/PuTTY/WinSCP)并且可访问机器上的端口 9006 和 9100 对应于目标机器的相同端口(它们承载两个以我为例的 Web 服务)。
首先 可以通过xargs -P 0
.
使用并行执行来完成
创建用于绑定端口的文件,例如
localhost:8080:localhost:8080
localhost:9090:localhost:8080
然后运行
xargs -P 0 -I xxx ssh -vNTCL xxx <REMOTE> < port-forward
或者你可以做一个单行
echo localhost:{8080,9090} | tr ' ' '\n' | sed 's/.*/&:&/' | xargs -P 0 -I xxx ssh -vNTCL xxx <REMOTE>
pros独立的ssh端口转发,它们是独立的==避免单点故障
cons 每个 ssh 端口转发都是单独分叉的,不知何故效率不高
second 可以使用 bash
中的 大括号扩展 功能来完成
echo "ssh -vNTC $(echo localhost:{10,20,30,40,50} | perl -lpe 's/[^ ]+/-L $&:$&/g') <REMOTE>"
# output
ssh -vNTC -L localhost:10:localhost:10 -L localhost:20:localhost:20 -L localhost:30:localhost:30 -L localhost:40:localhost:40 -L localhost:50:localhost:50 <REMOTE>
实例
echo "-vNTC $(echo localhost:{8080,9090} | perl -lpe 's/[^ ]+/-L $&:$&/g') gitlab" | xargs ssh
转发8080
和9090
到gitlab服务器。
优点 一个叉 == 高效
cons关闭这个进程(ssh
)所有转发都关闭==单点故障
另一种方法是使用 -D
标志告诉 ssh
作为 SOCKS 代理工作。
只要客户端应用程序能够通过 SOCKS 代理(或使用诸如 socksify
).
我使用并在 debian 上工作的另一个 liner:
ssh user@192.168.1.10 $(for j in $(seq 20000 1 20100 ) ; do echo " -L$j:127.0.0.1:$j " ; done | tr -d "\n")
我目前正在 运行宁一堆:
sudo ssh -L PORT:IP:PORT root@IP
其中 IP 是安全机器的目标,PORT 代表我转发的端口。
这是因为我使用了很多没有此转发就无法访问的应用程序。执行此操作后,我可以通过 localhost:PORT
.
现在主要问题出现了,我实际上有 4 个端口需要转发。
我的解决方案是打开 4 shells 并不断向后搜索我的历史记录以查找需要转发的确切端口等,然后 运行 这个命令 - 每个 shell(必须填写密码等)。
如果我能做这样的事情就好了:
sudo ssh -L PORT1+PORT2+PORT+3:IP:PORT+PORT2+PORT3 root@IP
那么这已经很有帮助了。
有没有办法让它更容易做到这一点?
-L
选项可以在同一命令中指定多次。每次都有不同的端口。 IE。 ssh -L localPort0:ip:remotePort0 -L localPort1:ip:remotePort1 ...
正是 NaN 回答的内容,您指定了多个 -L 参数。我一直这样做。下面是一个多端口转发的例子:
ssh remote-host -L 8822:REMOTE_IP_1:22 -L 9922:REMOTE_IP_2:22
注意:如果不指定localhost
,则与 -L localhost:8822:REMOTE_IP_1:22
相同。
有了这个,你现在可以(从另一个终端)做:
ssh localhost -p 8822
连接到 REMOTE_IP_1
端口 22
同样
ssh localhost -p 9922
连接到 REMOTE_IP_2
端口 22
当然,如果您有许多不同的 host/ports 要转发和转发给某些特定的人,没有什么能阻止您将其包装到脚本中或自动化它。
希望这对您有所帮助。
您可以使用以下 bash 函数(只需将其添加到您的 ~/.bashrc
):
function pfwd {
for i in ${@:2}
do
echo Forwarding port $i
ssh -N -L $i:localhost:$i &
done
}
用法示例:
pfwd hostname {6000..6009}
jbchichoko和yuval给出了可行的方案。但是 jbchichoko 的答案并不是一个灵活的函数答案,yuval 的答案打开的隧道不能被 ctrl+c
关闭,因为它在后台运行。我在下面给出解决这两个缺陷的解决方案:
在 ~/.bashrc
或 ~/.zshrc
中定义函数:
# fsshmap multiple ports
function fsshmap() {
echo -n "-L 1:127.0.0.1: " > $HOME/sh/sshports.txt
for ((i=(+1);i<;i++))
do
echo -n "-L 1$i:127.0.0.1:$i " >> $HOME/sh/sshports.txt
done
line=$(head -n 1 $HOME/sh/sshports.txt)
cline="ssh "" "$line
echo $cline
eval $cline
}
运行函数的一个例子:
fsshmap 6000 6010 hostname
这个例子的结果:
您可以像 hostname:6000~6009
127.0.0.1:16000~16009
我开发了 loco 来帮助进行 ssh 转发。它可用于在相同端口的远程本地共享端口 5000 和 7000:
pip install loco
loco listen SSHINFO -r 5000 -r 7000
使用端口转发登录服务器的好处之一是便于使用 Jupyter Notebook。这个 link 提供了关于如何做到这一点的精彩描述。在这里我想做一些总结和扩展,供大家参考。
情况 1. 从名为 Host-A 的本地计算机(例如您自己的笔记本电脑)登录到名为 Host-B.
的远程工作计算机ssh user@Host-B -L port_A:localhost:port_B
jupyter notebook --NotebookApp.token='' --no-browser --port=port_B
然后您可以打开浏览器并输入:http://localhost:port_A/ 在 Host-B 上完成您的工作,但会在 Host-A.
中看到它情况 2. 从名为 Host-A 的本地计算机(例如您自己的笔记本电脑)登录到名为 Host-B 的远程登录计算机,然后从那里登录到名为 Host-C 的远程工作计算机].这通常是大学内大多数分析服务器的情况,可以通过使用两个 ssh -L
与 -t
连接来实现。
ssh -L port_A:localhost:port_B user@Host-B -t ssh -L port_B:localhost:port_C user@Host-C
jupyter notebook --NotebookApp.token='' --no-browser --port=port_C
然后您可以打开浏览器并输入:http://localhost:port_A/ 在 Host-C 上完成您的工作,但会在 Host-A.
中看到它情况 3. 从名为 Host-A 的本地计算机(例如您自己的笔记本电脑)登录到名为 Host-B 的远程登录计算机,然后从那里登录到名为 Host-C 的远程工作计算机] 最后登录远程工作机器Host-D。通常情况并非如此,但有时可能会发生。它是情况 2 的扩展,相同的逻辑可以应用于更多机器。
ssh -L port_A:localhost:port_B user@Host-B -t ssh -L port_B:localhost:port_C user@Host-C -t ssh -L port_C:localhost:port_D user@Host-D
jupyter notebook --NotebookApp.token='' --no-browser --port=port_D
然后您可以打开浏览器并输入:http://localhost:port_A/ 以在 Host-D 上完成您的工作,但会在 Host-A.
中看到它注意port_A、port_B、port_C、port_D可以是随机数,除了here列出的常用端口号。情况1中,port_A和port_B可以相同,以简化程序。
对于通过 同一主机转发多个端口的人 可以在他们的 ~/ .ssh/config
Host all-port-forwards
Hostname 10.122.0.3
User username
LocalForward PORT_1 IP:PORT_1
LocalForward PORT_2 IP:PORT_2
LocalForward PORT_3 IP:PORT_3
LocalForward PORT_4 IP:PORT_4
它变得简单 ssh all-port-forwards
了。
您可以使用此 zsh 功能(可能也适用于 bash)(将其放入 ~/.zshrc
):
ashL () {
local a=() i
for i in "$@[2,-1]"
do
a+=(-L "${i}:localhost:${i}")
done
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NT "" "$a[@]"
}
示例:
ashL db@114.39.161.24 6480 7690 7477
ashL db@114.39.161.24 {6000..6050} # Forwards the whole range. This is simply shell syntax sugar.
如果您想要一个在后台运行且易于终止的简单解决方案 - 使用控制套接字
# start
$ ssh -f -N -M -S $SOCKET -L localhost:9200:localhost:9200 $HOST
# stop
$ ssh -S $SOCKET -O exit $HOST
这是一个灵感来自 Yuval Atzmon 的解决方案。
它比最初的解决方案有一些好处:
- 首先它创建一个后台进程,而不是每个端口一个
- 它生成允许您关闭隧道的别名
- 它只绑定到 127.0.0.1 更安全
您可以将其用作:
- tnl your.remote.com 1234
- tnl your.remote.com {1234,1235}
- tnl your.remote.com {1234..1236}
最后用tnlkill
杀死他们。
function tnl {
TUNNEL="ssh -N "
echo Port forwarding for ports:
for i in ${@:2}
do
echo " - $i"
TUNNEL="$TUNNEL -L 127.0.0.1:$i:localhost:$i"
done
TUNNEL="$TUNNEL "
$TUNNEL &
PID=$!
alias tnlkill="kill $PID && unalias tnlkill"
}
在我的公司,我和我的团队成员都需要访问无法访问的“目标”服务器的 3 个端口,因此我创建了一个 永久隧道 (这是一个隧道可以 运行 在后台 无限期地,请参阅参数 -f
and -N
) 从可访问的服务器到目标服务器。在我执行的可达服务器的命令行上:
ssh root@reachableIP -f -N -L *:8822:targetIP:22 -L *:9006:targetIP:9006 -L *:9100:targetIP:9100
我使用的是用户 root
,但您自己的用户也可以。您将必须输入所选用户的密码(即使您已经与该用户连接到可访问的服务器)。
现在可访问机器的端口 8822 对应于目标机器的端口 22(对于 ssh/PuTTY/WinSCP)并且可访问机器上的端口 9006 和 9100 对应于目标机器的相同端口(它们承载两个以我为例的 Web 服务)。
首先 可以通过xargs -P 0
.
创建用于绑定端口的文件,例如
localhost:8080:localhost:8080
localhost:9090:localhost:8080
然后运行
xargs -P 0 -I xxx ssh -vNTCL xxx <REMOTE> < port-forward
或者你可以做一个单行
echo localhost:{8080,9090} | tr ' ' '\n' | sed 's/.*/&:&/' | xargs -P 0 -I xxx ssh -vNTCL xxx <REMOTE>
pros独立的ssh端口转发,它们是独立的==避免单点故障
cons 每个 ssh 端口转发都是单独分叉的,不知何故效率不高
second 可以使用 bash
中的 大括号扩展 功能来完成echo "ssh -vNTC $(echo localhost:{10,20,30,40,50} | perl -lpe 's/[^ ]+/-L $&:$&/g') <REMOTE>"
# output
ssh -vNTC -L localhost:10:localhost:10 -L localhost:20:localhost:20 -L localhost:30:localhost:30 -L localhost:40:localhost:40 -L localhost:50:localhost:50 <REMOTE>
实例
echo "-vNTC $(echo localhost:{8080,9090} | perl -lpe 's/[^ ]+/-L $&:$&/g') gitlab" | xargs ssh
转发8080
和9090
到gitlab服务器。
优点 一个叉 == 高效
cons关闭这个进程(ssh
)所有转发都关闭==单点故障
另一种方法是使用 -D
标志告诉 ssh
作为 SOCKS 代理工作。
只要客户端应用程序能够通过 SOCKS 代理(或使用诸如 socksify
).
我使用并在 debian 上工作的另一个 liner:
ssh user@192.168.1.10 $(for j in $(seq 20000 1 20100 ) ; do echo " -L$j:127.0.0.1:$j " ; done | tr -d "\n")