Mochi MQTT Broker 2.7.9 on AWS User Guide
Overview
This guide covers launching and using Mochi MQTT Broker 2.7.9 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened Apache Kafka, RabbitMQ & Message Broker AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other brokers and streaming platforms in the listing are described on the listing's guide hub.
Mochi MQTT is a fast, self contained MQTT broker written in Go. It speaks MQTT v5 and v3.1.1 and is a popular choice for Internet of Things fleets, telemetry pipelines and application message buses. Upstream ships Mochi as a Go library whose example server allows every client, opens a WebSocket listener and serves a world readable statistics page. The cloudimg image ships none of that: it is a small broker built from the pinned Mochi 2.7.9 source with a secure default configuration.
What is on the image:
- Mochi MQTT 2.7.9, built from source with Go 1.27.2 into one static binary,
/usr/local/bin/mochi-mqtt-server(mochi-mqtt.service) - MQTT over TLS on port 8883, using a key and self-signed certificate created on your instance's first boot (TLS 1.2 or newer)
- One broker user,
cloudimg, with a password generated on your instance's first boot. Anonymous and wrong-password clients are refused - Plaintext MQTT on 127.0.0.1:1883 only, for programs running on the instance itself
mosquitto-clients(mosquitto_pub,mosquitto_sub) for testing and scripting- A self-test,
/usr/local/sbin/mochi-mqtt-selftest.sh, and a certificate helper,/usr/local/sbin/mochi-mqtt-mint-cert - The licence notices for Mochi and the libraries compiled into it, in
/usr/share/doc/mochi-mqtt-server/
Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3
Security posture
- No default login. The broker password is created on each instance's first boot and exists nowhere else. No two instances share one.
- Authentication required. The broker has one user in a deny-by-default ledger. A client that sends no credentials, a different user name or a wrong password is refused at connect.
- TLS by default. The only MQTT port open to the network is 8883, MQTT over TLS, with a certificate made for this instance's addresses. Plaintext MQTT listens on the loopback interface only, and the broker refuses to start a plaintext listener on any other address.
- The listing security group opens SSH (22) and MQTT over TLS (8883). Restrict both to the networks that need them.
- The password never sits in an environment variable. systemd hands it to the broker as a private credential from
/etc/mochi-mqtt/password(root only). It does not appear in the process environment, insystemctl showor in the logs. - No metadata access for the broker.
mochi-mqtt.serviceis blocked from reaching the instance metadata service (169.254.169.254 and fd00:ec2::254). Only cloudimg's first-boot unit reads the instance's addresses, over IMDSv2. - IMDSv2 required. The AMI is registered with
ImdsSupport v2.0, so instances launched from it refuse token-less (IMDSv1) metadata requests. - Fails closed. The broker unit only starts once first boot has created the password and the TLS key. If first boot cannot finish, it leaves the broker stopped and tries again on the next boot.
- Sandboxed service. The broker runs as the unprivileged
mochiuser with no capabilities and systemd sandboxing (read-only system, private/tmp, no new privileges, a system call filter). - Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- A VPC subnet, and the address ranges of the devices or services that will connect to the broker
Recommended instance type: m5.large. A small broker also runs comfortably on t3.small or larger.
Connecting to your instance
| Version | Operating system | SSH user |
|---|---|---|
| Mochi MQTT Broker 2.7.9 on Ubuntu 24.04 | Ubuntu 24.04 LTS | ubuntu |
Step 1: Launch the instance
Option A: AWS Marketplace console
- Open the cloudimg Hardened Apache Kafka, RabbitMQ & Message Broker AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Once the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose Mochi MQTT Broker 2.7.9 on Ubuntu 24.04, then choose your Region.
- Pick an instance type (
m5.largerecommended; the software charge is $0.04 per vCPU per hour) and your key pair. - Security group: the listing's default group allows SSH (22) and MQTT over TLS (8883). Restrict 22 to your own IP address and 8883 to the networks your clients use.
- Choose your VPC and subnet, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.
Option B: AWS CLI
Run this on your own workstation. It creates a security group that allows SSH from your management address and MQTT over TLS from your client network, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and address ranges with your own:
SG=$(aws ec2 create-security-group --group-name mochi-mqtt \
--description "Mochi MQTT broker" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 8883 --cidr 10.0.0.0/16
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=mochi-mqtt}]'
You do not need --metadata-options: the AMI already makes IMDSv2 required.
Step 2: Connect and read your credentials
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>
First boot finishes within a minute of launch. It creates the broker password and the TLS certificate, starts the broker, runs the self-test and then writes /root/mochi-mqtt-credentials.txt, which only root can read:
sudo cat /root/mochi-mqtt-credentials.txt
# Mochi MQTT Broker 2.7.9 - per-instance credentials (cloudimg). Generated 2026-10-19T18:21:59Z.
# Anonymous and wrong-password connections are refused. Remote clients use MQTT over TLS on 8883
# and trust this instance's certificate: copy /etc/ssl/mochi-mqtt/server.crt to the client.
MOCHI_MQTT_USER=cloudimg
MOCHI_MQTT_PASSWORD=<MOCHI_MQTT_PASSWORD>
MOCHI_MQTT_PUBLIC_IP=52.91.29.39
MOCHI_MQTT_PRIVATE_IP=172.31.88.245
MOCHI_MQTT_TLS_PORT=8883
MOCHI_MQTT_CA_FILE=/etc/ssl/mochi-mqtt/server.crt
MOCHI_MQTT_CERT_SHA256=5E:A9:DD:34:E9:42:ED:3B:6D:63:75:0D:FA:22:9F:82:32:2D:2E:30:DD:C9:A7:1F:5C:24:03:4A:B2:AE:A2:A6
MOCHI_MQTT_LOCAL_PLAINTEXT=127.0.0.1:1883
Your file shows your own password, addresses and certificate fingerprint. Keep the password safe: it is the only credential the broker accepts.
Step 3: Confirm the broker is running
mochi-mqtt.service is active with the metadata block drop-in loaded, and the self-test publishes and receives a message over TLS and over local plaintext, checks that anonymous and wrong-password clients are refused on both, that a client which does not trust the instance certificate is refused, that the only network ports are 22 and 8883, and that the broker cannot reach the instance metadata service:
systemctl is-active mochi-mqtt.service
systemctl status mochi-mqtt.service --no-pager | head -8
sudo /usr/local/sbin/mochi-mqtt-selftest.sh
active
● mochi-mqtt.service - cloudimg Mochi MQTT Broker (authenticated, TLS on 8883)
Loaded: loaded (/etc/systemd/system/mochi-mqtt.service; enabled; preset: enabled)
Drop-In: /etc/systemd/system/mochi-mqtt.service.d
└─50-cloudimg-imds-deny.conf
Active: active (running) since Mon 2026-10-19 18:22:45 UTC; 1min 57s ago
Docs: https://www.cloudimg.co.uk/guides/mochi-mqtt-broker-2-7-9-on-ubuntu-24-04-aws/
Main PID: 4687 (mochi-mqtt-serv)
Tasks: 7 (limit: 3736)
MOCHI_SELFTEST_OK tls+plain round-trip, anonymous+wrong-password refused on both, untrusted TLS refused, listeners 22/8883 (+127.0.0.1:1883), IMDS blocked in the broker cgroup

