SSH 命令的三种代理功能(-L/-R/-D)

ssh 命令除了登陆外还有三种代理功能:

  • 正向代理(-L):相当于 iptable 的 port forwarding
  • 反向代理(-R):相当于 frp 或者 ngrok
  • socks5 代理(-D):相当于 ss/ssr

如要长期高效的服务,应使用对应的专用软件。如没法安装软件,比如当你处在限制环境下想要访问下某个不可达到的目标,或者某个临时需求,那么 ssh 就是你的兜底方案。

正向代理:

所谓 “正向代理” 就是在本地启动端口,把本地端口数据转发到远端。

用法1:远程端口映射到其他机器

HostB 上启动一个 PortB 端口,映射到 HostC:PortC 上,在 HostB 上运行:

HostB$ ssh -L 0.0.0.0:PortB:HostC:PortC user@HostC

这时访问 HostB:PortB 相当于访问 HostC:PortC(和 iptable 的 port-forwarding 类似)。

用法2:本地端口通过跳板映射到其他机器

HostA 上启动一个 PortA 端口,通过 HostB 转发到 HostC:PortC上,在 HostA 上运行:

HostA$ ssh -L 0.0.0.0:PortA:HostC:PortC  user@HostB

这时访问 HostA:PortA 相当于访问 HostC:PortC。

两种用法的区别是,第一种用法本地到跳板机 HostB 的数据是明文的,而第二种用法一般本地就是 HostA,访问本地的 PortA,数据被 ssh 加密传输给 HostB 又转发给 HostC:PortC。

反向代理:

所谓“反向代理”就是让远端启动端口,把远端端口数据转发到本地。

HostA 将自己可以访问的 HostB:PortB 暴露给外网服务器 HostC:PortC,在 HostA 上运行:

HostA$ ssh -R HostC:PortC:HostB:PortB  user@HostC

那么链接 HostC:PortC 就相当于链接 HostB:PortB。使用时需修改 HostC 的 /etc/ssh/sshd_config,添加:

GatewayPorts yes

相当于内网穿透,比如 HostA 和 HostB 是同一个内网下的两台可以互相访问的机器,HostC是外网跳板机,HostC不能访问 HostA,但是 HostA 可以访问 HostC。

那么通过在内网 HostA 上运行 ssh -R 告诉 HostC,创建 PortC 端口监听,把该端口所有数据转发给我(HostA),我会再转发给同一个内网下的 HostB:PortB。

同内网下的 HostA/HostB 也可以是同一台机器,换句话说就是内网 HostA 把自己可以访问的端口暴露给了外网 HostC

按照前文《内网穿透:在公网访问你家的 NAS》中,相当于再 HostA 上启动了 frpc,而再 HostC 上启动了 frps。

本地 socks5 代理

在 HostA 的本地 1080 端口启动一个 socks5 服务,通过本地 socks5 代理的数据会通过 ssh 链接先发送给 HostB,再从 HostB 转发送给远程主机:

HostA$ ssh -D localhost:1080  HostB

那么在 HostA 上面,浏览器配置 socks5 代理为 127.0.0.1:1080,看网页时就能把数据通过 HostB 代理出去,类似 ss/ssr 版本,只不过用 ssh 来实现。

使用优化

为了更好用一点,ssh 后面还可以加上:-CqTnN 参数,比如:

$ ssh -CqTnN -L 0.0.0.0:PortA:HostC:PortC  user@HostB

其中 -C 为压缩数据,-q 安静模式,-T 禁止远程分配终端,-n 关闭标准输入,-N 不执行远程命令。此外视需要还可以增加 -f 参数,把 ssh 放到后台运行。

这些 ssh 代理没有短线重连功能,链接断了命令就退出了,所以需要些脚本监控重启,或者使用 autossh 之类的工具保持链接。

功能对比

正向代理(-L)的第一种用法可以用 iptable 的 port-forwarding 模拟,iptable 性能更好,但是需要 root 权限,ssh -L 性能不好,但是正向代理花样更多些。反向代理(-R)一般就作为没有安装 frp/ngrok/shootback 时候的一种代替,但是数据传输的性能和稳定性当然 frp 这些专用软件更好。

socks5 代理(-D)其实是可以代替 ss/ssr 的,区别和上面类似。所以要长久使用,推荐安装对应软件,临时用一下 ssh 挺顺手。

补充下 iptable 的 port-forwarding 怎么设置,十分管用的功能,两个函数即可:

#! /bin/sh

# create forward rule by source interface
# http://serverfault.com/questions/532569/how-to-do-port-forwarding-redirecting-on-debian
PortForward1() {
    local IN_IF=$1
    local IN_PORT=$2
    local OUT_IP=$3
    local OUT_PORT=$4
    local IPTBL="/sbin/iptables"
    echo "1" > /proc/sys/net/ipv4/ip_forward
    $IPTBL -A PREROUTING -t nat -i $IN_IF -p tcp --dport $IN_PORT -j DNAT --to-destination ${OUT_IP}:${OUT_PORT}
    $IPTBL -A FORWARD -p tcp -d $OUT_IP --dport $OUT_PORT -j ACCEPT
    $IPTBL -A POSTROUTING -t nat -j MASQUERADE
}

