16 min read

How to Expose an OPC UA Server to Remote Clients Securely

Access OPC UA servers across plant network boundaries using a Localtonet TCP tunnel, a Node-RED REST bridge, or an MQTT gateway. No VPN, no inbound firewall rules required.

🏭 OPC UA · IEC 62541 · Industrial Automation · Remote Access · IIoT Security

How to Expose an OPC UA Server to Remote Clients Securely

OPC UA is the lingua franca of modern industrial automation. Siemens, Beckhoff, Bosch, ABB, and virtually every major PLC and SCADA vendor implements it. It carries rich structured data, supports built-in security with X.509 certificates, and forms the foundation of Industry 4.0 data exchange. The challenge is that OPC UA servers on the shop floor are typically unreachable from outside the plant network. This guide covers three approaches to remote OPC UA access: a direct TCP tunnel for development and testing, a gateway proxy approach for production environments, and a Node-RED bridge for integrating OPC UA data into external systems over a Localtonet tunnel.

🔌 OPC UA port 4840 🛡️ X.509 certificate handling 🔗 Node-RED OPC UA bridge 🌍 Remote data access without VPN

What Is OPC UA and Why Does Remote Access Matter?

OPC UA (OPC Unified Architecture, standardised as IEC 62541) is a machine-to-machine communication protocol for industrial automation. Unlike older protocols such as Modbus, which only transfer raw register values, OPC UA carries a rich, self-describing information model. A client that connects to an OPC UA server can browse its address space to discover what data is available variable names, engineering units, data types, hierarchical relationships, and method definitions without any prior knowledge of the system.

This makes OPC UA the foundation of Industrial IoT data collection. ERP systems, MES platforms, data historians, cloud analytics pipelines, and digital twin frameworks all consume OPC UA data. The problem is that production OPC UA servers live inside tightly controlled OT network segments that have no direct path to the internet or the corporate IT network. Making that data available to systems and engineers outside the plant requires a controlled, secure bridge across that network boundary.

🏗️ Self-describing data model Clients browse the server's address space to discover available nodes, their types, and relationships — no hardcoded tag lists required.
🔒 Built-in security X.509 certificate-based authentication and message encryption. Security policies range from None (development) to Basic256Sha256 (production).
📡 Subscriptions Clients subscribe to node changes. The server pushes updates only when values change, reducing network load compared to constant polling.
🌐 Vendor neutral Every major PLC and SCADA vendor supports OPC UA. Siemens TIA Portal, Beckhoff TwinCAT, Rockwell FactoryTalk, AVEVA Wonderware, Ignition; all expose OPC UA servers.

The Network Access Challenge

OPC UA uses the opc.tcp:// URI scheme and communicates over TCP, default port 4840. The protocol includes a Local Discovery Server (LDS) that clients query on port 4840 to enumerate all OPC UA servers running on a host. Each server endpoint is identified by a URL that includes the server's hostname or IP address.

This endpoint URL creates a specific challenge for tunnel-based remote access. When a client connects through a tunnel to a relay address, the OPC UA server returns endpoint descriptions that contain its local IP address not the relay address. The client then tries to use that local IP to establish the actual session, which fails because the local IP is unreachable from outside the plant.

There are three practical approaches to solve this, each appropriate for different situations.

OT security policy applies

Any remote access path to an OPC UA server in a production environment must be reviewed against your organisation's cybersecurity policy and applicable standards including IEC 62443. The approaches in this guide are appropriate for development, testing, and controlled maintenance windows. For permanent production access, a properly architected DMZ with a dedicated OPC UA gateway is the recommended pattern. Always engage your OT security team before implementing remote access.

Approach A: Direct TCP Tunnel with Endpoint URL Override

For development, testing, and vendor commissioning support scenarios, a direct TCP tunnel to port 4840 works well. The endpoint URL mismatch is handled by configuring the OPC UA client to use a fixed endpoint URL rather than relying on the discovery process. Most professional OPC UA clients; UaExpert, Prosys OPC UA Browser, and SDK-based clients support bypassing discovery and connecting directly to a specified endpoint URL.

1

Install Localtonet on the gateway machine inside the OT network

curl -fsSL https://localtonet.com/install.sh | sh
localtonet --authtoken <YOUR_TOKEN>
2

