Mochi MQTT Broker 2.7.9
Overview
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. This image ships none of that. It is a small broker built from the pinned Mochi 2.7.9 source with a secure default configuration.
This guide covers Mochi MQTT Broker 2.7.9 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened Apache Kafka, RabbitMQ & Message Broker AMIs listing on AWS Marketplace, and you choose 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.
What you get:
- 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, SecureAnyCloud, 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 license 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.service is blocked from reaching the instance metadata service (169.254.169.254 and fd00:ec2::254). Only the SecureAnyCloud 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 starts only after first boot has created the password and the TLS key. If first boot cannot finish, the broker stays stopped and first boot 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 with 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
Launch the instance
Option A: AWS Marketplace console
- Open the SecureAnyCloud Hardened Apache Kafka, RabbitMQ & Message Broker AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- When 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. - Set the 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 the commands below on your own workstation. They create a security group that allows SSH from your management address and MQTT over TLS from your client network, then launch the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page. Replace 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, because the AMI already requires IMDSv2.
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 and runs the self-test. It 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 (sac). 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=sac 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:1883Your file shows your own password, addresses and certificate fingerprint. Keep the password safe, because it is the only credential the broker accepts.
Confirm the broker is running
Check that mochi-mqtt.service is active with the metadata block drop-in loaded. Then run the self-test. It publishes and receives a message over TLS and over local plaintext. It 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.shactive ● mochi-mqtt.service - sac 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-sac-imds-deny.conf Active: active (running) since Mon 2026-10-19 18:22:45 UTC; 1min 57s ago Docs: https://secureanycloud.com/stacks/mochi-mqtt-broker-2-7-9/ 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 cgroupThese are the only TCP ports the instance listens on. Port 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 [::]:22Publish and subscribe on the instance
Read the password into a shell variable, so it is never printed. Start a subscriber in the background, then 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 sac -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 sac -P "$MQTT_PASS" -t demo/hello -m 'hello from sac' waitdemo/hello hello from sacPrograms 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 SecureAnyCloud -P "$MQTT_PASS" ... That port is not reachable from the network.
See what the broker refuses
The broker refuses a client with no credentials, or with the wrong password, at connect (mosquitto_pub exits 5, "not authorised"). 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 sac -P wrong-password try -u sac -P wrong-passwordexit=5 Connection Refused: not authorised. exit=5 Connection Refused: not authorised. exit=14 Error: Protocol errorPlaintext 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 refusedThe 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 2time=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=sac remote=127.0.0.1:42306Connect a remote client
Copy the instance certificate to the machine that will connect. The certificate is public, not secret:
scp -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>:/etc/ssl/mochi-mqtt/server.crt ./mochi-ca.crtThen 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, run:
mosquitto_sub -h <public-ip> -p 8883 --cafile ./mochi-ca.crt -u sac -P '<MOCHI_MQTT_PASSWORD>' -t 'sensors/#' -v mosquitto_pub -h <public-ip> -p 8883 --cafile ./mochi-ca.crt -u sac -P '<MOCHI_MQTT_PASSWORD>' -t sensors/room1 -m '21.5'Any MQTT v5 or v3.1.1 client library works the same way. Set the host, port 8883, TLS on, the certificate as the trusted CA, user SecureAnyCloud 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 subjectAltNamesha256 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.comMetadata 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, using a reachable control request from your shell:
systemctl show -p IPAddressDeny mochi-mqtt.service cat /etc/systemd/system/mochi-mqtt.service.d/50-sac-imds-deny.confIPAddressDeny=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/128Configuration
The broker reads /etc/mochi-mqtt/mochi.conf, which holds no secrets:
cat /etc/mochi-mqtt/mochi.conf ls -l /etc/mochi-mqtt/ /etc/ssl/mochi-mqtt/# sac 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=sac
# 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.keyChange the password. Write a new password of at least 16 characters to the password file and restart the broker. Then 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-mqttNew 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 and pass any extra DNS names as 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-mqttTo 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.
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.
- Licenses.
/usr/share/doc/mochi-mqtt-server/holds the MIT license of Mochi MQTT, the licenses of the libraries compiled into the binary and the Go runtime license, plusBUILDINFOwith the exact module versions and checksums.
Support
SecureAnyCloud provides 24/7 technical support by email and live chat for every version in this listing. Contact sales@secureanycloud.com. The other versions in the listing are on the guide hub.
Deploy on AWS
Launch Mochi MQTT Broker 2.7.9 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com