Skip to content

DragOnFlow Linux server installation

Files naming convention

File names should not contain space, slash or back slash!! Whenever possible use lower case names, all other folders like ‘bin’, ‘obj’, ‘db’, ‘css’ are lower case (as this is the visual studio defaults), also for js and images we use lowercase Exceptions are VS or dot net that needs to be title-case (e.g., name of dll) or JS libraries that comes in title case.

Note

Never use backslash in names of files, since the system is designed for windows and Linux this may cause issues.

Typical file hierarchy:

├ dragonflow
  ├ current
  │ ├ modules
  │ │ ├ bin
  │ │ └ websites
  │ ├ projects
  │ │  └ project_x
  │ │    └ aml
  │ │      ├ source
  │ │      ├ bin
  │ │      ├ obj
  │ └ sdk
  ├ config

Prerequisites

Install DotNet SDK:

https://docs.microsoft.com/en-us/dotnet/core/install/linux

Try not to use SNAP to install the framework, as it causes unexpected errors like Segmentation Fault. Allways use APT-GET

Libraries

sudo apt-get install libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 libnss3 libgbm1

On newer systems (ubuntu 24...):

sudo apt-get install -y   libnss3   libx11-6   libx11-xcb1   libxcb1   libxcomposite1   libxcursor1   libxdamage1   libxext6   libxfixes3   libxi6   libxrender1   libxtst6   libatk1.0-0t64   libatk-bridge2.0-0t64 libcups2t64 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc-s1 libglib2.0-0t64 libgtk-3-0t64 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libxkbcommon0 libxrandr2 libasound2t64 fonts-dejavu-core

If you get error, for example with libgconf-2-4:

In Ubuntu 24.04 LTS, the libgconf-2-4 package has been removed from the official repositories, which can cause issues when installing applications that depend on this library. To resolve this, you can manually add a repository from an earlier Ubuntu release that still includes libgconf-2-4. Here's how to do it:

  1. Add the Ubuntu 22.04 (Jammy Jellyfish) repository:

  2. Open a terminal.

  3. Edit the sources list file using a text editor with superuser privileges. For example:

    sudo nano /etc/apt/sources.list.d/ubuntu.sources
    
  4. Add the following lines to include the Jammy repository:

    Types: deb
    URIs: http://archive.ubuntu.com/ubuntu/
    Suites: jammy
    Components: main universe
    
  5. Save and exit the editor.

  6. Update the package list:

sudo apt update

Note: You might encounter warnings about the new repository. Proceed with caution and ensure that adding this repository doesn't conflict with your current system setup.

  1. Install libgconf-2-4:
sudo apt install libgconf-2-4

If you encounter dependency issues, you can attempt to fix them with:

sudo apt --fix-broken install
  1. Remove the added repository (optional but recommended to prevent potential conflicts):

  2. Reopen the sources list file:

    sudo nano /etc/apt/sources.list.d/ubuntu.sources
    
  3. Remove or comment out the lines you added by placing a # at the beginning of each line.

  4. Save and exit the editor.

  5. Update the package list again:

sudo apt update

Caution: Adding repositories from different Ubuntu releases can lead to system instability due to potential package conflicts. Use this method judiciously and consider removing the added repository after installing the necessary package.

Alternatively, some users have created scripts to automate the installation of libgconf-2-4 on systems where it's missing. For instance, a GitHub repository provides a script that might assist in this process: .

Always ensure that adding external repositories or running third-party scripts aligns with your system's security policies and won't introduce vulnerabilities.

Fonts

Add NOTO font for emojis

sudo apt update
sudo apt install fonts-noto-color-emoji

Add Microsoft fonts

sudo apt update
sudo apt install ttf-mscorefonts-installer

Add other fonts (e.g. TTF)

cp [files] /usr/share/fonts/
fc-cache -fv

Verify by running fc-list

Install .NET offline