Create a TCP tunnel for port 4840

Go to the TCP/UDP tunnel page, select TCP, set local IP to the OPC UA server's IP address on the OT network (for example 192.168.10.10) and port to 4840. Click Create and start the tunnel. The dashboard shows a relay address such as example.localto.net:34840.

3

Connect with a direct endpoint URL in your OPC UA client

In UaExpert, go to Server → Add → Advanced and enter the endpoint URL manually. In SDK-based clients, specify the endpoint URL directly rather than using the discovery endpoint.

# Endpoint URL format for direct connection via tunnel
opc.tcp://example.localto.net:34840
Security policy selection for tunnelled connections

When connecting through a tunnel with the None security policy (no encryption), the OPC UA layer itself does not encrypt the connection. However, a Localtonet TCP tunnel is a separate transport layer and does not provide OPC UA-level encryption. For development and testing with non-sensitive data, this is acceptable. For production scenarios, use Basic256Sha256 with Sign and Encrypt so OPC UA encrypts the payload independently of the tunnel transport.

Approach B: Node-RED OPC UA to HTTP/REST Bridge

The cleanest production pattern for external OPC UA access is a Node-RED bridge running inside the plant network. Node-RED connects to the OPC UA server on the local OT network using the node-red-contrib-opcua palette, reads or subscribes to specific nodes, and exposes the data through a standard HTTP REST endpoint. A Localtonet HTTP tunnel then makes that REST endpoint accessible from outside. External clients never speak OPC UA directly they call a simple REST API.

This pattern solves the endpoint URL problem entirely because Node-RED connects to OPC UA over the internal network and external clients only see HTTP. It also gives you full control over which data nodes are exposed and how they are formatted.

1

Install Node-RED and the OPC UA palette

sudo npm install -g --unsafe-perm node-red
cd ~/.node-red
npm install node-red-contrib-opcua
node-red
2

Build the OPC UA to REST bridge flow

The flow below reads specific OPC UA nodes on a timer and serves the current values through an HTTP endpoint. External clients call the REST endpoint rather than connecting directly to OPC UA.

In the Node-RED editor, build a flow with these nodes:

A

http in node

Method: GET, URL: /opcua/data. This is the endpoint external clients call.

B

OpcUa-Item node

Set the item to the NodeId you want to read. NodeIds in OPC UA follow the format ns=2;s=Temperature (namespace 2, string identifier "Temperature") or ns=2;i=1001 (namespace 2, numeric identifier 1001). The exact NodeId depends on your OPC UA server's address space. Use UaExpert or the OPC UA Browser node to discover available NodeIds.

C

OpcUa-Client node

Configure the endpoint URL to the OPC UA server's local address: opc.tcp://192.168.10.10:4840. Action: Read. Security Policy: None for development, Basic256Sha256 for production.

D

function node to format the response

// Format OPC UA read result as a clean REST response
msg.payload = {
    nodeId: msg.payload.nodeId || "ns=2;s=Temperature",
    value: msg.payload.value !== undefined ? msg.payload.value : msg.payload,
    timestamp: new Date().toISOString(),
    quality: "Good"
};
return msg;
E

http response node

Returns the formatted JSON payload to the REST client.

Deploy the flow and test it locally:

curl http://localhost:1880/opcua/data

If it returns a JSON response with a value, the OPC UA to REST bridge is working. Now create a Localtonet HTTP tunnel for port 1880:

# Create tunnel for Node-RED (HTTP tunnel, port 1880)
# Use the Localtonet dashboard: http tunnel -> 127.0.0.1:1880

External clients now call the REST endpoint through the tunnel:

curl https://abc123.localto.net/opcua/data

Approach C: OPC UA to MQTT Gateway for Continuous Data Streaming

For scenarios where external systems need continuous real-time updates rather than on-demand reads, a Node-RED flow can subscribe to OPC UA node changes and forward them to a Mosquitto MQTT broker. The MQTT broker is then exposed through a Localtonet TCP tunnel. This is the pattern used in Industrial IoT data pipelines feeding cloud platforms, historians, and analytics engines.

This approach extends the monitoring stack described in the factory machine monitoring guide. The difference is the data source: instead of Modbus TCP, OPC UA subscriptions drive the data feed.

