Практическое руководство: Запуск и настройка OPC UA сервера iotechsys/opc-ua-sim в Docker

  • Михаил
  • 8 мин. на прочтение
  • 6
  • 28 Apr 2026
  • 28 Apr 2026

Цель: Краткая выжимка по запуску рабочего OPC UA сервера с поддержкой авторизации (пароль/сертификаты), настройкой нод и примерами Lua-скриптов.


1. Базовый запуск сервера

Минимальная команда (без безопасности)

 

docker run -d --name opc-ua-sim \
  -p 4840:49947 \
  -v /mnt/iscsi_disk/opcua:/data \
  iotechsys/opc-ua-sim:1.2 \
  -l /data/sensors.lua

Ключевые параметры командной строки

docs.iotechsys.com

Параметр

Кратко

Значение

Описание

--lua-script

-l

путь/к/скрипту.lua

Lua-скрипт для создания нод

--security-policy

-s

None | Basic128Rsa15 | Basic256Sha256

Политика шифрования канала

--security-mode

-m

None | Sign | SignEncrypt

Режим безопасности (подпись/шифрование)

--certificate

-c

путь/к/cert.der

Сертификат сервера (обязателен при политике ≠ None)

--private-key

-p

путь/к/key.der

Приватный ключ сервера

--discovery-url

-d

opc.tcp://lds:4840

Адрес Local Discovery Server

⚠️ Важно: При использовании политик безопасности отличных от None, обязательно указывать --certificate и --private-key


2. Настройка аутентификации

Сервер поддерживает три метода аутентификации пользователей

Вариант 1: Анонимный доступ (по умолчанию)

 

# Просто запускаем без дополнительных настроек
docker run -d --name opc-ua-sim -p 4840:49947 iotechsys/opc-ua-sim:1.2 -l /data/sensors.lua

 

Вариант 2: Логин/пароль (Username/Password)

Для включения аутентификации по паролю необходимо использовать конфигурационный файл сервера (не Lua-скрипт), так как управление пользователями реализуется на уровне компонента OPC-UA Server, а не симулятора.

Пример config.json для Edge XRT OPC-UA Server Component

{
  "AccessControl": {
    "AllowAnonymous": false,
    "EnableX509": false,
    "AccessControlUserPassList": {
      "admin": "SecureP@ss123",
      "operator": "Op3r@tor!2024"
    }
  },
  "SecurityPolicies": [
    {
      "SecurityPolicy": "Basic256Sha256",
      "Certificate": "/certs/server_cert.der",
      "PrivateKey": "/certs/server_key.der"
    }
  ],
  "Endpoints": [
    {
      "SecurityPolicy": "Basic256Sha256",
      "MessageSecurityModes": ["SignEncrypt"]
    }
  ]
}

Запуск с конфигурацией:

 

docker run -d --name opc-ua-sim \
  -p 4840:49947 \
  -v /mnt/iscsi_disk/opcua:/data \
  -v /mnt/iscsi_disk/opcua/certs:/certs:ro \
  iotechsys/opc-ua-sim:1.2 \
  -l /data/sensors.lua \
  --security-policy Basic256Sha256 \
  --security-mode SignEncrypt \
  --certificate /certs/server_cert.der \
  --private-key /certs/server_key.der

 

Вариант 3: Аутентификация по сертификатам (X.509)

  1. Сгенерируйте сертификат сервера (если нет):

 

# Создаём приватный ключ и самоподписанный сертификат
openssl req -x509 -newkey rsa:2048 -days 365 -nodes \
  -keyout server_key.pem -out server_cert.pem \
  -subj "/CN=opc-ua-server/O=MyOrg/C=RU"

# Конвертируем в DER-формат (требование OPC UA)
openssl x509 -in server_cert.pem -outform DER -out server_cert.der
openssl rsa -in server_key.pem -outform DER -out server_key.der
  1. Настройте доверенные клиентские сертификаты (опционально):

 

{
  "CertificateVerification": {
    "TrustList": ["/certs/trusted/client1_cert.der"],
    "IssuerList": ["/certs/ca/root_ca.der"],
    "RevocationList": []
  },
  "AccessControl": {
    "EnableX509": true,
    "AllowAnonymous": false
  }
}
  1. Подключайтесь с клиента, предоставив свой пользовательский сертификат.

3. Структура Lua-скрипта: основные паттерны

Создание пространства имён и папок

 

-- Создаём новое пространство имён (индекс 2+)
ns = Server.addNamespace("MySensors")

-- Корневая папка для нод
root_folder = ObjectNode.newRootFolder("Sensors", ns)
Server.addObjectNode(root_folder)

Переменные (VariableNode)

 

-- Создаём переменную с начальным значением
variant = Variant.new(DataType.DOUBLE)
variant:setScalar(42.5)

temp_node = VariableNode.new(
  NodeId.newString("Temperature", ns),  -- NodeId
  "Temperature",                         -- DisplayName
  root_folder:getNodeId(),               -- Parent
  variant,                               -- Initial value
  AccessLevel.READ | AccessLevel.WRITE   -- Права доступа
)

Server.addVariableNode(temp_node)

Методы (MethodNode)

 

-- Объявляем аргументы
input_arg = Argument.newStandardType("value", DataType.INT32, ValueRank.SCALAR, nil)
output_arg = Argument.newStandardType("result", DataType.STRING, ValueRank.SCALAR, nil)

-- Функция-обработчик
function my_method(inputs, outputs)
  local val = inputs[1]:getScalar()
  outputs[1]:setScalar("Вы ввели: " .. tostring(val))
end

-- Регистрируем метод
method_node = MethodNode.new("ProcessValue", ns, root_folder:getNodeId(), 
                             my_method, {input_arg}, {output_arg})
