Skip to main content

DWKit Deployment

IIS Deploy

  1. To run an ASP.NET Core application under IIS, the installation of .NET Core Hosting Bundle is required. Please, install the appropriate version, depending on your .NET Core preferences:

  2. Create a folder to keep the working files of the DWKit application.

  3. Create an IIS site for the DWKit application. Run Internet Information Services (IIS) Manager, select "Add Website…" in the Actions list.

    Fig1

  4. In the window that appears, fill in the following fields:

    • Site name: dwkit_app;
    • Physical path: the path to the folder created in Step 2;
    • Port: a free port through which the application is available, for example 48800.

    Fig2

  5. Set Application pool for the created site to avoid unnecessary restarts of the Workflow Runtime or shutdowns when idle. In Internet Information Services (IIS) Manager, go to Application Pools List and select the dwkit_app pool.

    Fig3

    Select Edit Application Pool -> Recycling; in the dialog box that appears turn off the option Regular time intervals (in minutes).

    Fig4

    Press Next -> Finish.

    Then, select Edit Application Pool -> Advanced Settings.

    In the window that appears, find the Process Model -> Idle time-out (minutes) option and change its value from 20 to 0.

    Fig5

    Press OK; the pool is set up.

  6. Publish the application Using Visual Studio 2019. In the context menu of the ASP.NET Core project, select Publish (or, select Build -> Publish <Project_Name> in the main menu):

    Fig6

    In the publishing window that appears, create a new profile by selecting "new":

    Fig7

    In the dialog box that appears, select Folder and press Next:

    Fig8

    As the Folder location, specify the path to the folder created in Step 2, and click Finish.

    Fig9

    Publish the application by pressing the Publish button.

  7. Alternatively, publishing can be performed without Visual Studio, through the command prompt. In the DWKit project folder, containing the application solution file (*.sln), run the command:

    dotnet publish <SLN_FILE_NAME> -o <WFS_ADMIN_PATH>

    Where:

    • <SLN_FILE_NAME> - the name of the application solution file.
    • <WFS_ADMIN_PATH> - the path to the folder created in Step 2.

    If the folder created in Step 2 is not available on the computer where the application is being developed, any available folder can be selected for publishing; then, its contents should be copied to the folder created in Step 2.

  8. An alternative option is publishing using Web Deploy. The Web Deploy installation is described here. An example of publishing using Web Deploy is described here.

  9. IIS deploy is completed, the application is available by the binding specified for the IIS-site, dwkit_app.

    Fig10

Docker Deploy Using nginx as a Reverse Proxy

To deploy a DWKit application with nginx as a reverse proxy, we need at least 2 Docker containers, one for the DWKit application, and the second for nginx. Docker Compose is used to manage the containers; we take the docker-compose.yml solution from the dwkit-starterpack project, which deploys the dwkit starterpack application and PostgreSQL, as the basic solution. The solution consists of the following three containers:

  • db – PostgreSQL DBMS container
  • dwkit_starterpack – DWKit starterpack container
  • start_db – container that prevents dwkit_starterpack from launching until PostgreSQL is fully activated and ready to accept queries.

To correctly determine the IP address and client protocol, as well as the IdentityServer’s endpoints, used in the DefaultSecurityProvider when working through a reverse proxy, the forwarded headers must be enabled. The settings to configure forwarding for an ASP.NET Core application are described here. You can configure forwarded headers either manually or using the provided DWKit extension method, which reads the necessary settings from the ASP.NET Core application configuration:

public static IApplicationBuilder ConfigureForwardHeaders(
this IApplicationBuilder app,
IConfigurationRoot configuration,
string settingSectionName = "ProxySettings",
ILogger logger = null)

Where:

  • configuration – the configuration of the ASP.NET Core application.
  • settingSectionName – the name of the configuration section with forwarding settings described.

The method should be called in Startup.Configure before calling app.UseIdentityServer(). For example:

app.ConfigureForwardHeaders(Configuration, logger: _loggerFactory.CreateLogger<Startup>());

The configuration settings look as follows:

"ProxySettings": {
"KnownNetworks": [ "172.27.0.0/16" ],
"KnownProxies": [ "128.0.0.1" ],
"Headers": [ "XForwardedFor", "XForwardedHost" ]
}

The Headers list contains the headers to be forwarded. The possible values are:

[ "All" ] is used by default.

For security reasons, header forwarding should be restricted to trusted proxies only. You can set the trusted proxies using the following properties:

  • KnownNetworks - the list of trusted subnets in the CIDR notation (IP address / mask).
  • KnownProxies - the list of the IPs of trusted proxy servers.

ProxySettings parameters can be configured using both appsettings.json and environment variables.