1

Add an OpcUa-Client node in subscription mode

In the OpcUa-Client node settings, set Action to Subscribe and configure the sampling interval (for example 1000 ms). The node pushes a message to the flow every time the subscribed value changes.

2

Add a function node to structure the payload

// Transform OPC UA subscription update to MQTT-ready JSON
var update = msg.payload;

msg.payload = JSON.stringify({
    nodeId: msg.topic,
    value: update.value !== undefined ? update.value : update,
    timestamp: new Date().toISOString(),
    source: "opcua"
});

// MQTT topic structure: plant/line/machine/variable
msg.topic = "plant/line1/cnc_01/spindle_speed";

return msg;
3

Connect to an mqtt out node

Configure the MQTT broker to 127.0.0.1:1883 (your local Mosquitto instance) with authentication credentials. QoS 1 ensures at-least-once delivery.

4

Expose the MQTT broker via a Localtonet TCP tunnel

Go to the TCP/UDP tunnel page, select TCP, set local IP to 127.0.0.1 and port to 1883. External MQTT clients subscribe to plant/# to receive all OPC UA updates forwarded from the plant floor.

Connecting a Python OPC UA Client via Tunnel

For developers building integrations or writing data collection scripts, the asyncua Python library provides a clean interface to OPC UA. When connecting through a Localtonet TCP tunnel, specify the relay address as the endpoint and configure the client to use the tunnel URL rather than the server's local IP.

pip install asyncua
import asyncio
from asyncua import Client

# Replace with your actual Localtonet relay address
RELAY_URL = "opc.tcp://example.localto.net:34840"

async def read_opcua_data():
    async with Client(url=RELAY_URL) as client:
        print(f"Connected to OPC UA server via tunnel")
        print(f"Server product name: {await client.get_namespace_array()}")

        # Browse the root objects folder to discover available nodes
        root = client.get_root_node()
        objects = await root.get_children()
        print("Root node children:")
        for obj in objects:
            name = await obj.read_browse_name()
            print(f"  {name}")

        # Read a specific node by NodeId
        # Adjust ns and identifier to match your server's address space
        node = client.get_node("ns=2;s=Temperature")
        value = await node.read_value()
        print(f"Temperature: {value}")

        # Read multiple nodes at once
        nodes = [
            client.get_node("ns=2;s=Temperature"),
            client.get_node("ns=2;s=Pressure"),
            client.get_node("ns=2;s=MotorSpeed"),
        ]
        values = await client.read_values(nodes)
        print(f"Temperature: {values[0]}, Pressure: {values[1]}, Speed: {values[2]}")

asyncio.run(read_opcua_data())

For subscription-based continuous monitoring through the tunnel:

import asyncio
from asyncua import Client
from asyncua.common.subscription import SubHandler

RELAY_URL = "opc.tcp://example.localto.net:34840"

class DataChangeHandler(SubHandler):
    def datachange_notification(self, node, val, data):
        print(f"Node {node}: value changed to {val}")

async def subscribe_opcua():
    async with Client(url=RELAY_URL) as client:
        handler = DataChangeHandler()
        subscription = await client.create_subscription(500, handler)

        # Subscribe to specific nodes
        nodes = [
            client.get_node("ns=2;s=Temperature"),
            client.get_node("ns=2;s=Pressure"),
        ]
        await subscription.subscribe_data_change(nodes)

        print("Subscribed. Waiting for data changes...")
        await asyncio.sleep(60)  # Collect data for 60 seconds

asyncio.run(subscribe_opcua())

Security Considerations for Remote OPC UA Access

🔐 Enable SSO authentication on all tunnels

In the Localtonet dashboard, enable Single Sign-On on every tunnel used for OPC UA access. For TCP tunnels, SSO adds an authentication layer at the relay before the TCP connection is forwarded. Only engineers authenticated via Google, GitHub, Microsoft, or GitLab can establish a connection. See the SSO documentation for setup steps.

🔑 Use OPC UA username and password authentication

Most OPC UA servers support username and password user identity tokens in addition to anonymous access. Configure the OPC UA server to require authenticated sessions and disable anonymous login. Remote clients must provide valid credentials to establish a session, providing a second authentication layer independent of the tunnel.

