Can zrok be used to expose local mqtt broker to internet?

what about this and the error that is being shown while sharing???

After you have solved the DNS problem that is preventing the mqtt server's zrok share from functioning, then you must run a zrok access command on the device where you will use the mqtt server via zrok.

Here's a straightforward writeup about zrok private shares: Private Shares | Zrok

1 Like

so i need to run a zrok instance in the device i wish to connect as an mqtt client to access this mqtt broker right??

You'll need a "zrok access" running on the same device as the mqtt client. The access will open a TCP proxy port like 127.0.0.1:9191 where you can connect to the mqtt server.

Clarification: like the "zrok share" running on the same device as the mqtt server, the "zrok access," too, must be able to lookup the DNS name of the device that provides the zrok instance (zrok controller, zrok frontend, ziti controller, ziti router).

1 Like

understood in my case the mqttclient is an android app and zrok is not available for android.
is it possible to directly access the mqtt broker using public url using just Openziti??

You could run zrok access on a host with public internet access, like an inexpensive VPC, and then access your MQTT broker using the address of that host.

I understand you are aiming to share the mqtt server privately and access it privately from an Android device.

Note: I recommended using only zrok for sharing and accessing if possible, and I agree there's not currently a way to access a share privately Android, so I will guide you to access it privately with the Ziti Mobile Edge app. If you want public TCP access for the MQTT server (not private), you do not need the Android app or any of the steps below! Instead, refer back to the earlier idea about a "personalized frontend."

You can create a new Ziti identity for your Android client device, install Ziti Mobile Edge app, and add the new identity's enrollment token. Remember, the Android device must be able to connect to the ziti controller and router with a global DNS name.

Example:

ziti edge create identity "android1" \
--role-attributes "mqtt-clients" \
--jwt-output-file "android1.jwt"

You'll need to copy the token to the Android device as a JWT file and select it to add the identity.

Finally, you must grant permission to the client identity with a dial service policy.

Find the Ziti service and update it with a role attribute like "mqtt-services."

ziti edge update service "my-mqtt-zrok-share" \
--role-attributes "mqtt-services"

Create a Ziti service policy authorizing clients to dial the service.

ziti edge create service-policy "mqtt-dial-policy" Dial \
--service-roles '#mqtt-services' \
--identity-roles '#mqtt-clients'

I prefer the personalized frontend method. I tried share the service as mentioned here but as i said that DNS lookup error is occurring. My question is it not possible to implement in a local setup (a server without a public domain name)??

Even i tried sharing the service to zrok.io but its giving the following error.

[   7.395]    INFO sdk-golang/ziti.(*listenerManager).createSessionWithBackoff: {session token=[c0fa97b3-84a5-4b26-b5cc-23dc9e4474e6]} new service session
[  19.887] WARNING channel/v2.(*classicDialer).Create [tls:1ba54d52-ffdb-4ac1-8e32-dc39ca0f89a1.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  19.888]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  19.889] WARNING channel/v2.(*classicDialer).Create [tls:1ba54d52-ffdb-4ac1-8e32-dc39ca0f89a1.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  20.793] WARNING channel/v2.(*classicDialer).Create [tls:ed9935f5-5d9d-4898-a3cf-4a8a05b4e4a6.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  20.795]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  20.796] WARNING channel/v2.(*classicDialer).Create [tls:ed9935f5-5d9d-4898-a3cf-4a8a05b4e4a6.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  20.951] WARNING channel/v2.(*classicDialer).Create [tls:f12da3a5-c651-4dbe-ace0-67723a5dda65.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  20.953]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  20.954] WARNING channel/v2.(*classicDialer).Create [tls:f12da3a5-c651-4dbe-ace0-67723a5dda65.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.114] WARNING channel/v2.(*classicDialer).Create [tls:ad2b1ffe-8cee-465d-b3fc-8d1100bb5f32.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.115]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.116] WARNING channel/v2.(*classicDialer).Create [tls:ad2b1ffe-8cee-465d-b3fc-8d1100bb5f32.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.122] WARNING channel/v2.(*classicDialer).Create [tls:60042e42-5eef-4378-9ade-538b5cde57a0.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.124]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.125] WARNING channel/v2.(*classicDialer).Create [tls:60042e42-5eef-4378-9ade-538b5cde57a0.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.211] WARNING channel/v2.(*classicDialer).Create [tls:8a458215-47d2-4a51-a854-d974443e7851.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.213]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.214] WARNING channel/v2.(*classicDialer).Create [tls:8a458215-47d2-4a51-a854-d974443e7851.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.226] WARNING channel/v2.(*classicDialer).Create [tls:def60534-ff9a-44db-bb9e-46b65c67b5ce.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.228]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.229] WARNING channel/v2.(*classicDialer).Create [tls:def60534-ff9a-44db-bb9e-46b65c67b5ce.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.303] WARNING channel/v2.(*classicDialer).Create [tls:2a112305-3f35-488d-8212-495a575939ba.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.305]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.306] WARNING channel/v2.(*classicDialer).Create [tls:2a112305-3f35-488d-8212-495a575939ba.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.363] WARNING channel/v2.(*classicDialer).Create [tls:69e048d6-5988-4dd6-886b-fb1f33cdff4f.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.364]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.366] WARNING channel/v2.(*classicDialer).Create [tls:69e048d6-5988-4dd6-886b-fb1f33cdff4f.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.371] WARNING channel/v2.(*classicDialer).Create [tls:92c34dbe-a505-48d8-81f9-ae47bdcad1fe.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.373]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.374] WARNING channel/v2.(*classicDialer).Create [tls:92c34dbe-a505-48d8-81f9-ae47bdcad1fe.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  21.392] WARNING channel/v2.(*classicDialer).Create [tls:8e55f926-faa1-4bdd-97fa-3a4338b408dc.production.netfoundry.io:443]: {error=[EOF]} error initiating channel with hello
[  21.394]    INFO channel/v2.getRetryVersionFor: defaulting to version 2
[  21.395] WARNING channel/v2.(*classicDialer).Create [tls:8e55f926-faa1-4bdd-97fa-3a4338b408dc.production.netfoundry.io:443]: Retrying dial with protocol version 2
[  32.607]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[Public AWS India(custom config)]} EOF
[  34.167]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[Public OCI Singapore(custom config)]} EOF
[  34.761]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS EU-Central-2(custom config)]} EOF
[  35.267]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS US-West-1-1(custom config)]} EOF
[  35.439]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS EU-West-2(custom config)]} EOF
[  35.479]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS US East 1-2(custom config)]} EOF
[  35.538]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[Public OCI US East(custom config)]} EOF
[  35.591]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS US East 1-1(custom config)]} EOF
[  35.595]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS US-West-1-2(custom config)]} EOF
[  35.665]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS AP-Southeast-4(custom config)]} EOF
[  35.734]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[AWS SA-East-1(custom config)]} EOF