For debugging purposes, ProxySettings can be used without specifying KnownNetworks or KnownProxies, then, the headers are forwarded for any addresses. To enable this mode, set the empty value of ProxySettings in appsettings.json:

"ProxySettings": {
}

or set the environment variable ProxySettings__Enabled to true.

Warning!

In production mode, ProxySettings without specifying KnownNetworks or KnownProxies are not recommended.

  1. We define the parameters of the subnet made for our containers. The subnet is created when the compose project is launched for the first time; thus, we start this project using startascontainer.bat or startascontainer.sh, and then end it by pressing Ctrl+C. In the command prompt, execute the following:

    docker network inspect dwkit-starterpack_default

    It shows the default network info of the dwkit-starterpack project.

    Fig1

    As you can see, in our case, the default network has 172.25.0.0/16 mask and 172.25.0.1 gateway.

    The containers are given dynamic addresses on creating. To set KnownProxies we assign static addresses for the existing containers by adding a node to each service configuration:

    networks:
    default:
    ipv4_address: <IP_address>

    Where <IP_address> is a unique IP-address within 172.25.0.2 - 172.25.1.254.

    Fig2

  2. We create the configuration file - nginx.conf – in the project folder, dwkit-starterpack, with the following contents:

    worker_processes 4;

    events { worker_connections 1024; }

    http {
    sendfile on;

    server {
    listen 48800;
    location / {
    proxy_pass http://dwkit_starterpack:80;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host:$server_port;
    }
    }
    }

    Fig3

    The file describes the server, corresponding to the web-host of the dwkit-starterpack application.

    Line 9:
    listen 48800;

    Sets the external port to access the application.

    Line 11:
    proxy_pass         http://dwkit_starterpack:80;

    Indicates the application address in the internal network, the host name - dwkit_starterpack - corresponds to the service name specified in the configuration file, docker-compose.yml.

    Line 19:
    proxy_set_header   X-Forwarded-Host $host:$server_port;

    Defines the header, X-Forwarded-Host, necessary to work properly with DefaultSecurityProvider.

  3. We remove the dwkit_starterpack container port setting, making it inaccessible from the external network. In docker-compose.yml, delete the lines

    ports:
    - "48800:80"

    Fig4

  4. We add the nginx container description. In docker-compose.yml, add the lines:

      nginx:
    depends_on:
    - dwkit_starterpack
    image: nginx:latest
    volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
    - "48800:48800"
    networks:
    default:
    ipv4_address: 172.25.0.5

    Fig5

  5. We add the IP-address of the nginx-server in the list of KnownProxies. In docker-compose.yml, in the environment section of the dwkit_starterpack , add the line:

    ProxySettings__KnownProxies__0: 172.25.0.5

    We also add the external address of the reverse-proxy as a valid OpenID Connect authentication redirect address. In the environment section of the dwkit_starterpack , add the line:

    IdentityServerSettings__RedirectHosts__0: http://localhost:48800

    Fig6

  6. docker-compose.yml is ready. The whole listing looks as follows:

    version: '3.4'

    services:
    db:
    image: postgres:alpine
    environment:
    POSTGRES_DB: dwkit
    POSTGRES_USER: dbuser
    POSTGRES_PASSWORD: dbuserpassword
    volumes:
    - dbdata:/var/lib/postgresql/data
    restart: always
    ports:
    - "5432"
    networks:
    default:
    ipv4_address: 172.25.0.2
    start_db:
    image: jbergknoff/postgresql-client
    depends_on:
    - db
    volumes:
    - ./docker-files:/home/.docker
    entrypoint: /home/.docker/wait-for-postgres.sh db dbuser dbuserpassword dwkit
    networks:
    default:
    ipv4_address: 172.25.0.3
    dwkit_starterpack:
    depends_on:
    - db
    build: .
    environment:
    ASPNETCORE_ENVIRONMENT: Development
    ConnectionStrings__default: HOST=db;User ID=dbuser;Password=dbuserpassword;Database=dwkit;Port=5432
    DWKit__MetadataPath: /home/metadata/
    DWKit__LicensePath: /home/license/
    DWKit__CreateDatabaseObjects: "true"
    DWKit__DatabaseScriptList: /home/sql/PostgreSQL/create_db.txt
    ProxySettings__KnownProxies__0: 172.25.0.5
    volumes:
    - ./sql:/home/sql
    - ./metadata:/home/metadata
    - ./license:/home/license
    - ./aspnet-keys:/root/.aspnet/DataProtection-Keys
    networks:
    default:
    ipv4_address: 172.25.0.4
    nginx:
    depends_on:
    - dwkit_starterpack
    image: nginx:latest
    volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
    - "48800:48800"
    networks:
    default:
    ipv4_address: 172.25.0.5
    volumes:
    dbdata:
  7. Since a new service has been added, we should modify the startup script. Open startascontainer.bat or startascontainer.sh, find the line:

    docker-compose up dwkit_starterpack

    Change it to:

    docker-compose up dwkit_starterpack nginx

    And save the changes.

    Now, launch the containers using startascontainer.bat or startascontainer.sh. As you can see, the application is running on port 80, while its external access goes through port 48800.

    Fig7

