powershellamazon-elastic-beanstalk

How to assign Application Pools to different ASP.Net Core web sites in AWS Elastic Beanstalk?


We have two ASP.Net Core 3.1 web sites (with different domain names / host headers) deployed in Elastic Beanstalk running Windows 2019 Core server and IIS. We were able to do this by following https://aws.amazon.com/blogs/developer/multi-app-support-with-custom-domains-for-net-and-aws-elastic-beanstalk/

However, both the websites are running under 'DefaultAppPool'. ASP.Net Core does not allow more than one application per application pool (HTTP Error 500.35 - ASP.NET Core does not support multiple apps in the same app pool).

So, we added the following section to aws-windows-deployment-manifest.json

"iisConfig": {
    "appPools": [
      {
        "name": "AppPool1",
        "managedPipelineMode": "Integrated",
        "managedRuntimeVersion": "v4.0"
      },
      {
        "name": "AppPool2",
        "managedPipelineMode": "Integrated",
        "managedRuntimeVersion": "v4.0"
      }
    ]
  }

And, EB deployment created corresponding app pools in IIS.

Now, we are not able to assign the app pool to each web site. Ideally, we'd like to use commands from WebAdministration module (https://learn.microsoft.com/en-us/powershell/module/webadministration/?view=windowsserver2019-ps) in 'install*.ps1' powershell scripts or in a '.config' file in '.ebextensions' folder. However, WebAdministration module is not available in either place and IMPORT-MODULE WebAdministration doesn't work either. Only IISAdministration module (https://learn.microsoft.com/en-us/powershell/module/iisadministration/?view=windowsserver2019-ps) is available at time 'install*.ps1' scripts are executed.

So, how to assign application pools to different ASP.Net Core web sites in AWS Elastic Beanstalk?


Solution

  • Very lightly documented (for Windows Server) secret sauce is hiding at https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/custom-platform-hooks.html

    So, for us the following strategy worked. We added the following contents in apppool.config (name doesn't matter as long as it has .config extension) file to .ebextensions

    files:
      "c:/Program Files/Amazon/ElasticBeanstalk/hooks/appdeploy/post/config.ps1":
        content: |
          Start-IISCommitDelay
          $site = Get-IISSite "site1"
          $site.Applications["/"].ApplicationPoolName = "AppPool1"
          $site = Get-IISSite "site2"
          $site.Applications["/"].ApplicationPoolName = "AppPool2"
          Stop-IISCommitDelay
    

    This created a powershell script config.ps1 in c:/Program Files/Amazon/ElasticBeanstalk/hooks/appdeploy/post/ folder. The powershell script executes after a new instance is created or a new version is deployed.

    The only shortcoming is config.ps1 is created every time new version is deployed on an existing instance. It doesn't hurt as old file is renamed to config.ps1.bak and is ignored by EB deployment process. There is definitely room for improvement here (will defer for another day).

    For the sake of completion, here's entire aws-windows-deployment-manifest.json

    {
      "manifestVersion": 1,
      "iisConfig": {
        "appPools": [
          {
            "name": "AppPool1",
            "managedPipelineMode": "Integrated",
            "managedRuntimeVersion": "v4.0"
          },
          {
            "name": "AppPool2",
            "managedPipelineMode": "Integrated",
            "managedRuntimeVersion": "v4.0"
          }
        ]
      },
      "deployments": {
        "custom": [
          {
            "name": "site1",        
            "scripts": {
              "install": {
                "file": "install1.ps1"
              },
              "restart": {
                "file": "restart.ps1"
              },
              "uninstall": {
                "file": "uninstall1.ps1"
              }
            }
          },
          {
            "name": "site2",        
            "scripts": {
              "install": {
                "file": "install2.ps1"
              },
              "restart": {
                "file": "restart.ps1"
              },
              "uninstall": {
                "file": "uninstall2.ps1"
              }
            }
          }  
        ]
      }
    }
    

    And Here's install1.ps1

    Copy-Item -Path "C:\staging\site1" -Destination "C:\inetpub" -Recurse -Force
    New-IISSite -Name "site1" -BindingInformation "*:80:*.site1.com" -PhysicalPath "C:\inetpub\site1" -Force
    

    And uninstall1.ps1

    Remove-IISSite -Name "site1" -Confirm:$False
    rm -r "c:\inetpub\site1" -Force
    

    And restart.ps1

    iisreset /timeout:1
    

    install2.ps1 and uninstall2.ps1 are similar to their site1 counterpart, as above.

    We have referred to a lot of articles online and owe a Thank You to all of them.