5 Replies Latest reply on Apr 23, 2016 1:45 PM by vianna_dbmax

    How to configure a bridge to a server behind a firewall

    vianna_dbmax

      I have a Wildfly 10 server installed on a local network binding to IP 192.168.1.9:8085.

      The firewall of the network have a public IP (myfirewall.com) and i created a port redirection from my firewall to the wildfly server.

      It works fine.

      I have another Wildfly 10 server running outside this local network and I need to create a bridge between them.

      The following configuration worked between two Wildfly instances running on the same network:

      <server>

          <http-acceptor name="http-acceptor" http-listener="default"/>

          <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http"/>

          <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>

          <connection-factory name="RemoteConnectionFactory" reconnect-attempts="-1" block-on-acknowledge="true" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>

               ...

      </server>

      <jms-bridge name="transport-bridge" max-batch-time="60000" max-batch-size="5" max-retries="-1" failure-retry-interval="10000" quality-of-service="DUPLICATES_OK">

          <source destination="jms/queue/mySource" connection-factory="ConnectionFactory"/>

          <target password="myPassord" user="myUser" destination="jms/queue/myTarget" connection-factory="jms/RemoteConnectionFactory">

             <target-context>

                <property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory"/>

                <property name="java.naming.provider.url" value="http-remoting://192.168.1.9:8085"/>

                <property name="java.naming.security.principal" value="myUser"/>

                <property name="java.naming.security.credentials" value="myPassword"/>

             </target-context>

          </target>

      </jms-bridge>

       

       

      But when I try to use this configuration in a Wildfly server outside my local network (changing the property java.naming.provider.url from 192.168.1.9:8085 to myfirewall.com:8085) I get the following error:

      2016-04-15 14:27:13,494 WARN  [org.apache.activemq.artemis.jms.bridge] (ServerService Thread Pool -- 67) AMQ342010: Failed to connect JMS Bridge: javax.jms.JMSException: Failed to create session factory

              at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:727)

              at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:233)

              at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl.createConnection(JMSBridgeImpl.java:937)

              at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl.setupJMSObjects(JMSBridgeImpl.java:1104)

              at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl.start(JMSBridgeImpl.java:383)

              at org.wildfly.extension.messaging.activemq.jms.bridge.JMSBridgeService.startBridge(JMSBridgeService.java:105)

              at org.wildfly.extension.messaging.activemq.jms.bridge.JMSBridgeService$1.run(JMSBridgeService.java:76)

      ...

      Caused by: ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ119007: Cannot connect to server(s). Tried with all available servers.]

              at org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:777)

              at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:724)

              ... 10 more

       

      Trying to better understand the problem I created a client to connect to the same server. It worked fine using both IPs (192.168.1.9 from inside the network and myfirewall.com from outside the network), but I was creating my own ConnectionFactory. When I changed the code to get the connection factory throught JNDI, I reproduced the bridge error.

      Inspecting the ConnectionFactory instance returned by the JNDI I got the following:

      ActiveMQConnectionFactory [serverLocator=ServerLocatorImpl [initialConnectors=[TransportConfiguration(name=null, factory=org-apache-activemq-artemis-core-remoting-impl-netty-NettyConnectorFactory) ?httpUpgradeEnabled=true&port=8085&host=192-168-1-9], discoveryGroupConfiguration=null], clientID=null, consumerWindowSize = 1048576, dupsOKBatchSize=1048576, transactionBatchSize=1048576, readOnly=false]

       

      So I understand that the problem is that the Wildfly server only knows the IP 192.168.1.9, so the ConnectionFactory obtained by JNDI is configured to estabilish the connection in a IP that is not public.

      My question is: how can I configure the bridge or the connection factory to recognizes the public IP.

      It is important to emphasize that the public IP (myfirewall.com) is in an interface of another server (the firewall), so I can't bind the Wildfly to this IP.

       

      Thanks in advance!

        • 1. Re: How to configure a bridge to a server behind a firewall
          jbertram

          When an Artemis JMS client (e.g. standalone client or a bridge) looks up a connection factory in JNDI it ultimately receives a simple stub with information about how to construct its connection factory.  If you notice, a "connection-factory" element in the XML server configuration has a "connectors" attribute, and a connector (of which there are several types) typically has a "socket-binding" attribute which indicates the IP and port where the connector points.  You simply need to create a new "remote-connector" and a new socket-binding which points where you want the connector to connect.  The IP and port can be anything you like.

           

          Another option would be to just create an Artemis "core" bridge to push messages from one server to the other.  You would still need to create a new connector and socket binding (on the sending server), but you wouldn't need to mess with the JNDI configuration on the JMS bridge. 

          • 2. Re: How to configure a bridge to a server behind a firewall
            vianna_dbmax

            Hi Justin! Thanks for the answer!

             

            I tried to create the new connector. The changes in my standalone-full.xml are:

                    <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">

                        <server name="default">

                          ...

                            <http-connector name="external-http-connector" endpoint="http-acceptor" socket-binding="external-http"/>

                            <connection-factory name="ExternalConnectionFactory" reconnect-attempts="-1" block-on-acknowledge="true" entries="java:jboss/exported/jms/ExternalConnectionFactory" connectors="external-http-connector"/>

                          ...

                        </server>

                    </subsystem>

                <interfaces>

                    ...

                    <interface name="external">

                        <inet-address value="myfirewall.com"/>

                    </interface>

                    ...

                </interfaces>

                <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">

                    ...

                    <socket-binding name="external-http" interface="external" port="${jboss.http.port:8080}"/>

                    ...

                </socket-binding-group>

             

            When I start the Wildfly I get the following errors:

            10:57:28,239 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-1) MSC000001: Failed to start service jboss.network.external: org.jboss.msc.service.StartException in service jboss.network.external: WFLYSRV0082: failed to resolve interface external

              at org.jboss.as.server.services.net.NetworkInterfaceService.start(NetworkInterfaceService.java:91)

              at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1948)

              at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1881)

              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

              at java.lang.Thread.run(Thread.java:745)

            ...

            10:57:29,897 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([("interface" => "external")]) - failure description: {"WFLYCTL0080: Failed services" => {"jboss.network.external" => "org.jboss.msc.service.StartException in service jboss.network.external: WFLYSRV0082: failed to resolve interface external"}}

             

            What I understand from these errors is that it doesn't accept an interface that it can't bind. Isn't it ? The address myfirewall.com is the interface of my firewall server it's not the same server where Wildfly is running.

            Did I do something wrong ?

             

            I am interested in using the core bridge, but I couldn't find any documentation about how configure a core bridge inside the Wildfly. The only documentation about artemis core bridge is the documentation of the product, which shows me how to configure the broker.xml. But this file, as far as I can see, doesn't exist in Wildfly. In Wildfly, this configuration is in the messaging subsystem of the standalone-full.xml. But the messaging system uses a different schema than the broker schema. So I am lost!

            For example, I added an empty bridge definition, taken from the artemis core bridge documentation, in the same place I put the jms-bridge, as follows:

                    <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">

                        <server name="default">

                        ...

                        </server>

                        <bridge name="my-bridge">

                        </bridge>

                    </subsystem>

            When I start the Wildfly I get the following error:

            Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[337,14]

            Message: WFLYCTL0377: Unexpected element '{urn:jboss:domain:messaging-activemq:1.0}bridge' encountered. Valid elements are: 'server, jms-bridge'

              at org.jboss.as.controller.parsing.ParseUtils.unexpectedElement(ParseUtils.java:98)

              at org.jboss.as.controller.PersistentResourceXMLDescription.parseChildren(PersistentResourceXMLDescription.java:264)

              at org.jboss.as.controller.PersistentResourceXMLDescription.parse(PersistentResourceXMLDescription.java:136)

              at org.wildfly.extension.messaging.activemq.MessagingSubsystemParser_1_0.readElement(MessagingSubsystemParser_1_0.java:610)

              at org.wildfly.extension.messaging.activemq.MessagingSubsystemParser_1_0.readElement(MessagingSubsystemParser_1_0.java:66)

              at org.jboss.staxmapper.XMLMapperImpl.processNested(XMLMapperImpl.java:110)

              at org.jboss.staxmapper.XMLExtendedStreamReaderImpl.handleAny(XMLExtendedStreamReaderImpl.java:69)

              at org.jboss.as.server.parsing.StandaloneXml_4.parseServerProfile(StandaloneXml_4.java:546)

              at org.jboss.as.server.parsing.StandaloneXml_4.readServerElement(StandaloneXml_4.java:242)

              at org.jboss.as.server.parsing.StandaloneXml_4.readElement(StandaloneXml_4.java:141)

              at org.jboss.as.server.parsing.StandaloneXml.readElement(StandaloneXml.java:103)

              at org.jboss.as.server.parsing.StandaloneXml.readElement(StandaloneXml.java:49)

              at org.jboss.staxmapper.XMLMapperImpl.processNested(XMLMapperImpl.java:110)

              at org.jboss.staxmapper.XMLMapperImpl.parseDocument(XMLMapperImpl.java:69)

              at org.jboss.as.controller.persistence.XmlConfigurationPersister.load(XmlConfigurationPersister.java:123)

              ... 3 more

             

            Thanks in advance!

            • 3. Re: How to configure a bridge to a server behind a firewall
              ctomc

              error message is telling you what is wrong

              WFLYCTL0377: Unexpected element '{urn:jboss:domain:messaging-activemq:1.0}bridge' encountered. Valid elements are: 'server, jms-bridge'

               

              jms-bridge is expected not bridge.

              • 4. Re: How to configure a bridge to a server behind a firewall
                jbertram

                Aside from what Tomaz already pointed out, you're configuring an "interface" with the address of your firewall.  The server will attempt to resolve that interface during startup but will fail because that interface does not exist on that machine.  You need to create an outbound-socket-binding instead of the socket-binding/interface combination.

                 

                Lastly, you can always find the authoritative guide to any configuration in the docs/schema directory.  In this case you need to look at docs/schema/wildfly-messaging-activemq_1_0.xsd.

                • 5. Re: How to configure a bridge to a server behind a firewall
                  vianna_dbmax

                  Hi Justin, sorry for the late answer. I have been busy...

                  Using the outbound-socket-binding solved my problem.

                  Here is how I configure the server behind the firewall:

                          <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">

                              <server name="default">

                                ...

                                <http-connector name="external-http-connector" endpoint="http-acceptor" socket-binding="external-http"/>

                                <connection-factory name="ExternalConnectionFactory" reconnect-attempts="-1" block-on-acknowledge="true" entries="java:jboss/exported/jms/ExternalConnectionFactory" connectors="external-http-connector"/>

                                ...

                              </server>

                          </subsystem>

                      <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">

                          ...

                          <outbound-socket-binding name="external-http">

                              <remote-destination host="myfirewall.com" port="8085"/>

                          </outbound-socket-binding>

                          ...

                      </socket-binding-group>

                   

                  And here is how I configure the bridge in the server outside my private network:

                  <jms-bridge name="transport-bridge" max-batch-time="60000" max-batch-size="5" max-retries="-1" failure-retry-interval="10000" quality-of-service="DUPLICATES_OK">

                      <source destination="jms/queue/mySource" connection-factory="ConnectionFactory"/>

                      <target password="myPassord" user="myUser" destination="jms/queue/myTarget" connection-factory="jms/ExternalConnectionFactory">

                        <target-context>

                            <property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory"/>

                            <property name="java.naming.provider.url" value="http-remoting://myfirewall.com:8085"/>

                            <property name="java.naming.security.principal" value="myUser"/>

                            <property name="java.naming.security.credentials" value="myPassword"/>

                        </target-context>

                      </target>

                  </jms-bridge>


                  I didn't have time to try to configure the core bridge, but I could find it in the schema you mentioned.

                  Thanks a lot for the help!