if need to install the framework offline, goto a system with same OS and same version (exactly), install .net following the regular instaructions (this will update the package repositories with everything). Now on the machine that is connected to the internet, download the DEB files, like this example:

apt-get download  dotnet-targeting-pack-8.0

you will get the files on the folder, copy to the offline machine, and install using:

sudo dpkg -i dotnet-sdk-8.0_8.0.108-0ubuntu1~22.04.1_amd64.deb

you will get errors on missing packages, simply add those one by one.

the correct order is: - dotnet-runtime-8.0_8.0.8-0ubuntu1~22.04.1_amd64.deb - aspnetcore-runtime-8.0_8.0.8-0ubuntu1~22.04.1_amd64.deb - dotnet-apphost-pack-8.0_8.0.8-0ubuntu1~22.04.1_amd64.deb - dotnet-sdk-8.0_8.0.108-0ubuntu1~22.04.1_amd64.deb

when finished, you should be able to dotnet --info and see the SDK & runtime.

Web server

The instructions are for NGINX, but you can use other web servers.

Note

Keep in mind that NGINX is case sensitive

Install:

sudo apt-get install nginx
sudo apt install nginx-extras

Start service:

sudo systemctl start nginx

Configuration of nginX done via Config file, location: '/etc/nginx/sites-available/default'

Configuration

After each config file changes, NGINX must re-read it, use this command

sudo nginx -s reload

Allow HTTP2

server {
    ...
    listen 443 ssl http2  
}

Allow GZIP

http {
    ...
    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/javascript application/xml text/javascript
}

note !! if using certbot it may place: listen [::]:443 ssl ipv6only=on, this can interrupt with ipv4 change the on to off

Security in NGINX

We want to avoid leaking information like server type and version.

Remove server information:

install sudo apt install libnginx-mod-http-headers-more-filter

Edit /etc/nginx/nginx.conf

make sure:

http {

    server_tokens off;   # hides version globally
    more_clear_headers Server;  # remove the Server header completely

custom errors:

in each server section in the nginx configuration place the following:

    # --- Custom error pages ---
    error_page 404 /custom_404.html;
    error_page 500 502 503 504 /custom_50x.html;

    location = /custom_404.html {
        internal;
        root /var/www/errors;  # store a minimal 404 page here
        add_header Content-Security-Policy "default-src 'none';script-src 'none';img-src 'none';font-src 'none';connect-src 'none';frame-src 'none';object-src 'none';media-src 'none';style-src 'self';base-uri 'none';form-action 'none';frame-ancestors 'none';" always;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    }

    location = /custom_50x.html {
        internal;
        root /var/www/errors;  # store a minimal 50x page here
        add_header Content-Security-Policy "default-src 'none';script-src 'none';img-src 'none';font-src 'none';connect-src 'none';frame-src 'none';object-src 'none';media-src 'none';style-src 'self';base-uri 'none';form-action 'none';frame-ancestors 'none';" always;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    }

Place custom error files /var/www/errors/custom_404.html , /var/www/errors/custom_50X.html

Note: We set headers to error files for better complience

  • Sample files can be found in: \dragonflow\current\modules\websites\error_files

Debugging

You can type: tail -f /var/log/nginx/error.log to view the NginX log

Nats-Server

Optionally Dragonflow can use Nats-server for it's internal messaging. You can read about Nats-server in: nats.io.

To install

sudo wget https://github.com/nats-io/nats-server/releases/download/v2.9.7/nats-server-v2.9.7-amd64.deb
sudo apt install ./nats-server-v2.9.7.amd64.deb

don't use snap, it is not updated

create a service:

nano /etc/systemd/system/nats-server.service

place the following:

[Unit]
Description=NATS Server
After=network.target ntp.service

[Service]
PrivateTmp=true
Type=simple
ExecStart=/bin/nats-server
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s SIGINT $MAINPID
User=root


[Install]
WantedBy=multi-user.target

Use a proper user with correct permissions (don't use root unless debugging). you can also add a config file using the /c command option example: nats-server -c /etc/nats-server.conf

then add the service start and check for status

systemctl enable nats-server.service
systemctl start nats-server.service
systemctl status nats-server.service

Database

You can use MySQL or external MSSQL. the following instructions install a typical local MySQL.

Install MySQL UBUNTU:

sudo apt install mysql-server

DEBIAN:

You might need to install:
apt install gnupg

Install the repository then MySQL (Check the latest version in https://dev.mysql.com/downloads/repo/apt/)

wget https://dev.mysql.com/get/mysql-apt-config_0.8.18-1_all.deb
dpkg -i mysql-apt-config_0.8.18-1_all.deb

apt install mysql-server

rm mysql-apt-config_0.8.18-1_all.deb

Allow remote

nano /etc/mysql/mysql.conf.d/mysqld.cnf

Find 'bind-address' and change to required range or 0.0.0.0 for full access

# If MySQL is running as a replication slave, this should be
# changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
# tmpdir                = /tmp
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address            = 0.0.0.0
mysqlx-bind-address     = 127.0.0.1

Allow Loading local data

Dof is using local data to allow quicker DB access, on MySQL this must be enabled

nano /etc/mysql/mysql.conf.d/mysqld.cnf

Add the following:

[mysqld]
# Other mysqld settings...
local_infile=ON

Setup users

default MySQL user is root, so typing (must be sudo)

 sudo mysql -u root

Will enter MySql with root

Create a user that can access from the network

create user 'root'@'%' identified by 'password';

Give user admin permissions

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;

SECURITY

Setup security (remove guest…)

sudo mysql_secure_installation

Allow external connections:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Change:
bind-address           = 0.0.0.0
# skip-networking

Create Application users

In MySQL create an account for the application:

CREATE USER 'aml'@'localhost' IDENTIFIED BY 'password';
CREATE SCHEMA dragonflow ;
GRANT ALL PRIVILEGES ON dragonflow.* TO 'aml'@'localhost';

Install DragOnFlow

Copy the entire installation folder into: '/dragonflow'

Initial configuration

We automatically create aml.universal.json in (calling it the settings file): '/etc/aml/ folder'

The actual configuration (e.g., services, folders…) is stored in a place defined by aml.universal.json. This method allows us to use UI to select the services configuration file (and keep multiple files), this is very useful in dev environments.

AML.ORB

For internal messaging you can use the orb, it is part of DragOnFlow, so you just need to Create service

nano /etc/systemd/system/aml-orb.service

File content:

Description=AmlOrb

[Service]
WorkingDirectory=/dragonflow/v4/modules/bin/
ExecStart=/usr/bin/dotnet Aml.Orb.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

When completed, enable the service:

'sudo systemctl enable aml-orb.service'

Aml VM service

nano /etc/systemd/system/amlvmservicev4.service

place the content:

[Unit]
Description=AmlVmServiceV4
After=nats-server.service mysql.service
Requires=mysql.service nats-server.service



[Service]
WorkingDirectory=/dragonflow/v4/modules/bin/
ExecStart=/usr/bin/dotnet Aml.VmServiceV4.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=30
KillSignal=SIGINT
SyslogIdentifier=AmlVmServiceV4
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

you may want to change After=aml-orb.service to After=nats-server.service and ExecStart=/usr/bin/dotnet to the actual location of the dotnet, for example if you installed using snap /snap/bin/dotnet

ASP.NET

Run Asp.net app in ubuntu and making it accessible from outside

dotnet AmlAdmin.dll --urls=https://*:6001

This will listen on port 6001 on all interfaces

Setup AmlAdmin

Example for blazor/signalR: HTML setup (above the server section)

  map $http_connection $connection_upgrade {
    "~*Upgrade" $http_connection;
    default keep-alive;
}

open NginX config files

sudo nano /etc/nginx/sites-available/default

Location block: place the following

    location /AmlAdmin {
      proxy_pass http://localhost:6000;

      # Configuration for WebSockets
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_cache off;
      # WebSockets were implemented after http/1.0
      proxy_http_version 1.1;

      # Configuration for ServerSentEvents
      proxy_buffering off;

      # Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds
      proxy_read_timeout 100s;

      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }

Also in Startup.Cs, we add

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  //  this is for NginX
  app.UseForwardedHeaders(new ForwardedHeadersOptions
    {
       ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
    });

  //  Config relative path (for NginX)          
  var r = Configuration.GetValue<string>("relpath");
  if (!string.IsNullOrWhiteSpace(r))
  {
    Console.WriteLine(r);
    app.UsePathBase(r);
   }

Finally the whole thing runs with adding parameter in the command line like this:

dotnet AmlAdmin.dll relpath=/AmlAdmin --urls=http://*:6000

Setup kestrel AmlAdminService

NGINX removes environment To automatically start the NET web site create a service file:

/etc/systemd/system/kestrel-amladmin.service

Service file content (Pay attention to the user, create a user that has the permissions):

[Unit]
Description=AmlAdmin Kestrel site
After=nats-server.service mysql.service
Requires=mysql.service nats-server.service


[Service]
WorkingDirectory=/dragonflow/v4/modules/websites/amladmin/bin/
ExecStart=/usr/bin/dotnet AmlAdmin.dll relpath=/AmlAdmin  --urls=http://*:6000
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=[user]
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

When completed, enable the service:

sudo systemctl enable kestrel-amladmin.service

To view the service status

sudo systemctl status kestrel-amladmin.service

To view the entire log you can

journalctl -r -u kestrel-amladmin.service

Setup kestrel AMLVWS4 service

Service file

nano /etc/systemd/system/kestrel-amlvmws4.service

Service file content (Pay attention to the user, create a user that has the permissions):

[Unit]
Description=AmlVmWs4Admin Kestrel site
After=nats-server.service mysql.service
Requires=mysql.service nats-server.service


[Service]
WorkingDirectory=/dragonflow/V4/Modules/WebSites/AmlVmWs4/bin/
ExecStart=/usr/bin/dotnet AmlVmWs4.dll relpath=/AmlVmWs4  --urls=http://*:6001
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

DOF

sudo nano /etc/systemd/system/dof.service

setup DOF service

[Unit]
Description=dof Kestrel site

[Service]
WorkingDirectory=/dragonflow/current/modules/websites/dof/bin/
ExecStart=dotnet dof.dll relpath=/dof  --urls=http://*:6011
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dof
User=nahi_n
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false



[Install]
WantedBy=multi-user.target

Database configuration

After installation, you will need to create database, use the administration tools of the database to create 2 databases (those don't need to be on the same server). One for reports and another for user session and profile management.

Usually we name the reports database 'Depot' and the users database 'AmlUsers'.

Now you will need to configure the database connections in the config file.

Reports Database

Setup the connection in configuration file. See the following examples:

<Db>
  <Connection Provider="SQLite" ConnectionString="Data Source=\dragonflow\Depot\AmlDepot.db;;cache=Shared;"/>
</Db>
<Report>
  <RealTime>
    <Db/>
  </RealTime>
</Report>

now we need to build the database tables (apply the EF migrations). use the Aml.Report.dll/exe to create the tables:

When the database schema changes, you will need to rerun the command.

User databases

In the configuration file, set the UsersData element. you can set it on the root of the configuration file, but also per project.

Example:

Useful commands

Listed here are useful commands you may need

Subject Command Description
Daemon / Service sudo systemctl edit --full [service name] Edit existing service in Linux
Daemon / Service systemctl start [service name] Start service
Daemon / Service systemctl status [service name] get service status
NginX tail -f /var/log/nginx/access.log view access log
NginX tail -f /var/log/nginx/error.log view nginx error logs
NginX sudo systemctl restat nginx restart NginX
NginX nginx -s reload Reload NginX configurati

FAQ

System.DllNotFoundException: Unable to load shared library 'libdl'

Short Answer:

This warning usually occurs because .NET is attempting to load the libdl library directly and not finding the exact expected name or its development symlink in the environment. On Ubuntu, libdl functionality is part of the standard C library (libc) and typically resides in libdl.so.2. If a direct libdl.so symlink is missing (usually provided by development packages), the runtime logs a warning but then falls back gracefully. This does not affect functionality and can often be ignored, or resolved by installing the appropriate development packages.

Detailed Explanation:

Why the Warning Occurs:
On many Linux distributions, libdl.so is a symbolic link to the actual library file libdl.so.2. The .so file (without the version number) is usually provided by the development package of libc rather than just the runtime libraries. In a minimal environment (such as a stripped-down container image), the development symlinks may not be present.

When the .NET runtime tries NativeLibrary.Load("libdl"), it may fail to find libdl in its unversioned form. The runtime will log a warning:
"Unable to load shared library 'libdl' or one of its dependencies."
After logging the warning, the runtime often falls back to alternative load strategies, eventually succeeding by loading libdl.so.2 or relying on other pre-loaded system functionalities.

How to Fix or Suppress the Warning: - Install Development Packages:
Installing libc6-dev or a similar package that provides the libdl.so symlink can eliminate the warning. For example:

sudo apt-get update
sudo apt-get install libc6-dev
This provides libdl.so and other headers/symlinks, satisfying the runtime’s expectation.

  • Ignore the Warning:
    Since this does not affect the actual database operations or other functionalities, you may choose to simply ignore the warning if you do not want extra packages installed.

If installing libc6-dev did not resolve the issue, it likely means that the unversioned libdl.so symlink still isn’t present on your system’s library paths. While libc6-dev should generally provide development symlinks, some environments (especially minimal Docker images or certain Ubuntu variants) may not create them as expected, or the symlink may live in a directory not searched by default.

What’s Happening?
The .NET runtime tries to load libdl by its base name (libdl.so) when dynamically loading native libraries. On Ubuntu, the actual library file is usually libdl.so.2. The development package (libc6-dev) normally installs a libdl.so symlink pointing to libdl.so.2. If that symlink is missing or located in a directory not searched by default, the runtime logs a warning. It eventually succeeds in using libdl.so.2 anyway, which is why functionality isn’t impacted—just the noisy log.

How to Fix It:

  1. Check for the Symlink:
    Run:

    ls -l /usr/lib/x86_64-linux-gnu/libdl.so
    
    or
    ls -l /lib/x86_64-linux-gnu/libdl.so
    
    If you don’t see a libdl.so file (just libdl.so.2), you’ll need to create the symlink manually.

  2. Create the Symlink Manually:
    First, identify the correct location. Typically, libdl.so.2 resides in /usr/lib/x86_64-linux-gnu or /lib/x86_64-linux-gnu. Adjust paths as necessary for your system. For a 64-bit Ubuntu system, try:

    sudo ln -s /lib/x86_64-linux-gnu/libdl.so.2 /lib/x86_64-linux-gnu/libdl.so
    
    Then:
    sudo ldconfig
    

After this, re-run your .NET application and check if the warning disappears.

  1. Verify Architecture and Packages:
  2. If you’re in a minimal container or using a special build of Ubuntu, ensure the system’s architecture matches. For a standard 64-bit environment, the above paths should work.
  3. Check if libc6-dev is correctly installed:

    dpkg -l | grep libc6-dev
    

  4. If Still Not Working:

  5. Try placing the symlink in /usr/lib/x86_64-linux-gnu instead of /lib/...:

    sudo ln -s /lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so
    sudo ldconfig
    

  6. Confirm that the directory containing libdl.so is included in the system’s default library search paths. Running ldconfig -p | grep libdl should show both libdl.so (libc6,x86-64) and libdl.so.2 (libc6,x86-64) entries after creating the symlink.