DWKit Deployment

Table of contents

  1. IIS deploy
  2. Docker Deploy Using niginx as a Reverse Proxy
  3. Docker Deploy Using Apache HTTPD as a Reverse Proxy

IIS Deploy

Table of contents

  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 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 niginx as a Reverse Proxy

Table of contents

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 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

Table of contents

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 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

Table of contents