If i integrate this android SDK to app will i be able to achieve this intended behaviour??

is there any possible way to get unique urls for each shares like http for mqtt??

OK, I'll guide you toward a personalized zrok frontend that provides a public TCP proxy to your MQTT server.

You can access the public TCP proxy with any device anywhere on the internet without any additional client software. The MQTT client will only need the address of the personalized frontend, which you must self-host on a public IP.

Yes, it's quite possible to simulate global DNS in a local setup. Your local network's devices can not distinguish between "real" global DNS and the DNS you provide in your environment. You're running everything as Linux services, not in containers, so I will not recommend using Docker DNS aliases.

You have some options for providing DNS in your local environment:

  • Use magic wildcard DNS from provider like sslip.io, e.g., router1.ziti.192.168.1.5.sslip.io. This approach avoids the need to run a local nameserver.
  • If you have a nameserver in your local infrastructure, add a zone like ziti.internal
  • Run a nameserver, e.g., dnsmasq, on a private address that is reachable by all devices in your local environment. Configure your local network to send all DNS queries to dnsmasq. Configure dnsmasq with a custom zone like ziti.internal.
  • If all parts of your local environment are on the same device you could override DNS with the local hosts database file, e.g., /etc/hosts, but remember to remove the overrides from the hosts database when you're finished experimenting. :slightly_smiling_face:

I think you ran a command like zrok share ... with a zrok account that's enabled for NetFoundry's zrok.io and got an unexpected result. What was the full command? What was the result? The error messages from connectEdgeRouter may indicate a problem with the internet connection on the device where you ran the zrok command.

I think you're asking whether the OpenZiti Android/Kotlin SDK can be integrated in a mobile app for the purpose of accessing a public zrok frontend. There's no need for additional software or SDKs on the mobile device if the zrok frontend is public. Any device anywhere on the internet can reach the public frontend's public IP address and open TCP proxy port.

You have complete control of the address and port you publish as a personalized zrok frontend. You could have many personalized zrok frontends on the same VPS with a public IP, one per open TCP port.

Thaks for the reply i resolved the dns issue. But got some other error

calixto_admin@glowfy:/etc/avahi$ zrok share private --backend-mode tcpTunnel 192.168.1.12:1883
[ERROR]: error creating tcpTunnel backend (error listening: failed to listen: no apiSession, authentication attempt failed: Post "https://raspi.local:1280/edge/client/v1/authenticate?method=cert": dial tcp 192.168.1.11:1280: i/o timeout (Client.Timeout exceeded while awaiting headers))

that means if i need to bring multiple brokers to frontend i need to use seperate ports for it.
if so is it an efficient method to use in a production environment.

This means the value of ZROK_API_ENDPOINT (or run zrok config set apiEndpoint) is incorrect on the device where you ran zrok share private.

The incorrect address is raspi.local:1280. I am guessing that is the address of the ziti controller, but you must set the address of the zrok controller. The correct value might be raspi.local:18080.

