OPC UA Reverse Connect: When the Server Has to Dial the Client
How reverse connect flips the TCP direction through a cell firewall, and the certificate, endpoint and diagnostic traps that still bite afterward.
The firewall team will not open an inbound port into the production cell, and they are right not to. Your SCADA client normally dials the OPC UA server on opc.tcp port 4840, which means an inbound rule from the SCADA VLAN into the cell — exactly the direction a segmented plant is trying to kill. Reverse connect is how you get the data anyway without arguing about it.
The trick is one extra message. In a normal session the client sends Hello first. With reverse connect the server opens the TCP socket outbound and sends a ReverseHello (defined in OPC UA Part 6, the UA Connection Protocol) carrying its ServerUri and EndpointUrl. The client, sitting on a listener socket, answers with the usual Hello and from there the secure channel and session run exactly as they always do. Nothing about security changes — you have only reversed who dials whom on the first packet, so the firewall rule becomes an outbound allow from the cell, which is the rule the site will actually sign off on.
Where it earns its keep:
- OEM machine servers that need to reach plant SCADA but sit behind the machine builder's own firewall.
- Skids and package units inside a cell you segmented on purpose.
- A DMZ collector that must never initiate connections into the production zone (per the IEC 62443 zone-and-conduit model).
- NAT that makes the server's address unstable from the client side.
One thing it does not do: reverse connect gets you a TCP socket. It does not hand you certificate trust, endpoint selection, user authentication, or a working subscription. Every OPC UA failure mode that existed before still exists — you have just changed which side blocks on the network.
Write down who listens and who dials
"SCADA talks to the PLC" is useless here. Reverse connect inverts the direction, so before anything else pin down who holds the listener socket and who opens the outbound connection to it.
| Item | Example | Field check |
|---|---|---|
| Reverse connect client listener | 10.40.8.21:4841 | Port is open on the SCADA or collector host. |
| Server outbound target | opc.tcp://10.40.8.21:4841 | Server configuration matches the listener address. |
| Firewall direction | Cell to SCADA network | Rule allows server source to client listener destination. |
| Application URI | urn:Line3:Press01:UaServer | Certificate identity matches the expected application. |
| Endpoint after handoff | Security policy and mode | Client chooses the intended secure endpoint. |
| Reconnect behavior | 10 s retry, bounded logs | Server retries without flooding diagnostics. |
This table prevents a common commissioning argument: the firewall team sees allowed outbound traffic, while the SCADA team is still testing the old inbound server port.
The socket is up and it still won't trust you
Certificate validation (Part 4, application instance certificates) does not care which direction the TCP connection came from. Both ends still swap and check certificates the same way they would on a normal connection. The most common reverse-connect ticket I get is "the server is connecting but the session never comes up" — and nine times out of ten the network is fine and one side rejected a certificate silently.
Things that actually go wrong:
- Server cert isn't in the client's trust store, or the client cert isn't in the server's — reverse connect doesn't change that both directions may validate.
- The certificate's ApplicationUri doesn't match the
applicationUriin the endpoint description. UA stacks treat that as a hard reject, and the error text is often just "BadSecurityChecksFailed". - After you swap a client or server, the old cert lands in the rejected folder and the new one never gets promoted to trusted. Clean the rejected folder as part of the swap, not after the outage.
- Expiry. A three-year cert issued at commissioning fails on a random Tuesday with nobody watching. Put the expiry date on the same review as UPS batteries.
Worth doing once in a maintenance window: pull trust deliberately and confirm the diagnostic actually says certificate rejected, not a generic "connection failed". If the only thing an operator ever sees is "connection failed", you've bought yourself a two-hour phone call the day it happens for real.
The client will happily pick the wrong endpoint
A typical server advertises a fistful of endpoints: SecurityPolicy#None, Sign and SignAndEncrypt over Basic256Sha256, and the newer Aes128Sha256RsaOaep / Aes256Sha256RsaPss profiles, each crossed with anonymous and username/password token policies. (Basic128Rsa15 and Basic256 are deprecated in the current spec — turn them off, don't just leave them advertised.) Reverse connect gets the socket up; it does nothing to guarantee the client lands on the endpoint you meant.
What I check before signing off:
- Kill the
#Noneand anonymous endpoints if site policy allows — otherwise a "temporary" test config quietly ships to production on no security. - Write down the exact endpoint URL, security policy, message security mode, and user token type that the client actually negotiated, not the one you intended.
- Confirm the client isn't silently falling back to anonymous when the username token fails.
- Check whether endpoint discovery rides the reverse connection or opens a separate normal
GetEndpointsconnection — some stacks do the latter, which reintroduces the inbound direction you were trying to avoid. - Restart the client and the server separately and watch each recover.
If the first connection comes up but browsing dies, don't blame reverse connect. Capture the client log around endpoint selection — it's almost always user token policy or certificate trust.
Keep the firewall rule narrow — that was the whole point
If reverse connect exists to tighten segmentation, a wide-open rule throws away the reason you did the work. The rule should be as specific as any other:
- Source: the known OPC UA server host or cell subnet.
- Destination: the SCADA client or collector listener host.
- Destination port: the configured reverse connect listener port.
- Protocol: TCP.
- Logging: enabled at least during commissioning.
- Owner: named system or project, not "temporary test".
The failure mode to avoid is a rule that reads "cell network → SCADA network, any high port". That defeats the segmentation you did all this for, and it makes the next person's troubleshooting harder because now anything could be talking to anything.
Capture one good connection and one bad one
Keep a short record of a successful connection and a failed one, with timestamps from both sides. When the connection drops at 3am, having a known-good log to diff against turns a diagnosis into a five-minute comparison instead of a rediscovery.
Worth keeping:
- Firewall accept or deny log for the server outbound connection.
- Client listener log showing the incoming reverse connection.
- Server log showing reverse connect retry and handoff.
- OPC UA secure channel creation result.
- Session creation result and user identity.
- Subscription creation result and monitored item counts.
- First good data timestamp and quality.
Clock sync matters more than people expect here. If the firewall, SCADA server, and machine gateway disagree by even a couple of minutes, correlating a deny log on one box with a channel error on another turns into guesswork. Point all three at the same NTP source before you start.
The failures you'll actually see
| Symptom | Likely checks |
|---|---|
| Server keeps retrying, client sees nothing | Wrong listener IP, firewall direction, NAT address, local host firewall. |
| TCP connects then closes immediately | Product does not support compatible reverse connect handoff, TLS/UA stack mismatch, certificate rejection. |
| Session fails after secure channel | User token policy, username/password, role permissions, server session limit. |
| Browsing works but data does not update | Subscription settings, monitored item limits, namespace mismatch, bad source quality. |
| Works after manual restart only | Reconnect timer, listener startup order, stale connection cleanup. |
| Works in test VLAN but not production | NAT, route asymmetry, firewall object mismatch, DNS difference. |
"Port's open" proves nothing. Reverse connect has three layers to clear, in order: the TCP path, secure channel trust, and a session with a subscription actually delivering good-quality data. A green light on layer one tells you exactly nothing about layers two and three.
What to leave for the next person
Everything above is worthless if the next engineer has to rediscover it under an outage clock. Hand over:
- Listener host, port, and service owner.
- Server reverse target configuration.
- Firewall rule ID and change ticket.
- Certificate locations and renewal owner.
- Expected endpoint security policy and user token type.
- Normal reconnect interval and expected log messages.
- A simple test tag or folder used to prove live data.
Reverse connect isn't a hack — it's a legitimate answer to a firewall that won't open inbound. But it only stays reliable when the direction, trust, and endpoint choices live in the design docs instead of in one commissioning engineer's memory.