diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs
new file mode 100644
index 0000000..1dbaa27
--- /dev/null
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs
@@ -0,0 +1,117 @@
+using Microsoft.Extensions.Logging;
+using Opc.Ua;
+using Opc.Ua.Configuration;
+using Opc.Ua.Server;
+
+namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
+
+public sealed class OpcUaApplicationHostOptions
+{
+ public string ApplicationName { get; set; } = "OtOpcUa";
+ public string ApplicationUri { get; set; } = "urn:OtOpcUa";
+ public string ProductUri { get; set; } = "https://zb.com/otopcua";
+
+ /// Listening port for the binary endpoint (default 4840).
+ public int OpcUaPort { get; set; } = 4840;
+
+ /// Hostname or IP advertised in endpoint descriptions.
+ public string PublicHostname { get; set; } = "0.0.0.0";
+
+ /// Application config XML path; when set, loaded instead of building from defaults.
+ public string? ApplicationConfigPath { get; set; }
+}
+
+///
+/// Thin facade over the OPC Foundation .NET Standard SDK's application bootstrap.
+/// Owns the + lifetime
+/// and starts a with the supplied node-manager factory.
+///
+/// Full extraction from legacy OtOpcUa.Server (security wiring, ScriptedAlarmDescriptor
+/// pipeline, ResilienceController, history backend, observability hooks) is tracked as
+/// follow-up F13. This facade compiles + boots the SDK so Task 53 can wire the fused Host's
+/// driver-role startup against it.
+///
+public sealed class OpcUaApplicationHost : IAsyncDisposable
+{
+ private readonly OpcUaApplicationHostOptions _options;
+ private readonly ILogger _logger;
+ private ApplicationInstance? _application;
+ private StandardServer? _server;
+
+ public OpcUaApplicationHost(
+ OpcUaApplicationHostOptions options,
+ ILogger logger)
+ {
+ _options = options;
+ _logger = logger;
+ }
+
+ public ApplicationInstance? ApplicationInstance => _application;
+ public StandardServer? Server => _server;
+
+ public async Task StartAsync(StandardServer server, CancellationToken cancellationToken)
+ {
+ _server = server;
+ _application = new ApplicationInstance
+ {
+ ApplicationName = _options.ApplicationName,
+ ApplicationType = ApplicationType.Server,
+ ConfigSectionName = "OtOpcUa",
+ };
+
+ _ = await BuildConfigurationAsync(cancellationToken);
+ // Certificate validation + auto-creation is part of the full extraction (F13).
+ // For the facade we trust that the configured cert store already exists.
+ await _application.Start(server).ConfigureAwait(false);
+
+ _logger.LogInformation("OPC UA server started on opc.tcp://{Host}:{Port}",
+ _options.PublicHostname, _options.OpcUaPort);
+ }
+
+ private async Task BuildConfigurationAsync(CancellationToken ct)
+ {
+ if (!string.IsNullOrWhiteSpace(_options.ApplicationConfigPath))
+ {
+ return await _application!.LoadApplicationConfiguration(_options.ApplicationConfigPath, silent: true);
+ }
+
+ // Minimal defaults — security and certificate stores hardcoded to local files in
+ // the app's working directory. Full security wiring stays in legacy Server until F13.
+ var config = new ApplicationConfiguration
+ {
+ ApplicationName = _options.ApplicationName,
+ ApplicationUri = _options.ApplicationUri,
+ ProductUri = _options.ProductUri,
+ ApplicationType = ApplicationType.Server,
+ ServerConfiguration = new ServerConfiguration
+ {
+ BaseAddresses = { $"opc.tcp://{_options.PublicHostname}:{_options.OpcUaPort}/OtOpcUa" },
+ MinRequestThreadCount = 5,
+ MaxRequestThreadCount = 100,
+ MaxQueuedRequestCount = 200,
+ },
+ SecurityConfiguration = new SecurityConfiguration
+ {
+ ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = "pki/own", SubjectName = $"CN={_options.ApplicationName}" },
+ TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "pki/issuer" },
+ TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "pki/trusted" },
+ RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = "pki/rejected" },
+ AutoAcceptUntrustedCertificates = false,
+ },
+ TransportQuotas = new TransportQuotas(),
+ ClientConfiguration = new ClientConfiguration(),
+ TraceConfiguration = new TraceConfiguration(),
+ };
+
+ await config.Validate(ApplicationType.Server).ConfigureAwait(false);
+ _application!.ApplicationConfiguration = config;
+ return config;
+ }
+
+ public ValueTask DisposeAsync()
+ {
+ try { _application?.Stop(); }
+ catch (Exception ex) { _logger.LogWarning(ex, "OpcUaApplicationHost: Stop threw on dispose"); }
+ return ValueTask.CompletedTask;
+ }
+}