Docker Deploy Using Apache HTTPD as a Reverse Proxy

To deploy a DWKit application with Apache httpd as a reverse proxy, we need at least 2 Docker containers, one for the DWKit application, and the second for Apache httpd. Docker Compose is used to manage the containers; we take the docker-compose.yml solution from the dwkit-starterpack project, which deploys the dwkit starterpack application and PostgreSQL, as the basic solution. The solution consists of the following three containers:

  • db – PostgreSQL DBMS container;
  • dwkit_starterpack – DWKit starterpack container;
  • start_db – container that prevents dwkit_starterpack from launching until PostgreSQL is fully activated and ready to accept queries.

To correctly determine the IP address and client protocol, as well as the IdentityServer’s endpoints, used in the DefaultSecurityProvider when working through a reverse proxy, the forwarded headers must be enabled. The settings to configure forwarding for an ASP.NET Core application are described here. You can configure forwarded headers either manually or using the provided DWKit extension method, which reads the necessary settings from the ASP.NET Core application configuration:

public static IApplicationBuilder ConfigureForwardHeaders(
this IApplicationBuilder app,
IConfigurationRoot configuration,
string settingSectionName = "ProxySettings",
ILogger logger = null)

Where:

  • configuration – the configuration of the ASP.NET Core application.
  • settingSectionName – the name of the configuration section with forwarding settings described.

The method should be called in Startup.Configure before calling app.UseIdentityServer(). For example:

app.ConfigureForwardHeaders(Configuration, logger: _loggerFactory.CreateLogger<Startup>());

The configuration settings look as follows:

"ProxySettings": {
"KnownNetworks": [ "172.27.0.0/16" ],
"KnownProxies": [ "128.0.0.1" ],
"Headers": [ "XForwardedFor", "XForwardedHost" ]
}

The Headers list contains the headers to be forwarded. The possible values are:

[ "All" ] is used by default.

For security reasons, header forwarding should be restricted to trusted proxies only. You can set the trusted proxies using the following properties:

  • KnownNetworks - the list of trusted subnets in the CIDR notation (IP address / mask).
  • KnownProxies - the list of the IPs of trusted proxy servers.

ProxySettings parameters can be configured using both appsettings.json and environment variables.

For debugging purposes, ProxySettings can be used without specifying KnownNetworks or KnownProxies, then, the headers are forwarded for any addresses. To enable this mode, set the empty value of ProxySettings in appsettings.json:

"ProxySettings": {
}

or set the environment variable ProxySettings__Enabled to true.

Warning!