I'm unsure about the efficiency of the personalized frontend approach. If you suggest a comparison then I might be able to shed some light on how it's more or less efficient.

The complexity of the configuration of the personalized frontend is proportional to the number of public TCP proxies that you require. If you have only one then it's simple, one hundred and you're going to need a configuration management system.

1 Like

Understood but my apiEndpoint is set to raspi.local:18080

calixto_admin@glowfy:~$ zrok config set apiEndpoint http://raspi.local:18080
zrok configuration updated
calixto_admin@glowfy:~$ zrok enable A3SbgpdDQECV
⣻  the zrok environment was successfully enabled...
calixto_admin@glowfy:~$ zrok share private --backend-mode tcpTunnel localhost:1883
[ERROR]: error creating tcpTunnel backend (error listening: failed to listen: no apiSession, authentication attempt failed: Post "https://raspi.local:1280/edge/client/v1/authenticate?method=cert": dial tcp 192.168.1.11:1280: i/o timeout (Client.Timeout exceeded while awaiting headers))

Thank you for confirming the zrok API endpoint is set correctly. I misinterpreted the error message and gave you incorrect diagnosis.

The error message is arising from correctly configured zrok environment that is failing to contact the ziti controller.

The ziti controller's address must be the same for all nodes in your solution. It appears that the zrok controller was previously able to connect to the ziti controller at raspi.local:1280, but the device running zrok share is not.

You already confirmed the DNS name raspi.local is resolving to static IP 192.168.1.11, but the ziti controller did not respond at that address on port 1280/tcp.

If you confirm the ziti controller is indeed listening at 192.168.1.11:1280, then there must be a problem at the network layer between the device running zrok share and the ziti controller.

For example, a missing firewall rule or route.

My guess is that the ziti controller is not yet listening at that address or the device where the ziti controller is listening has a firewall.

you were correct server firewall rules didnt allow the service to listen on port 1280. I didnt check that becuase i remeber doing it for frontend.

it started successfully but later gave this error

calixto_admin@glowfy:~$ zrok share private --backend-mode tcpTunnel localhost:1883
[   2.800]    INFO sdk-golang/ziti.(*listenerManager).createSessionWithBackoff: {session token=[c8924f71-c15f-4399-859a-75d7852d5da6]} new service session
[  17.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[  33.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[  49.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[  65.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[  81.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[  97.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 113.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 129.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 145.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 161.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 177.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 193.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 209.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 225.806]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 241.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 257.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 273.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ 289.805]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} dial tcp 192.168.1.11:3022: i/o timeout
[ERROR]: error creating tcpTunnel backend (error listening: timed out waiting for 1 listeners to be established, only had 0)

i am using the same server to access the frontend too is that okay to do? if its okay how will i acess the broker using an mqtt client??

You configured the firewall to allow other nodes to send input to 192.168.1.11:1280, but you must allow all the TCP ports that are listening for zrok and ziti.

For example:

  • ziti controller - 1280
  • ziti router - 3022
  • zrok controller - 18080
  • zrok frontend - 8080
1 Like

sorry for being careless

[ 111.916]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11

do i need to generate my own certificates??

No, the Linux router deployment will correct this problem when it is restarted after the config.yml is updated to match your environment.

The symptom is that the router presents a server certificate that does not match the address by which the zrok share command is connecting. It's not clear how this mismatch occurred, but you can inspect the router's /var/lib/private/ziti-router/config.yml to add "192.168.1.11" to the list of IP SANs the router should allow.

edge:
  csr:
    country: CA
    province: ON
    locality: Quebec
    organization: Acme Corp
    organizationalUnit: Research
    sans:
      dns:
        - localhost
        - raspi.local
      ip:
        - "127.0.0.1"
        - "::1"
        - "192.168.1.11"

Are you able to share here (or confidentially in a direct message) your router's answer file that was used to generate the configuration from /opt/openziti/etc/router/bootstrap.env? I wish to understand how the mismatch occurred.

did run the bootstrap again

but the error is still coming

calixto_admin@glowfy:~$ zrok share private --backend-mode tcpTunnel localhost:1883
[   2.809]    INFO sdk-golang/ziti.(*listenerManager).createSessionWithBackoff: {session token=[e505620c-a210-4545-8746-0af623dbb37a]} new service session
[   2.897]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   3.893]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   4.894]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   5.953]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   6.944]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   7.892]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   8.893]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[   9.893]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[  10.921]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11
[  11.895]   ERROR sdk-golang/ziti.(*ContextImpl).connectEdgeRouter: {router=[router1]} tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, ::1, not 192.168.1.11

Does your config.yml have a section like this?

edge:
  csr:
    country: CA
    province: ON
    locality: Quebec
    organization: Acme Corp
    organizationalUnit: Research
    sans:
      dns:
        - localhost
      ip:
        - "127.0.0.1"
        - "::1"
        - "192.168.1.11"
1 Like