These are the only TCP ports the instance listens on. 8883 is MQTT over TLS on every interface, 1883 is plaintext on the loopback interface only, 22 is SSH and 53 is the local DNS stub:
sudo ss -Hltn | awk '{print $4}' | sort -u
*:8883
0.0.0.0:22
127.0.0.1:1883
127.0.0.53%lo:53
127.0.0.54:53
[::]:22
Step 4: Publish and subscribe on the instance
Read the password into a shell variable (it is never printed), start a subscriber in the background and publish a message to it over TLS. --cafile tells the client to trust this instance's certificate, and localhost is one of the names in it:
MQTT_PASS="$(sudo sed -n 's/^MOCHI_MQTT_PASSWORD=//p' /root/mochi-mqtt-credentials.txt)"
mosquitto_sub -h localhost -p 8883 --cafile /etc/ssl/mochi-mqtt/server.crt \
-u cloudimg -P "$MQTT_PASS" -t 'demo/#' -C 1 -W 10 -v &
sleep 1
mosquitto_pub -h localhost -p 8883 --cafile /etc/ssl/mochi-mqtt/server.crt \
-u cloudimg -P "$MQTT_PASS" -t demo/hello -m 'hello from cloudimg'
wait
demo/hello hello from cloudimg
Programs on the instance itself can also use plaintext MQTT on 127.0.0.1:1883 with the same user and password (for example mosquitto_pub -h 127.0.0.1 -p 1883 -u cloudimg -P "$MQTT_PASS" ...). That port is not reachable from the network.
Step 5: See what the broker refuses
A client with no credentials, or with the wrong password, is refused by the broker at connect (mosquitto_pub exits 5, "not authorised"), and a client that does not trust the instance certificate fails the TLS handshake (exit 14). The small try helper prints the exit code and the client's first error line for each attempt:
try() { out="$(mosquitto_pub -h localhost -p 8883 "$@" -t demo/hello -m nope 2>&1)"; echo "exit=$? $(printf '%s' "$out" | head -n 1 | sed 's/^Connection error: //')"; }
try --cafile /etc/ssl/mochi-mqtt/server.crt
try --cafile /etc/ssl/mochi-mqtt/server.crt -u cloudimg -P wrong-password
try -u cloudimg -P wrong-password
exit=5 Connection Refused: not authorised.
exit=5 Connection Refused: not authorised.
exit=14 Error: Protocol error
Plaintext MQTT is closed on the instance's network address:
timeout 5 bash -c "exec 3<>/dev/tcp/$(hostname -I | cut -d' ' -f1)/1883" 2>/dev/null && echo open || echo "1883 on the private IP: connection refused"
1883 on the private IP: connection refused