# create forward rule by source ip
# http://blog.youkuaiyun.com/zzhongcy/article/details/42738285
ForwardPort2() {
    local IN_IP=$1
    local IN_PORT=$2
    local OUT_IP=$3
    local OUT_PORT=$4
    local IPTBL="/sbin/iptables"
    echo "1" > /proc/sys/net/ipv4/ip_forward
    $IPTBL -t nat -A PREROUTING --dst $IN_IP -p tcp --dport $IN_PORT -j DNAT --to-destination ${OUT_IP}:${OUT_PORT}
    $IPTBL -t nat -A POSTROUTING --dst $OUT_IP -p tcp --dport $OUT_PORT -j SNAT --to-source $IN_IP
}

第一个函数是按照网卡名称设置转发:

PortForward1 eth1 8765 202.115.8.2 8765

这时,本地 eth1 网卡的 8765 端口就会被转发给 202.115.8.2 的 8765 端口。

第二个函数是按照本机的 ip 地址,比如本机是 192.168.1.2:

PortForward2 192.168.1.2 8765 202.115.8.2 8765

那么任何访问本机 192.168.1.2 这个地址 8765 端口,都会被转发到 202.115.8.2:8765

这个 iptable 的 port forwarding 是内核层运行的,性能极好,只不过每次重启都需要重新设置下。