🛡️ Use Basic256Sha256 security policy in production

The Basic256Sha256 security policy with Sign and Encrypt mode encrypts OPC UA message payloads end-to-end between client and server. This protects process data even if the tunnel transport is compromised. Both client and server must exchange and trust each other's X.509 certificates before a session can be established. The None security policy is acceptable for development and testing on isolated test systems only.

📋 Prefer Approach B or C for production access

The direct TCP tunnel (Approach A) gives a remote client full OPC UA access to the server's address space, including the ability to call Methods and potentially write variable values if the server allows it. The Node-RED REST bridge (Approach B) and the MQTT gateway (Approach C) expose only the specific data points you explicitly include in the flow, giving you fine-grained control over what information leaves the OT network.

⏱ Open tunnels only during approved maintenance windows

Do not leave OPC UA tunnels running continuously unless there is an operational requirement. Define a change management process for opening and closing tunnels, log the access windows, and restrict access to named individuals. A stopped tunnel creates no attack surface.

Frequently Asked Questions

Why does my OPC UA client connect but fail to establish a session through the tunnel?

This is typically the endpoint URL mismatch issue. The OPC UA server advertises its endpoint using its local IP address. When the client receives that endpoint URL, it tries to connect directly to the local IP, which is unreachable from outside the plant. The solution is to configure your OPC UA client to use a direct endpoint URL rather than relying on the discovery response. In the asyncua Python library, pass the relay URL directly to the Client constructor. In UaExpert, use Advanced mode to enter the endpoint URL manually.

Does the OPC UA server need any configuration changes to allow tunnel-based connections?

For the direct TCP tunnel approach, the server itself requires no changes. The tunnel is transparent at the TCP layer. For security policy selection, ensure the server has an endpoint configured with the security policy your client will use. If the server only offers a Basic256Sha256 endpoint, the client must have a valid certificate to connect. For the Node-RED bridge and MQTT gateway approaches, no OPC UA server changes are required at all Node-RED connects over the local network as a normal OPC UA client.

Can I write values to the OPC UA server through a tunnel?

Technically yes, if the OPC UA server's access control allows it and the client has the appropriate user permissions. However, writing process values remotely to a production system requires careful consideration. Setpoint changes and output writes should only be done through the direct TCP tunnel approach with authenticated sessions, and only during defined maintenance windows with explicit authorisation. Never expose a write-capable OPC UA connection through a permanently open tunnel.

Which approach is best for feeding data to a cloud analytics platform?

Approach C the MQTT gateway is best for continuous data streaming to cloud platforms. Most cloud IoT platforms (AWS IoT, Azure IoT Hub, Google Cloud IoT) have native MQTT connectors. Node-RED subscribes to OPC UA changes on the local network, publishes to a local MQTT broker, and the cloud platform subscribes to that broker through the Localtonet TCP tunnel. For larger installations, consider an MQTT bridge configured at the broker level rather than at the Node-RED level for better throughput.

Is OPC UA over a tunnel compliant with IEC 62443?

Compliance depends on how the tunnel is implemented and governed, not the tunnel technology itself. A tunnel approach can be part of a compliant architecture if it implements the zone and conduit model (the gateway machine forms a conduit between the OT zone and the external zone), enforces authentication at the tunnel level, uses OPC UA security policies with encryption, is subject to change management, and is logged and monitored. Engage your OT security team and review against the specific IEC 62443-3-3 security level requirements for your installation.

Can the same gateway machine handle multiple OPC UA servers?

Yes. Create a separate TCP tunnel for each OPC UA server endpoint. Each tunnel gets its own relay address. A single Localtonet client instance handles all tunnels associated with its AuthToken simultaneously. In Node-RED, you can create separate OpcUa-Client nodes pointing at different servers, all publishing to the same MQTT broker through a single TCP tunnel.

Bring OPC UA Data Across Your Network Boundary Securely

Deploy a Node-RED bridge inside your OT network, subscribe to OPC UA nodes from local PLCs and SCADA servers, and expose the data through a Localtonet tunnel. External systems get clean REST or MQTT access to live process data without any VPN provisioning.

Create Free Localtonet Account →

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support