Skip to Content

Reading the log, reaching it from outside, and getting it back

evidence, distance, and a way back
EMQX Guide · Part 8

Reading the log, reaching it from outside, and getting it back

The Dashboard tells you that something is wrong. It rarely tells you why. This part covers the three things you reach for when the pretty pages run out: the log, Log Trace and the REST API, which between them answer “why was this one client rejected” — in the Dashboard, or from a script with no browser open at all; the built-in ngrok tunnel, which puts port 1883 on the public internet and comes with everything that implies; and backup, restore and migration, which are what stand between one mistyped ACL rule and an evening of rebuilding from nothing.

6 levels
From debug up to critical. The default is warning, and that is where a healthy broker sits
512 MB
The trace log cap on each node. Past it, EMQX stops appending and warns in the main log
1883 only
All the add-on's ngrok tunnel carries. WebSocket on 8083 is outside its scope
Where to look

The Dashboard shows you that something is wrong, not why

Everything so far in this series has been about making the broker do things: connect clients, check passwords, decide who may publish where, move messages into other systems. Part 7 added the pages that show you the state of it all. Those pages are excellent at the general question and useless at the specific one.

The questionWhy was this one client rejected, when the other twenty connect perfectly well?
The questionWhy did this rule never match, when the topic looks exactly right?
The questionCan I check the living-room sensor from the train, or turn the hallway light off while I am out?
The questionOne ACL rule was edited wrong and every light in the house went offline. What is there to roll back to?

Four questions, three sets of tools. The first two are answered by the log and by Log Trace, with the Diagnose module and the REST API alongside them. The third is answered by the ngrok tunnel built into the add-on, and by a hard prerequisite that comes before it. The fourth is answered by knowing what a backup of /data/emqx actually contains — and, just as importantly, what it leaves out.

One order runs through this whole part. Authentication and the ACL come before exposure, and a backup comes before an update. Neither is a stylistic preference. Turning on the ngrok tunnel while EMQX still accepts anonymous connections hands the broker to the internet, and updating without a backup means the version you were happy with is gone.

Everything below is written against EMQX 5.8.9 (Open Source) as shipped in the Woow EMQX add-on. Where a feature belongs to EMQX Enterprise instead, it says so — several of the Diagnose tools do, and so does the Dashboard's own backup page.

Log levels

Six levels, and the one you should be sitting on

EMQX writes its log to two output streams: Console Log, out to the console, and File Log, into a file. Both are adjusted on the same Dashboard page, at Management → Logging, which has a tab for each. The default level for both is warning, and a change takes effect immediately — there is no restart to plan around.

EMQX supports 6 levels, which are 6 of the 8 defined in RFC 5424. From weakest to strongest:

debug < info < notice < warning < error < critical

The source guide describes five of the six in words. They are worth reading slowly, because picking a level is really a question of which of these you want to see:

  • debug — fine-grained debugging data such as variables and functions.
  • info — minor anomalies such as an authorization denial, and the result of a configuration change that succeeded.
  • warning — things that may need a look: a dropped connection, a connection timeout, an authentication failure.
  • error — cannot reach an external database, a subscription that does not exist, and similar errors.
  • critical — a configuration error that stops a component from starting, for example.

notice sits between info and warning in that ordering and the source does not describe it separately, so this article does not invent a description for it. What matters in practice is the shape: everything at or above the level you set gets written, everything below it does not. Sitting at warning means you keep dropped connections and authentication failures, and you throw away the per-variable detail that would fill the disk.

What else the file handler lets you set

The File Log tab carries more than a level. The defaults are sensible and worth knowing before you change them:

SettingDefaultWhat it decides
The log file name log/emqx.log Where the file handler writes. Note that this is the broker's own log, and in the add-on it is separate from the add-on log you read in Home Assistant
Maximum number of rotated files 10 How far back the history goes before the oldest file is discarded
Rotation size Enabled Whether a file is rolled over once it reaches a size, rather than growing without limit

Log Throttling, and why your log looks incomplete

EMQX also has Log Throttling. Within a time window it records only the first occurrence of a repeated event and counts the rest, which is what keeps one misbehaving device from producing a hundred thousand identical lines overnight. It is on by default, with a window of 1 minute.

In plain terms