The broker logs each refused connection with the client's address as seen on the socket:
sudo journalctl -u mochi-mqtt --no-pager -o cat | grep 'failed authentication' | tail -n 2
time=2026-10-19T18:23:21.021Z level=INFO msg="client failed authentication check" hook=auth-ledger username="" remote=127.0.0.1:42294
time=2026-10-19T18:23:21.025Z level=INFO msg="client failed authentication check" hook=auth-ledger username=cloudimg remote=127.0.0.1:42306
Step 6: Connect a remote client
Copy the instance certificate to the machine that will connect. It is public, not secret:
scp -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>:/etc/ssl/mochi-mqtt/server.crt ./mochi-ca.crt
Then connect over TLS to the instance's public or private IP (both are in the certificate), with the user and password from Step 2. From a workstation with mosquitto-clients installed:
mosquitto_sub -h <public-ip> -p 8883 --cafile ./mochi-ca.crt -u cloudimg -P '<MOCHI_MQTT_PASSWORD>' -t 'sensors/#' -v
mosquitto_pub -h <public-ip> -p 8883 --cafile ./mochi-ca.crt -u cloudimg -P '<MOCHI_MQTT_PASSWORD>' -t sensors/room1 -m '21.5'
Any MQTT v5 or v3.1.1 client library works the same way: host, port 8883, TLS on, the certificate as the trusted CA, user cloudimg and your password. You can also check the certificate fingerprint against MOCHI_MQTT_CERT_SHA256 in Step 2:
openssl x509 -in /etc/ssl/mochi-mqtt/server.crt -noout -fingerprint -sha256 -ext subjectAltName
sha256 Fingerprint=5E:A9:DD:34:E9:42:ED:3B:6D:63:75:0D:FA:22:9F:82:32:2D:2E:30:DD:C9:A7:1F:5C:24:03:4A:B2:AE:A2:A6
X509v3 Subject Alternative Name:
DNS:localhost, IP Address:127.0.0.1, IP Address:172.31.88.245, DNS:ip-172-31-88-245.ec2.internal, IP Address:52.91.29.39, DNS:ec2-52-91-29-39.compute-1.amazonaws.com
Step 7: Metadata access is blocked for the broker
The broker never needs the instance metadata service, so mochi-mqtt.service carries an IPAddressDeny drop-in for it. The self-test in Step 3 proves the block from inside the broker's own cgroup, with a reachable control request from your shell:
systemctl show -p IPAddressDeny mochi-mqtt.service
cat /etc/systemd/system/mochi-mqtt.service.d/50-cloudimg-imds-deny.conf
IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32
[Service]
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128

