Do you need to access data from your OPC UA servers from web applications or IT systems easily and securely? This Gateway acts as a robust bridge, offering a modern REST API and advanced monitoring over OPC UA.
graph TD
A[OPC UA Server] -- Secure Connection --> B(OPC UA Gateway);
B -- REST API --> D[Web Application];
B -- REST API --> E[Python/Node Script];
B -- REST API --> F[IoT Platform];
B -- REST API --> G[Kepware IoT GW Client];
subgraph Consumer Clients
direction LR %% Force internal layout if necessary %%
D
E
F
G
end
- Simplifies OPC UA Access: Forget the complexities of the OPC UA protocol. Interact using a simple REST API.
- IT/OT Integration: Facilitates the connection between the operational technology (OT) world and information technology (IT) systems.
- Centralized Security: Manage OPC UA connection security and API security in one place.
- Standard Monitoring: Use SNMP (v1/v2c/v3) and/or the REST API to monitor the gateway's status and performance.
- Compatibility:
/iotgatewayendpoints designed to ease migration from or coexistence with Kepware IoT Gateway. - Open Source: Completely free, open-source code (MIT License) with the possibility to contribute.
- Modern and Lightweight: Built with Node.js, ideal for efficient deployments.
- Visualize production data from PLCs (via OPC UA) on web dashboards (Grafana, etc.) in real-time.
- Integrate OPC UA alarms with ticketing systems, databases, or notification services (Email, Slack).
- Store historical process data from a SCADA system in time-series databases (InfluxDB, TimescaleDB).
- Allow scripts (Python, Node.js) to read/write data in control systems in a controlled and secure manner.
- Migrate client applications that used Kepware IoT Gateway to an open-source solution.
- Quick Start (Docker)
- Main Features
- Installation and Deployment
- Configuration
- Detailed Security
- Metrics and Monitoring
- API Endpoints
- Project Structure
- Error Handling
- Security Best Practices
- Requirements
- Code of Conduct
- Contributing
- License
- Author
The fastest and recommended way to run the gateway using Docker and the official Docker Hub image:
-
Create
docker-compose.ymlfile: Create a file nameddocker-compose.ymlin a folder of your choice with the following content:version: '3.8' services: opcua-gateway: image: exacross/opcua-gateway:latest # Use the image from Docker Hub container_name: opcua-gw ports: - '3000:3000' # Map host port to container port env_file: - .env # Load environment variables from .env file restart: unless-stopped # Optional: Mount volume for certificates if using secure modes # volumes: # - ./certificates:/app/certificates
-
Create
.envfile: In the same folder where you createddocker-compose.yml, create a file named.env. Copy and paste the necessary configuration variables from the Environment Variables section. At a minimum, you need to configure:# Required for basic connection OPC_ENDPOINT=opc.tcp://YOUR_OPCUA_SERVER:4840 # Required for API security (choose one or both) API_KEY=A_SECURE_API_KEY_HERE # or AUTH_USERNAME=your_basic_user AUTH_PASSWORD=your_basic_password # Recommended (adjust as needed) LOG_LEVEL=info LOG_TO_CONSOLE=true # ... other variables you need to modify ...
Replace the example values with your actual configuration.
-
Start the Container: Open a terminal in the folder where you created the files and run:
docker-compose up -d
Docker will automatically download (
pull) theexacross/opcua-gateway:latestimage if you don't have it locally and then start the container. -
Verify Status: Wait a few seconds and check the health endpoint:
curl http://localhost:3000/health # You should see a JSON response indicating "UP" and "CONNECTED" status
Done! The gateway is running and accessible at http://localhost:3000, using the official image and your local configuration.
- π Secure Connection: Support for different OPC UA security modes and policies.
- π Modern REST API: Intuitive endpoints for reading and writing OPC UA values.
- π€ Kepware Compatibility:
/iotgatewayendpoints for easy integration/migration. - π Connection Pooling: Efficient management of OPC UA sessions.
- π Automatic Reconnection: Robust handling of disconnections with configurable retries.
- π‘οΈ Complete API Security: Dual authentication (Basic/API Key), Rate Limiting, CORS, Helmet.
- π Advanced Monitoring: Detailed metrics via REST API and SNMP (v1/v2c/v3) with Zabbix template.
- π Configurable Logging: Log levels, output to console and/or files.
- βοΈ Modular and Maintainable: Clear and organized project structure.
- π³ Easy Deployment: Ready to use with Docker and Docker Compose.
- π Open Source (MIT): Freedom to use, modify, and distribute.
See the Quick Start (Docker) section.
To build the image manually:
docker build -t opcua-gateway .To run the container manually (make sure you have your .env file ready):
docker run -d \
-p 3000:3000 \
--name opcua-gw \
--env-file .env \
opcua-gateway# 1. Clone the repository (if you haven't already)
git clone https://github.com/tinroad/opcua-gateway
cd opcua-gateway
# 2. Install dependencies
npm install
# 3. Configure environment variables
cp .env.example .env
# Edit .env with your development settings
# 4. Start development server (with nodemon for auto-reloading)
npm run dev# 1. Make sure you have Node.js >= 14.0.0 on your server
# 2. Clone or copy the source code to your server
# 3. Install ONLY production dependencies
npm install --production
# 4. Configure environment variables in `.env`
# MAKE SURE TO USE SECURE CREDENTIALS AND SETTINGS FOR PRODUCTION!
# 5. Start the server (recommended to use a process manager like pm2)
npm start
# Or with pm2:
# pm2 start src/server.js --name opcua-gatewayThe gateway is fully configured via environment variables defined in a .env file in the project root. Copy .env.example to get started.
# === Core OPC UA Configuration ===
OPC_ENDPOINT=opc.tcp://127.0.0.1:4840 # OPC UA Server URL
OPC_SECURITY_MODE=1 # 1:None, 2:Sign, 3:SignAndEncrypt
OPC_SECURITY_POLICY=None # None, Basic128Rsa15, Basic256, Basic256Sha256, Aes128_Sha256_RsaOaep, Aes256_Sha256_RsaPss
OPC_NAMESPACE=2 # Default namespace for Node IDs (if not specified)
OPC_APPLICATION_URI=urn:CLIENT:NodeOPCUA-Client # Client application URI
# === OPC UA Certificate Configuration (only for secure modes > 1) ===
OPC_CERTIFICATE_FILE=./certificates/client_cert.pem
OPC_PRIVATE_KEY_FILE=./certificates/client_key.pem
OPC_TRUSTED_FOLDER=./certificates/trusted # Trusted server certificates
OPC_REJECTED_FOLDER=./certificates/rejected # Rejected certificates
# === OPC UA Connection Configuration ===
CONNECTION_RETRY_MAX=5 # Max retries per connection attempt
CONNECTION_INITIAL_DELAY=1000 # Initial delay before first attempt (ms)
CONNECTION_MAX_RETRY=10 # Global max reconnection attempts (-1 for infinite)
CONNECTION_MAX_DELAY=10000 # Max delay between retries (ms)
CONNECTION_RETRY_DELAY=5000 # Base delay between retries (ms)
# === Web Server Configuration ===
SERVER_PORT=3000 # Port the gateway will listen on
# === API Security Configuration ===
API_KEY=your_api_key_here # Secret key for X-API-Key authentication
AUTH_USERNAME=admin # User for Basic Authentication
AUTH_PASSWORD=your_secure_password # Password for Basic Authentication
ALLOWED_ORIGINS=http://localhost:3000,[https://your-frontend-domain.com](https://your-frontend-domain.com) # Allowed CORS origins (comma-separated)
CORS_MAX_AGE=600 # CORS preflight cache time (seconds)
RATE_LIMIT_WINDOW_MS=900000 # Rate limit time window (15 minutes default)
RATE_LIMIT_MAX=100 # Max requests per IP in the window
# === Logging Configuration ===
LOG_LEVEL=info # Log level: error, warn, info, http, verbose, debug, silly
LOG_FILE_ERROR=error.log # File for error logs
LOG_FILE_COMBINED=combined.log # File for all logs
LOG_TO_CONSOLE=true # Log to console? (true/false)
# === SNMP Configuration ===
ENABLE_SNMP=true # Enable SNMP agent (true/false)
SNMP_PORT=161 # SNMP agent port
SNMP_COMMUNITY=public # Community for SNMP v1/v2c
SNMP_VERSION=3 # SNMP version: 1, 2c, or 3
# --- SNMPv3 Configuration (if SNMP_VERSION=3) ---
SNMP_SECURITY_NAME=opcgwuser # Main SNMPv3 user
SNMP_SECURITY_LEVEL=authPriv # Level: noAuthNoPriv, authNoPriv, authPriv
SNMP_AUTH_PROTOCOL=SHA256 # Auth protocol: MD5, SHA1, SHA224, SHA256, SHA384, SHA512
SNMP_AUTH_KEY=opcgw_auth_key # Auth key (min 8 chars)
SNMP_PRIV_PROTOCOL=AES128 # Privacy protocol: DES, AES128, AES192, AES256, AES192C, AES256C
SNMP_PRIV_KEY=opcgw_priv_key # Privacy key (min 8 chars)
# --- Additional SNMPv3 User (Optional) ---
# SNMP_USER_2_NAME=zabbix
# SNMP_USER_2_LEVEL=authPriv
# ... (full configuration for user 2)Security is paramount. This gateway implements several layers:
You can protect the /iotgateway and /api endpoints using one or both methods simultaneously:
-
Basic Authentication:
- Uses username and password (
AUTH_USERNAME,AUTH_PASSWORD). - Ideal for quick tests or human access.
- Example with
curl:curl -X GET "http://localhost:3000/iotgateway/read?ids=ns=2;s=MiVariable" \ -u "admin:your_secure_password"
- Uses username and password (
-
API Key Authentication:
- Uses a secret key (
API_KEY) sent in theX-API-Keyheader. - Recommended for machine-to-machine (M2M) communication.
- Example with
curl:curl -X GET "http://localhost:3000/iotgateway/read?ids=ns=2;s=MiVariable" \ -H "X-API-Key: your_api_key_here"
- Uses a secret key (
- Protects against brute force and DoS attacks by limiting the number of requests per IP (
RATE_LIMIT_WINDOW_MS,RATE_LIMIT_MAX). - Responds with
429 Too Many Requestsif the limit is exceeded.
- Controls which origins (web browsers) can make requests to the API (
ALLOWED_ORIGINS). - Configurable to allow credentials and specific methods.
- Automatically applies various security-related HTTP headers to protect against common attacks (XSS, clickjacking, etc.).
Gain visibility into the gateway's performance and status:
Endpoints under /api/metrics (require authentication) expose metrics in JSON format:
/api/metrics: All metrics./api/metrics/opcua: OPC UA specific metrics./api/metrics/http: HTTP request metrics./api/metrics/system: System metrics (CPU, memory, etc.).
If ENABLE_SNMP=true, the gateway acts as an SNMP agent.
- Supports SNMP v1, v2c, and v3.
- Exposes metrics using OIDs under the enterprise base
1.3.6.1.4.1.12345.
- Configure the version, port, community (v1/v2c), or security credentials (v3) using the
SNMP_*environment variables. - SNMPv3 is recommended for production due to its enhanced security (authentication and encryption).
Simplify Zabbix integration!
- Make sure
ENABLE_SNMPis active in.env. - Generate the Zabbix XML template:
npm run generate:zabbix # Options to customize SNMP version and security: # node src/tools/generateZabbixTemplate.js --help
- Import the generated
tools/zabbix_template.xmlfile into your Zabbix server. - Add the gateway as a Host in Zabbix, configure the SNMP interface (IP, port, version, community/credentials), and link the imported template.
Key metrics are monitored across three categories (non-exhaustive list):
- OPC UA: Active connections, errors, retries, read/write latency.
- HTTP: Request counts (by status code), errors, latency, rate limit blocks.
- System: CPU usage, memory utilization, uptime.
Check the logs on startup with SNMP enabled or the source code for a detailed OID mapping.
GET /iotgateway/read?ids=<node-id1>,<node-id2>,...- Authentication: Basic Auth (
-u user:pass) OR API Key (-H "X-API-Key: key"). - Query Parameters:
ids(required): One or more OPC UA Node IDs, comma-separated. (E.g.,ns=2;s=MyVariable,ns=3;i=1001)
- Successful Response (200 OK):
{ "readResults": [ { "id": "ns=2;s=MyVariable", "s": true, // Success (OPC UA status code) "r": "Good", // Reason / Status description "v": "123.45", // Read value "t": 1678886400000 // Timestamp (OPC UA source timestamp) } // ... more results ] } - Error Response (e.g., 400 Bad Request if
idsis missing):{ "error": "Parameter 'ids' is required" }
POST /iotgateway/write
Content-Type: application/json- Authentication: Basic Auth OR API Key.
- Request Body (JSON): An array of objects to write.
[ { "id": "ns=2;s=MyVariable", "value": "NewValue" // "dataType": "String" // Optional: Specify OPC UA data type (e.g., Double, Int32, Boolean) }, { "id": "ns=3;i=1002", "value": true, "dataType": "Boolean" } // ... more values to write ] - Successful Response (200 OK):
{ "writeResults": [ { "id": "ns=2;s=MyVariable", "success": true, "message": "Good" // OPC UA status of the write operation } // ... more results ] } - Error Response (e.g., 400 Bad Request if body is invalid):
{ "error": "Invalid or empty request body" }
These endpoints provide additional functionality or direct access (require authentication):
GET /api/opcua/status: OPC UA connection status.GET /api/opcua/read/:nodeId: Direct read of a single node (URL-encoded ID).POST /api/opcua/write/:nodeId: Direct write to a single node (URL-encoded ID, value in JSON body{"value": ...}).GET /api/metrics/...: Detailed metrics endpoints.
GET /health: Basic health status of the gateway (no authentication required). Ideal for load balancers or service checks.{ "status": "UP", "opcClient": "CONNECTED", // or "DISCONNECTED", "CONNECTING" "opcEndpoint": "opc.tcp://127.0.0.1:4840", "time": 1678886500000 }
project/
βββ src/
β βββ config/ # Configuration files (central, CORS)
β βββ services/ # Main business logic (OPC UA Service)
β βββ middleware/ # Express Middlewares (Auth, Logging, Rate Limit)
β βββ routes/ # API Route definitions (Express)
β βββ utils/ # Utilities (Logger, etc.)
β βββ tools/ # Tools (Zabbix template generator)
β βββ app.js # Express application setup
β βββ server.js # Entry point, server start
βββ certificates/ # OPC UA Certificates (client, trusted, rejected)
βββ public/ # Static files (if any)
βββ .env # Environment variables (DO NOT version control)
βββ .env.example # Example environment variables
βββ Dockerfile # Docker image definition
βββ docker-compose.yml # Docker Compose service definition
- Robust automatic reconnection to OPC UA with exponential backoff.
- Detailed logging of OPC UA and HTTP errors.
- Centralized middleware to catch Express application errors.
- Consistent JSON error responses for the API (4xx/5xx).
401 Unauthorized: Authentication required or invalid.403 Forbidden: Authenticated but not permitted (not currently applicable).429 Too Many Requests: Rate limit exceeded.400 Bad Request: Malformed request (missing parameters, invalid JSON).500 Internal Server Error: Unexpected server error.503 Service Unavailable: OPC UA connection error or other critical service failure.
- Credentials: Use strong API keys and rotate them periodically. Use robust passwords for Basic Auth. Never commit the
.envfile! - HTTPS: In production, ALWAYS run this gateway behind a reverse proxy (Nginx, Traefik, Caddy) that handles HTTPS/TLS.
- Network: Limit access to the gateway port (
SERVER_PORT) only to necessary IPs/networks (firewall). - CORS: Configure
ALLOWED_ORIGINSrestrictively to only the frontend domains needing access. - Rate Limiting: Adjust limits (
RATE_LIMIT_*) based on expected traffic to prevent abuse. - SNMPv3: If using SNMP in production, prefer SNMPv3 with
authPrivfor maximum security. - Updates: Keep dependencies (Node.js, npm libraries) updated to patch vulnerabilities.
- Node.js >= 14.0.0
- Accessible OPC UA server on the network.
- (Optional) Valid OPC UA certificates if using Sign or SignAndEncrypt security modes.
- (Recommended) Docker and Docker Compose for easy deployment.
This project adheres to a Code of Conduct. By participating, you agree to abide by its terms.
Contributions are welcome! If you want to help improve this project, here are some ideas:
- Report bugs or suggest new features by creating a GitHub Issue.
- Check the open issues, especially those tagged
good first issueorhelp wanted. - Improve the documentation.
- Submit Pull Requests with fixes or new features.
This project uses Conventional Commits for commit messages. This helps maintain a clean history and automatically generate changelogs. The basic format is:
<type>(<scope>): <description>
Where <type> can be feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, config.
For more details on how to contribute, please see CONTRIBUTING.md.
Distributed under the MIT License. See LICENSE for more information.
