我目前正在运行一堆:

sudo ssh -L PORT:IP:PORT root@IP

其中IP是安全机器的目标,PORT表示我正在转发的端口。

这是因为我使用了很多应用程序,没有这个转发我就无法访问。执行此操作后,我可以通过localhost:PORT进行访问。

现在的主要问题是,我实际上有4个这样的端口,我必须转发。

我的解决方案是打开4个shell,不断地向后搜索我的历史记录,以查找需要转发的端口,然后在每个shell中运行这个命令(必须填写密码等)。

要是我能做些什么就好了:

sudo ssh -L PORT1+PORT2+PORT+3:IP:PORT+PORT2+PORT3 root@IP

那已经很有帮助了。

有什么方法能让这一切变得更容易吗?


-L选项可以在同一个命令中指定多次。每次都有不同的端口。例如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

,在22号端口上连接REMOTE_IP_1

和类似的

ssh localhost -p 9922

,在22号端口上连接REMOTE_IP_2

当然,如果您有许多不同的主机/端口要转发或转发到某些特定的主机/端口,那么没有什么可以阻止您将其包装到一个脚本中或将其自动化。


您可以使用以下bash函数(只需将其添加到~/.bashrc):

function pfwd {
  for i in ${@:2}
  do
    echo Forwarding port $i
    ssh -N -L $i:localhost:$i $1 &
  done  
}

使用的例子:

pfwd hostname {6000..6009}

Jbchichoko和yuval给出了可行的解决方案。但是jbchichoko的答案作为一个函数并不是一个灵活的答案,yuval的答案所打开的隧道不能被ctrl+c关闭,因为它在后台运行。下面我给出了解决这两个缺陷的解决方案:

在~/中定义函数。Bashrc或~/.zshrc:

# fsshmap multiple ports
function fsshmap() {
  echo -n "-L 1$1:127.0.0.1:$1 " > $HOME/sh/sshports.txt
  for ((i=($1+1);i<$2;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 "$3" "$line
  echo $cline
  eval $cline
}

运行函数的例子:

fsshmap 6000 6010 hostname

本例的结果:

您可以访问127.0.0.1:16000~16009,与主机名:6000~6009相同


我开发了loco来帮助ssh转发。它可以用于共享端口5000和7000在远程本地相同的端口:

pip install loco

loco listen SSHINFO -r 5000 -r 7000

使用端口转发登录到服务器的好处之一是方便使用Jupyter Notebook。这个链接提供了如何使用它的极好描述。在这里,我想做一些总结和拓展,供大家参考。

情况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/在主机- b上进行工作,但在主机- 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可以是除常见端口号外的随机数。在情况1中,port_A和port_B可以相同,以简化过程。


对于通过同一主机转发多个端口的人,可以在~/.ssh/config中设置类似的东西

主机all-port-forwards 主机名10.122.0.3 用户的用户名 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全端口转发。


你可以使用这个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 "$1" "$a[@]"
}

例子:

ashL db@114.39.161.24 6480 7690 7477

ashL db@114.39.161.24 {6000..6050} #转发整个范围这只是shell语法糖。


如果你想要一个简单的解决方案,在后台运行,很容易杀死-使用控制套接字

# start
$ ssh -f -N -M -S $SOCKET -L localhost:9200:localhost:9200 $HOST
# stop
$ ssh -S $SOCKET -O exit $HOST

这是一个受到尤瓦尔·阿兹蒙启发的解决方案。

与最初的解决方案相比,它有一些好处:

首先,它创建一个单独的后台进程,而不是每个端口一个进程 它生成别名,允许您终止隧道 它只绑定到127.0.0.1,这更安全一些

你可以这样使用它:

你的电话。 tnl your.remote.com (124,1235) 你的地址。

最后用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 $1"
  $TUNNEL &
  PID=$!
  alias tnlkill="kill $PID && unalias tnlkill"
}

在我的公司,我和我的团队成员都需要访问一个不可达的“目标”服务器的3个端口,所以我创建了一个从可达服务器到目标服务器的永久隧道(这是一个可以无限期在后台运行的隧道,参见params -f和-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端口转发,它们是独立的==避免单点故障 缺点:每个SSH端口转发是分开分叉的,在某种程度上效率不高


其次,可以使用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服务器。

优点:单叉==高效 通过关闭这个进程(ssh),所有转发都被关闭==单点故障


另一种方法是使用-D标志告诉ssh作为SOCKS代理工作。

这样,只要客户端应用程序能够通过SOCKS代理(或使用类似socksify的东西),您就能够连接到通过ssh服务器访问的任何远程网络地址/端口。


另一个我在debian上使用的内衬:

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")