This can be partially fixed with setting this in jboss's run.conf as per http://www.jboss.org/community/wiki/UsingJBossBehindAFirewall:
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=<ExternalIP> -Djava.rmi.server.useLocalHostname=false"
However, this breaks some MDB's (won't deploy, I suspect they try to get to ExternalIP and that's not resolvable from behind the firewall).
Also, the client (Tomcat) still gets stuck while trying to bind to LocalIP:3873 which is the ejb3.deployer port -- from server/all/deploy/ejb3.deployer/META-INF/jboss-service.xml:
I ran into this problem, I fixed it by binding to the hostname in DNS, then configuring the external and internal DNS servers to resolve this hostname to external and internal IP addresses respectively.
Resolved, after more reading of the above wiki page.
The final piece of the puzzle was taking the first step in the "PooledInvoker" section, that is adding
<attribute name="clientConnectAddress">webaddress.com</attribute> <attribute name="clientConnectPort">3873</attribute>
(I didn't change the http-invoker.sar).