# Deploy the application

> How-to guide: Deploy a server application: files and dependencies, application certificate, XML configuration, ports, discovery server, and licensing.

> This content was machine translated and may contain errors. [Read in German](https://www.traeger.de/docs/development/opcua/server/deployment)

This page shows how to prepare your server application for production.

## Ship the files

The OPC UA .NET SDK consists of a single assembly per target framework. The OPC UA stack and the other libraries of the SDK are included in it. The [Requirements](https://www.traeger.de/en/docs/development/opcua/requirements#target-frameworks) page lists the target frameworks. No installation or registration of the SDK on the target computer is required.

Depending on the target framework, the package `Opc.UaFx.Advanced` depends on other NuGet packages, for example `Newtonsoft.Json`, `BouncyCastle.Cryptography`, and the packages of the embedded web server Kestrel. As of version 2.59, `BouncyCastle.Cryptography` (version 2.7.0) replaces the package `Portable.BouncyCastle`. If your application deploys the assemblies itself, therefore deploy `BouncyCastle.Cryptography.dll` instead of `BouncyCastle.Crypto.dll`. For the target framework `netcoreapp3.1`, it references `Microsoft.AspNetCore.App` instead of the Kestrel packages. The full list per target framework is on the [package page at nuget.org](https://www.nuget.org/packages/Opc.UaFx.Advanced/). These packages are part of the application: `dotnet publish` and the build directory include them automatically. Therefore, ship the complete output directory, not only your own assembly and the SDK assembly.

By default, the SDK creates the certificate stores as directories under the application path (folder `CertificateStores`, see [Application certificate](https://www.traeger.de/en/docs/development/opcua/server/configuration#application-certificate)).

Available on Windows only:

- **OPC Classic:** Access to OPC Classic servers through COM and DCOM requires the [OPC Classic runtime](https://www.traeger.de/en/docs/development/opcua/downloads#opc-classic-runtime) installed on the target computer.
- **Windows service:** You can run a server application as a Windows service (class `OpcServerServiceApplication`) only with the target framework `net472`.
- **Windows certificate stores:** The SDK uses them only if the path of a certificate store starts with `CurrentUser\` or `LocalMachine\`.

## Use your own application certificate

In production, do not use a certificate that the OPC UA .NET SDK created automatically.

**If you already have a suitable certificate**, load your PFX-based certificate from any location with the `OpcCertificateManager` and assign it to the server instance. If a password protects the certificate, use the overload of the `LoadCertificate` method that takes the password (see [Application certificate](https://www.traeger.de/en/docs/development/opcua/server/configuration#application-certificate)):

```csharp
var certificate = OpcCertificateManager.LoadCertificate("MyServerCertificate.pfx");
server.Certificate = certificate;
```

```vbnet
Dim certificate = OpcCertificateManager.LoadCertificate("MyServerCertificate.pfx")
server.Certificate = certificate
```

The certificate must contain the name of the application as its "Common Name" (CN). The name must match the value of the `AssemblyTitle` attribute of the application:

```csharp
[assembly: AssemblyTitle("<Common Name (CN) in Certificate>")]

```

```vbnet
' The AssemblyTitle attribute declaration is used in the AssemblyInfo.vb file of a VB.NET project:
' <Assembly: AssemblyTitle("<Common Name (CN) in Certificate>")> 

```

If it does not, set the name used in the certificate through the `ApplicationName` property of the server instance. If you assign the certificate directly through the `Certificate` property as shown above, the server does not search for it by name:

```csharp
server.ApplicationName = "<Common Name (CN) in Certificate>";
```

```vbnet
server.ApplicationName = "<Common Name (CN) in Certificate>"
```

You do not have to set the `ApplicationUri` property. At startup, the server takes the value from the Subject Alternative Name of the certificate.

**If you do not have a suitable certificate yet** that you can use as the application certificate of your server, create at least a self-signed certificate. Deploy it with the application and load it as shown above. You create the certificate with the `OpcCertificateManager` class. You define the properties of the certificate through an instance of `OpcCertificateSettings`, for example the name of the application, the `ApplicationUri`, the validity in months, or the names of the domains under which clients can reach the server:

```csharp
// Lifetime in months, default: 600.
var settings = new OpcCertificateSettings("MyServerAppName") {
    ApplicationUri = new Uri("urn:localhost:MyServerAppName"),
    Lifetime = 60
};
 
settings.DomainNames.Add("localhost");
settings.DomainNames.Add("myserver.mydomain.com");
 
var certificate = OpcCertificateManager.CreateCertificate(settings);
OpcCertificateManager.SaveCertificate("MyServerCertificate.pfx", certificate);
```

```vbnet
'Lifetime in months, default: 600.
Dim settings = New OpcCertificateSettings("MyServerAppName") With { _
    .ApplicationUri = New Uri("urn:localhost:MyServerAppName"), _
    .Lifetime = 60 _
}

settings.DomainNames.Add("localhost")
settings.DomainNames.Add("myserver.mydomain.com")

Dim certificate = OpcCertificateManager.CreateCertificate(settings)
OpcCertificateManager.SaveCertificate("MyServerCertificate.pfx", certificate)
```

As the name of the application, use the value of the `AssemblyTitle` attribute, or set the same value through the `ApplicationName` property of the server instance. If the server should take the certificate from the store for application certificates instead of loading it directly, save it in the `ApplicationStore`. By default, this is the `CertificateStores\App` folder next to the application (see [Application certificate](https://www.traeger.de/en/docs/development/opcua/server/configuration#application-certificate)).

## Deploy the files of the XML configuration

If you configure the application through an XML file, deploy this file with the application. The application must be able to reach the file:

- If the application loads the configuration with `LoadServerConfigFile`, the file must be at the path specified there.
- If the application loads the configuration with `LoadServerConfig`, the file `<Name>.Config.xml` (for example `Opc.UaFx.Server.Config.xml`) must be in the working directory of the application. The working directory is not always the directory of the application, for example if the application runs as a service.

The server does not evaluate the `App.config` of the application for its configuration (see [Configuration through an XML file](https://www.traeger.de/en/docs/development/opcua/server/configuration#configuration-through-an-xml-file)).

## Set up ports and permissions

The server opens a separate port for each base address, and for `https` it uses an embedded web server (Kestrel). On Windows, it needs neither a reservation of the address (URL ACL, URL Access Control List) nor administrator rights. On Linux, an application needs elevated permissions for ports below 1024 (for example 443). Also make sure that the firewall of the target system allows the ports in use.

## Run your own discovery server

Types used: `OpcDiscoveryServer`, `OpcDiscoveryClient`, `OpcApplicationDescription`, `OpcServer`, `OpcServerDiscovery`

If clients should find the servers of a network through a central address, you can run your own discovery server. A discovery server does not provide an address space. It accepts the registrations of other servers (`RegisterServer` and `RegisterServer2` services) and answers the client requests for the registered servers (`FindServers` service). By default, it offers one endpoint per base address with the mode `SignAndEncrypt` and the algorithm `Basic256Sha256`, but no endpoint with the mode `None`. You create and start it like an `OpcServer`:

```csharp
using (var discoveryServer = new OpcDiscoveryServer("opc.tcp://localhost:4840/")) {
    discoveryServer.Start();
 
    Console.WriteLine("Press any key to stop the discovery server.");
    Console.ReadKey(intercept: true);
}
```

```vbnet
Using discoveryServer = New OpcDiscoveryServer("opc.tcp://localhost:4840/")
    discoveryServer.Start()

    Console.WriteLine("Press any key to stop the discovery server.")
    Console.ReadKey(intercept:=True)
End Using
```

A client determines the servers registered with the discovery server through the `DiscoverServers` method of an `OpcDiscoveryClient` instance:

```csharp
using (var discovery = new OpcDiscoveryClient("opc.tcp://localhost:4840/")) {
    foreach (var application in discovery.DiscoverServers())
        Console.WriteLine("{0}: {1}", application.Name, application.Uri);
}

```

```vbnet
Using discovery = New OpcDiscoveryClient("opc.tcp://localhost:4840/")
    For Each application In discovery.DiscoverServers()
        Console.WriteLine("{0}: {1}", application.Name, application.Uri)
    Next
End Using
```

An `OpcServer` registers itself regularly with the discovery server on its machine, by default at `opc.tcp://localhost:4840` and every 30000 milliseconds. The `Discovery.RegistrationInterval` property sets the interval; the value 0 turns the registration off. A change takes effect with the next start of the server.

## Enter the license

Enter the license key in the application before you deploy the server application. Otherwise, it runs with the trial license, which stops after 30 minutes per application start. The [Set up the license](https://www.traeger.de/en/docs/development/opcua/license-setup) page describes how to enter the key, query the license in use, and check the license at startup.