It is the difference between a smoke alarm and a burglar alarm. The smoke alarm sounds once and keeps sounding; the log without throttling is that. Throttling turns it into the note the night porter leaves: “back door alarm, 07:14, and then another 412 times.” You have lost nothing you needed and gained a log you can actually read.

If the detail you wanted keeps getting cut short, that is throttling doing its job. The way to get the full run of lines is to set the log level to debug — throttling is disabled at that level. Which is also the reason not to leave a production broker at debug for longer than the investigation takes.
Log Trace and Diagnose

Debug on one client, instead of on the whole broker

Turning the whole node down to debug to investigate one device is the blunt instrument. Log Trace is the precise one: live debug-level logging aimed at a single named target and nothing else. That is what makes it usable in production, where the broker is still carrying everybody else's traffic while you investigate. You will find it under Diagnose → Log Trace.

  1. Step 1

    Diagnose → Log Trace → Create

    The list page holds whatever traces are currently running. Create opens the form.

  2. Step 2

    Choose the Type, and give it an exact target

    Under Type you choose Client ID, Topic, IP Address or Rule ID. Client ID and IP Address have to be entered in full — a partial client ID matches nothing. Topic is the only type that takes wildcards, and the wildcard rules are the ordinary MQTT ones: + stands for exactly one level, and # is allowed only at the end of the filter.

  3. Step 3

    Set the start and end times, then Create

    Collection starts as soon as the trace is created. Bounding it with an end time is the difference between a trace that stops on its own and one you have to remember to go back and clear up.

  4. Step 4

    View or download the log from the list

    Each trace in the list can be viewed in the browser or downloaded. The files also live on the server itself, in the /data/trace directory, which is where to look if the Dashboard is not cooperating.

Two limits are worth committing to memory before you start creating traces liberally. The system runs at most 30 traces at a time. And each node caps its trace logs at 512MB — once that is full it stops appending and raises a warning in the main log, so a trace that seems to have gone quiet may simply have hit the ceiling.

