First browse
One command against any OPC UA server: opcua-cli browse opc.tcp://… — and you're inside the address space.
The fastest verification that everything works. Three to five seconds from the prompt to a list of root folders.
Pick a server
Any OPC UA server will do. If you don't have one handy:
docker run --rm -d --name opcua-test -p 4840:4840 open62541/open62541:latest
# The php-opcua test suite ships a Docker stack with several endpoints
git clone https://github.com/php-opcua/uanetstandard-test-suite
cd uanetstandard-test-suite
docker compose up -d
# Server on opc.tcp://localhost:4840 (no security)
Use the endpoint your PLC publishes — typically opc.tcp://<host>:4840.
Browse the Objects folder
opcua-cli browse opc.tcp://localhost:4840
Output (against a vanilla open62541 instance):
├── Server (i=2253) [Object]
├── DeviceSet (ns=2;i=5001) [Object]
├── Aliases (ns=2;i=5002) [Object]
└── PublishSubscribe (ns=0;i=14443) [Object]
That is the canonical first browse — the root Objects folder
(i=85) and its immediate children, rendered as a tree with the
node display name, the canonical NodeId in parentheses, and the
node class in brackets. Every OPC UA server exposes some variant
of this.
Drill down
opcua-cli browse opc.tcp://localhost:4840 /Objects/Server
├── ServerArray (i=2254) [Variable]
├── NamespaceArray (i=2255) [Variable]
├── ServerStatus (i=2256) [Variable]
├── ServiceLevel (i=2267) [Variable]
├── Auditing (i=2994) [Variable]
├── ServerCapabilities (i=2268) [Object]
├── ServerDiagnostics (i=2274) [Object]
├── VendorServerInfo (i=2295) [Object]
├── ServerRedundancy (i=2296) [Object]
└── Namespaces (i=11715) [Object]
/Objects/Server is the standard well-known node every OPC UA
server publishes — covering its product name, status, capabilities,
namespace table.
Read a value
opcua-cli read opc.tcp://localhost:4840 i=2261
NodeId: i=2261
Attribute: Value
Value: open62541 OPC UA Server
Type: String
Status: Good (0x00000000)
Source: 2026-05-15T10:30:00+00:00
Server: 2026-05-15T10:30:00+00:00
i=2261 is the well-known NodeId for the server's product name —
the value you would have read in code as
$client->getServerProductName() from opcua-client. Same
result, no PHP.
Get the endpoints map
opcua-cli endpoints opc.tcp://localhost:4840
Endpoint: opc.tcp://localhost:4840
Security: None (mode: None)
Auth: Anonymous
Endpoint: opc.tcp://localhost:4840
Security: Basic256Sha256 (mode: Sign)
Auth: Anonymous, Username
Endpoint: opc.tcp://localhost:4840
Security: Basic256Sha256 (mode: SignAndEncrypt)
Auth: Anonymous, Username, Certificate
That is the "what does this server support?" probe. You now know which policies + modes + auth combinations the server publishes — the starting point for any real production setup.
Output as JSON
Every command supports --json for scripting:
opcua-cli endpoints opc.tcp://localhost:4840 --json | jq -r '.[].Security'
None (mode: None)
Basic256Sha256 (mode: Sign)
Basic256Sha256 (mode: SignAndEncrypt)
Aes128Sha256RsaOaep (mode: Sign)
See Output formats.
Where to go next
You have run four real OPC UA commands. The next reads, in order of usefulness:
- How it works — twenty seconds of mental model.
- Commands · browse — the full
browsecommand page (recursive, depth, JSON, filters). - Connecting · Trust store workflow — what to do the first time a server requires a trusted certificate (which is most production servers).