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:
-
Add the Ubuntu 22.04 (Jammy Jellyfish) repository:
-
Open a terminal.
-
Edit the sources list file using a text editor with superuser privileges. For example:
sudo nano /etc/apt/sources.list.d/ubuntu.sources -
Add the following lines to include the Jammy repository:
Types: deb URIs: http://archive.ubuntu.com/ubuntu/ Suites: jammy Components: main universe -
Save and exit the editor.
-
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.
- 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
-
Remove the added repository (optional but recommended to prevent potential conflicts):
-
Reopen the sources list file:
sudo nano /etc/apt/sources.list.d/ubuntu.sources -
Remove or comment out the lines you added by placing a
#at the beginning of each line. -
Save and exit the editor.
-
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
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:
-
Check for the Symlink:
Run:orls -l /usr/lib/x86_64-linux-gnu/libdl.soIf you don’t see als -l /lib/x86_64-linux-gnu/libdl.solibdl.sofile (justlibdl.so.2), you’ll need to create the symlink manually. -
Create the Symlink Manually:
First, identify the correct location. Typically,libdl.so.2resides in/usr/lib/x86_64-linux-gnuor/lib/x86_64-linux-gnu. Adjust paths as necessary for your system. For a 64-bit Ubuntu system, try:Then:sudo ln -s /lib/x86_64-linux-gnu/libdl.so.2 /lib/x86_64-linux-gnu/libdl.sosudo ldconfig
After this, re-run your .NET application and check if the warning disappears.
- Verify Architecture and Packages:
- 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.
-
Check if
libc6-devis correctly installed:dpkg -l | grep libc6-dev -
If Still Not Working:
-
Try placing the symlink in
/usr/lib/x86_64-linux-gnuinstead of/lib/...:sudo ln -s /lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so sudo ldconfig -
Confirm that the directory containing
libdl.sois included in the system’s default library search paths. Runningldconfig -p | grep libdlshould show bothlibdl.so (libc6,x86-64)andlibdl.so.2 (libc6,x86-64)entries after creating the symlink.