Testing a rule gets you a trace for free. Test Rule creates a trace automatically and deletes it again when the test ends. So when you are debugging a rule that never matches, you are getting the log from the other direction without setting anything up.
flowchart TD
  A["Warning level is not telling you
enough about this problem"] --> B{"Can you name one client ID,
IP address, topic filter or rule ID?"} B -->|"yes"| C["Log Trace, under Diagnose.
Debug detail for that target only,
while the rest of the broker
stays at its normal level"] B -->|"no, it is broker-wide"| D["Management then Logging.
Drop the level for the
length of the investigation"] C --> E["The file lands in /data/trace.
Capped at 512MB per node,
at most 30 traces at once"] D --> F["At debug, Log Throttling is off,
so repeated events are no
longer folded into a count"]
Two levers, and they are not interchangeableBoth routes end somewhere you have to manage: one has a size cap and a count cap, the other has a log that grows fast because throttling has stopped folding repeats.

What else is in the Diagnose module

Diagnose is the folder where the Dashboard keeps its debugging tools. Five things live there, and three of them belong to EMQX Enterprise:

ToolEditionWhat it gives you
WebSocket Client Open Source A built-in MQTT test client. Open a connection, subscribe, publish, and see how a topic behaves without standing up a separate tool
Log Trace Open Source The targeted debug logging described above
Topic Metrics Enterprise Counts and rates of messages received, sent and dropped for a specific topic
Slow Subscriptions Enterprise Finds subscriptions whose delivery time is over a threshold
Alerts Enterprise Current and historical system alerts
If Topic Metrics, Slow Subscriptions and Alerts are not in your sidebar, nothing is broken. All three are EMQX Enterprise features, so they are not visible under Diagnose in Open Source 5.8.9 — which is the edition the Woow add-on ships. Looking for them and not finding them is the expected outcome, not a failed install.

The one you will use constantly is WebSocket Client. When a device is not receiving what you think it should, opening a connection here and subscribing to the same topic filter settles in ten seconds whether the message is reaching the broker at all — which splits the problem cleanly into “the publisher is not publishing” and “the subscriber is not subscribing.”

The REST API

Two ways to drive the same engine

The Dashboard is one interface onto EMQX. The REST API is the other, and everything you can do by clicking has an HTTP equivalent. It follows the OpenAPI 3.0 specification, and every path starts with /api/v5. There is a browsable copy on the broker itself: open http://<host>:18083/api-docs/ and you can try calls straight from the Swagger UI.

Authentication is the part that catches people. The REST API authenticates with an API Key, which you create in the Dashboard under System → API Key. It arrives as a pair. Over HTTP Basic, the API Key is the username and the Secret Key is the password. And the rule that produces most of the confusion: a Dashboard user account cannot call the API directly. That has been true from EMQX 5.0 onward.

In plain terms

The staff badge that gets you through the turnstile in reception is not the key cut for the delivery driver. They open different doors, they are issued by different people, and holding one tells you nothing about the other. Presenting your badge at the loading bay does not get a shrug — it gets a flat refusal, which in this case is spelled 401.

flowchart LR
  subgraph U["A Dashboard user account"]
    direction LR
    U1["Sign in on port 18083"] --> U2["Full use of the
Dashboard in a browser"] U1 --> U3["A call to any path
under /api/v5:
401 Unauthorized"] end subgraph K["An API Key from System then API Key"] direction LR K1["HTTP Basic:
API Key as the username,
Secret Key as the password"] --> K2["Any path under /api/v5"] K2 --> K3["JSON comes back"] end
Two credentials, and only one of them opens the APIThe two lanes never join. Whatever a Dashboard account can do in the browser, it still gets 401 on /api/v5 — which is the single most common cause of that error.

The call to prove it with is the node list. This is one command spread over three lines, with the trailing backslashes joining them:

curl -X GET http://localhost:18083/api/v5/nodes \
-u <your-api-key>:<your-api-secret> \
-H "Content-Type: application/json"

The two angle-bracketed pieces are placeholders. Substitute the Key and the Secret you were shown when you created the API Key — and nothing else in the command changes.

Write every key, secret and token as a placeholder, every time. The real value belongs nowhere except the store you created it in. Not in your own notes, not in a chat message, and above all not pasted into a log or an issue report — a log is exactly the file people copy around when they are asking for help.

The health check endpoint

If you are putting a load balancer in front of EMQX, there is a purpose-built endpoint for it:

GET /api/v5/load_rebalance/availability_check

A healthy node answers 200, meaning it can take connections. A node that has been evacuated — or has already left the cluster — answers 503. That is precisely the shape a health check in HAProxy or nginx wants, and it means a node being drained stops receiving new connections without anyone editing the balancer's configuration.

Reaching it from outside

One switch that puts 1883 on the public internet

The EMQX on your home network accepts connections from the local network only. Outside devices cannot reach it at all, which is a security posture rather than a limitation — until the afternoon you want to check the living-room sensor after you have gone out, or turn off the hallway light from somewhere else. Then you need a path between the local network and the outside world.

From add-on version 5.9.0 onward, Woow EMQX has ngrok built in, and one setting turns raw MQTT on port 1883 into a public TCP tunnel. ngrok is a tunneling service: an agent runs on your machine, opens a connection out to the ngrok cloud, and traffic arriving from outside is forwarded back down that connection to a local port.

Keep the two version numbers apart. Add-on version 5.9.0 adds the built-in ngrok TCP tunnel and nothing else; the core underneath is still EMQX 5.8.9. Changing ngrok_enabled or ngrok_authtoken changes the add-on layer. The authentication, ACL and monitoring behavior that EMQX 5.8.9 already has does not change at all.
Do this before anything else in this section. Once 1883 is open to the public internet, anyone who can reach that address can attempt a connection — and if EMQX has no Authentication configured, it lets every client in. The order is not negotiable: set up authentication and the ACL first, and only then decide whether to switch ngrok on.
In plain terms

You have a shed at the bottom of the garden that nobody outside the family has ever found. Switching on ngrok puts that shed on the map with a street number and a signpost from the main road. It is a genuinely useful thing to do if you need deliveries. It does not put a lock on the shed door, and nobody checked whether there was one.

Turning it on

  1. Step 1

    Check your authentication first

    In the EMQX Dashboard, go to Access Control → Authentication and create a user, then set least privilege under Authorization. At a minimum, make sure that going public will not leave anonymous connections from the internet open.

  2. Step 2

    Turn on the add-on's ngrok settings

    In Home Assistant, go to Settings → Add-ons → Woow EMQX and open the Configuration tab. Find the three ngrok options and set ngrok_enabled to true.

  3. Step 3

    Fill in the authtoken, which is required

    Paste your ngrok authtoken into ngrok_authtoken — shown throughout this guide as <your-ngrok-authtoken>. If you have already reserved a TCP address on your ngrok account, put it in ngrok_tcp_addr; otherwise leave that one empty.

  4. Step 4

    Restart, and read the log

    Go back to the Overview tab and click Restart. Once the add-on is up, open the Log and look for a line of this form:

    >>> MQTT ngrok: <public_url>

    That public address, port included, is what an outside MQTT client connects to. It is not your Home Assistant address on the local network, and configuring the remote client with the local address is the most common reason a connection from outside fails.

The three options, and exactly what each one does

Three options control the whole feature. Their types and defaults come straight from the add-on's config.yaml, where ngrok_enabled is declared bool with a default of false, ngrok_authtoken is password? and ngrok_tcp_addr is str?.

OptionTypeDefaultWhat it does
ngrok_enabledboolfalseStarts and stops the ngrok TCP 1883 tunnel
ngrok_authtokenpasswordemptyAccount credential, required when you enable the tunnel
ngrok_tcp_addrstringemptyNames a reserved address, so you get a fixed endpoint

The authtoken is a secret in the full sense — it carries the permissions on your ngrok account. Do not write your own token into a document, and do not paste it into a log.

flowchart TD
  A["The add-on starts"] --> B{"ngrok_enabled"}
  B -->|"false"| C["The ngrok service idles.
Nothing is exposed"] B -->|"true"| D{"Is ngrok_authtoken filled in?"} D -->|"empty"| E["The service logs an error
and stays idle.
EMQX itself keeps running"] D -->|"filled in"| F{"Is ngrok_tcp_addr set?"} F -->|"empty"| G["Runs ngrok tcp 1883.
ngrok assigns a temporary address,
which can change on every restart"] F -->|"a reserved address"| H["Runs ngrok tcp 1883 with the
remote-addr option set to it.
The endpoint survives a restart"] G --> I["ngrok-announce prints the
public URL into the add-on log"] H --> I
Four combinations, two of which expose nothingThe authtoken is the switch that actually matters: enabled with an empty token behaves the same as not enabled, except that it says so in the log. Only the two routes past a filled-in authtoken put 1883 on the internet.

The runtime behavior in words, because it is worth being able to predict: with ngrok_enabled set to false, the ngrok service simply idles. Enabled but with an empty authtoken, the service logs an error and stays idle — and EMQX itself keeps running as usual. Only once the authtoken has a value does it run ngrok tcp 1883; and if you filled in ngrok_tcp_addr, it runs ngrok tcp 1883 --remote-addr=<address> instead.

If you only want outside access now and then, the simplest setup is an authtoken with everything else left empty, and let ngrok assign a temporary address.

Where the public address comes from

When ngrok is enabled the add-on runs a second service called ngrok-announce. It polls the ngrok agent's own local API at http://127.0.0.1:4040/api/tunnels every two seconds, for up to about 120 seconds, and once it has the public URL of the first tunnel it prints it into the add-on log.

So the place to read the public URL is Home Assistant → Settings → Add-ons → Woow EMQX → Log. If it is not there immediately after a start, the service is most likely still waiting for ngrok to come up, which takes up to about two minutes. If it still has not appeared after that, look at the ngrok service's own log — the usual cause is an authtoken that was not filled in correctly.

The risks, stated plainly

Exposing raw MQTT is not a matter of pushing a port out and forgetting about it. Read these four before you decide:

  • Anyone can attempt a connection. The ngrok address is public by definition, so it hands the broker's 1883 entrance to the whole internet. With Authentication not set up, EMQX lets anonymous clients through.
  • TLS is a separate job. The ngrok TCP tunnel is raw TCP and it does not encrypt the connection for you. If you need encryption, switch to or add an MQTTS (8883) listener.
  • A temporary address does not last. With no reserved address filled in, the endpoint ngrok assigns can change on every restart.
  • Keep exposure minimal. If you need it only occasionally, open it for a set window and close it again when you are done. For long-term exposure, finish authentication, the ACL and whatever TLS you need first.
WebSocket does not go through this tunnel. The add-on's ngrok covers 1883 (raw MQTT) only, and 8083 (MQTT over WebSocket) is outside its scope. If WebSocket is what you need from outside, use Cloudflare Tunnel — that is the alternative the official CHANGELOG and README point to.

When it does not come up

  • Enabled, but no URL in the log. First confirm that ngrok_enabled is true and the authtoken is filled in, then check whether the log holds an “enabled but authtoken is empty” error. If both are right and there is still nothing, restart the add-on or look at the ngrok service's own log.
  • All you see is “ngrok not enabled”. The setting has not taken effect. Go back to the Configuration tab, check ngrok_enabled, restart, and read the log again.
  • An outside client cannot connect. Check that it is using the full URL and port that ngrok printed rather than a local-network address, that you have created the account in EMQX, and that the ACL allows that topic. If the address keeps changing on you, switch to a reserved address in ngrok_tcp_addr.
  • Any client on the internet can get into 1883. Turn ngrok off first. Go back to EMQX, set up Authentication and Authorization, and only then decide whether to expose it again. A public broker that accepts anonymous connections is an obvious warning sign, not an edge case.
Backup and restore

What /data/emqx holds, and what it quietly leaves out

Over time EMQX builds up two kinds of thing you do not want to lose. The configuration is the structure: Authentication, Authorization, rules, connectors and sinks. The data is what sits in the built-in database: accounts, API keys, the blacklist and retained messages. Lose either and you are rebuilding by hand from memory.

EMQX keeps its runtime data in one place, the data directory, and the add-on puts it at /data/emqx. The add-on README states the principle in one line: a backup contains everything under /data/emqx. Here is the exact scope, including the one path that is not in it:

PathWhat it stores
/data/emqx/dataEMQX data, and the persisted built-in database (Mnesia)
/data/emqx/etcEMQX config files, including listener, authentication and integration rewrites
/data/emqx/pluginsPlugin files
/config/logLogs — not part of the backup scope
flowchart LR
  A["A Home Assistant backup
takes the add-on's /data"] --> B["/data/emqx/data
EMQX data and the persisted
built-in database"] A --> C["/data/emqx/etc
config files"] A --> D["/data/emqx/plugins
plugin files"] E["/config/log, and any certificate
or ACL file stored outside
the data directory"] -.-> F["Not in the archive.
Copy these yourself,
before you need them"]
Three paths in, and the exception that catches peopleThe dotted edge is the one to remember. A certificate or ACL file that lives inside the data directory travels with the backup; the same file kept anywhere else does not, and nothing warns you until the restore.
In plain terms

The removal van takes everything inside the house. The bike chained to the lamp post outside is still chained to the lamp post, and the driver is not going to mention it. This is why people say, quite genuinely, “I did take a backup, and the ACL is still missing.” The backup worked. The file was never in the house.

Two ways to take one

A Home Assistant backup covers the add-on's /data, and therefore /data/emqx with it. That makes it the least-effort way to get everything back in one go, and it is the habit worth forming first.

  1. Step 1

    Create a backup in Home Assistant

    Go to Settings → System → Backups and click Back up now. A full backup takes in the add-on's /data. Then sync the backup file somewhere safe — a backup that only exists on the machine you are protecting is not a backup.

  2. Step 2

    Optionally, export a config bundle from the EMQX CLI

    Run emqx ctl data export in the add-on terminal or inside the container. It packs the configuration and the built-in database into a file named on this pattern:

    emqx-export-YYYY-MM-DD-HH-mm-ss.sss.tar.gz

    and writes it into the backup subfolder of the data directory. This is the file-level route, and it suits you when you want the configuration on its own, or want to move it to another EMQX of the same version. The matching command to bring it back is emqx ctl data import.

  3. Step 3

    Know the order you would restore in

    To restore the whole host, roll straight back to that backup. If you are replacing EMQX only — after a reinstall, say — stop the add-on first, put the contents of /data/emqx back where they belong, then start EMQX. Finally, check in the Dashboard that the accounts and the ACL rules are all there. Checking is part of the procedure, not an optional flourish.

  4. Step 4

    Update the add-on, backup in hand

    On the add-on page, click Check for updates at the bottom. Only click update once a new version actually shows up — 5.9.0, for example — and restart as prompted when it finishes. Take a backup before you update. If a release only adds ngrok and leaves the EMQX core alone, the regression risk is relatively low, but low is not zero.

What an export archive actually covers

Read against the EMQX documentation, an export tar usually covers:

  • Authentication and authorization settings.
  • Data Integration — Rules, Connectors, Sinks and Sources.
  • Listener and Gateway settings.
  • The built-in database: Dashboard users and REST API keys, client password-based authentication and enhanced authentication, PSK, Authorization rules, and the Blacklist.
  • Retained messages.

TLS certificates and ACL files that sit inside the data directory travel with it. Ones that sit outside it do not, and you have to move those back by hand before you restore.

The conditions on a CLI import

When you import from the CLI you can name the file by absolute path, by relative path, or — once it is in the backup subfolder of the data directory — by file name alone. The EMQX 5.8 documentation attaches four hard conditions:

  • The EMQX node has to be running when you import.
  • In a core plus replica cluster, import on a core node only.
  • Data exported from the Enterprise edition cannot be imported into Open Source.
  • The file you import must not be renamed.
An import adds and updates; it does not delete. Importing means “add this in, and update what is already there” — the rest of your existing data stays. In a few cases it can be incompatible with what is already present: if the authentication method differs, in the salt position or the password storage mode, old user credentials may stop working after the import. Which is the argument for backing up first and restoring carefully, rather than importing hopefully.
The Dashboard has a backup page, but not in this edition. EMQX Enterprise offers System → Backup & Restore in the Dashboard, which creates and restores backup files from the browser. The Woow add-on ships 5.8.9 Open Source, so your two routes are the CLI pair and host-level Home Assistant backups.

When the restore does not go to plan

  • /data/emqx is not in the backup. Check that the Home Assistant backup includes add-on data — in some cases you back up the system only, or only certain add-ons. If you are replacing EMQX alone and want the existing configuration back at the file level, a CLI export gives you more control.
  • The Dashboard will not open after a restore. Check whether another service is holding 1883 or 18083, and stop whatever conflicts first. Then read the Log and confirm the data directory went back to the right place.
  • The CLI import reports “file not found”. The import file must not be renamed. If it sits in the backup subdirectory, the basename alone is enough. A relative path is resolved against the EMQX root directory.
  • The version looks unchanged after an update. Read the CHANGELOG first. Add-on 5.9.0 only adds the ngrok TCP tunnel; the EMQX core is still 5.8.9. A newer release in the add-on store does not necessarily mean the broker version has moved — the CHANGELOG is what decides. If what you were expecting was a new core feature, you may have to wait for another version.
A backup file is a credential file. Anything holding passwords, API keys or tokens belongs somewhere only you can read. Not in a repository, not in a shared folder that half the household can open, and not attached to a support thread.
Coming from Mosquitto

Only one add-on can hold 1883

Plenty of people arrive at EMQX from the Mosquitto add-on, and there is one fact that shapes the whole migration: Mosquitto and Woow EMQX cannot run at the same time, because both of them bind port 1883.

flowchart LR
  M["The Mosquitto add-on"] --> P["Port 1883"]
  E["The Woow EMQX add-on"] --> P
  P --> R["They cannot run
at the same time"]
One port, two claimantsBoth edges point at the same port, and that is the whole constraint. Stopping Mosquitto is step one of the migration, not tidying up afterwards.
  1. Step 1

    Stop Mosquitto

    Stop — or remove — the Mosquitto add-on to free up 1883.

  2. Step 2

    Move the configuration to EMQX

    Recreate the same users in EMQX; you can keep the credentials you set up before. Then rebuild the ACL rules there, which EMQX manages under Access Control.

  3. Step 3

    Point everything at EMQX

    Change the broker address in Home Assistant's MQTT integration, in Zigbee2MQTT and on each external device to EMQX — homeassistant, port 1883 — and sign in with the EMQX users.

  4. Step 4

    Verify, and finish up

    Confirm that Home Assistant, Zigbee2MQTT and every device connect, and that you can see them on the Clients page. If the old Mosquitto had ACL rules built up over a long time, reviewing them one by one as you convert them to EMQX Authorization is what keeps you from letting something through by mistake.

The backup principle applies to the migration too. Before you start, keep a record of the old Mosquitto configuration exactly as it stands, so you have something to fall back to if the migration does not go through in one sitting.

The two things most often missed are the ACL and the integrations. Mosquitto has no graphical interface and its ACL lives in a config file, so there is nothing on screen to remind you it exists; on EMQX you rebuild it under Access Control → Authorization. And the broker address has to change in Home Assistant's MQTT integration, in Zigbee2MQTT and on your external devices at the same time — a device still pointed at the old broker fails quietly rather than loudly.

Questions people ask

The ones that come up every time

Which log level should I pick?
Stay at warning or higher day to day. When you need to force out the detail — an authentication failure on one particular client, say — dropping the level with Log Trace is the better move: it collects debug for that one target, so you do not have to turn the whole node's log up to debug.
Do trace files grow forever?
No. Each node caps traces at 512 MB; once that is full it stops appending and raises a warning in the main log. It is also worth bounding a trace with start and end times, so that it stops when the window closes rather than when the cap is hit.
Why do the REST API and the Dashboard have different permissions?
From EMQX 5.0 on, the REST API does not accept a Dashboard user login; you have to create an API Key and use HTTP Basic. An API Key comes as its own Key and Secret pair, and that pair is what the API authenticates.
Where is the Health Check endpoint?
The health check endpoint is GET /api/v5/load_rebalance/availability_check. 200 means the node can take connections; 503 means the node is being evacuated or has already left the cluster. It is a good fit for a load balancer such as HAProxy or nginx.
Do I have to use ngrok to reach EMQX from outside?
No. ngrok is only the most convenient method the add-on ships with; a VPN, Cloudflare Tunnel or another reverse proxy can forward to 1883 just as well. If you already run a VPN or a tunneling service, use that first — it keeps the broker off the public internet.
Does the automatic address really change on every restart?
Quite possibly. The temporary TCP endpoint ngrok assigns often comes back with a different number after a restart. When you want a fixed public endpoint, reserve one on your ngrok account and put it in ngrok_tcp_addr; the same address then survives a restart.
Can 8083, MQTT over WebSocket, go through ngrok?
No. The add-on's ngrok handles 1883 raw MQTT only. To serve WebSocket externally, use Cloudflare Tunnel — that is the alternative the official CHANGELOG and README point to.
What is the minimum to configure before going public?
At a minimum you have to be able to refuse anonymous connections: create an authenticator under Access Control → Authentication in EMQX — Password-Based with the Built-in Database is the recommended choice — then set least privilege under Authorization. If you need encryption, consider an MQTTS (8883) listener, because the ngrok TCP tunnel does not provide it.
Do backups have to go through a Home Assistant snapshot?
Do not overthink it. Making a full Home Assistant backup a habit is the most practical thing to do first. When you want to carry the configuration to another EMQX of the same version, reach for the emqx ctl data export and emqx ctl data import pair instead.
Will my MQTT accounts still be there after a restore?
As long as the backup holds the built-in database (emqx_authn_mnesia), password-based users are restored. If you were using an external authenticator such as file or HTTP, check that its settings and its data are in the backup as well.
Does updating the add-on wipe my configuration?
No, as long as /data is not replaced. Upgrading the add-on does not delete the data directory. Even so, take a backup before every upgrade, so you can roll back if the new version does not behave the way you expect.
What gets missed most often when moving over from Mosquitto?
Usually the ACL, and pointing the integrations at EMQX. Mosquitto has no graphical interface and its ACL lives in a config file; on EMQX you rebuild it under Access Control → Authorization. Remember to change the broker address in the Home Assistant MQTT integration, in Zigbee2MQTT and on your external devices at the same time.
Next

Where to go from here

one part left

You can now see it, reach it, and put it back.

Part 9 closes the operations run with the two subjects everything above has been circling: a secure deployment checklist for a broker that is genuinely exposed, and the troubleshooting playbook for the failures you have not met yet.

Open the full guide

Part 8 of the WoowTech EMQX Complete Guide series on the Apporo blog.

Adapted from the WoowTech EMQX Complete Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.

Light · Air · Water · Control · apporo

in EMQX
Nothing is coming through, and the four records that say why