Step 8: Configuration
The broker reads /etc/mochi-mqtt/mochi.conf, which holds no secret:
cat /etc/mochi-mqtt/mochi.conf
ls -l /etc/mochi-mqtt/ /etc/ssl/mochi-mqtt/
# cloudimg Mochi MQTT broker configuration (non-secret). The password is the systemd credential
# mqtt-password, loaded from /etc/mochi-mqtt/password (root 0600, generated on first boot).
# After editing: sudo systemctl restart mochi-mqtt
MOCHI_MQTT_USERNAME=cloudimg
# MQTT over TLS, all interfaces (the listing security group opens 8883).
MOCHI_MQTT_TLS_ADDR=:8883
MOCHI_MQTT_TLS_CERT=/etc/ssl/mochi-mqtt/server.crt
MOCHI_MQTT_TLS_KEY=/etc/ssl/mochi-mqtt/server.key
# Plaintext MQTT, loopback only (local clients on this instance). "off" disables it.
MOCHI_MQTT_TCP_ADDR=127.0.0.1:1883
/etc/mochi-mqtt/:
total 8
-rw-r--r-- 1 root root 588 Oct 19 18:21 mochi.conf
-rw------- 1 root root 49 Oct 19 18:21 password
/etc/ssl/mochi-mqtt/:
total 8
-rw-r--r-- 1 root root 912 Oct 19 18:21 server.crt
-rw-r----- 1 root mochi 241 Oct 19 18:21 server.key
Change the password. Write a new password of at least 16 characters to the password file, restart the broker, and update /root/mochi-mqtt-credentials.txt so it stays accurate:
printf '%s\n' '<new-password>' | sudo sh -c 'umask 077; cat > /etc/mochi-mqtt/password'
sudo systemctl restart mochi-mqtt
New address or your own DNS name. The certificate names the addresses the instance had at first boot. After you attach an Elastic IP or point a DNS name at the broker, mint a new certificate (extra DNS names are arguments), restart the broker and give clients the new server.crt:
sudo /usr/local/sbin/mochi-mqtt-mint-cert <your-domain>
sudo systemctl restart mochi-mqtt
To use a certificate from your own CA instead, replace server.crt and server.key in /etc/ssl/mochi-mqtt/ (key owned root:mochi, mode 0640) and restart the broker.
Step 9: Maintenance
- Operating system updates. Unattended security upgrades are on. Apply the rest with
sudo apt update && sudo apt upgradein a maintenance window. - Logs.
sudo journalctl -u mochi-mqtt -ffollows the broker log; first boot logs to/var/log/mochi-mqtt-firstboot.log. - Persistence. The broker keeps sessions and retained messages in memory, so they are cleared when it restarts. Clients reconnect and resubscribe automatically.
- Licences.
/usr/share/doc/mochi-mqtt-server/holds the MIT licence of Mochi MQTT, the licences of the libraries compiled into the binary and the Go runtime licence, plusBUILDINFOwith the exact module versions and checksums.
Support
cloudimg provides 24/7 technical support by email and live chat for every version in this listing: support@cloudimg.co.uk. The other versions in the listing are on the guide hub.