JORAM
Overview
OW2 JORAM (Java Open Reliable Asynchronous Messaging) is a mature, standalone JMS 2.0 message broker from the OW2 consortium. It implements the full Java Message Service model: queues for point-to-point delivery and topics for publish and subscribe. Messages are stored persistently and transactionally, so they survive a restart. Applications connect over JORAM's TCP protocol or through its built-in JNDI naming service, and they do not need to be online at the same time.
This SecureAnyCloud image installs the stock upstream JORAM 5.24.0 release (LGPL-2.1) on Ubuntu 24.04 LTS. It runs as a single agent server under an Apache Felix OSGi container. The image is secure by default: the broker binds only to the VM's loopback interface, a host firewall blocks the JMS and JNDI ports from outside the VM, and the unauthenticated OSGi remote shell is removed. There is no default login. Each VM generates its own broker admin password and a dedicated messaging user on first boot.
What you get:
- OW2 JORAM 5.24.0 message broker (JMS 2.0), running as
joram.service - Ubuntu's security-patched OpenJDK 11 runtime (
openjdk-11.0.31) - JMS TCP endpoint on
127.0.0.1:16010and JNDI naming on127.0.0.1:16400 - A ready-to-use messaging user SecureAnyCloud and a sac.demo queue, provisioned on first boot
- Per-VM broker admin and messaging passwords generated on first boot into a root-only credentials file
- A host firewall (nftables) that blocks the JMS and JNDI ports from outside the VM
- 24/7 SecureAnyCloud support
This is a messaging appliance. You reach JORAM locally on the VM or over an SSH tunnel, and there is no web console. The message bus is never exposed to the public internet by default. You open it to remote clients deliberately, as the last step shows.
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting size.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network only. You need no inbound application ports, because you reach JORAM over the SSH tunnel unless you deliberately open it.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for JORAM by SecureAnyCloud, and select Create.
On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) only. Then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:joram:default:latest
az vm create \
--resource-group <your-rg> \
--name joram \
--image sac1647283583153:joram:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku StandardStep 3 - Connect to your VM
Connect to the VM over SSH as azureuser:
ssh azureuser@<vm-public-ip>Step 4 - Confirm JORAM is installed and running
Check the broker service, the enabled units and the listening ports:
systemctl is-active joram.service
systemctl is-enabled joram.service joram-firstboot.service nftables.service ss -tln | grep -E ':(16010|16400) 'The broker reports active, the units report enabled, and the JMS (16010) and JNDI (16400) listeners are bound on the VM:
active enabled enabled enabled LISTEN 0 50 *:16400 *:* LISTEN 0 10 *:16010 *:*Step 5 - Retrieve your per-VM credentials
On first boot, each VM generates its own broker admin password and a dedicated messaging user password, and writes them to a root-only file. There is no default login. Read the file with sudo:
sudo cat /root/joram-credentials.txt# OW2 JORAM - generated on first boot by joram-firstboot.service.
# These credentials are unique to this VM. Store them somewhere safe. JORAM_ADMIN_USER=root JORAM_ADMIN_PASSWORD=<set-at-first-boot> JORAM_APP_USER=sac JORAM_APP_PASSWORD=<set-at-first-boot>
#
# The JORAM broker listens on LOCALHOST ONLY (secure by default):
# JMS core (TCP proxy): tcp://127.0.0.1:16010
# JNDI naming service: 127.0.0.1:16400
# A ready-to-use messaging user 'sac' and queue 'sac.demo' are provisioned.Step 6 - Verify messaging with a send and receive test
The image ships a self-test that connects as the per-VM SecureAnyCloud user and performs a real JMS round trip. It sends a uniquely tagged message to the sac.demo queue, receives it back and asserts the exact payload. It also checks that anonymous, default (root/root) and wrong-password connections are all refused.
sudo /usr/local/sbin/joram-smoke.sh verifyROUNDTRIP_OK payload=sac-joram-smoke-1786175951075 NEGATIVE_OK anonymous+default-root+wrong-pw all refused ALL_OKROUNDTRIP_OK confirms end-to-end messaging with the per-VM credentials. NEGATIVE_OK confirms there is no unauthenticated or default access.
Step 7 - Review the secure defaults
A host firewall blocks the broker's ports from outside the VM. Its input policy is drop, and only SSH and the Azure platform are allowed. The unauthenticated OSGi remote shell is removed, and the credentials file is readable by root only. Confirm the firewall rules, the absence of a management port and the file permissions:
sudo nft list ruleset | sed -n '/chain input/,/}/p' ss -tln | grep -E ':6666 ' || echo 'no unauthenticated management port (6666) listening'
sudo stat -c '%a %U:%G' /root/joram-credentials.txtchain input { type filter hook input priority filter; policy drop; ct state established,related accept ct state invalid drop iif "lo" accept ip protocol icmp accept ip6 nexthdr ipv6-icmp accept ip saddr 168.63.129.16 accept udp sport 67 udp dport 68 accept tcp dport 22 accept } no unauthenticated management port (6666) listening 600 root:rootStep 8 - Connect your own JMS application
The SecureAnyCloud messaging user and the sac.demo queue are already provisioned. From code running on the VM, connect to tcp://127.0.0.1:16010 with the JORAM client library. The jars are under /opt/joram/current/ship/bundle. A minimal Java producer and consumer looks like this:
import javax.jms.*; import org.objectweb.joram.client.jms.tcp.TcpConnectionFactory; import org.objectweb.joram.client.jms.Queue; ConnectionFactory cf = TcpConnectionFactory.create("localhost", 16010); Connection cnx = cf.createConnection("sac", "<JORAM_APP_PASSWORD>"); Session s = cnx.createSession(false, Session.AUTO_ACKNOWLEDGE); cnx.start(); Queue q = Queue.create(0, "sac.demo"); s.createProducer(q).send(s.createTextMessage("hello")); Message m = s.createConsumer(q).receive(5000); System.out.println(((TextMessage) m).getText());To reach the broker from another host, tunnel over SSH. This keeps the message bus private:
ssh -L 16010:127.0.0.1:16010 azureuser@<vm-public-ip>To expose JORAM to remote clients directly instead, first decide who should reach the message bus. Then edit /var/lib/joram/a3servers.xml to advertise the VM's address, allow the port in the host firewall (/etc/nftables.conf), and open the matching inbound rule in your Azure NSG.
Support
SecureAnyCloud images come with 24/7 support. For questions about this JORAM image or help with your deployment, contact us through the SecureAnyCloud website.
Deploy on Azure
Launch OW2 JORAM on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com