ESP32 remote access: reaching its web server from outside the network

The page works on your desk at 192.168.1.50. Once the device is at a customer's site, behind their router, that address means nothing to you. These are the ways around it.

Why it does not just work

The device has a private address that exists only inside its own network. The router lets connections go out and refuses the ones coming in, which is what you want from a router and exactly what stands between you and the device.

1. Port forwarding

You ask the owner of the router to send one of its public ports to the device. It costs nothing on the device, and that is its only advantage. The web server on an ESP32 has no TLS by default and was not written to face the internet; the customer has to change their router and keep it that way; the public address changes unless they pay for a fixed one; and many mobile and business connections share one address between customers, so there is no port to forward at all.

2. A VPN

The device joins a private network that you are also in. WireGuard has been ported to the ESP32 and is light for what it does. You still need a server to run it on, a key pair for every device, and something that hands those out when devices are made. It gives you the device's address and nothing else: logs, crash reports and updates are still yours to build.

3. A message broker

The device connects out to an MQTT broker, and you send it commands and read its answers as messages. This is the usual answer and it works well for telemetry. It does not give you the device's web page, though: you write a second interface, in messages, for everything the page already does. The connection is TLS, which on an ESP32 costs 20 to 40 KB of RAM.

4. An outbound tunnel

The device opens one connection out to a server and keeps it open. When someone asks the server for the device's page, the request travels down that connection to the web server already running on the device, and the answer travels back. Nothing changes on the customer's router, and the page you built is the page you get.

This is what Pinscope does. Setup is a dependency, a key and one call:

#include "pinscope.h"

void app_main(void)
{
    /* your WiFi and web server setup */

    pinscope_start(NULL);
}

Whatever listens on port 80 of the device is then served at an HTTPS address of its own, behind your login, a share link that expires, or an API token for scripts. WebSockets pass through. The connection uses the Noise protocol instead of TLS, so the whole component needs 9.4 KB of RAM.

Which one

Customer changes their networkYou run a serverYou get the device's own page
Port forwardingYesNoYes, without encryption
VPNNoYesYes
Message brokerNoYes, or a paid oneNo
Outbound tunnelNoNo, with a hosted oneYes

Try it

Three devices are free with every feature, and no card is needed. Create an account, or read the five-minute guide first.

More