【问题标题】:JConsole over ssh local port forwardingJConsole 通过 ssh 本地端口转发
【发布时间】:2013-02-12 03:43:45
【问题描述】:

我希望能够远程连接到暴露了 JMX 的 Java 服务,但是它被防火墙阻止了。我尝试使用 ssh 本地端口转发,但是连接失败。查看wireshark,似乎当您尝试连接jconsole时,它想在连接到端口9999后通过一些临时端口进行连接,这些端口被防火墙阻止。

有没有办法让 jconsole 只通过 9999 连接或使用代理?是this article still the best solution?或者,我错过了什么?

【问题讨论】:

标签: java ssh jmx


【解决方案1】:

有没有办法让 jconsole 只通过 9999 连接或使用代理? this article 仍然是最好的解决方案吗?或者,我错过了什么?

是的,那篇文章说的很对。

当您在服务器上指定 JMX 端口 (-Dcom.sun.management.jmxremote.port=####) 时,您实际上是在指定只是应用程序的注册表端口。当你连接它时,它会提供一个额外的服务器端口,jconsole 实际上会使用它来完成所有工作。要转入工作,您需要了解注册表和服务器端口。

在注册表和服务器端口都设置为 8000 的情况下,类似下面的内容应该可以运行您的应用程序。请参阅 here for more details

-Dcom.sun.management.jmxremote.port=8000
-Dcom.sun.management.jmxremote.rmi.port=8000
-Djava.rmi.server.hostname=127.0.0.1

顺便说一句,我的SimpleJMX library 允许您轻松设置两个端口,并且您可以将它们都设置为同一个端口。

因此,一旦您知道需要转发的两个端口,您就可以设置ssh 命令。例如,如果您将注册表和服务器端口配置为 8000,您会这样做:

ssh -L 8000:localhost:8000 remote-host

这将创建一个本地端口 8000,该端口转发到远程主机上的 localhost:8000。如果需要转发多个端口,可以指定多个-L 参数。然后您可以将您的 jconsole 连接到 localhost:8000,它会正确连接到远程主机。

另外,如果您的服务器有多个接口,您可能需要设置java.rmi.server.hostname 变量以绑定到正确的接口。

-Djava.rmi.server.hostname=10.1.2.3

【讨论】:

  • 好的。谢谢。我希望这不是答案,因为我真的不想编写额外的代码来监控我们可能有很多实例的服务。但是,您的回答非常清楚地描述了正在发生的事情,因此会有所帮助。
  • 如果你正在编写自己的 JMX 代码@blockcipher,你真的应该看看我的 SimpleJMX 库。它确实使 JMX 非常容易编码。 256.com/sources/simplejmx
  • 我尝试了很多东西,只有在我打开门,直接连接并使用这种特定形式的 url “service:jmx:...”后才有效。谢谢!
【解决方案2】:

由于 JConsole 支持 SOCKS,因此使用 SSH socks 隧道有更好的方法:

  1. 在某个空闲端口(例如 7777)上本地创建 SSH socks 代理:

    ssh -fN -D 7777 user@firewalled-host

  2. 通过指定 SOCKS 代理(例如 localhost:7777)和 JMX 服务器的地址(例如 localhost:2147)来运行 JConsole

    jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=7777 服务:jmx:rmi:///jndi/rmi://localhost:2147/jmxrmi -J-DsocksNonProxyHosts=

正如以下答案之一所述,从 JDK 8u60+ 开始,您还需要拥有 -J-DsocksNonProxyHosts= 选项才能使其正常工作。

【讨论】:

  • 如果您在远程主机上运行的 jvm 只能通过 ssh 访问,如果您可以重新启动该 jvm 并修改其远程管理选项,并且您只想将本地 jconsole 连接到此远程 jvm,这是要走的路。它对我有用。非常感谢。
  • 对于第 1 部分,如果您不需要远程 SSH 会话(仅端口转发),请添加 -N 标志,即:ssh -N -D 7777 user@host
  • 谢谢 - 我尝试了许多不同的方法来尝试使远程 JMX 连接正常工作,这是唯一对我有用的方法。
  • 如其他答案之一所述,在较新版本的 Java (>=8u60?) 中,您还需要添加 -J-DsocksNonProxyHosts=
  • 你能告诉我你的例子中“localhost:2147”是从哪里来的吗?
【解决方案3】:

现在几乎所有当前的 JDK 版本(7u25 或更高版本)都可以通过 SSH 轻松使用 JConsole 和 Visual JVM (because now you can bind JMX to single port)。

我使用以下JVM参数

-Dcom.sun.management.jmxremote.port=8090
-Dcom.sun.management.jmxremote.rmi.port=8090
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

然后我启动 SSH 连接

ssh my.javaserver.domain -L 8090:127.0.0.1:8090

在我可以从 JConsole 连接之后

远程进程:-> localhost:8090

还有 Java Visual VM

右键本地 -> 添加 JMX 连接 -> localhost:8090

【讨论】:

  • 尝试了这么多方法,你的答案真的奏效了!非常感谢
  • 非常感谢!我尝试了我发现的所有其他方法,这是唯一有效的方法。
  • 太棒了,正是我想要的。以下是我与 VisualVM 一起使用时的个人观察:java.rmi.server.hostname=localhost(而不是 IP 地址)也可以正常工作....另外:属性 com.sun.management.jmxremote.portcom.sun.management.jmxremote.rmi.port 必须具有 相同 值。跨度>
  • 6 小时后 wwwooooooooooohhhhhhaaaaa。我的天啊。就像你拯救了世界我亲爱的朋友!!!!
  • 对我有用,JDK1.8.0_60。非常感谢。
【解决方案4】:

继续使用 SSH socks 方法,对于较新的 java 版本(大约 8u66),您还需要将 socksNonProxyHosts 设置为空,从而导致:

jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=7777 -J-DsocksNonProxyHosts=

【讨论】:

  • 拯救了这一天! Java 8u60 也需要它。
  • '-J-DsocksNonProxyHosts=' 让我与众不同!