Server.addMethodNode(method_node)

События (Event)

 

-- Создаём тип события
event_type_id = NodeId.newString("AlarmEvent", ns)
base_event_id = NodeId.newNumeric(ObjectType.BASEEVENTTYPE, 0)
event_type = ObjectTypeNode.new(event_type_id, "AlarmEvent", base_event_id)

-- Источник событий (должен иметь EventNotifier=true)
event_source = ObjectNode.newFolder("AlarmSource", ns, root_folder:getNodeId())
event_source:setEventNotifier(true)

-- Функция генерации события
function trigger_alarm(inputs, outputs)
  Server.triggerEvent(event_type, event_source, 2, "High Temperature!", "LuaScript")
end

 

-- Метод для вызова
alarm_method = MethodNode.new("TriggerAlarm", ns, root_folder:getNodeId(), 
                              trigger_alarm, {}, {})

-- Регистрация
Server.addObjectTypeNode(event_type)
Server.addObjectNode(event_source)
Server.addMethodNode(alarm_method)

Периодическое обновление (Update())

 

last_update = os.time()
wait_time = 1  -- интервал в секундах

function should_update()
  if os.time() - last_update < wait_time then return false end
  last_update = os.time()
  return true
end

function Update()
  if not should_update() then return end
  
  -- Обновляем значение переменной
  local current = temp_node:getVariant():getScalar() + 0.1
  temp_node:getVariant():setScalar(current)
  temp_node:updateValue()  -- Важно: уведомляем клиентов об изменении!
end

4. Пример структуры проекта

 

/mnt/iscsi_disk/opcua/
├── sensors.lua                 # Основной скрипт нод
├── config.json                 # Конфигурация безопасности (опционально)
├── certs/
│   ├── server_cert.der         # Сертификат сервера
│   ├── server_key.der          # Приватный ключ
│   └── trusted/
│       └── client1_cert.der    # Доверенные клиентские сертификаты
└── logs/                       # Опционально: лог-файлы

5. Чеклист безопасности

 

Задача

Решение

🔒 Шифрование канала

Использовать --security-policy Basic256Sha256 + --security-mode SignEncrypt

👤 Аутентификация пользователей

Настроить AccessControlUserPassList в конфиге сервера

🪪 Проверка клиентских сертификатов

Заполнить TrustList и IssuerList в CertificateVerification

🚫 Отключение анонимного доступа

Установить "AllowAnonymous": false

📜 Ротация сертификатов

Использовать внешние скрипты + перезапуск контейнера

💡 Совет: Для продакшена всегда используйте SignEncrypt и отключайте Anonymous. Для тестов допустимо None + Anonymous


6. Проверка подключения

Через uaexpert (бесплатный OPC UA клиент):

  1. Добавьте сервер: opc.tcp://<host>:4840
  2. При запросе безопасности выберите:
    • Security Policy: Basic256Sha256
    • Security Mode: SignAndEncrypt
    • User Identity: Username/Password или Certificate
  3. Введите учётные данные → подключайтесь.

Через командную строку (проверка эндпоинтов):


# Установите opcua-cli: https://github.com/FreeOpcUa/opcua-cli
opcua-cli endpoints --url opc.tcp://localhost:4840

7. Полный пример запуска с безопасностью

#!/bin/bash
# start-secure-opcua.sh

# 1. Генерация сертификатов (если нет)
if [ ! -f /mnt/iscsi_disk/opcua/certs/server_cert.der ]; then
  mkdir -p /mnt/iscsi_disk/opcua/certs
  openssl req -x509 -newkey rsa:2048 -days 365 -nodes \
    -keyout /mnt/iscsi_disk/opcua/certs/server_key.pem \
    -out /mnt/iscsi_disk/opcua/certs/server_cert.pem \
    -subj "/CN=opc-ua-server/O=MyCompany/C=RU"
  
  openssl x509 -in /mnt/iscsi_disk/opcua/certs/server_cert.pem -outform DER \
    -out /mnt/iscsi_disk/opcua/certs/server_cert.der
  openssl rsa -in /mnt/iscsi_disk/opcua/certs/server_key.pem -outform DER \
    -out /mnt/iscsi_disk/opcua/certs/server_key.der
fi

 

# 2. Запуск контейнера
docker run -d --name opc-ua-sim \
  --restart unless-stopped \
  -p 4840:49947 \
  -v /mnt/iscsi_disk/opcua:/data \
  -v /mnt/iscsi_disk/opcua/certs:/certs:ro \
  iotechsys/opc-ua-sim:1.2 \
  -l /data/sensors.lua \
  --security-policy Basic256Sha256 \
  --security-mode SignEncrypt \
  --certificate /certs/server_cert.der \
  --private-key /certs/server_key.der

echo "✅ Сервер запущен. Подключайтесь к opc.tcp://<host>:4840"

Полезные ссылки

  • Официальная документация симулятора:(https://docs.iotechsys.com/edge-xrt21/simulators/opc-ua/simulator/overview.html)
  • Настройка безопасности OPC-UA Server Component:(https://docs.iotechsys.com/edge-xrt21/server-components/opc-ua-server-component.html)
  • Примеры Lua-скриптов: docker exec -it opc-ua-sim ls /example-scripts/
  • Генерация сертификатов OpenSSL:(https://docs.devolutions.net/workspace/kb/general-knowledge/secure-self-signed-certificates/)

⚠️ Важное замечание: Симулятор opc-ua-sim предназначен для тестирования и разработки. Для промышленного использования рассмотрите полнофункциональные OPC UA серверы (например, Prosys, Unified Automation, open62541 с кастомной логикой)