<think>我们正在排查Jenkins通过SSH执行Java命令时提示'Unable to access jarfile remoting.jar'的问题。根据用户提供的上下文和引用内容,我们可以从以下几个方面进行排查: ### 1. **检查文件路径是否正确** - **问题描述**:Jenkins在执行命令时可能不在预期的目录下,导致相对路径`remoting.jar`无法找到。 - **引用支持**:引用[3]中提到,将jar包的路径改为绝对路径后问题解决。 - **排查步骤**: - 确认Jenkins节点的工作目录(workDir)设置正确。在Jenkins节点配置中,查看“远程工作目录”设置。 - 在启动命令中,使用绝对路径指定`remoting.jar`的位置,例如: ```bash java -jar /path/to/remoting.jar ``` - 或者,在命令中先切换到包含`remoting.jar`的目录,再执行: ```bash cd /correct/path && java -jar remoting.jar ``` ### 2. **检查文件是否存在** - **问题描述**:`remoting.jar`文件可能没有正确部署到目标机器上。 - **排查步骤**: - 通过SSH登录到目标机器(Jenkins节点),检查`remoting.jar`是否存在于预期目录中。 ```bash ls /path/to/remoting.jar ``` - 如果文件不存在,需要确保Jenkins在启动代理时能够自动下载该文件,或者手动上传。 ### 3. **检查Java环境** - **问题描述**:目标机器上可能没有安装Java,或者Java路径配置不正确。 - **引用支持**:引用[2]中显示,Jenkins在检查Java版本时失败,提示`No such file or directory`,并建议安装Java 8或Java 11。 - **排查步骤**: - 在目标机器上检查Java是否安装: ```bash java -version ``` - 如果未安装,请安装Java 8或Java 11(根据Jenkins要求)。 - 如果已安装,确保Java可执行文件的路径正确,并且在Jenkins节点配置中指定了正确的Java路径(如果有必要)。 ### 4. **检查文件权限** - **问题描述**:运行Jenkins代理进程的用户可能没有权限读取`remoting.jar`文件。 - **排查步骤**: - 在目标机器上检查文件权限: ```bash ls -l /path/to/remoting.jar ``` - 确保运行命令的用户(例如,Jenkins进程使用的用户)有读取权限。如果没有,使用以下命令添加读取权限: ```bash chmod +r /path/to/remoting.jar ``` ### 5. **检查工作目录(workDir)设置** - **问题描述**:Jenkins在启动代理时可能会设置一个工作目录,但命令执行时可能没有正确切换到这个目录。 - **引用支持**:用户提供的命令中包含了`-workDir D:\testtest`参数,但执行的是`cd "D:\testtest" && java -jar remoting.jar ...`。如果`D:\testtest`不存在,或者cd命令失败,会导致后续命令找不到文件。 - **排查步骤**: - 确保`-workDir`指定的目录在目标机器上存在,并且有正确的权限。 - 检查Jenkins日志,确认`cd`命令是否成功执行。 ### 6. **使用绝对路径替代相对路径** - **解决方案**:为了避免工作目录切换失败导致的问题,建议直接使用绝对路径指定`remoting.jar`,如引用[3]所述: ```bash java -jar /absolute/path/to/remoting.jar -workDir /absolute/path/to/workdir ... ``` ### 总结步骤 1. **登录目标机器**,确认`remoting.jar`文件存在且路径正确。 2. **检查Java环境**,确保已安装且版本符合要求(Java 8或11)。 3. **检查文件权限**,确保运行用户有读取权限。 4. **修改Jenkins节点启动命令**,使用绝对路径指定`remoting.jar`。 5. **检查工作目录**是否存在,并确保有写入权限(因为Jenkins代理需要写入日志等)。 ### 示例命令修改 原始命令: ```bash cd "D:\testtest" && java -jar remoting.jar -workDir D:\testtest ... ``` 修改为(使用绝对路径): ```bash java -jar "D:\testtest\remoting.jar" -workDir "D:\testtest" ``` 这样即使cd命令失败,也能找到jar文件。 ### 引用说明 - 引用[3]提供了类似问题的解决方案:使用绝对路径指定jar文件[^3]。 - 引用[2]提醒我们检查Java环境是否正确安装[^2]。 §§相关问题§§ 1. Jenkins节点如何配置Java路径? 2. 如何在Jenkins中设置节点的远程工作目录? 3. 如何通过SSH在目标机器上部署remoting.jar文件? 4. Jenkins代理启动时常见问题有哪些?</think>### 全面排查 Jenkins SSH 执行 `java -jar remoting.jar` 报错 "Unable to access jarfile remoting.jar" 根据引用内容和 Jenkins 特性,以下是系统化排查步骤: --- #### 1. **验证文件存在性**(首要检查) - **登录目标节点**执行: ```bash ls -l /path/to/remoting.jar # Linux dir D:\testtest\remoting.jar # Windows ``` - **关键点**: - 确认文件存在于 `-workDir` 指定目录(如 `D:\testtest`) - 检查文件大小 > 0(空文件会导致此错误) - **解决方案**: - 手动上传缺失的 jar 文件 - 或修改 Jenkins 节点配置使用绝对路径(引用[3]已验证有效)[^3] --- #### 2. **检查工作目录切换**(Jenkins 常见问题) ```bash # 原始问题命令 cd "D:\testtest" && java -jar remoting.jar ... ``` - **排查步骤**: 1. 在节点上测试目录切换: ```bash cd "D:\testtest" && pwd ``` 2. 检查目录权限: ```bash ls -ld "D:\testtest" # Linux icacls "D:\testtest" # Windows ``` - **典型问题**: - 目录路径包含空格未正确转义 - Jenkins 服务账户无权访问目录(如 Windows 的 SYSTEM 账户) --- #### 3. **Java 环境验证**(引用[2]相关) ```bash # 在节点上执行 /usr/local/java/bin/java -version # 检查路径是否正确 echo $JAVA_HOME # 检查环境变量 ``` - **错误特征**: ```log bash: /usr/local/java/bin/java: No such file or directory Install Java 8 or Java 11 on the Agent [^2] ``` - **解决方案**: - 在节点上安装正确版本的 Java(8 或 11) - 在 Jenkins 节点配置中指定 `JAVA_HOME` 路径 --- #### 4. **路径格式问题**(Windows 特别注意) - **问题命令**: ```cmd -workDir D:\testtest # 无引号 ``` - **修复方案**: ```cmd -workDir "D:\testtest" # 添加双引号 ``` - **原因**:Windows 路径包含空格或特殊字符时需引号包裹 --- #### 5. **Jar 文件权限检查** ```bash # Linux 节点 ls -l remoting.jar chmod +r remoting.jar # 添加读取权限 # Windows 节点 icacls remoting.jar /grant "Jenkins_User":(R) ``` --- #### 6. **Jenkins 配置检查** 在 Jenkins 节点配置界面: 1. **Remote root directory** → 确认与 `-workDir` 一致 2. **Launch method** → 选择 _"Launch agent via Java Web Start"_ 测试 3. **Advanced** → 指定 `JAVA_HOME` 绝对路径 --- ### 终极解决方案 修改启动命令为 **绝对路径引用**(引用[3]方案)[^3]: ```bash # 原始问题命令(相对路径) cd "D:\testtest" && java -jar remoting.jar ... # 修复后命令(绝对路径) java -jar "D:\testtest\remoting.jar" -workDir "D:\testtest" ... ``` --- ### 排查流程图 ```mermaid graph TD A[报错 Unable to access jarfile] --> B{文件是否存在?} B -->|否| C[手动上传 jar 文件] B -->|是| D{工作目录权限?} D -->|无权限| E[修改目录权限] D -->|正常| F{Java 环境?} F -->|未安装| G[安装 Java 8/11] F -->|路径错误| H[配置 JAVA_HOME] F -->|正常| I{路径格式?} I -->|相对路径| J[改为绝对路径] I -->|特殊字符| K[添加双引号] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值