Запуск OPC UA сервера с веб-интерфейсом
⚠️ Важное предупреждение перед началом: Образ hilschernetpi/netpi-opcua-server поддерживает только архитектуру ARM (Raspberry Pi 3B, netPI). Если ваш сервер работает на x86_64 (обычный ПК/сервер), см. раздел «Альтернативы для x86_64» ниже.Структура решения
📁 /mnt/iscsi_disk/opcuaserver/
├── 📁 certs/ # Сертификаты и ключи (автогенерация)
├── 📁 config/ # Конфигурационные файлы
│ └── 📄 mySensors.xml # Ваша модель данных (эквивалент sensors.lua)
└── 📄 docker-compose.yml # Файл развёртывания (опционально)Шаг 1: Создайте директорию и структуру
# Создайте основную директорию
sudo mkdir -p /mnt/iscsi_disk/opcuaserver/{certs,config}
sudo chown -R $USER:$USER /mnt/iscsi_disk/opcuaserverШаг 2: Создайте XML Nodeset (эквивалент вашего sensors.lua)
Создайте файл /mnt/iscsi_disk/opcuaserver/config/mySensors.xml:
<?xml version="1.0" encoding="utf-8"?>
<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
xmlns:s1="http://mycompany.org/MySensors/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Объявление пространства имён -->
<NamespaceUris>
<Uri>http://mycompany.org/MySensors/</Uri>
</NamespaceUris>
<!-- Алиасы для типов данных -->
<Aliases>
<Alias Alias="Double">i=11</Alias>
<Alias Alias="HasComponent">i=47</Alias>
<Alias Alias="HasTypeDefinition">i=40</Alias>
<Alias Alias="Organizes">i=35</Alias>
</Aliases>
<!-- Папка-контейнер "Sensors" в Objects -->
<UAObject NodeId="ns=1;s=SensorsFolder" BrowseName="1:Sensors">
<DisplayName>Sensors</DisplayName>
<References>
<Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
</References>
</UAObject>
<!-- Переменная: Temperature (Double, начальное значение 22.5, READ|WRITE) -->
<UAVariable NodeId="ns=1;s=Temperature"
BrowseName="1:Temperature"
DataType="Double"
ValueRank="-1"
AccessLevel="3"
UserAccessLevel="3">
<DisplayName>Temperature</DisplayName>
<References>
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;s=SensorsFolder</Reference>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
</References>
<Value>
<uax:Double>22.5</uax:Double>
</Value>
</UAVariable>
<!-- Переменная: Pressure (Double, начальное значение 1013.25, READ|WRITE) -->
<UAVariable NodeId="ns=1;s=Pressure"
BrowseName="1:Pressure"
DataType="Double"
ValueRank="-1"
AccessLevel="3"
UserAccessLevel="3">
<DisplayName>Pressure</DisplayName>
<References>
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;s=SensorsFolder</Reference>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
</References>
<Value>
<uax:Double>1013.25</uax:Double>
</Value>
</UAVariable>
<!-- Переменная: Humidity (Double, начальное значение 45.0, READ|WRITE) -->
<UAVariable NodeId="ns=1;s=Humidity"
BrowseName="1:Humidity"
DataType="Double"
ValueRank="-1"
AccessLevel="3"
UserAccessLevel="3">
<DisplayName>Humidity</DisplayName>
<References>
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;s=SensorsFolder</Reference>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
</References>
<Value>
<uax:Double>45.0</uax:Double>
</Value>
</UAVariable>
</UANodeSet>
Ключевые параметры:
Параметр | Значение | Пояснение |
|---|---|---|
| 3 = READ | WRITE | Разрешает чтение и запись через клиента |
| i=11 | Тип данных (аналог |
| String ID | Удобный идентификатор для клиентов |
| Имя для навигации | Отображается в клиенте (например, в UA Expert) |
Шаг 3: Запуск контейнера
Вариант А: Docker CLI (быстрый старт)
# 1. Создаём volume для сертификатов (если ещё нет)
docker volume create opcuaserver_certs# 2. Запускаем контейнер с вашими параметрами:
docker run -d \
--name opc-ua-server \
--restart=always \
-p 8073:8080/tcp \ # Веб-интерфейс: хост 8073 → контейнер 8080
-p 4840:4840/tcp \ # OPC UA: хост 4840 → контейнер 4840
-v opcuaserver_certs:/certs \
-v /mnt/iscsi_disk/opcuaserver/config:/config:ro \
hilschernetpi/netpi-opcua-server:1.2.1Вариант Б: Docker Compose (рекомендуется для продакшена)
Создайте файл /mnt/iscsi_disk/opcuaserver/docker-compose.yml:
version: "2"
services:
opcuaserver:
image: hilschernetpi/netpi-opcua-server:1.2.1
container_name: opc-ua-server
restart: always
ports:
- "8073:8080/tcp" # Веб-интерфейс
- "4840:4840/tcp" # OPC UA endpoint
volumes:
- opcuaserver_certs:/certs
- ./config:/config:ro # Только чтение для конфигурации
# Для ARM-хостов (Raspberry Pi) не требуется дополнительных настроек
# Для x86_64 см. раздел "Альтернативы" ниже
volumes:
opcuaserver_certs:
external: falseЗапуск:
cd /mnt/iscsi_disk/opcuaserver
docker compose up -dШаг 4: Доступ к веб-интерфейсу и настройка
4.1 Откройте веб-интерфейс
http://:80734.2 Загрузка и компиляция модели
- Загрузите XML: Нажмите
Choose File→ выберитеmySensors.xml→Compile... - Выберите режим компиляции:
Compile unsecure— для тестов (без шифрования)Compile secure— для продакшена (требует сертификаты)
- Запустите сервер: Нажмите
Run...
📝 При первом запуске контейнер автоматически сгенерирует самоподписанный сертификат в /certs.4.3 Подключение клиента (например, UA Expert)
Endpoint URL: opc.tcp://:4840
Security Policy: None (для unsecure) или Basic256Sha256 (для secure)Ваши переменные будут доступны по пути:
Root → Objects → Sensors → [Temperature, Pressure, Humidity]Управление сертификатами (для secure-режима)
# Просмотр сгенерированных сертификатов
docker exec -it opc-ua-server ls -la /certs/
# Копирование сертификата на хост для доверия в клиенте
docker cp opc-ua-server:/certs/server_certificate.der ./myserver_cert.der
# Замена на свой доверенный сертификат:
# 1. Подготовьте файлы: server_certificate.der + server_private_key.pem
# 2. Скопируйте в volume:
docker cp server_certificate.der opc-ua-server:/certs/
docker cp server_private_key.pem opc-ua-server:/certs/# 3. Перезапустите компиляцию в веб-интерфейсе с опцией "secure"
Обновление конфигурации (без пересоздания контейнера)
- Отредактируйте
/mnt/iscsi_disk/opcuaserver/config/mySensors.xml - В веб-интерфейсе: загрузите обновлённый файл →
Compile...→Run... - Старый сервер автоматически остановится, новый запустится с обновлённой моделью
💡 Значения переменных сбрасываются при перезапуске сервера (in-memory хранение). Для персистентности значений требуется доработка сервера или использование внешней БД.Если ваш хост — x86_64 (не ARM)
Образ hilschernetpi/netpi-opcua-server не запустится на обычном сервере. Выберите один из вариантов:
Вариант 1: Официальный open62541 (минималистичный, без веб-интерфейса)
docker run -d \
--name opc-ua-server \
--restart=always \
-p 4840:4840 \
-v /mnt/iscsi_disk/opcuaserver:/data \
open62541/open62541:latest⚠️ Нет веб-интерфейса. Конфигурация — через C-код или предкомпилированный Nodeset.Вариант 2: Сборка собственного образа с веб-интерфейсом
Используйте репозиторий HilscherAutomation/netPI-opcua-server как основу, но:
- Замените базовый образ на
debian:bullseye(x86_64) - Пересоберите open62541 под вашу архитектуру
- Добавьте Node.js веб-интерфейс вручную
Вариант 3: Альтернативные решения с веб-интерфейсом
Решение | Веб-интерфейс | Архитектуры | Лицензия |
|---|---|---|---|
node-opcua + свой UI | ✅ (свой) | x86_64, ARM | MIT |
✅ | x86_64, ARM | Бесплатно для тестов | |
❌ | x86_64, ARM | Коммерческая |
Тестирование работы сервера
Проверка через командную строку (opcua-client):
# Установка клиента (если нет)
pip install opcua-client# Подключение и чтение переменной
opcua-client --url opc.tcp://localhost:4840 \
--node "ns=1;s=Temperature" \
--readПроверка через Python:
from opcua import Client
client = Client("opc.tcp://localhost:4840")
client.connect()
# Чтение
temp = client.get_node("ns=1;s=Temperature")
print(f"Temperature: {temp.get_value()}")
# Запись
temp.set_value(25.0)
print("✓ Значение обновлено")
client.disconnect()Сводная таблица портов и путей
Компонент | Порт контейнера | Порт хоста | Назначение |
|---|---|---|---|
Веб-интерфейс | 8080 | 8073 | Управление сервером через браузер |
OPC UA endpoint | 4840 | 4840 | Подключение клиентов (UA Expert, SCADA) |
Сертификаты |
|
| Хранение ключей и сертификатов |
Конфигурация |
|
| XML Nodeset файлы |
Частые вопросы
❓ Почему значения сбрасываются после перезапуска?
→ Сервер open62541 хранит данные в памяти. Для персистентности нужно:
- Либо доработать сервер (добавить callback на запись в файл/БД)
- Либо использовать внешний источник данных (например, Redis)
❓ Как добавить динамику (как в Lua Update())?
→ В open62541 это делается через DataSource callbacks в C-коде. Веб-интерфейс Hilscher не поддерживает динамическую логику — только статическую модель. Для сложной логики рассмотрите:
- Самостоятельную сборку open62541 с кастомным кодом
- Использование node-opcua с JavaScript-логикой
❓ Как включить шифрование?
- В веб-интерфейсе загрузите свой сертификат + ключ (или используйте сгенерированные)
- Выберите
Compile secure... - В клиенте укажите политику безопасности:
Basic256Sha256+ режимSign & Encrypt
💡 Рекомендация: Если вам критически важна динамическая логика и веб-интерфейс, рассмотрите создание собственного образа на базе node-opcua + Express.js. Это даст гибкость скриптов и современный веб-интерфейс, но потребует больше начальных усилий.
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.