In production mode, ProxySettings without specifying KnownNetworks or KnownProxies are not recommended.

  1. We define the parameters of the subnet made for our containers. The subnet is created when the compose project is launched for the first time; thus, we start this project using startascontainer.bat or startascontainer.sh, and then end it by pressing Ctrl+C. In the command prompt, execute the following:

    docker network inspect dwkit-starterpack_default

    It shows the default network info of the dwkit-starterpack project.

    Fig1

    As you can see, in our case, the default network has 172.25.0.0/16 mask and 172.25.0.1 gateway.

    The containers are given dynamic addresses on creating. To set KnownProxies we assign static addresses for the existing containers by adding a node to each service configuration:

    networks:
    default:
    ipv4_address: <IP_address>

    Where <IP_address> is a unique IP-address within 172.25.0.2 - 172.25.1.254.

    Fig2

  2. We create the configuration Apache httpd file - my-httpd.conf - in the project folder, dwkit-starterpack, with the following contents:

    LoadModule mpm_event_module modules/mod_mpm_event.so
    LoadModule authn_file_module modules/mod_authn_file.so
    LoadModule authn_core_module modules/mod_authn_core.so
    LoadModule authz_host_module modules/mod_authz_host.so
    LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
    LoadModule authz_user_module modules/mod_authz_user.so
    LoadModule authz_core_module modules/mod_authz_core.so
    LoadModule access_compat_module modules/mod_access_compat.so
    LoadModule auth_basic_module modules/mod_auth_basic.so
    LoadModule reqtimeout_module modules/mod_reqtimeout.so
    LoadModule filter_module modules/mod_filter.so
    LoadModule mime_module modules/mod_mime.so
    LoadModule log_config_module modules/mod_log_config.so
    LoadModule env_module modules/mod_env.so
    LoadModule headers_module modules/mod_headers.so
    LoadModule setenvif_module modules/mod_setenvif.so
    LoadModule version_module modules/mod_version.so
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
    LoadModule unixd_module modules/mod_unixd.so
    LoadModule status_module modules/mod_status.so
    LoadModule autoindex_module modules/mod_autoindex.so
    LoadModule dir_module modules/mod_dir.so
    LoadModule alias_module modules/mod_alias.so
    LoadModule rewrite_module modules/mod_rewrite.so

    <IfModule unixd_module>

    User daemon
    Group daemon

    </IfModule>

    Listen 48800

    ServerName localhost

    <VirtualHost *:*>
    RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
    ProxyPreserveHost On
    ProxyPass / http://dwkit_starterpack:80/
    ProxyPassReverse / http://dwkit_starterpack:80/
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://dwkit_starterpack:80/$1 [P]
    </VirtualHost>

    Fig3

    The file describes the virtual host, corresponding to the web-host of the dwkit-starterpack application.

    Line 35:
    Listen 48800

    It sets the external port to access the application.

    Lines 42-43:
        ProxyPass / http://dwkit_starterpack:80/
    ProxyPassReverse / http://dwkit_starterpack:80/

    Redirect queries between the proxy server and the dwkit-starterpack application; the host name dwkit_starterpack corresponds to the service name specified in the configuration file, docker-compose.yml.

    Lines 45-46:
        RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://dwkit_starterpack:80/$1 [P]

    Define the websocket redirection, to work with SignalR.

  3. We remove the dwkit_starterpack container port setting, making it inaccessible from the external network. In docker-compose.yml, delete the lines:

        ports:
    - "48800:80"

    Fig4

  4. We add the apache container description. In docker-compose.yml, add the lines:

      apache:
    depends_on:
    - dwkit_starterpack
    image: httpd:latest
    volumes:
    - ./my-httpd.conf:/usr/local/apache2/conf/httpd.conf
    ports:
    - "48800:48800"
    networks:
    default:
    ipv4_address: 172.25.0.5

    Fig5

  5. We add the IP-address of the apache-server in the list of KnownProxies. In docker-compose.yml, in the environment section of the dwkit_starterpack, add the line:

    ProxySettings__KnownProxies__0: 172.25.0.5

    We also add the external address of the reverse-proxy as a valid OpenID Connect authentication redirect address. In the environment section of the dwkit_starterpack , add the line:

    IdentityServerSettings__RedirectHosts__0: http://localhost:48800

    Fig6

  6. docker-compose.yml is ready. The whole listing looks as follows:

    version: '3.4'

    services:
    db:
    image: postgres:alpine
    environment:
    POSTGRES_DB: dwkit
    POSTGRES_USER: dbuser
    POSTGRES_PASSWORD: dbuserpassword
    volumes:
    - dbdata:/var/lib/postgresql/data
    restart: always
    ports:
    - "5432"
    networks:
    default:
    ipv4_address: 172.25.0.2
    start_db:
    image: jbergknoff/postgresql-client
    depends_on:
    - db
    volumes:
    - ./docker-files:/home/.docker
    entrypoint: /home/.docker/wait-for-postgres.sh db dbuser dbuserpassword dwkit
    networks:
    default:
    ipv4_address: 172.25.0.3
    dwkit_starterpack:
    depends_on:
    - db
    build: .
    environment:
    ASPNETCORE_ENVIRONMENT: Development
    ConnectionStrings__default: HOST=db;User ID=dbuser;Password=dbuserpassword;Database=dwkit;Port=5432
    DWKit__MetadataPath: /home/metadata/
    DWKit__LicensePath: /home/license/
    DWKit__CreateDatabaseObjects: "true"
    DWKit__DatabaseScriptList: /home/sql/PostgreSQL/create_db.txt
    ProxySettings__KnownProxies__0: 172.25.0.5
    IdentityServerSettings__RedirectHosts__0: http://localhost:48800
    volumes:
    - ./sql:/home/sql
    - ./metadata:/home/metadata
    - ./license:/home/license
    - ./aspnet-keys:/root/.aspnet/DataProtection-Keys
    networks:
    default:
    ipv4_address: 172.25.0.4
    apache:
    depends_on:
    - dwkit_starterpack
    image: httpd:latest
    volumes:
    - ./my-httpd.conf:/usr/local/apache2/conf/httpd.conf
    ports:
    - "48800:48800"
    networks:
    default:
    ipv4_address: 172.25.0.5
    volumes:
    dbdata:
  7. Since a new service has been added, we should modify the startup script. Open startascontainer.bat or startascontainer.sh, find the line:

    docker-compose up dwkit_starterpack

    Change it to:

    docker-compose up dwkit_starterpack apache

    And save the changes.

    Now, launch the containers using startascontainer.bat or startascontainer.sh. As you can see, the application is running on port 80, while its external access goes through port 48800.

    Fig7