Skip to main content

creating-an-opcua-server

Good news, you can already create an OPC UA server using Node-RED, and you don't need a special module for that.

This tutorial shows how to create an OPC UA server directly in a Node-RED Function node using only scripts. It also lets you inject configuration values (port, endpoint, namespace, and a variable value) from other nodes so you can change the server behavior dynamically.

What you will build

  • A Node-RED flow that starts an OPC UA server from a Function node.
  • A dynamic variable that reads its value from msg.value.
  • A simple way to configure the server from an Inject/Change node.

Prerequisites

  • Node-RED installed and running.
  • node-opcua available in the Node-RED runtime.

Install the package in your Node-RED user directory (or wherever your runtime is installed):

npm install node-opcua

Step 1 — Create the flow

Create a basic flow with these nodes:

  1. Inject (or Change) node to set the configuration
  2. Function node to start the server
  3. Debug node to show status

Wire them like this:

Inject/Change → Function → Debug

Step 2 — Configure the Inject or Change node

Set the following properties in the message:

  • msg.port (example: 4840)
  • msg.endpoint (example: my-opcua-server)
  • msg.namespace (example: http://my-opcua-server)
  • msg.value (optional, example: 42.5)

If you prefer, you can use a Change node to set these fields, or use a Function node that returns the message.

Step 3 — Add the Function node code

Paste the following code into the Function node:

// Create a node-opcua server using only scripts
// Variables are injected from other nodes (msg.port, msg.endpoint, msg.namespace, etc.)

const opcua = require("node-opcua");

// Check if required variables are provided
if (!msg.port || !msg.endpoint || !msg.namespace) {
node.error("Missing required variables: port, endpoint, or namespace");
return;
}

// Create OPC UA server
const server = new opcua.OPCUAServer({
port: msg.port || 4840, // Default port if not provided
nodeset_filename: [
opcua.nodesets.standard // Load standard nodeset
],
serverInfo: {
applicationUri: `urn:${msg.endpoint}`,
productUri: "MyOPCUAServer",
applicationName: { text: "MyOPCUAServer", locale: "en-US" },
gatewayServerUri: null,
discoveryProfileUri: null,
discoveryUrls: [],
isOnline: true
}
});

// Define a namespace
const namespace = server.engine.addressSpace.getOwnNamespace();

// Add a variable to the server (example: a dynamic variable)
const variable = namespace.addVariable({
organizedBy: "RootFolder",
nodeId: "s=MyDynamicVariable",
browseName: "MyDynamicVariable",
dataType: "Double",
value: {
get: function () {
return new opcua.Variant({ dataType: opcua.DataType.Double, value: msg.value || 0.0 });
}
}
});

// Start the server
server.start(function (err) {
if (err) {
node.error("Server failed to start: " + err.message);
} else {
node.send({ payload: `OPC UA Server running on port ${msg.port}, endpoint: ${msg.endpoint}` });
}
});

// Handle shutdown
node.on("close", function () {
server.shutdown(1000, function () {
node.log("Server shut down");
});
});

return null; // Prevents sending an output message immediately

Step 4 — Deploy and test

  1. Click Deploy in Node-RED.
  2. Trigger the Inject node.
  3. You should see a status message in the Debug panel.

If the server starts correctly, the Function node will emit a message like:

OPC UA Server running on port 4840, endpoint: my-opcua-server

Step 5 — Update the variable dynamically

To update the variable exposed by the server, send a new message with msg.value to the Function node. The variable MyDynamicVariable will return the updated value on read.

Notes and tips

  • The server shuts down gracefully when the flow stops or is redeployed.
  • You can extend the address space with more variables, objects, or methods using the same namespace.addVariable() pattern.
  • For production deployments, consider adding security policies and certificate handling.

Next steps

Would you like help extending this server with:

  • Custom objects and methods
  • User authentication
  • Security policies and certificates
  • A structured namespace layout