From a949b302e5dd67d4a3896a60b8741041d1f344fd Mon Sep 17 00:00:00 2001 From: selmankoc Date: Wed, 23 Oct 2024 15:25:57 +0300 Subject: [PATCH 1/4] Moved deployment docs from old docs --- .../azure-deployment/azure-deployment.md | 36 + .../step1-create-azure-resources.md | 174 ++ .../step2-configuration-application.md | 231 ++ .../step3-deployment-github-action.md | 735 +++++++ .../terraform-web-app-service.md | 572 +++++ .../deployment/deployment-docker-compose.md | 1933 +++++++++++++++++ .../deployment/deployment-iis.md | 261 +++ .../deployment/identityserver-deployment.md | 111 + .../deployment/index.md | 20 + .../deployment/openiddict-deployment.md | 127 ++ 10 files changed, 4200 insertions(+) create mode 100644 docs/en/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/azure-deployment/terraform-web-app-service.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/index.md create mode 100644 docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md new file mode 100644 index 00000000000..49d3750da24 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md @@ -0,0 +1,36 @@ +# Azure Deployment using Application Service + +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. + +## Prerequisites + +- An active Azure account. If you don't have one, you can sign up for a [free account](https://azure.microsoft.com/en-us/free/) + +- Your ABP **{{ UI_Value }}** project must be ready at a GitHub repository because we will use GitHub Actions to deploy the ABP application to the Azure Web App Service. + +- **{{ DB_Value }}** database must be ready to use with your project. If you don't have a database, you can create a new Azure SQL database or Cosmos DB by following the instructions below: + + - [Create a new Azure SQL Database](https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal) + + - [Create a new Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/create-cosmosdb-resources-portal) + + +### Description of the process in three steps: + +1. [Creating an Azure Web App Service Environment ](step1-create-azure-resources) +2. [Customizing the Configuration of Your ABP Application](step2-configuration-application) +3. [Deploying Your Application to Azure Web App Service](step3-deployment-github-action) + + +## What's next? + +- [Creating an Azure Web App Service Environment](step1-create-azure-resources) diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md new file mode 100644 index 00000000000..a818c1287d5 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md @@ -0,0 +1,174 @@ +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +## Step 1: Creating an Azure Web App Service Environment + +To create a new Azure Web App Service, choose one of the following options: + +- [Create a new Azure Web App Service using the Azure Portal](#create-a-new-azure-web-app-service-using-the-azure-portal) (Recommended) + +- [Create a new Azure Web App Service using the Terraform Template](terraform-web-app-service.md) (If you have experience with Terraform) + +{{ if UI == "MVC" && Tiered == "No" }} + +### Create a new Azure Web App service using the Azure Portal + +1. Log in to the [Azure Portal](https://portal.azure.com/). + +2. Click the **Create a resource** button. + +3. Search for **Web App** and select **Web App** from the results. + + ![Create a resource](../../../images/azure-deploy-create-a-resource.png) + +4. Click the **Create** button. + +5. Fill in the required fields and click the **Review + create** button. + +6. Click the **Create** button. + + ![Create Web App](../../../images/azure-deploy-create-web-app-2.png) + +7. Wait for the deployment to complete. + + ![Create Web App](../../../images/azure-deploy-create-web-app-3.png) + +{{else}} + +{{ if UI == "BlazorServer" || UI == "MVC" }} + +### Create a new Azure Web App service using the Azure Portal + +1. Log in to the [Azure Portal](https://portal.azure.com/). + +2. Click the **Create a resource** button. + +3. Search for **Web App** and select **Web App** from the results. + + ![Create a resource](../../../images/azure-deploy-create-a-resource.png) + +4. Click the **Create** button. + +5. Fill in the required fields and click the **Review + create** button. + +6. Click the **Create** button. + + ![Create Web App](../../../images/azure-deploy-create-web-app-2.png) + +7. Wait for the deployment to complete. + + ![Create Web App](../../../images/azure-deploy-create-web-app-3.png) + +{{ else if UI == 'NG' }} + +### Create a new Azure Static Web App for Angular using the Azure Portal + +1. Log in to the [Azure Portal](https://portal.azure.com/). + +2. Click the **Create a resource** button. + +3. Search for **Static Web App** and select **Static Web App** from the results. + + ![Create a resource angular](../../../images/azure-deploy-create-a-resource-angular.png) + +4. Click the **Create** button. + +5. Fill in the required fields and click the **Review + create** button. + +6. Click the **Create** button. + + ![Create Web App](../../../images/azure-deploy-create-web-app-4.png) + +7. Wait for the deployment to complete. + + ![Create Web App](../../../images/azure-deploy-create-web-app-5.png) + +{{else}} + +### Create a new Azure Static Web App for Blazor using the Azure Portal + +1. Log in to the [Azure Portal](https://portal.azure.com/). + +2. Click the **Create a resource** button. + +3. Search for **Static Web App** and select **Static Web App** from the results. + + ![Create a resource blazor](../../../images/azure-deploy-create-a-resource-angular.png) + +4. Click the **Create** button. + +5. Fill in the required fields and click the **Review + create** button. + +6. Click the **Create** button. + + ![Create Web App](../../../images/azure-deploy-create-web-app-7.png) + +7. Wait for the deployment to complete. + + ![Create Web App](../../../images/azure-deploy-create-web-app-8.png) + +{{end}} + +### Create a new Azure Web App Service for API application + +1. You can create a new Azure Web App Service for an API application in the same resource group. + +2. Click the **Create** button on the top of the resource group page. + +3. Search for **Web App** and select **Web App** from the results. + + ![Create a resource](../../../images/azure-deploy-create-a-resource.png) + +4. Click the **Create** button. + +5. Fill in the required fields and click the **Review + create** button. + +6. Click the **Create** button. + + ![Create Web App](../../../images/azure-deploy-create-web-app-6.png) + +7. Wait for the deployment to complete. + + ![Create Web App](../../../images/azure-deploy-create-web-app-3.png) + +{{ if Tiered == "Yes" && (UI == "MVC" || UI == "BlazorServer")}} + +### Create a new Azure Web App Service for AuthServer application + +Similar to the API application, you can create a new Azure Web App Service for an AuthServer application in the same resource group. + +Same as above, but you only need to modify the name of the web app service to **authserver-yourapp** in step 5. + +### Create Azure Cache for Redis + +1. Click the **Create** button on the top of the resource group page. + +2. Search for **Redis Cache** and select **Redis Cache** from the results. + + ![Create a resource](../../../images/azure-deploy-create-redis.png) + +3. Click the **Create** button. + +4. Fill in the required fields and click the **Review + create** button. + +5. Click the **Create** button. + + ![Create Redis](../../../images/azure-deploy-create-redis-2.png) + +6. Wait for the deployment to complete. + + ![Create Redis](../../../images/azure-deploy-create-redis-3.png) + +{{ end }} + +{{ end }} + +## What's next? + +- [Customizing the Azure Web App Service](step2-configuration-application.md) diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md new file mode 100644 index 00000000000..5f1ba5aafe8 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md @@ -0,0 +1,231 @@ +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +## Step 2: Customizing the Configuration of the ABP Application + +- To customize the configuration of your ABP application, modify the `ConnectionString` values in every location throughout your project. The `ConnectionString` values are stored in the `appsettings.json` files. + + This includes the following files: +{{ if UI == "MVC" && Tiered == "No" }} + **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.Web/appsettings.json** +{{else}} + **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** +{{end}} +{{if Tiered == "Yes"}} + **./src/yourapp.AuthServer/appsettings.json** +{{end}} + +```json +"ConnectionStrings": { + "Default": "Server=tcp:yourserver.database.windows.net,1433;Initial Catalog=yourdatabase;Persist Security Info=False;User ID=yourusername;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" +} +``` + +{{ if UI == "MVC" }} + +{{if Tiered == "No"}} + +- Modify the **yourapp.Web** URL in every location throughout your project, especially within the **./src/yourapp.Web/appsettings.json** and **./src/yourapp.DbMigrator/appsettings.json** files, to match your Azure Web App Service URL. + +```json + "App": { + "SelfUrl": "https://yourapp.azurewebsites.net" + } +``` + +{{else}} + +- Modify the **yourapp.Web** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Web/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** , **./src/yourapp.HttpApi.Host/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp.azurewebsites.net" +} +``` + +- Modify the **yourapp.ApiHost** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Web/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp-apihost.azurewebsites.net" +} +``` + +- Modify the **yourapp.AuthServer** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Web/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp-authserver.azurewebsites.net" +} +``` + +- Modify the **Redis__Configuration** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Web/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json +"Redis": { + "Configuration": "redis-abpdemo.redis.cache.windows.net:6380,password={yourpassword},ssl=true,abortConnect=False" + }, +``` + +{{end}} + +{{ else if UI == "NG" }} + +- Modify the **`localhost:4200`** in every location throughout your project. + + This includes the following files: + + **./angular/src/environments/environment.prod.ts** , **./aspnet-core/src/yourapp.DbMigrator/appsettings.json** and **./aspnet-core/src/yourapp.HttpApi.Host/appsettings.json** + +```typescript + application: { + baseUrl: 'https://yourapp.azurestaticapps.net' + } +``` + +- Modify the **yourapp.HttpApi.Host** URL in every location throughout your project. + + This includes the following files: + + **./angular/src/environments/environment.prod.ts** , **./aspnet-core/src/yourapp.DbMigrator/appsettings.json** and **./aspnet-core/src/yourapp.HttpApi.Host/appsettings.json** + +```json + "App": { + "SelfUrl": "https://yourApiHost.azurewebsites.net" + } +``` + +{{ else if UI == "Blazor" }} + +- Modify the **yourapp.Blazor** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json + "App": { + "SelfUrl": "https://yourapp.azurewebsites.net" + } +``` + +- Modify the **yourapp.HttpApi.Host** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json + "App": { + "SelfUrl": "https://yourApiHost.azurewebsites.net" + } +``` + +{{ else }} + +{{if Tiered == "No"}} + +- Modify the **yourapp.Web** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp.azurewebsites.net" +} +``` + +- Modify the **yourapp.ApiHost** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Blazor/appsettings.json** and **./src/yourapp.DbMigrator/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp-apihost.azurewebsites.net" +} +``` + +{{else}} + +- Modify the **yourapp.Web** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** , **./src/yourapp.HttpApi.Host/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp.azurewebsites.net" +} +``` + +- Modify the **yourapp.ApiHost** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp-apihost.azurewebsites.net" +} +``` + +- Modify the **yourapp.AuthServer** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json +"App": { + "SelfUrl": "https://yourapp-authserver.azurewebsites.net" +} +``` + +- Modify the **Redis__Configuration** URL in every location throughout your project. + + This includes the following files: + + **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** + +```json +"Redis": { + "Configuration": "redis-abpdemo.redis.cache.windows.net:6380,password={yourpassword},ssl=true,abortConnect=False" + }, +``` + +{{end}} + +{{end}} + + +## What's next? + +- [Deploying Your ABP Application to Azure](step3-deployment-github-action.md) diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md new file mode 100644 index 00000000000..32e51a2a58e --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md @@ -0,0 +1,735 @@ +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +## Step 3: Deploying the ABP Application to Azure Web App Service + +### Deploying the ABP Application to Azure Web App Service using GitHub Actions + +1. Create a new GitHub repository for your project if you don't have one. + +2. Push your project to the new GitHub repository. + +3. Navigate to the **Actions** tab of your GitHub repository. + +4. Click the **set up a workflow yourself** button. + + ![Set up this workflow](../../../images/azure-deploy-set-up-this-workflow.png) + +5. Copy this content to the opened file and commit it. + +{{if UI == "NG"}} + +{%{ + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy ASP.Net Core with Angular app to Azure Web App + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build-backend: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install ABP CLI + run: | + dotnet tool install -g Volo.Abp.Cli + abp install-libs + shell: bash + + - name: Build with dotnet + run: dotnet build --configuration Release + working-directory: ./aspnet-core + + - name: Run migrations + run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" + working-directory: ./aspnet-core/src/Demo.AzureAppsAngular.DbMigrator # Replace with your project name + + - name: dotnet publish apihost + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost + working-directory: ./aspnet-core/src/Demo.AzureAppsAngular.HttpApi.Host # Replace with your project name + + - name: Generate authserver.pfx + run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password + + - name: Upload artifact for apihost + uses: actions/upload-artifact@v4 + with: + name: .net-apihost + path: ${{env.DOTNET_ROOT}}/apihost + + deploy-backend: + runs-on: ubuntu-latest + needs: build-backend + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp-1.outputs.webapp-url }} + + steps: + - name: Download artifact from apihost + uses: actions/download-artifact@v1 + with: + name: .net-apihost + path: ./apihost + + - name: Deploy apihost + id: deploy-to-webapp-1 + uses: azure/webapps-deploy@v3 + with: + app-name: 'apihost-angular' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.apihostangularPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings + path: ./apihost + + build-deploy-frontend: + runs-on: ubuntu-latest + needs: deploy-backend + name: Build and Deploy Angular App + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PROUD_STONE }} # Set your Azure Static Web App API token as a secret in your repository settings + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (eg: PR comments) + action: "upload" + app_location: "angular" # App source code path + api_location: "" # Api source code path - optional + output_location: "dist/AzureAppsAngular" # Built app content directory - optional +``` + +}%} + +{{ else if UI == "Blazor" }} + +{%{ + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy ASP.Net Core with Blazor to Azure Web App + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build-apihost: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install ABP CLI + run: | + dotnet tool install -g Volo.Abp.Cli + abp install-libs + shell: bash + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: Run migrations + run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" + working-directory: ./src/demo.BlazorNonTierEfCore.DbMigrator # Replace with your project name + + - name: dotnet publish apihost + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost + working-directory: ./src/demo.BlazorNonTierEfCore.HttpApi.Host # Replace with your project name + + - name: Generate authserver.pfx + run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password + + - name: Upload artifact for apihost + uses: actions/upload-artifact@v4 + with: + name: .net-apihost + path: ${{env.DOTNET_ROOT}}/apihost + + deploy-apihost: + runs-on: ubuntu-latest + needs: build-apihost + environment: + name: 'Production' + + steps: + - name: Download artifact from apihost + uses: actions/download-artifact@v4 + with: + name: .net-apihost + path: ./apihost + + - name: Deploy apihost + id: deploy-to-webapp-2 + uses: azure/webapps-deploy@v3 + with: + app-name: 'apihost-blazor' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.apihostblazorPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings + + build-deploy-frontend: + runs-on: ubuntu-latest + needs: deploy-apihost + name: Build and Deploy Job + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS }} # Set your Azure Static Web App API token as a secret in your repository settings + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (eg: PR comments) + action: "upload" + app_location: "src/demo.BlazorNonTierEfCore.Blazor" # App source code path + api_location: "" # Api source code path - optional + output_location: "wwwroot" # Built app content directory - optional +``` + +}%} + +{{ else if UI == "BlazorServer" }} + +{{ if Tiered == "No" }} + +{%{ + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy ASP.Net Core with BlazorServer to Azure Web App + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install ABP CLI + run: | + dotnet tool install -g Volo.Abp.Cli + abp install-libs + shell: bash + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: Run migrations + run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings + working-directory: ./src/blazorservertierdemo.DbMigrator # Replace with your project name + + - name: dotnet publish apihost + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost + working-directory: ./src/blazorservertierdemo.HttpApi.Host # Replace with your project name + + - name: Generate authserver.pfx + run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password + + - name: dotnet publish webapp + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp + working-directory: ./src/blazorservertierdemo.Blazor # Replace with your project name + + - name: Upload artifact for apihost + uses: actions/upload-artifact@v4 + with: + name: .net-apihost + path: ${{env.DOTNET_ROOT}}/apihost + + - name: Upload artifact for webapp + uses: actions/upload-artifact@v4 + with: + name: .net-webapp + path: ${{env.DOTNET_ROOT}}/webapp + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }} + + - name: Download artifact from apihost + uses: actions/download-artifact@v4 + with: + name: .net-apihost + path: ./apihost + + - name: Deploy apihost + id: deploy-to-webapp-2 + uses: azure/webapps-deploy@v3 + with: + app-name: 'apihost-blazorserver' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.apihostblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings + package: ./apihost + + - name: Download artifact from webapp + uses: actions/download-artifact@v4 + with: + name: .net-webapp + path: ./webapp + + - name: Deploy webapp + id: deploy-to-webapp-3 + uses: azure/webapps-deploy@v3 + with: + app-name: 'webapp-blazorserver' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.webappblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings + package: ./webapp +``` + +}%} + +{{ else }} + +{%{ + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy ASP.Net Core with BlazorServer to Azure Web App + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install ABP CLI + run: | + dotnet tool install -g Volo.Abp.Cli + abp install-libs + shell: bash + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: Run migrations + run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings + working-directory: ./src/blazorservertierdemo.DbMigrator # Replace with your project name + + - name: dotnet publish authserver + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/authserver + working-directory: ./src/blazorservertierdemo.AuthServer # Replace with your project name + + - name: Generate authserver.pfx + run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/authserver/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password + + - name: dotnet publish apihost + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost + working-directory: ./src/blazorservertierdemo.HttpApi.Host # Replace with your project name + + - name: dotnet publish webapp + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp + working-directory: ./src/blazorservertierdemo.Blazor # Replace with your project name + + - name: Upload artifact for authserver + uses: actions/upload-artifact@v4 + with: + name: .net-authserver + path: ${{env.DOTNET_ROOT}}/authserver + + - name: Upload artifact for apihost + uses: actions/upload-artifact@v4 + with: + name: .net-apihost + path: ${{env.DOTNET_ROOT}}/apihost + + - name: Upload artifact for webapp + uses: actions/upload-artifact@v4 + with: + name: .net-webapp + path: ${{env.DOTNET_ROOT}}/webapp + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }} + + steps: + - name: Download artifact from authserver + uses: actions/download-artifact@v4 + with: + name: .net-authserver + path: ./authserver + + - name: Deploy authserver + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'authserver-blazorserver' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.authserverblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings + package: ./authserver + + - name: Download artifact from apihost + uses: actions/download-artifact@v4 + with: + name: .net-apihost + path: ./apihost + + - name: Deploy apihost + id: deploy-to-webapp-2 + uses: azure/webapps-deploy@v3 + with: + app-name: 'apihost-blazorserver' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.apihostblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings + package: ./apihost + + - name: Download artifact from webapp + uses: actions/download-artifact@v4 + with: + name: .net-webapp + path: ./webapp + + - name: Deploy webapp + id: deploy-to-webapp-3 + uses: azure/webapps-deploy@v3 + with: + app-name: 'webapp-blazorserver' # Replace with your app name + slot-name: 'Production' + publish-profile: ${{ secrets.webappblazorserverPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings +``` + +}%} + +{{end}} + +{{ else if UI == "MVC" }} + +{{ if Tiered == "No" }} + +{%{ + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy ASP.Net Core with MVC to Azure Web App + +on: +push: + branches: + - main +workflow_dispatch: + +jobs: +build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install ABP CLI + run: | + dotnet tool install -g Volo.Abp.Cli + abp install-libs + shell: bash + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: Run migrations + run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings + working-directory: ./src/yourapp.DbMigrator # Replace with your project name + + - name: dotnet publish + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp + working-directory: ./src/yourapp.Web # Replace with your project name + + - name: Generate authserver.pfx + run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/myapp/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: ${{env.DOTNET_ROOT}}/myapp + +deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'yourapp' # Replace with your azure web app name + slot-name: 'Production' + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE }} # Set your Azure Web App publish your profile as a secret in your repository settings + package: . +``` + +}%} + +{{ else }} + +{%{ + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy ASP.Net Core with MVC to Azure Web App + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install ABP CLI + run: | + dotnet tool install -g Volo.Abp.Cli + abp install-libs + shell: bash + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: Run migrations + run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings + working-directory: ./src/mvctierdemo.DbMigrator # Replace with your project name + + - name: dotnet publish authserver + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/authserver + working-directory: ./src/mvctierdemo.AuthServer # Replace with your project name + + - name: Generate authserver.pfx + run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/authserver/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password + + - name: dotnet publish apihost + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost + working-directory: ./src/mvctierdemo.HttpApi.Host # Replace with your project name + + - name: dotnet publish webapp + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp + working-directory: ./src/mvctierdemo.Web # Replace with your project name + + - name: Upload artifact for authserver + uses: actions/upload-artifact@v4 + with: + name: .net-authserver + path: ${{env.DOTNET_ROOT}}/authserver + + - name: Upload artifact for apihost + uses: actions/upload-artifact@v4 + with: + name: .net-apihost + path: ${{env.DOTNET_ROOT}}/apihost + + - name: Upload artifact for webapp + uses: actions/upload-artifact@v4 + with: + name: .net-webapp + path: ${{env.DOTNET_ROOT}}/webapp + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }} + + steps: + - name: Download artifact from apihost + uses: actions/download-artifact@v4 + with: + name: .net-apihost + path: ./apihost + + - name: Deploy apihost + id: deploy-to-webapp-2 + uses: azure/webapps-deploy@v3 + with: + app-name: 'apihost-prodemo' + slot-name: 'Production' + publish-profile: ${{ secrets.apihostprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings + package: ./apihost + + - name: Download artifact from authserver + uses: actions/download-artifact@v4 + with: + name: .net-authserver + path: ./authserver + + - name: Deploy authserver + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'authserver-prodemo' + slot-name: 'Production' + publish-profile: ${{ secrets.authserverprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings + package: ./authserver + + - name: Download artifact from webapp + uses: actions/download-artifact@v4 + with: + name: .net-webapp + path: ./webapp + + - name: Deploy webapp + id: deploy-to-webapp-3 + uses: azure/webapps-deploy@v3 + with: + app-name: 'webapp-prodemo' + slot-name: 'Production' + publish-profile: ${{ secrets.webappprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings + package: ./webapp +``` + +}%} + +{{end}} + +{{end}} + + +7. Navigate to the **Settings** tab of your GitHub repository. + +8. Click the **Secrets** button. + +9. Click the **New repository secret** button. + + ![New repository secret](../../../images/azure-deploy-new-repository-secret.png) + +10. Add the following secrets: + + - **CONNECTION_STRING**: The connection string of your database. + + Example of Azure SQL connection string: + + ![Azure sql connection string](../../../images/azure-deploy-connection-string.png) + + - **AZUREAPPSERVICE_PUBLISHPROFILE**: The publish the profile of your Azure Web App Service. You can download it from the **Overview** tab of your Azure Web App Service. + + ![Publish profile](../../../images/azure-deploy-publish-profile.png) + +{{ if UI == "NG" || UI == "Blazor"}} + + - **AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS**: The API token of your Azure Static Web App. You can get it from the **Overview** tab of your Azure Static Web App. + + ![API token](../../../images/azure-deploy-api-token.png) + +{{end}} + +11. Navigate to the **Actions** tab of your GitHub repository. + +12. Click the **Deploy to Azure Web App** workflow. + + ![Deploy to Azure Web App](../../../images/azure-deploy-deploy-to-azure-web-app.png) + +13. Click the **Run workflow** button. + + ![Run workflow](../../../images/azure-deploy-run-workflow.png) + +14. Navigate to the web app URL to see the deployed application. + + ![Azure Web App](../../../images/azure-deploy-runtime-stack2.png) + +> If deploying your application was unsuccessful, you can check the logs of the deployment by clicking the **Deploy to Azure Web App** workflow and then clicking the **deploy-to-webapp** job. + +> If deployment is successful, but you get an error when you navigate to the web app url, you can check the logs of the web app by clicking the **Logs** button on the **Overview** tab of your Azure Web App Service. + +> Finally, you have the CI/CD pipeline for your application. Every time you push your code to the main branch, your application will be deployed to Azure Web App Service automatically. + + +## What's next? + +- [Docker Deployment using Docker Compose](../deployment-docker-compose.md) + +- [IIS Deployment](../deployment-iis.md) diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/terraform-web-app-service.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/terraform-web-app-service.md new file mode 100644 index 00000000000..c1678c4961b --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/terraform-web-app-service.md @@ -0,0 +1,572 @@ +# Provisioning an Azure Web App using Terraform + +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +In this tutorial, we'll walk through the steps to provision an Azure Web App using Terraform. Terraform is an open-source infrastructure as a code tool that allows you to define and manage your infrastructure in a declarative way. + +## Prerequisites + +Before you begin, you'll need the following: + +- [Azure account](https://azure.microsoft.com/en-us/free/) +- [Terraform installed](https://developer.hashicorp.com/terraform/downloads) on your local machine +- [Azure CLI installed](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) on your local machine + +## Creating a Service Principal for Terraform in Azure + +When working with Terraform on Azure, you'll need a "Service Principal" for authentication. A "Service Principal" is an identity created to be used with applications, hosted services, and automated tools to access Azure resources. + +[To create a service principal](https://learn.microsoft.com/en-us/azure/developer/terraform/authenticate-to-azure?tabs=bash#create-a-service-principal), run the following command in the Azure CLI: + +1. Login to Azure CLI + + Before you begin, make sure you are logged into your Azure account with the Azure CLI: + ```bash + az login + ``` + +2. Set your Subscription: + + If you have multiple Azure subscriptions, specify the one you intend to use: + ```bash + az account set --subscription="YOUR_SUBSCRIPTION_ID" + ``` + +3. Create the Service Principal: + + The following command will create a service principal. Replace YOUR_APP_NAME with a suitable name for your application: + ```bash + az ad sp create-for-rbac --name "YOUR_APP_NAME" --role contributor --scopes /subscriptions/YOUR_SUBSCRIPTION_ID + ``` + > Replace `YOUR_SUBSCRIPTION_ID` with your subscription id. + + The output of this command will provide the **appId**, **displayName**, **name**, **password**, and **tenant**. It's crucial to note these values, especially **appId (Client ID)** and **password (Client Secret)**, as you'll need them for Terraform authentication. + +4. Specify the service principal credentials in environment variables + + bash: + ```bash + export ARM_SUBSCRIPTION_ID="" + export ARM_TENANT_ID="" + export ARM_CLIENT_ID="" + export ARM_CLIENT_SECRET="" + ``` + To execute the ~/.bashrc script, run source ~/.bashrc (or its abbreviated equivalent . ~/.bashrc). You can also exit and reopen Cloud Shell for the script to run automatically. + Run the following bash command to verify the Azure environment variables: + ```bash + . ~/.bashrc + ``` + powershell: + ```powershell + $env:ARM_SUBSCRIPTION_ID="" + $env:ARM_TENANT_ID="" + $env:ARM_CLIENT_ID="" + $env:ARM_CLIENT_SECRET="" + ``` + Run the following PowerShell command to verify the Azure environment variables: + ```powershell + gci env:ARM_* + ``` + > Replace the values with your own. + +## Creating a Terraform Configuration + +1. Create a new directory for your Terraform configuration files. + +2. Create a new file named `main.tf` in the directory and add the following code: + +{{if UI == "NG"}} + +```terraform +# Configure the Azure provider +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0.0" + } + } + required_version = ">= 0.14.9" +} +provider "azurerm" { + features {} +} + +# Create the resource group +resource "azurerm_resource_group" "rg" { + name = "demo-angular-web-app-rg" + location = "westeurope" +} + +# Create the Linux App Service Plan +resource "azurerm_service_plan" "appserviceplan" { + name = "demo-angular-web-app-plan" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + sku_name = "B3" +} + + +resource "azurerm_linux_web_app" "apihost" { + name = "apihost-angular" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } +} + +resource "azurerm_static_site" "angularweb" { + name = "angularweb" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name +} +``` + +{{ else if UI == "Blazor" }} + +```terraform +# Configure the Azure provider +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0.0" + } + } + required_version = ">= 0.14.9" +} +provider "azurerm" { + features {} +} + +# Create the resource group +resource "azurerm_resource_group" "rg" { + name = "blazor-app-nontier-rg" + location = "westeurope" +} + +# Create the Linux App Service Plan +resource "azurerm_service_plan" "appserviceplan" { + name = "blazor-app-nontier-plan" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + sku_name = "B3" +} + +# Create the web app, pass in the App Service Plan ID + +resource "azurerm_linux_web_app" "apihost" { + name = "apihost-blazor" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } +} +resource "azurerm_static_site" "blazorweb" { + name = "blazorweb" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name +} +``` + +{{ else if UI == "BlazorServer" }} + + {{if Tiered == "No"}} + +```terraform +# Configure the Azure provider +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0.0" + } + } + required_version = ">= 0.14.9" +} +provider "azurerm" { + features {} +} + +# Create the resource group +resource "azurerm_resource_group" "rg" { + name = "blazorserver-app-nontier-rg" + location = "westeurope" +} + +# Create the Linux App Service Plan +resource "azurerm_service_plan" "appserviceplan" { + name = "blazorserver-app-nontier-plan" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + sku_name = "B3" +} + +# Create the web app, pass in the App Service Plan ID +resource "azurerm_linux_web_app" "authserver" { + name = "authserver-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } +} +resource "azurerm_linux_web_app" "apihost" { + name = "apihost-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } +} +resource "azurerm_linux_web_app" "webapp" { + name = "webapp-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } +} +``` + + {{ else }} + +```terraform +# Configure the Azure provider +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0.0" + } + } + required_version = ">= 0.14.9" +} +provider "azurerm" { + features {} +} + +# Create the resource group +resource "azurerm_resource_group" "rg" { + name = "blazorserver-app-tier-rg" + location = "westeurope" +} + +# Create the Linux App Service Plan +resource "azurerm_service_plan" "appserviceplan" { + name = "blazorserver-app-tier-plan" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + sku_name = "B3" +} + +# Create the web app, pass in the App Service Plan ID +resource "azurerm_linux_web_app" "authserver" { + name = "authserver-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } + app_settings = { + "Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string + } +} +resource "azurerm_linux_web_app" "apihost" { + name = "apihost-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } + app_settings = { + "Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string + } +} +resource "azurerm_linux_web_app" "webapp" { + name = "webapp-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } + app_settings = { + "Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string + } +} + +resource "azurerm_redis_cache" "redis" { + name = "redis-blazorserver" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + capacity = 0 + family = "C" + sku_name = "Basic" + enable_non_ssl_port = false + minimum_tls_version = "1.2" + + redis_configuration { + maxmemory_reserved = 2 + maxmemory_delta = 2 + maxmemory_policy = "volatile-lru" + } +} +``` + + {{end}} + +{{ else if UI == "MVC" }} + + {{ if Tiered == "No" }} + +```terraform +# Configure the Azure provider +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0.0" + } + } + required_version = ">= 0.14.9" +} +provider "azurerm" { + features {} +} + +# Create the resource group +resource "azurerm_resource_group" "rg" { + name = "demo-abp-web-app" + location = "westeurope" +} + +# Create the Linux App Service Plan +resource "azurerm_service_plan" "appserviceplan" { + name = "demo-abp-web-app-plan" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + sku_name = "B3" +} + +# Create the web app, pass in the App Service Plan ID +resource "azurerm_linux_web_app" "webapp" { + name = "demo-abp-web-app" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } +} + +output "webappurl" { + + value = "${azurerm_linux_web_app.webapp.name}.azurewebsites.net" +} +``` + + {{ else }} + +```terraform +# Configure the Azure provider +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0.0" + } + } + required_version = ">= 0.14.9" +} +provider "azurerm" { + features {} +} + +# Create the resource group +resource "azurerm_resource_group" "rg" { + name = "demo-abp-web-app-tier-rg" + location = "westeurope" +} + +# Create the Linux App Service Plan +resource "azurerm_service_plan" "appserviceplan" { + name = "demo-abp-web-app-tier-plan" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + os_type = "Linux" + sku_name = "B3" +} + +# Create the web app, pass in the App Service Plan ID +resource "azurerm_linux_web_app" "authserver" { + name = "authserver-prodemo" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } + app_settings = { + "Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string + } +} +resource "azurerm_linux_web_app" "apihost" { + name = "apihost-prodemo" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } + app_settings = { + "Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string + } +} +resource "azurerm_linux_web_app" "webapp" { + name = "webapp-prodemo" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + service_plan_id = azurerm_service_plan.appserviceplan.id + https_only = true + site_config { + application_stack { + dotnet_version = "6.0" + } + minimum_tls_version = "1.2" + } + app_settings = { + "Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string + } +} + +resource "azurerm_redis_cache" "redis" { + name = "redis-prodemo" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + capacity = 0 + family = "C" + sku_name = "Basic" + enable_non_ssl_port = false + minimum_tls_version = "1.2" + + redis_configuration { + maxmemory_reserved = 2 + maxmemory_delta = 2 + maxmemory_policy = "volatile-lru" + } +} + +output "authserver" { + + value = "${azurerm_linux_web_app.authserver.name}.azurewebsites.net" +} + +output "apihost" { + + value = "${azurerm_linux_web_app.apihost.name}.azurewebsites.net" +} + +output "webapp" { + + value = "${azurerm_linux_web_app.webapp.name}.azurewebsites.net" +} + +output "redis_hostname" { + value = azurerm_redis_cache.redis.hostname + description = "The hostname for the Redis instance." +} +``` + + {{end}} + +{{end}} + + +3. Run `terraform init` to initialize the directory. + +4. Run `terraform plan` to see the execution plan. + +5. Run `terraform apply` to apply the changes. Write `yes` when prompted to confirm the deployment. + +6. Wait for the deployment to complete. + +7. Navigate to the web app URL to see the deployed application. + +> You can also see the web app URL in the output of the `terraform apply` command. + +> You have to change the **dotnet version** of the runtime stack according to your application. For example, if you are using .NET 7, you should change `dotnet_version = "6.0"` to `dotnet_version = "7.0"`. + +![Azure Web App](../../../images/azure-deploy-runtime-stack.png) + +## Destroying the Terraform Configuration + +1. Run `terraform destroy` to destroy the created resources. + +2. Type `yes` when prompted to confirm the destruction. + diff --git a/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md b/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md new file mode 100644 index 00000000000..6c9c7246387 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md @@ -0,0 +1,1933 @@ +# Docker Deployment using Docker Compose + +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference at the top of this document. + +This guide will guide you through how to build docker images for your application and run on localhost using `docker compose`. You will learn the provided build scripts and docker compose files in detail and how to modify them for the production environment. + +## Building Docker Images + +Each application contains a dockerfile called `Dockerfile.local` for building the docker image. As the naming implies, these Dockerfiles are not multi-stage Dockerfiles and require the project to be built in `Release` mode to create the image. Currently, if you are building your images using CI & CD pipeline, you either need to include the SDK to your pipeline before building the images or add your own [multi-stage dockerfiles](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/docker/building-net-docker-images?view=aspnetcore-7.0). + +Since they are not multi-staged Dockerfiles, if you want to build the images individually, you can navigate to the related to-be-hosted application folder and run the following command: + +``````powershell +dotnet publish -c Release +`````` + +To populate the **Release** folder first, which will be used to build the docker images. Afterward, you can run the following command: + +```powershell +docker build -f Dockerfile.local -t mycompanyname/myappname:version . +``` + +To manually build your application image. + +To ease the process, application templates provide a build script to build all the images with a single script under `etc/build` folder named `build-images-locally.ps1`. +Based on your application name, UI and type, a build image script will be generated. + +{{ if UI == "MVC"}} + +```powershell +param ($version='latest') + +$currentFolder = $PSScriptRoot +$slnFolder = Join-Path $currentFolder "../../" + +Write-Host "********* BUILDING DbMigrator *********" -ForegroundColor Green +$dbMigratorFolder = Join-Path $slnFolder "src/Acme.BookStore.DbMigrator" +Set-Location $dbMigratorFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-db-migrator:$version . + +Write-Host "********* BUILDING Web Application *********" -ForegroundColor Green +$webFolder = Join-Path $slnFolder "src/Acme.BookStore.Web" +Set-Location $webFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-web:$version . + + {{ if Tiered == "Yes"}} +Write-Host "********* BUILDING Api.Host Application *********" -ForegroundColor Green +$hostFolder = Join-Path $slnFolder "src/Acme.BookStore.HttpApi.Host" +Set-Location $hostFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-api:$version . + +Write-Host "********* BUILDING AuthServer Application *********" -ForegroundColor Green +$authServerAppFolder = Join-Path $slnFolder "src/Acme.BookStore.AuthServer" +Set-Location $authServerAppFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-authserver:$version . + {{ end }} + +### ALL COMPLETED +Write-Host "COMPLETED" -ForegroundColor Green +Set-Location $currentFolder +``` + +{{ end }} + +{{ if UI == "NG"}} + +```powershell +param ($version='latest') + +$currentFolder = $PSScriptRoot +$slnFolder = Join-Path $currentFolder "../../" + +Write-Host "********* BUILDING DbMigrator *********" -ForegroundColor Green +$dbMigratorFolder = Join-Path $slnFolder "src/Acme.BookStore.DbMigrator" +Set-Location $dbMigratorFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-db-migrator:$version . + +Write-Host "********* BUILDING Angular Application *********" -ForegroundColor Green +$angularAppFolder = Join-Path $slnFolder "../angular" +Set-Location $angularAppFolder +yarn +npm run build:prod +docker build -f Dockerfile.local -t acme/bookstore-angular:$version . + +Write-Host "********* BUILDING Api.Host Application *********" -ForegroundColor Green +$hostFolder = Join-Path $slnFolder "src/Acme.BookStore.HttpApi.Host" +Set-Location $hostFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-api:$version . + + {{ if Tiered == "Yes"}} +$authServerAppFolder = Join-Path $slnFolder "src/Acme.BookStore.AuthServer" +Set-Location $authServerAppFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-authserver:$version . + {{ end }} + +### ALL COMPLETED +Write-Host "COMPLETED" -ForegroundColor Green +Set-Location $currentFolder +``` + +{{ end }} + +{{ if UI == "Blazor" }} + +```powershell +param ($version='latest') + +$currentFolder = $PSScriptRoot +$slnFolder = Join-Path $currentFolder "../../" + +Write-Host "********* BUILDING DbMigrator *********" -ForegroundColor Green +$dbMigratorFolder = Join-Path $slnFolder "src/Acme.BookStore.DbMigrator" +Set-Location $dbMigratorFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-db-migrator:$version . + +Write-Host "********* BUILDING Blazor Application *********" -ForegroundColor Green +$blazorFolder = Join-Path $slnFolder "src/Acme.BookStore.Blazor" +Set-Location $blazorFolder +dotnet publish -c Release -p:PublishTrimmed=false +docker build -f Dockerfile.local -t acme/bookstore-blazor:$version . + +Write-Host "********* BUILDING Api.Host Application *********" -ForegroundColor Green +$hostFolder = Join-Path $slnFolder "src/Acme.BookStore.HttpApi.Host" +Set-Location $hostFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-api:$version . + {{ if Tiered == "Yes"}} +$authServerAppFolder = Join-Path $slnFolder "src/Acme.BookStore.AuthServer" +Set-Location $authServerAppFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-authserver:$version . + {{ end }} +### ALL COMPLETED +Write-Host "COMPLETED" -ForegroundColor Green +Set-Location $currentFolder +``` + +{{ end }} + +{{ if UI == "BlazorServer" }} + +```powershell +param ($version='latest') + +$currentFolder = $PSScriptRoot +$slnFolder = Join-Path $currentFolder "../../" + +Write-Host "********* BUILDING DbMigrator *********" -ForegroundColor Green +$dbMigratorFolder = Join-Path $slnFolder "src/Acme.BookStore.DbMigrator" +Set-Location $dbMigratorFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-db-migrator:$version . + +Write-Host "********* BUILDING Blazor Application *********" -ForegroundColor Green +$blazorFolder = Join-Path $slnFolder "src/Acme.BookStore.Blazor" +Set-Location $blazorFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-blazor:$version . + + {{ if Tiered == "Yes"}} +$authServerAppFolder = Join-Path $slnFolder "src/Acme.BookStore.AuthServer" +Set-Location $authServerAppFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-authserver:$version . + +Write-Host "********* BUILDING Api.Host Application *********" -ForegroundColor Green +$hostFolder = Join-Path $slnFolder "src/Acme.BookStore.HttpApi.Host" +Set-Location $hostFolder +dotnet publish -c Release +docker build -f Dockerfile.local -t acme/bookstore-api:$version . + {{ end }} +### ALL COMPLETED +Write-Host "COMPLETED" -ForegroundColor Green +Set-Location $currentFolder +``` + +{{ end }} + +The **image tag** is set to `latest` by default. You can update the `param $version` at the first line to set it as a tag for your images. + +You can examine all the provided Dockerfiles required to publish your application below; + +### DBMigrator + +DbMigrator is a console application that is used to migrate the database of your application and seed the initial important data to run your application. Such as pre-defined languages, admin user and role, OpenIddict applications and scopes. + +`Dockerfile.local` is provided under this project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app +ENTRYPOINT ["dotnet", "BookStore.DbMigrator.dll"] +``` + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to **DbMigrator** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-db-migrator:latest . #Builds the image with "latest" tag +``` + +{{ if UI == "MVC" }} + +### MVC/Razor Pages + +​ {{ if Tiered == "Yes" }}MVC/Razor Pages application is a server-side rendering application that uses Cookie authentication as the default scheme and OpenIdConnect as the default challenge scheme. + +In the **WebModule** under authentication configuration, there is an extra configuration for containerized environment support: + +```csharp +if (Convert.ToBoolean(configuration["AuthServer:IsContainerizedOnLocalhost"])) +{ + context.Services.Configure("oidc", options => + { + options.TokenValidationParameters.ValidIssuers = new[] + { + configuration["AuthServer:MetaAddress"].EnsureEndsWith('/'), + configuration["AuthServer:Authority"].EnsureEndsWith('/') + }; + + options.MetadataAddress = configuration["AuthServer:MetaAddress"].EnsureEndsWith('/') + + ".well-known/openid-configuration"; + + var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider; + options.Events.OnRedirectToIdentityProvider = async ctx => + { + // Intercept the redirection so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/authorize"; + + if (previousOnRedirectToIdentityProvider != null) + { + await previousOnRedirectToIdentityProvider(ctx); + } + }; + var previousOnRedirectToIdentityProviderForSignOut = options.Events.OnRedirectToIdentityProviderForSignOut; + options.Events.OnRedirectToIdentityProviderForSignOut = async ctx => + { + // Intercept the redirection for signout so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/logout"; + + if (previousOnRedirectToIdentityProviderForSignOut != null) + { + await previousOnRedirectToIdentityProviderForSignOut(ctx); + } + }; + }); + +} +``` + +This is used when the **AuthServer is running on docker containers(or pods)** to configure the redirection URLs for the internal network and the web. The application must be redirected to real DNS (localhost in this case) when the `/authorize` and `/logout` requests over the browser but handle the token validation inside the isolated network without going out to the internet. `"AuthServer:MetaAddress"` appsetting should indicate the container/pod service name while the `AuthServer:Authority` should be pointing to real DNS for the browser to redirect. + +The `appsettings.json` file does not contain `AuthServer:IsContainerizedOnLocalhost` and `AuthServer:MetaAddress` settings since they are used for orchestrated deployment scenarios, you can see these settings are overridden by the `docker-compose.yml` file. + +`Dockerfile.local` is provided under this project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app +ENTRYPOINT ["dotnet", "Acme.BookStore.Web.dll"] +``` + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to the **Web** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-web:latest . #Builds the image with "latest" tag +``` + +​ {{ end }} {{ if Tiered == "No" }}MVC/Razor Pages application is a server-side rendering application that contains both the OpenID-provider and the Http.Api endpoints within self; it will be a single application to deploy. `Dockerfile.local` is provided under this project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +RUN dotnet dev-certs https -v -ep authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED + +FROM base AS final +WORKDIR /app +COPY --from=build /src . + +ENTRYPOINT ["dotnet", "Acme.BookStore.Web.dll"] +``` + +You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. + +![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) + +Since it contains the openid-provider within, it also uses multi-stages to generate `authserver.pfx` file which is **used by OpenIddict as signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **WebModule**: + +```csharp +if (!hostingEnvironment.IsDevelopment()) +{ + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(builder => + { + builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.SetIssuer(new Uri(configuration["AuthServer:Authority"])); + }); +} +``` + +This configuration disables the *DevelopmentEncryptionAndSigningCertificate* and uses a self-signed certificate called `authserver.pfx`. for **signing and encrypting the tokens**. This certificate is created when the docker image is built using the `dotnet dev-certs` tooling. It is a sample-generated certificate, and it is **recommended** to update it for the production environment. You can check the [OpenIddict Encryption and signing credentials documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html) for different options and customization. + +The `GetSigningCertificate` method is a private method located under the same **WebModule**: + +```csharp +private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration) +{ + var fileName = "authserver.pfx"; + var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED"; + var file = Path.Combine(hostingEnv.ContentRootPath, fileName); + + if (!File.Exists(file)) + { + throw new FileNotFoundException($"Signing Certificate couldn't found: {file}"); + } + + return new X509Certificate2(file, passPhrase); +} +``` + +> You can always create any self-signed certificate using any other tooling outside the Dockerfile. You need to remember to set them as **embedded resource** since the `GetSigningCertificate` method will be checking this file physically. + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to the **Web** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-web:latest . #Builds the image with "latest" tag +``` + +​ {{ end }} + +{{ end }} + +{{ if UI == "BlazorServer" }} + +### Blazor Server + +​ {{ if Tiered == "Yes" }}Blazor Server application is a server-side rendering application that uses Cookie authentication as the default scheme and OpenIdConnect as the default challenge scheme. + +In the **BlazorModule** under authentication configuration, there is an extra configuration for containerized environment support: + +```csharp +if (Convert.ToBoolean(configuration["AuthServer:IsContainerizedOnLocalhost"])) +{ + context.Services.Configure("oidc", options => + { + options.TokenValidationParameters.ValidIssuers = new[] + { + configuration["AuthServer:MetaAddress"].EnsureEndsWith('/'), + configuration["AuthServer:Authority"].EnsureEndsWith('/') + }; + + options.MetadataAddress = configuration["AuthServer:MetaAddress"].EnsureEndsWith('/') + + ".well-known/openid-configuration"; + + var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider; + options.Events.OnRedirectToIdentityProvider = async ctx => + { + // Intercept the redirection so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/authorize"; + + if (previousOnRedirectToIdentityProvider != null) + { + await previousOnRedirectToIdentityProvider(ctx); + } + }; + var previousOnRedirectToIdentityProviderForSignOut = options.Events.OnRedirectToIdentityProviderForSignOut; + options.Events.OnRedirectToIdentityProviderForSignOut = async ctx => + { + // Intercept the redirection for signout so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/logout"; + + if (previousOnRedirectToIdentityProviderForSignOut != null) + { + await previousOnRedirectToIdentityProviderForSignOut(ctx); + } + }; + }); + +} +``` + +This is used when the **AuthServer is running on docker containers(or pods)** to configure the redirection URLs for the internal network and the web. The application must be redirected to real DNS (localhost in this case) when the `/authorize` and `/logout` requests over the browser but handle the token validation inside the isolated network without going out to the internet. `"AuthServer:MetaAddress"` appsetting should indicate the container/pod service name while the `AuthServer:Authority` should be pointing to real DNS for the browser to redirect. + +The `appsettings.json` file does not contain `AuthServer:IsContainerizedOnLocalhost` and `AuthServer:MetaAddress` settings since they are used for orchestrated deployment scenarios, you can see these settings are overridden by the `docker-compose.yml` file. + +`Dockerfile.local` is provided under this project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app +ENTRYPOINT ["dotnet", "Acme.BookStore.Blazor.dll"] +``` + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to **Blazor** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-blazor:latest . #Builds the image with "latest" tag +``` + +​ {{ end }} {{ if Tiered == "No" }}Blazor Server application is a server-side rendering application that contains both the OpenID-provider and the Http.Api endpoints within self; it will be a single application to deploy. `Dockerfile.local` is provided under this project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +RUN dotnet dev-certs https -v -ep authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED + +FROM base AS final +WORKDIR /app +COPY --from=build /src . + +ENTRYPOINT ["dotnet", "Acme.BookStore.Blazor.dll"] +``` + +You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. + +![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) + +Since it contains the OpenID-provider within, it also uses multi-stages to generate `authserver.pfx` file which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **BlazorModule**: + +```csharp +if (!hostingEnvironment.IsDevelopment()) +{ + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(builder => + { + builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.SetIssuer(new Uri(configuration["AuthServer:Authority"])); + }); +} +``` + +This configuration disables the *DevelopmentEncryptionAndSigningCertificate* and uses a self-signed certificate called `authserver.pfx`. for **signing and encrypting the tokens**. This certificate is created when the docker image is built using the `dotnet dev-certs` tooling. It is a sample-generated certificate, and it is **recommended** to update it for the production environment. You can check the [OpenIddict Encryption and signing credentials documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html) for different options and customization. + +The `GetSigningCertificate` method is a private method located under the same **BlazorModule**: + +```csharp +private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration) +{ + var fileName = "authserver.pfx"; + var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED"; + var file = Path.Combine(hostingEnv.ContentRootPath, fileName); + + if (!File.Exists(file)) + { + throw new FileNotFoundException($"Signing Certificate couldn't found: {file}"); + } + + return new X509Certificate2(file, passPhrase); +} +``` + +> You can always create any self-signed certificate using any other tooling outside the dockerfile. You need to remember to set them as **embedded resource** since the `GetSigningCertificate` method will be checking this file physically. + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to the **BlazorModule** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-blazor:blazor . #Builds the image with "latest" tag +``` + +​ {{ end }} + +{{ end }} + +{{ if UI == "NG" }} + +### Angular + +The angular application uses [nginx:alpine-slim](https://hub.docker.com/layers/library/nginx/alpine-slim/images/sha256-0f859db466fda2c52f62b48d0602fb26867d98edbd62c26ae21414b3dea8d8f4?context=explore) base image to host the angular application. You can modify the base image based on your preference in the `Dockerfile.local`, which is provided under the angular folder of your solution as below; + +```dockerfile +FROM nginx:alpine-slim +WORKDIR /app +COPY dist/BookStore /usr/share/nginx/html +COPY dynamic-env.json /usr/share/nginx/html +COPY /nginx.conf /etc/nginx/conf.d/default.conf +``` + +You can notice that two more files are copied into the application image beside the built Angular application. + +The `dynamic-env.json` file is an empty JSON file representing the angular application's environment variables. The environment variable on image runtime will override this file. If you examine the `environment.prod.ts` file under the `angular/src/environments` folder, **there is a remote environment configuration for production**: + +```json +remoteEnv: { + url: '/getEnvConfig', + mergeStrategy: 'deepmerge' + } +``` + +[This configuration is used to get the environment variables from a remote service](https://docs.abp.io/en/abp/latest/UI/Angular/Environment#remoteenvironment). This configuration is used to **override environment variables without rebuilding the image.** The URL `/getEnvConfig` is defined in the `nginx.conf` file: + +```nginx +server { + listen 80; + listen [::]:80; + server_name _; + + #listen 443 ssl; + #server_name www.myapp.com; + #ssl_certificate www.myapp.com.crt; + #ssl_certificate_key www.myapp.com.key; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html =404; + } + + location /getEnvConfig { + default_type 'application/json'; + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Content-Type' 'application/json'; + try_files $uri /dynamic-env.json; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} +``` + +This configuration allows returning the `dynamic-env.json` file as a static file, which ABP Angular application uses for environment variables in one of the first initial requests when rendering the page. **The `dynamic-env.json` file you need to override is located under `aspnet-core/etc/docker`** folder. + +​ {{ if Tiered == "No" }} + +```json +{ + "production": true, + "application": { + "baseUrl":"http://localhost:4200", // https://myapp.com + "name": "BookStore", + "logoUrl": "" + }, + "oAuthConfig": { + "issuer": "https://localhost:44354/", // https://myapi.com/ + "redirectUri": "http://localhost:4200", // https://myapp.com + "clientId": "BookStore_App", + "responseType": "code", + "scope": "offline_access openid profile email phone BookStore" + }, + "apis": { + "default": { + "url": "https://localhost:44354", // https://myapi.com + "rootNamespace": "BookStore" + }, + "AbpAccountPublic": { + "url": "https://localhost:44354", // https://myapi.com + "rootNamespace": "AbpAccountPublic" + } + } +} +``` + +​ {{ end }} + +​ {{ if Tiered == "Yes" }} + +```json +{ + "production": true, + "application": { + "baseUrl":"http://localhost:4200", // https://myapp.com + "name": "BookStore", + "logoUrl": "" + }, + "oAuthConfig": { + "issuer": "https://localhost:44334/", // https://myauthserver.com/ + "redirectUri": "http://localhost:4200", // https://myapp.com + "clientId": "BookStore_App", + "responseType": "code", + "scope": "offline_access openid profile email phone BookStore" + }, + "apis": { + "default": { + "url": "https://localhost:44354", // https://myapi.com + "rootNamespace": "BookStore" + }, + "AbpAccountPublic": { + "url": "https://localhost:44334", // https://myauthserver.com + "rootNamespace": "AbpAccountPublic" + } + } +} +``` + +​ {{ end }} + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to the **angular** folder and run: + +```powershell +yarn #Restores the project +npm run build:prod #Builds on production environment. You can also use "ng build --prod" if you have the angular CLI +docker build -f Dockerfile.local -t acme/bookstore-angular:latest . #Builds the image with "latest" tag +``` + +{{ end }} + +{{ if UI == "Blazor" }} + +### Blazor + +The Blazor application uses [nginx:alpine-slim](https://hub.docker.com/layers/library/nginx/alpine-slim/images/sha256-0f859db466fda2c52f62b48d0602fb26867d98edbd62c26ae21414b3dea8d8f4?context=explore) base image to host the blazor application. You can modify the base image based on your preference in the `Dockerfile.local` which provided under the Blazor folder of your solution as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS build +COPY bin/Release/net7.0/publish/ app/ + +FROM nginx:alpine-slim AS final +WORKDIR /usr/share/nginx/html +COPY --from=build /app/wwwroot . +COPY /nginx.conf /etc/nginx/conf.d/default.conf +``` + +Other than the built Blazor application, there is also `nginx.conf` file is copied into the application image. The `nginx.conf` file: + +```nginx +server { + listen 80; + listen [::]:80; + server_name _; + + #listen 443 ssl; + #server_name www.myapp.com; + #ssl_certificate www.myapp.com.crt; + #ssl_certificate_key www.myapp.com.key; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html =404; + } + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} +``` + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to **Blazor** folder and run: + +```powershell +##Builds the projects in Release mode with the Trimming option disabled. You can enable or configure it as you like +dotnet publish -c Release -p:PublishTrimmed=false +docker build -f Dockerfile.local -t acme/bookstore-blazor:latest . #Builds the image with "latest" tag +``` + +{{ end }} + +{{ if Tiered == "No" }} + +​ {{ if UI == "NG" }} + +### Http.Api.Host + +This is the backend application that contains the openid-provider functionality as well. The `dockerfile.local` is located under the `Http.Api.Host` project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +RUN dotnet dev-certs https -v -ep authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED + +FROM base AS final +WORKDIR /app +COPY --from=build /src . + +ENTRYPOINT ["dotnet", "Acme.BookStore.HttpApi.Host.dll"] +``` + +You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. + +![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) + +Since it contains the OpenID-provider within, it also uses multi-stages to generate `authserver.pfx` file, which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **HttpApiHostModule**: + +```csharp +if (!hostingEnvironment.IsDevelopment()) +{ + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(builder => + { + builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.SetIssuer(new Uri(configuration["AuthServer:Authority"])); + }); +} +``` + +This configuration disables the *DevelopmentEncryptionAndSigningCertificate* and uses a self-signed certificate called `authserver.pfx`. for **signing and encrypting the tokens**. This certificate is created when the docker image is built using the `dotnet dev-certs` tooling. It is a sample-generated certificate, and it is **recommended** to update it for the production environment. You can check the [OpenIddict Encryption and signing credentials documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html) for different options and customization. + +The `GetSigningCertificate` method is a private method located under the same **HttpApiHostModule**: + +```csharp +private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration) +{ + var fileName = "authserver.pfx"; + var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED"; + var file = Path.Combine(hostingEnv.ContentRootPath, fileName); + + if (!File.Exists(file)) + { + throw new FileNotFoundException($"Signing Certificate couldn't found: {file}"); + } + + return new X509Certificate2(file, passPhrase); +} +``` + +> You can always create any self-signed certificate using any other tooling outside of the dockerfile. You need to keep in mind to set them as **embedded resource** since the `GetSigningCertificate` method will be checking this file physically. + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to **Http.Api.Host** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-api:latest . #Builds the image with "latest" tag +``` + +​ {{ end }} + +​ {{ if UI == "Blazor" }} + +### Http.Api.Host + +This is the backend application that contains the OpenID-provider functionality as well. The `dockerfile.local` is located under the `Http.Api.Host` project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +RUN dotnet dev-certs https -v -ep authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED + +FROM base AS final +WORKDIR /app +COPY --from=build /src . + +ENTRYPOINT ["dotnet", "Acme.BookStore.HttpApi.Host.dll"] +``` + +You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. + +![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) + +Since it contains the openid-provider within, it also uses multi-stages to generate `authserver.pfx` file which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **HttpApiHostModule**: + +```csharp +if (!hostingEnvironment.IsDevelopment()) +{ + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(builder => + { + builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.SetIssuer(new Uri(configuration["AuthServer:Authority"])); + }); +} +``` + +This configuration disables the *DevelopmentEncryptionAndSigningCertificate* and uses a self-signed certificate called `authserver.pfx`. for **signing and encrypting the tokens**. This certificate is created when the docker image is built using the `dotnet dev-certs` tooling. It is a sample-generated certificate, and it is **recommended** to update it for the production environment. You can check the [OpenIddict Encryption and signing credentials documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html) for different customization options. + +The `GetSigningCertificate` method is a private method located under the same **HttpApiHostModule**: + +```csharp +private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration) +{ + var fileName = "authserver.pfx"; + var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED"; + var file = Path.Combine(hostingEnv.ContentRootPath, fileName); + + if (!File.Exists(file)) + { + throw new FileNotFoundException($"Signing Certificate couldn't found: {file}"); + } + + return new X509Certificate2(file, passPhrase); +} +``` + +> You can always create any self-signed certificate using any other tooling outside the dockerfile. You need to remember to set them as **embedded resource** since the `GetSigningCertificate` method will be checking this file physically. + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to **Http.Api.Host** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-api:latest . #Builds the image with "latest" tag +``` + +​ {{ end }} + +{{ end }} + +{{ if Tiered == "Yes" }} + +### AuthServer + +This is the openid-provider application, the authentication server, which should be individually hosted compared to non-tiered application templates. The `dockerfile.local` is located under the `AuthServer` project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +RUN dotnet dev-certs https -v -ep authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED + +FROM base AS final +WORKDIR /app +COPY --from=build /src . + +ENTRYPOINT ["dotnet", "Acme.BookStore.AuthServer.dll"] +``` + +You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This is not an important error since we aim to generate the **authserver.pfx** file and discard the container it is built in. + +![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) + +The AuthServer docker image building process contains multi-stages to generate `authserver.pfx` file, which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **AuthServerModule**: + +```csharp +if (!hostingEnvironment.IsDevelopment()) +{ + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(builder => + { + builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration)); + builder.SetIssuer(new Uri(configuration["AuthServer:Authority"])); + }); +} +``` + +This configuration disables the *DevelopmentEncryptionAndSigningCertificate* and uses a self-signed certificate called `authserver.pfx`. for **signing and encrypting the tokens**. This certificate is created when the docker image is built using the `dotnet dev-certs` tooling. It is a sample-generated certificate, and it is **recommended** to update it for the production environment. You can check the [OpenIddict Encryption and signing credentials documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html) for different options and customization. + +The `GetSigningCertificate` method is a private method located under the same **AuthServerModule**: + +```csharp +private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration) +{ + var fileName = "authserver.pfx"; + var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED"; + var file = Path.Combine(hostingEnv.ContentRootPath, fileName); + + if (!File.Exists(file)) + { + throw new FileNotFoundException($"Signing Certificate couldn't found: {file}"); + } + + return new X509Certificate2(file, passPhrase); +} +``` + +> You can always create any self-signed certificate using any other tooling outside the dockerfile. You need to remember to set them as **embedded resource** since the `GetSigningCertificate` method will be checking this file physically. + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to the **AuthServer** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-authserver:latest . #Builds the image with "latest" tag +``` + +### Http.Api.Host + +This is the backend application that exposes the endpoints and swagger UI. It is not a multi-stage dockerfile; hence you need to have already built this application in **Release mode** to use this dockerfile. The `dockerfile.local` is located under the `Http.Api.Host` project as below; + +```dockerfile +FROM mcr.microsoft.com/dotnet/aspnet:7.0 +COPY bin/Release/net7.0/publish/ app/ +WORKDIR /app +ENTRYPOINT ["dotnet", "Acme.BookStore.HttpApi.Host.dll"] +``` + +If you don't want to use the `build-images-locally.ps1` to build the images or to build this image individually and manually, navigate to **Http.Api.Host** folder and run: + +```powershell +dotnet publish -c Release #Builds the projects in Release mode +docker build -f Dockerfile.local -t acme/bookstore-api:latest . #Builds the image with "latest" tag +``` + +{{ end }} + +## Running Docker-Compose on Localhost + +Under the `etc/docker` folder, you can find the `docker-compose.yml` to run your application. To ease the running process, the template provides `run-docker.ps1` (and `run-docker.sh`) scripts that handle the HTTPS certificate creation, which is used in environment variables; + +```powershell +$currentFolder = $PSScriptRoot + +$slnFolder = Join-Path $currentFolder "../" +$certsFolder = Join-Path $currentFolder "certs" + +If(!(Test-Path -Path $certsFolder)) +{ + New-Item -ItemType Directory -Force -Path $certsFolder + if(!(Test-Path -Path (Join-Path $certsFolder "localhost.pfx") -PathType Leaf)){ + Set-Location $certsFolder + dotnet dev-certs https -v -ep localhost.pfx -p 91f91912-5ab0-49df-8166-23377efaf3cc -t + } +} + +Set-Location $currentFolder +docker-compose up -d +``` + +`run-docker.ps1` (or `run-docker.sh`) script will check if there is an existing dev-cert already under the `etc/certs` folder and generate a `localhost.pfx` file if it doesn't exist. **Kestrel will use this file as an HTTPS certificate**. + +You can also manually create the **localhost.pfx** file in a different path with different name and a different password by using `dotnet dev-certs https -v -ep myCert.pfx -p YOUR_PASSWORD_FOR_HTTPS_CERT -t` or with using any other self-signed certificate generation tool. + +You need to update the service environment variables `Kestrel__Certificates__Default__Path` with the path and filename you have created and the `Kestrel__Certificates__Default__Password` with your new password in the `docker-compose.yml` file. + +Now lets break down each docker compose service under the `docker-compose.yml` file: + +{{ if UI == "Blazor" }} + +### bookstore-blazor + +```yaml +services: + bookstore-blazor: + image: acme/bookstore-blazor:latest + container_name: bookstore-blazor + build: + context: ../../ + dockerfile: src/Acme.BookStore.Blazor/Dockerfile.local + ports: + - "44307:80" + depends_on: + - bookstore-api + restart: on-failure + volumes: + - ./appsettings.json:/usr/share/nginx/html/appsettings.json + networks: + - abp-network +``` + +This is the Blazor application we deploy on http://localhost:44307 by default using the `acme/bookstore-blazor:latest` image that we have built using the `build-images-locally.ps1` script. **It is not running on HTTPS** using the `localhost.pfx` since it is running on **Nginx** and it doesn't accept `pfx` files for SSL. You can check [Nginx Configuring HTTPS Servers documentation](http://nginx.org/en/docs/http/configuring_https_servers.html) for more information and apply the necessary configurations to `nginx.conf` file under the `Blazor` folder. + +> Don't forget to rebuild the `acme/bookstore-blazor:latest` image after updating the `nginx.conf` file. + + On **volumes**, it mounts the **appsettings.json** file under the `docker` folder to achieve **changing the environment variables without re-building the image**. The overriding `docker/appsettings.json` file is as below: + +```json +{ + "App": { + "SelfUrl": "http://localhost:44307" + }, + "AuthServer": { {{ if Tiered == "Yes" }} + "Authority": "https://localhost:44334", {{ end }} {{ if Tiered == "No" }} + "Authority": "https://localhost:44354", {{ end }} + "ClientId": "BookStore_Blazor", + "ResponseType": "code" + }, + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:44354" + }, + "AbpAccountPublic": { {{ if Tiered == "Yes" }} + "BaseUrl": "https://localhost:44334" {{ end }} {{ if Tiered == "No" }} + "BaseUrl": "https://localhost:44354" {{ end }} + } + }, + "AbpCli": { + "Bundle": { + "Mode": "BundleAndMinify", + "Name": "global", + "Parameters": { + "LeptonXTheme.Layout": "side-menu" + } + } + } +} + +``` + +> This service runs in Docker network called `abp-network`, awaits for the the `bookstore-api` to start up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +### bookstore-api + +```yaml +bookstore-api: + image: acme/bookstore-api:latest + container_name: bookstore-api + hostname: bookstore-api + build: + context: ../../ + dockerfile: src/Acme.BookStore.HttpApi.Host/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44354 + - App__CorsOrigins=http://localhost:44307 + - App__HealthCheckUrl=http://bookstore-api/health-status {{ if Tiered == "Yes" }} + - AuthServer__Authority=http://bookstore-authserver {{ end }} {{ if Tiered == "No" }} + - AuthServer__Authority=http://bookstore-api {{ end }} + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} {{ if Tiered == "Yes" }} + - Redis__Configuration=redis {{ end }} + ports: + - "44354:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} {{ if Tiered == "Yes" }} + redis: + condition: service_healthy + restart: on-failure {{ end }} + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This service is the **backend** application of the Blazor application that uses the `acme/bookstore-api:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44354` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44354`. It must point to a **real DNS when deploying to production**. + +- `App__CorsOrigins` is the override configuration for CORS. We add the angular application URL here `http://localhost:44307`. It must point to a **real DNS when deploying to production**. + +- `App__HealthCheckUrl` is the override configuration for the health check URL. Since this request will be done **internally**, it points to the **service name** in containerized environment `http://bookstore-api/health-status` + +- `AuthServer__Authority` is the issuer URL. {{ if Tiered == "Yes" }} `http://bookstore-authserver` {{ end }}{{ if Tiered == "No" }} `http://bookstore-api` {{ end }} is the containerized issuer. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. {{ if Tiered == "Yes" }}Docker-compose is using an isolated internal docker network called `abp-network`. We want to use HTTP in the internal network communication without SSL overhead. Therefore, it is set to `false` by default. {{ end }}{{ if Tiered == "No" }} Since the backend itself is the OpenID-provider, we set it `true` by default.{{ end }} + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default.{{ if Tiered == "Yes" }} + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + + {{ end }} + +> This service runs in a Docker network called `abp-network`, awaits for {{ if Tiered == "Yes" }}the redis service and {{ end }}the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ if Tiered == "Yes" }} + +### bookstore-authserver + +```yaml +bookstore-authserver: + image: acme/bookstore-authserver:latest + container_name: bookstore-authserver + build: + context: ../../ + dockerfile: src/Acme.BookStore.AuthServer/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44334 + - App__CorsOrigins=http://localhost:44307 + - AuthServer__Authority=http://bookstore-authserver + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44334:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This is the authentication server application that handles the authentication between applications using the OpenIddict library. It uses the `acme/bookstore-authserver:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44334` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44334`. It must point to a **real DNS when deploying to production**. + +- `App__CorsOrigins` is the override configuration for CORS. We add the angular and the Blazor application URLs here by default. It must point to a **real DNS when deploying to production**. + +- `AuthServer__Authority` is the issuer URL. `http://bookstore-authserver` is the endpoint for the authserver by default. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Docker-compose uses using isolated internal docker network called `abp-network`. We want to use HTTP in the internal network communication without SSL overhead. Therefore, it is set to `false` by default. + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in Docker network called `abp-network`, awaits for the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ end }} + +### db-migrator + +```yaml +db-migrator: + image: acme/bookstore-db-migrator:latest + container_name: db-migrator + build: + context: ../../ + dockerfile: src/BookStore.DbMigrator/Dockerfile.local + environment: + - OpenIddict__Applications__BookStore_Blazor__RootUrl=http://localhost:44307 {{ if Tiered == "Yes" }} + - OpenIddict__Applications__BookStore_Swagger__RootUrl=https://localhost:44354 {{ end }} {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + networks: + - abp-network +``` + +The database migrator service migrates the database and seeds the initial data. **OpenIddict data** is one of your application's most important seeded data. On **production environment,** you need to override the root URL of your application (http://localhost:44307) {{ if Tiered == "Yes" }} and the swagger-ui client URL (https://localhost:44354){{ end }} so that the authentication can work properly. + +{{ end }} + +{{ if UI == "NG" }} + +### bookstore-angular + +```yaml +services: + bookstore-angular: + image: acme/bookstore-angular:latest + container_name: bookstore-angular + build: + context: ../../../ + dockerfile: angular/Dockerfile.local + ports: + - "4200:80" + depends_on: + - bookstore-api + volumes: + - ./dynamic-env.json://usr/share/nginx/html/dynamic-env.json + networks: + - abp-network +``` + +This is the angular application we deploy on http://localhost:4200 by default using the image that we have built using the `build-images-locally.ps1` script. **It is not running on HTTPS** using the `localhost.pfx` since it is running on **Nginx** and it doesn't accept `pfx` files for SSL. You can check [Nginx Configuring HTTPS Servers documentation](http://nginx.org/en/docs/http/configuring_https_servers.html) for more information and apply the necessary configurations to `nginx.conf` file under the `angular` folder. + +> Don't forget to rebuild the `acme/bookstore-angular:latest` image after updating the `nginx.conf` file. + +The bookstore-angular service mounts the `etc/docker/dynamic-env.json` file to change the existing dynamic-env.json file, which is copied during image creation, to change the environment variables on deployment time instead of re-creating the docker image after each environmental variable change. **Do not forget to override the `dynamic-env.json` located under the `aspnet-core/etc/docker`** folder. + +> If you are not using Docker with WSL, you may have problems with the volume mount permissions. You need to grant docker to be able to use the local file system. See this [SO answer](https://stackoverflow.com/a/20652410) for more information. + +​ {{ if Tiered == "No" }} + +```json +{ + "production": true, + "application": { + "baseUrl":"http://localhost:4200", // https://myapp.com + "name": "BookStore", + "logoUrl": "" + }, + "oAuthConfig": { + "issuer": "https://localhost:44354/", // https://myapi.com/ + "redirectUri": "http://localhost:4200", // https://myapp.com + "clientId": "BookStore_App", + "responseType": "code", + "scope": "offline_access openid profile email phone BookStore" + }, + "apis": { + "default": { + "url": "https://localhost:44354", // https://myapi.com + "rootNamespace": "BookStore" + }, + "AbpAccountPublic": { + "url": "https://localhost:44354", // https://myapi.com + "rootNamespace": "AbpAccountPublic" + } + } +} +``` + +​ {{ end }} + +​ {{ if Tiered == "Yes" }} + +```json +{ + "production": true, + "application": { + "baseUrl":"http://localhost:4200", // https://myapp.com + "name": "BookStore", + "logoUrl": "" + }, + "oAuthConfig": { + "issuer": "https://localhost:44334/", // https://myauthserver.com/ + "redirectUri": "http://localhost:4200", // https://myapp.com + "clientId": "BookStore_App", + "responseType": "code", + "scope": "offline_access openid profile email phone BookStore" + }, + "apis": { + "default": { + "url": "https://localhost:44354", // https://myapi.com + "rootNamespace": "BookStore" + }, + "AbpAccountPublic": { + "url": "https://localhost:44334", // https://myauthserver.com + "rootNamespace": "AbpAccountPublic" + } + } +} +``` + +​ {{ end }} + +### bookstore-api + +```yaml +bookstore-api: + image: acme/bookstore-api:latest + container_name: bookstore-api + hostname: bookstore-api + build: + context: ../../ + dockerfile: src/Acme.BookStore.HttpApi.Host/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44354 + - App__AngularUrl=http://localhost:4200 + - App__CorsOrigins=http://localhost:4200 + - App__HealthCheckUrl=http://bookstore-api/health-status {{ if Tiered == "Yes" }} + - AuthServer__Authority=http://bookstore-authserver + - AuthServer__RequireHttpsMetadata=false {{ end }} {{ if Tiered == "No" }} + - App__RedirectAllowedUrls=http://localhost:4200 + - AuthServer__Authority=https://localhost:44354 + - AuthServer__RequireHttpsMetadata=true {{ end }} {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44354:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + redis: + condition: service_healthy + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This service is the **backend** application of the angular application that uses the `acme/bookstore-api:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44354` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44354`. It must point to a **real DNS when deploying to production**. + +- `App__AngularUrl` is the override configuration of URLs for account-related endpoints. It is `http://localhost:4200` by default. It must point to a **real DNS when deploying to production**. + + {{ if Tiered == "No" }} + +- `App__RedirectAllowedUrls` is the override configuration of redirect URLs for the angular application. It is `http://localhost:4200` by default. It must point to a **real DNS when deploying to production**. + + {{ end }} + +- `App__CorsOrigins` is the override configuration for CORS. It is `http://localhost:4200` by default. It must point to a **real DNS when deploying to production**. + +- `App__HealthCheckUrl` is the override configuration for the health check URL. Since this request will be done **internally**, it points to the **service name** in the containerized environment `http://bookstore-api/health-status`. + +- `AuthServer__Authority` is the issuer URL. {{ if Tiered == "Yes" }} `http://bookstore-authserver` {{ end }}{{ if Tiered == "No" }} `http://bookstore-api` {{ end }} is the containerized issuer. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. {{ if Tiered == "Yes" }}Docker-compose is using an isolated internal docker network called `abp-network`. We want to use HTTP in the internal network communication without SSL overhead; therefore it is set to `false` by default. {{ end }}{{ if Tiered == "No" }} Since the backend itself is the openid-provider, we set it `true` by default.{{ end }} + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in a docker network called `abp-network`, and awaits the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ if Tiered == "Yes" }} + +### bookstore-authserver + +```yaml +bookstore-authserver: + image: acme/bookstore-authserver:latest + container_name: bookstore-authserver + build: + context: ../../ + dockerfile: src/Acme.BookStore.AuthServer/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44334 + - App__CorsOrigins=http://localhost:4200 + - App__RedirectAllowedUrls=http://localhost:4200 + - AuthServer__Authority=https://localhost:44334/ + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44334:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy + {{ end }} + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This is the authentication server application that handles the authentication between applications using the OpenIddict library. It uses the `acme/bookstore-authserver:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44334` by default, by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44334`. It must point to a **real DNS when deploying to production**. +- `App__CorsOrigins` is the override configuration for CORS. It is `http://localhost:4200` by default. It must point to a **real DNS when deploying to production**. +- `App__RedirectAllowedUrls` is the override configuration of redirect URLs for the angular application. It is `http://localhost:4200` by default. It must point to a **real DNS when deploying to production**. +- `AuthServer__Authority` is the issuer URL. `https://localhost:44334/` is the endpoint for the authserver by default. It must point to a **real DNS when deploying to production**. +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Docker-compose uses using isolated internal docker network called `abp-network`. It is set to `false` by default. +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in Docker network called `abp-network`, awaits for the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ end }} + +### db-migrator + +```yaml +db-migrator: + image: acme/bookstore-db-migrator:latest + container_name: db-migrator + build: + context: ../../ + dockerfile: src/BookStore.DbMigrator/Dockerfile.local + environment: + - OpenIddict__Applications__BookStore_App__RootUrl=http://localhost:4200 {{ if Tiered == "Yes" }} + - OpenIddict__Applications__BookStore_Swagger__RootUrl=https://localhost:44354 {{ end }} {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + networks: + - abp-network +``` + +This is the database migrator service that migrates the database and seeds the initial data. **OpenIddict data** is one of the most important seeded data for your application to run. On **production environment,** you need to override the root URL of your application (http://localhost:4200) and the swagger-ui client URL (https://localhost:44354) so that the authentication can work properly. + +> This service runs in Docker network called `abp-network`, awaits for the database container to start up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ end }} + +{{ if UI == "MVC" }} + +### bookstore-web + +```yaml +bookstore-web: + image: acme/bookstore-web:latest + container_name: bookstore-web + hostname: bookstore-web + build: + context: ../../ + dockerfile: src/Acme.BookStore.Web/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44353 + - AuthServer__RequireHttpsMetadata=false {{ if Tiered == "Yes" }} + - AuthServer__IsContainerizedOnLocalhost=true + - AuthServer__Authority=https://localhost:44334/ + - RemoteServices__Default__BaseUrl=http://bookstore-api + - RemoteServices__AbpAccountPublic__BaseUrl=http://bookstore-authserver + - AuthServer__MetaAddress=http://bookstore-authserver {{ end }} {{ if Tiered == "No" }} + - AuthServer__Authority=http://bookstore-web {{ end }} + - App__HealthCheckUrl=http://bookstore-web/health-status {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} {{ if Tiered == "Yes" }} + - Redis__Configuration=redis {{ end }} + ports: + - "44353:443" + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This is the MVC/Razor Page application docker service is using the `acme/bookstore-web:latest` image that we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44353` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +​ {{ if Tiered == "Yes" }} + +The MVC/Razor Page is a server-side rendering application that uses the **hybrid flow**. This flow uses **browser** to login/logout process to the OpenID-provider but issues the **access_token from the back-channel** (server-side). To achieve this functionality, the module class has extra `OpenIdConnectOptions` to override some of the events: + +```csharp +if (Convert.ToBoolean(configuration["AuthServer:IsContainerizedOnLocalhost"])) +{ + context.Services.Configure("oidc", options => + { + options.TokenValidationParameters.ValidIssuers = new[] + { + configuration["AuthServer:MetaAddress"].EnsureEndsWith('/'), + configuration["AuthServer:Authority"].EnsureEndsWith('/') + }; + + options.MetadataAddress = configuration["AuthServer:MetaAddress"].EnsureEndsWith('/') + + ".well-known/openid-configuration"; + + var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider; + options.Events.OnRedirectToIdentityProvider = async ctx => + { + // Intercept the redirection so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/authorize"; + + if (previousOnRedirectToIdentityProvider != null) + { + await previousOnRedirectToIdentityProvider(ctx); + } + }; + var previousOnRedirectToIdentityProviderForSignOut = options.Events.OnRedirectToIdentityProviderForSignOut; + options.Events.OnRedirectToIdentityProviderForSignOut = async ctx => + { + // Intercept the redirection for signout so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/logout"; + + if (previousOnRedirectToIdentityProviderForSignOut != null) + { + await previousOnRedirectToIdentityProviderForSignOut(ctx); + } + }; + }); +} +``` + +​ {{ end }} + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44353`. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Since we are using an isolated internal docker network. We want to use HTTP in the internal network communication without SSL overhead; therefore it is set to `false` by default. + + {{ if Tiered == "Yes" }} + +- `AuthServer__IsContainerizedOnLocalhost` is the configuration to enable the **OpenIdConnectOptions** to provide a different endpoint for the MetaAddress of the OpenID-provider and intercepting the URLS for *authorization* and *logout* endpoints. + +- `AuthServer__MetaAddress` is the `.well-known/openid-configuration` endpoint for issuing access_token and internal token validation. It is the containerized `http://bookstore-authserver` by default. + +- `AuthServer__Authority` is the issuer URL. `https://localhost:44334/` is the issuer that the application redirects to on `authorization` and `logout` process. It must point to a **real DNS when deploying to production**. + +- `RemoteServices__Default__BaseUrl` is the backend; API endpoint application uses the access_token to get the resources. It is the containerized `http://bookstore-api` by default. + +- `RemoteServices__AbpAccountPublic__BaseUrl` is the account URL used to get the profile picture of the user. Since account-related information is located in the authserver, it is the containerized `http://bookstore-authserver` by default. + + {{ end }} + + {{ if Tiered == "No" }} + +- `App__HealthCheckUrl` is the health check url. Since this request will be done **internally**, it points to the **service name** in the containerized environment `http://bookstore-api/health-status`. + +- `AuthServer__Authority` is the issuer URL. `http://bookstore-web` is the containerized issuer. It must point to a **real DNS when deploying to production**. + + {{ end }} + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. + + {{ if Tiered == "Yes" }} + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + + {{ end }} + +> This service runs in Docker network called `abp-network`, awaits for {{ if Tiered == "Yes" }}the redis service and{{ end }} the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +​ {{ if Tiered == "Yes" }} + +### bookstore-api + +```yaml +bookstore-api: + image: acme/bookstore-api:latest + container_name: bookstore-api + hostname: bookstore-api + build: + context: ../../ + dockerfile: src/Acme.BookStore.HttpApi.Host/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44354 + - App__HealthCheckUrl=http://bookstore-api/health-status + - AuthServer__Authority=http://bookstore-authserver + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44354:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + redis: + condition: service_healthy + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This service is the **backend** application of the MVC/Razor Page application that uses the `acme/bookstore-api:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44354` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44354`. It must point to a **real DNS when deploying to production**. + +- `App__HealthCheckUrl` is the health check url. Since this request will be done **internally**, it points to the **service name** in containerized environment `http://bookstore-api/health-status` + +- `AuthServer__Authority` is the issuer URL. `http://bookstore-authserver` is the containerized issuer. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Since we are using an isolated internal docker network. We want to use HTTP in the internal network communication without SSL overhead, therefore, it is set to `false` by default. + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in Docker network called `abp-network`, awaits the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +### bookstore-authserver + +```yaml +bookstore-authserver: + image: acme/bookstore-authserver:latest + container_name: bookstore-authserver + build: + context: ../../ + dockerfile: src/Acme.BookStore.AuthServer/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44334 + - App__CorsOrigins=https://localhost:44353,https://localhost:44354 + - AuthServer__Authority=http://bookstore-authserver + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44334:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + redis: + condition: service_healthy + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This is the authentication server application that handles the authentication between applications using the OpenIddict library. It uses the `acme/bookstore-authserver:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44334` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44334`. It must point to a **real DNS when deploying to production**. +- `App__CorsOrigins` is the override configuration for CORS. It is `https://localhost:44353,https://localhost:44354` by default. It must point to a **real DNS when deploying to production**. +- `AuthServer__Authority` is the issuer URL. `http://bookstore-authserver` is the endpoint for the authserver by default. +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Docker-compose uses using isolated internal docker network called `abp-network`. It is set to `false` by default. +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in Docker network called `abp-network`, awaits the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +​ {{ end }} + +### db-migrator + +```yaml +db-migrator: + image: acme/bookstore-db-migrator:latest + container_name: db-migrator + build: + context: ../../ + dockerfile: src/BookStore.DbMigrator/Dockerfile.local + environment: + - OpenIddict__Applications__BookStore_Web__RootUrl=https://localhost:44353 {{ if Tiered == "Yes" }} + - OpenIddict__Applications__BookStore_Swagger__RootUrl=https://localhost:44354 {{ end }} {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + networks: + - abp-network +``` + +This is the database migrator service that migrates the database and seeds the initial data. **OpenIddict data** is one of the most important seeded data for your application to run. On **production environment,** you need to override the root URL of your application (https://localhost:44353) and the swagger-ui client URL (https://localhost:44354) so that the authentication can work properly. + +> This service runs in Docker network called `abp-network`, awaits for the database container to start up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ end }} + +{{ if UI == "BlazorServer" }} + +### bookstore-blazor + +```yaml +bookstore-blazor: + image: acme/bookstore-blazor:latest + container_name: bookstore-blazor + build: + context: ../../ + dockerfile: src/Acme.BookStore.Blazor/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44314 + - AuthServer__RequireHttpsMetadata=false {{ if Tiered == "Yes" }} + - AuthServer__IsContainerizedOnLocalhost=true + - AuthServer__Authority=https://localhost:44334/ + - AuthServer__MetaAddress=http://bookstore-authserver + - RemoteServices__Default__BaseUrl=http://bookstore-api + - RemoteServices__AbpAccountPublic__BaseUrl=http://bookstore-authserver {{ end }} {{ if Tiered == "No" }} + - AuthServer__Authority=http://bookstore-blazor {{ end }} {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} {{ if Tiered == "Yes" }} + - Redis__Configuration=redis {{ end }} + ports: + - "44353:443" {{ if Tiered == "Yes" }} + depends_on: + - bookstore-api {{ end }} + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This is the Blazor Server application Docker service is using the `acme/bookstore-blazor:latest` image that we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44314` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +{{ if Tiered == "Yes" }} + +The Blazor Server is a server-side rendering application that uses the **hybrid flow**. This flow uses **browser** to login/logout process to the OpenID-provider but issues the **access_token from the back-channel** (server-side). To achieve this functionality, the module class has extra `OpenIdConnectOptions` to override some of the events: + +```csharp +if (Convert.ToBoolean(configuration["AuthServer:IsContainerizedOnLocalhost"])) +{ + context.Services.Configure("oidc", options => + { + options.TokenValidationParameters.ValidIssuers = new[] + { + configuration["AuthServer:MetaAddress"].EnsureEndsWith('/'), + configuration["AuthServer:Authority"].EnsureEndsWith('/') + }; + + options.MetadataAddress = configuration["AuthServer:MetaAddress"].EnsureEndsWith('/') + + ".well-known/openid-configuration"; + + var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider; + options.Events.OnRedirectToIdentityProvider = async ctx => + { + // Intercept the redirection so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/authorize"; + + if (previousOnRedirectToIdentityProvider != null) + { + await previousOnRedirectToIdentityProvider(ctx); + } + }; + var previousOnRedirectToIdentityProviderForSignOut = options.Events.OnRedirectToIdentityProviderForSignOut; + options.Events.OnRedirectToIdentityProviderForSignOut = async ctx => + { + // Intercept the redirection for signout so the browser navigates to the right URL in your host + ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"].EnsureEndsWith('/') + "connect/logout"; + + if (previousOnRedirectToIdentityProviderForSignOut != null) + { + await previousOnRedirectToIdentityProviderForSignOut(ctx); + } + }; + }); +} +``` + +{{ end }} + +- `App__SelfUrl` points to the localhost with the port we expose, `https://localhost:44314`. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Since we are using an isolated internal docker network. We want to use HTTP in the internal network communication without SSL overhead, therefore, it is set to `false` by default. + + {{ if Tiered == "Yes" }} + +- `AuthServer__IsContainerizedOnLocalhost` is the configuration to enable the **OpenIdConnectOptions** to provide a different endpoint for the MetaAddress of the OpenID-provider and intercept the URLS for *authorization* and *logout* endpoints. + +- `AuthServer__MetaAddress` is the `.well-known/openid-configuration` endpoint for issuing the access_token and internal token validation. It is the containerized `http://bookstore-authserver` by default. + +- `AuthServer__Authority` is the issuer URL. `https://localhost:44334/` is the issuer that the application redirects to on `authorization` and `logout` process. It must point to a **real DNS when deploying to production**. + +- `RemoteServices__Default__BaseUrl` is the backend; API endpoint application uses the access_token to get the resources. It is the containerized `http://bookstore-api` by default. + +- `RemoteServices__AbpAccountPublic__BaseUrl` is the account URL used to get the profile picture of the user. Since account-related information is located in the authserver, it is the containerized `http://bookstore-authserver` by default. + + {{ end }} + + {{ if Tiered == "No" }} + +- `AuthServer__Authority` is the issuer URL. `http://bookstore-blazor` is the containerized issuer. It must point to a **real DNS when deploying to production**. + + {{ end }} + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. + + {{ if Tiered == "Yes" }} + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + + {{ end }} + +> This service runs in docker network called `abp-network`. {{ if Tiered == "Yes" }}It awaits the Redis service and the bookstore-api containers for starting up.{{ end }} It also restarts when it fails. You can customize these orchestration behaviors as you prefer. + +​ {{ if Tiered == "Yes" }} + +### bookstore-api + +```yaml +bookstore-api: + image: acme/bookstore-api:latest + container_name: bookstore-api + hostname: bookstore-api + build: + context: ../../ + dockerfile: src/Acme.BookStore.HttpApi.Host/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44354 + - App__HealthCheckUrl=http://bookstore-api/health-status + - AuthServer__Authority=http://bookstore-authserver + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44354:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + redis: + condition: service_healthy + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This service is the **backend** application of the MVC/Razor Page application that uses the `acme/bookstore-api:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44354` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44354`. It must point to a **real DNS when deploying to production**. + +- `App__HealthCheckUrl` is the health check url. Since this request will be done **internally**, it points to the **service name** in containerized environment `http://bookstore-api/health-status` + +- `AuthServer__Authority` is the issuer URL. `http://bookstore-authserver` is the containerized issuer. It must point to a **real DNS when deploying to production**. + +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Since we are using an isolated internal docker network. We want to use HTTP in the internal network communication without SSL overhead, therefore, it is set to `false` by default. + +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. + +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in Docker network called `abp-network`, awaits the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +### bookstore-authserver + +```yaml +bookstore-authserver: + image: acme/bookstore-authserver:latest + container_name: bookstore-authserver + build: + context: ../../ + dockerfile: src/Acme.BookStore.AuthServer/Dockerfile.local + environment: + - ASPNETCORE_URLS=https://+:443;http://+:80; + - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx + - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc + - App__SelfUrl=https://localhost:44334 + - AuthServer__Authority=http://bookstore-authserver + - AuthServer__RequireHttpsMetadata=false {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + - Redis__Configuration=redis + ports: + - "44334:443" + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + redis: + condition: service_healthy + restart: on-failure + volumes: + - ./certs:/root/certificate + networks: + - abp-network +``` + +This is the authentication server application that handles the authentication between applications using the OpenIddict library. It is using the `acme/bookstore-authserver:latest` image we have built using the `build-images-locally.ps1` script. It runs on `https://localhost:44334` by default by mounting the self-signed certificate we've generated under the `etc/certs` folder. + +- `App__SelfUrl` points to the localhost with the port we expose `https://localhost:44334`. It must point to a **real DNS when deploying to production**. +- `AuthServer__Authority` is the issuer URL. `http://bookstore-authserver` is the endpoint for the authserver by default. +- `AuthServer__RequireHttpsMetadata` is the option for the **openid-provider** to enforce HTTPS. Docker-compose uses using isolated internal docker network called `abp-network`. It is set to `false` by default. +- `ConnectionStrings__Default` is the overridden default connection string. It uses {{ if DB == "Mongo" }}the containerized mongodb service {{ end }}{{ if DB == "EF" }}the containerized sql-server with the **sa** user {{ end }} by default. +- `Redis__Configuration` is the overridden Redis configuration. It uses the containerized **redis** service. If you are not using containerized Redis, update your Redis URL. + +> This service runs in Docker network called `abp-network`, awaits the Redis service and the database container for starting up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +​ {{ end }} + +### db-migrator + +```yaml +db-migrator: + image: acme/bookstore-db-migrator:latest + container_name: db-migrator + build: + context: ../../ + dockerfile: src/BookStore.DbMigrator/Dockerfile.local + environment: + - OpenIddict__Applications__BookStore_BlazorServerTiered__RootUrl=https://localhost:44314 {{ if Tiered == "Yes" }} + - OpenIddict__Applications__BookStore_Swagger__RootUrl=https://localhost:44354 {{ end }} {{ if DB == "EF" }} + - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True; {{ end }} {{ if DB == "Mongo" }} + - ConnectionStrings__Default=mongodb://mongodb/BookStore {{ end }} + depends_on: {{ if DB == "EF" }} + sql-server: + condition: service_healthy {{ end }} {{ if DB == "Mongo" }} + mongo-db: + condition: service_healthy {{ end }} + networks: + - abp-network +``` + +The database migrator service migrates the database and seeds the initial data. **OpenIddict data** is one of the most important seeded data for your application. On **production environment,** you need to override the root URL of your application (https://localhost:44353) and the swagger-ui client URL (https://localhost:44354) so that the authentication can work properly. + +> This service runs in Docker network called `abp-network`, awaits for the database container to start up and restarts when it fails. You can customize these orchestration behaviors as you prefer. + +{{ end }} + + + +## What's next? + +- [Azure Deployment using Application Service](deployment-azure-application-service.md) + +- [IIS Deployment](deployment-iis.md) diff --git a/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md b/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md new file mode 100644 index 00000000000..5be87f85cbf --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md @@ -0,0 +1,261 @@ +# IIS Deployment + +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. + +## Prerequisites + +- An IIS Server that is ready for deployment. + +- Install the [hosting bundle](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/hosting-bundle). + +- **{{ DB_Value }}** database must be ready to use with your project. + +- If you want to publish in a local environment, this guide will use mkcert to create self-signed certificates. Follow the [installation guide](https://github.com/FiloSottile/mkcert#installation) to install mkcert. + +{{ if Tiered == "Yes" }} + +- A Redis instance prepared for caching. + +{{end}} + +## Generate an Authentication Certificate + +If you're using OpenIddict, you need to generate an authentication certificate. You can execute this command in {{ if Tiered == "Yes" }}AuthServer{{ else if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }} folder. + +````bash +dotnet dev-certs https -v -ep authserver.pfx -p 00000000-0000-0000-0000-000000000000 +```` + +> `00000000-0000-0000-0000-000000000000` is the password of the certificate, you can change it to any password you want. + +## Creating the Publish Files + +You can execute this commands in your project root folder. + +````bash +dotnet publish ./src/Volo.Sample.DbMigrator/Volo.Sample.DbMigrator.csproj -c Release -o ./publish/dbmigrator # Replace with your project name +```` + +{{ if UI == "NG" }} + +````bash +cd angular && yarn build:prod --output-path ../publish/angular && cd .. +dotnet publish ./aspnet-core/src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name +{{ if Tiered == "Yes" }} +dotnet publish ./aspnet-core/src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name +{{ end }} +```` + +{{ else if UI == "Blazor" }} + +````bash +dotnet publish ./src/Volo.Sample.Blazor/Volo.Sample.Blazor.csproj -c Release -o ./publish/blazor # Replace with your project name +dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name +{{ if Tiered == "Yes" }} +dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name +{{ end }} +```` + +{{ else if UI == "BlazorServer" }} + +````bash +dotnet publish ./src/Volo.Sample.Blazor/Volo.Sample.Blazor.csproj -c Release -o ./publish/blazor # Replace with your project name +{{ if Tiered == "Yes" }} +dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name +dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name +{{ end }} +```` + +{{ else }} + +````bash +dotnet publish ./src/Volo.Sample.Web/Volo.Sample.Web.csproj -c Release -o ./publish/web # Replace with your project name +{{ if Tiered == "Yes" }} +dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name +dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name +{{ end }} +```` + +{{ end }} + +## Run the DbMigrator With Your Custom Settings + +Update the connection string and OpenIddict section with your domain names. Run the DbMigrator app. + +> For example, in a tiered MVC project. + +````json +{ + "ConnectionStrings": { + "Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true" + }, + "Redis": { + "Configuration": "volo.sample" + }, + "OpenIddict": { + "Applications": { + "Sample_Web": { + "ClientId": "Sample_Web", + "ClientSecret": "1q2w3e*", + "RootUrl": "https://web.sample" + }, + "Sample_Swagger": { + "ClientId": "Sample_Swagger", + "RootUrl": "https://api.sample" + } + } + } +} +```` + +## Preparing for Local Deployment + +You can skip this part if you're going to deploy on a server with real domain names. + +### Creating a Self-Signed Certificate with mkcert + +You can execute this command in your command prompt. + +````bash +cd Desktop # or another path +mkcert -pkcs12 auth.sample api.sample web.sample # Replace with your domain names +```` + +Rename the created file extension to ".pfx" + +Import the certificate to IIS + +![Import the certificate](../../images/iis-install-cert.gif) + +### Add domain names to hosts file + +Add domain names to hosts file(in Windows: `C:\Windows\System32\drivers\etc\hosts`, in Linux and macOS: `/etc/hosts`). + +> For example, in a tiered MVC project. +````json +127.0.0.1 auth.sample +127.0.0.1 api.sample +127.0.0.1 web.sample +```` + +## Publish the Application(s) On IIS + +### Update the appsettings + +Update the appsettings according to your project type and domain names. + +> For example, in a tiered MVC project. + +````json +//AuthServer +{ + "App": { + "SelfUrl": "https://auth.sample", + "CorsOrigins": "https://api.sample,https://web.sample", + "RedirectAllowedUrls": "https://api.sample,https://web.sample", + "DisablePII": "false" + }, + "ConnectionStrings": { + "Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true" + }, + "AuthServer": { + "Authority": "https://auth.sample", + "RequireHttpsMetadata": "true" + }, + "StringEncryption": { + "DefaultPassPhrase": "f9uRkTLdtAZLmlh3" + }, + "Redis": { + "Configuration": "volo.sample" + } +} +//HttpApi.Host +{ + "App": { + "SelfUrl": "https://api.sample", + "CorsOrigins": "https://web.sample", + "DisablePII": "false", + "HealthCheckUrl": "/health-status" + }, + "ConnectionStrings": { + "Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true" + }, + "Redis": { + "Configuration": "volo.sample" + }, + "AuthServer": { + "Authority": "https://auth.sample", + "RequireHttpsMetadata": "true", + "SwaggerClientId": "Sample_Swagger" + }, + "StringEncryption": { + "DefaultPassPhrase": "f9uRkTLdtAZLmlh3" + } +} +//Web +{ + "App": { + "SelfUrl": "https://web.sample", + "DisablePII": "false" + }, + "RemoteServices": { + "Default": { + "BaseUrl": "https://api.sample/" + }, + "AbpAccountPublic": { + "BaseUrl": "https://auth.sample/" + } + }, + "Redis": { + "Configuration": "volo.sample" + }, + "AuthServer": { + "Authority": "https://auth.sample", + "RequireHttpsMetadata": "true", + "ClientId": "Sample_Web", + "ClientSecret": "1q2w3e*" + }, + "StringEncryption": { + "DefaultPassPhrase": "f9uRkTLdtAZLmlh3" + } +} +```` + +### Copy the .pfx file + +You need to copy pfx file from ./src/{{ if Tiered == "Yes" }}AuthServer{{ else if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }} to ./publish/{{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} folder. + +### Publish the Applications(s) + +You can add as website from IIS. + +> For {{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} we need to enable load user profile to true from application pool for created web site. + +![Load User Profile](../../images/load-user-profile-iis.png) + +> For local deployment select the SSL certificate when you add the web site. + +![SSL Certificate Selection](../../images/ssl-cert-selection-in-iis.png) + +The final result should look like this (depending on your project type). + +![IIS deployment](../../images/iis-sample-deployment.png) + +We can visit the websites from a browser. + +![Tiered IIS deployment](../../images/iis-sample-tiered-deployment.gif) + +## What's next? + +- [Docker Deployment using Docker Compose](deployment-docker-compose.md) + +- [Azure Deployment using Application Service](deployment-azure-application-service.md) diff --git a/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md b/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md new file mode 100644 index 00000000000..b73968c6325 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md @@ -0,0 +1,111 @@ +# IdentityServer Deployment + +IdentityServer configuration may be different based on deployment configurations. Basically, you need update identityserver client related data and update your hosting preferences based on your deployment environment. + +## Update Cors Origins + +Cors origins configuration for **gateways**, **microservices** swagger authorization and **Angular/Blazor** (web assembly) must be updated for deployment. This can be found under **App** configuration in *appsettings.json* + +```json +"CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361", +``` + +## Update Redirect Allowed Urls + +This configuration must be done if **Angular** or **Blazor** (web assembly) is used as back-office web application. It is found under **App** configuration in appsettings.json + +```json +"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" +``` + +## Update DbMigrator + +`IdentityServerDataSeedContributor` uses **IdentityServer.Clients** section of `appsettings.json` for `ClientId`, `RedirectUri`, `PostLogoutRedirectUri`, `CorsOrigins`. + +Update DbMigrator project `appsettings.json` **IdentityServer.Clients.RootUrls** with production values: + +![db-migrator-appsettings](../../images/db-migrator-appsettings.png) + +Or, manually add production values to `IdentityServerClientRedirectUris`, `IdentityServerClientPostLogoutRedirectUris`, `IdentityServerClientCorsOrigins` tables in your database. + +> If you are using microservice template on-the-fly migration and not using dbmigrator project, update **IdentityService** appsettings. + +Eventually, you shouldn't have `localhost` related data. + +## Update IdentityServer + +You need to update token signing certificate and identityserver midware based on your hosting environment. + +### Signing Certificate + +Default development environment uses [developer signing certificates option](https://github.com/abpframework/abp/blob/dev/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs#L29). Using developer signing certificates may cause *IDX10501: Signature validation failed* error on production. + +Update **IdentityServerModule** with using real certificate on `IIdentityServerBuilder` pre-configuration. + +![idsrv-certificate](../../images/idsrv-certificate.png) + +You can also [create self-signed certificate](https://docs.abp.io/en/commercial/5.0/startup-templates/microservice/tye-integration#create-developer-certificates) and use it. + +> If you are using self signed certificate, do not forget to set the certificate (.pfx file) as `EmbeddedResource` and set `CopyToOutputDirectory`. File needs to exist physically. + +### Use HTTPS + +Update **IdentityServerModule** to [enfcore https](https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-6.0&tabs=visual-studio). Add `UseHsts` to add hsts headers to clients, add `UseHttpsRedirection` to redirect http requests to https. + +![use-https](../../images/use-https.png) + +### Behind Load Balancer + +To redirect http requests to https from load balancer, update `OnApplicationInitialization` method of the **IdentityServerModule** with the midware below: + +```csharp +app.Use((httpContext, next) => +{ + httpContext.Request.Scheme = "https"; + return next(); +}); +``` + +### Kubernetes + +A common scenario is running applications in kubernetes environment. While IdentityServer needs to face internet on https, internal requests can be done using http. + +![idsrv-k8s](../../images/idsrv-k8s.png) + +**HttpApi.Host** and **Web** applications authority should be set to http since token validations will done using http request. + +![api-resource-internal-idsrv](../../images/api-resource-internal-idsrv.png) + +> You can use different appsettings files like *appsettings.production.json* to override these values or directly override environment values from kubernetes. + +To isolate internal identityserver requests from external network (internet), append extra header instead of overwriting. +For ingress, you can use `nginx.ingress.kubernetes.io/configuration-snippet`: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: myidentityserver-ingress + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-buffer-size: "32k" + nginx.ingress.kubernetes.io/proxy-buffers-number: "8" + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_input_headers "from-ingress: true"; +spec: +``` + +You need to set the IdentityServer origin based on header. Update `OnApplicationInitialization` method of the **IdentityServerModule** with the midware below: + +```csharp +app.Use(async (ctx, next) => +{ + if (ctx.Request.Headers.ContainsKey("from-ingress")) + { + ctx.SetIdentityServerOrigin("https://myidentityserver.com"); + } + + await next(); +}); +``` diff --git a/docs/en/solution-templates/layered-web-application/deployment/index.md b/docs/en/solution-templates/layered-web-application/deployment/index.md new file mode 100644 index 00000000000..a81823a7f75 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/index.md @@ -0,0 +1,20 @@ +# Deployment + +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +```` + +> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. + +This guide explains how to deploy your application in staging and production environments based on your application architecture; + +- [Docker Deployment using Docker Compose](deployment-docker-compose.md) + +- [Azure Deployment using Application Service](azure-deployment/azure-deployment.md) + +- [IIS Deployment](deployment-iis.md) diff --git a/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md b/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md new file mode 100644 index 00000000000..72608e5ccc0 --- /dev/null +++ b/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md @@ -0,0 +1,127 @@ +# OpenIddict Deployment + +[OpenIddict](https://github.com/openiddict/openiddict-core) is the default OpenId Provider library used by ABP templates through the [OpenIddict Module](https://docs.abp.io/en/abp/latest/Modules/OpenIddict). It is hosted by the **AuthServer** project in the tiered/seperate-authserver application templates. For non-tiered applications, it is hosted by the Web (MVC/Razor), BlazorServer or the **HttpApi.Host** project for Blazor and Angular applications. + +## Update Cors Origins + +Cors origins configuration for ***gateways***, ***microservices*** swagger authorization, and ***Angular/Blazor*** (web assembly) must be updated for deployment. This can be found under the ***App*** configuration in **appsettings.json** + +```json +"CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361", +``` +## Update Redirect Allowed URLs + +If **Angular** or **Blazor** (Web Assembly) is used as a back-office web application, this configuration must be done. It is found under **App** configuration in `appsettings.json`. + +```json +"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" +``` +## Update DbMigrator + +`OpenIddictDataSeedContributor` uses **OpenIddict.Applications** section of `appsettings.json` for `ClientId`, `RedirectUri`, `PostLogoutRedirectUri` and `CorsOrigins`. + +Update DbMigrator project `appsettings.json` **OpenIddict.Applications.RootUrls** with production values or override them: + +![db-migrator-appsettings](../images/db-migrator-openiddict-appsettings.png) + + +> If you are using microservice template self-migration and not using DbMigrator project, update **IdentityService** appsettings. + +Eventually, you shouldn't have any `localhost` related data. + +## Update AuthServer + +In the development environment, OpenIddict uses a development encryption and signing certificate. In the production environment, this must be disabled. OpenIddict needs a real certificate for signing and encrypting the tokens. + +### Signing and Encryption Certificate + +The default development environment uses [developer signing certificates option](https://github.com/abpframework/abp/blob/bda231b319b62582dee4f8389494cd4442ac474f/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs#L104-L105). Using developer signing certificates may cause *IDX10501: Signature validation failed* error on production. + +Update **AuthServerModule** by using a real certificate on `OpenIddictBuilder` pre-configuration. + +![openiddict-certificate](../images/openiddict-certificate.png) + +When you create a new application from the application template, ABP CLI automatically generates a new self-signed certificate with the name `openiddict.pfx` and a random password. This file and the password are provided in the `GetSigningCertificate` method. + +> Note: If you are receiving errors about not being able to reach the `openiddict.pfx` file on the server, make sure you have the necessary permissions. + +The best place to store your certificates will depend on your host: + +- For IIS applications, [storing the certificates in the machine store](https://www.sonicwall.com/support/knowledge-base/how-can-i-import-certificates-into-the-ms-windows-local-machine-certificate-store/170504615105398/) is the recommended option. +- On Azure, certificates can be uploaded and exposed to Azure App Service applications using the special `WEBSITE_LOAD_CERTIFICATES` flag. For more information, visit the [Use a TLS/SSL certificate in your code in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code) document. + +Please check [OpenIddict documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-certificate-recommended-for-production-ready-scenarios) for more information and using different types of signing/encryption keys. + +### Using or Disabling the HTTPS + +AuthServer that hosts the OpenIddict openid-provider library uses the SSL/TLS binding of the ASP.NET Core middleware. If you host it on `HTTPS`, the **Issuer** will be hosted on `HTTPS`. + +In some deployment scenarios, you may come across an error: + +```json +error: invalid_request +error_description: This server only accepts HTTPS requests. +error_uri: https//documnentation.openiddict.com/errors/ID2083 +``` + +You can easily disable the HTTPS requirement from the **appsettings.json**: +```json +"AuthServer": { + "Authority": "https://localhost:44369", + "RequireHttpsMetadata": "false" + }, +``` + +This configuration can be found under the `ConfigureServices` method of the AuthServer project: +```csharp +if (!Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"])) +{ + Configure(options => + { + options.DisableTransportSecurityRequirement = true; + }); +} +``` + +### Behind Load Balancer + +You may need to forward the headers if you are using [Nginx](https://www.nginx.com/) or [Kubernetes Nginx Ingress](https://github.com/kubernetes/ingress-nginx). +Configure the options in the **ConfigureServices** method of `AuthServerModule`: + +```csharp +Configure(options => +{ + options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; +}); +``` +And use the middleware in the **OnApplicationInitialization** method of `AuthServerModule`: +```csharp +if (env.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} + +app.UseForwardedHeaders(); +... +``` + +Sometimes, including forwarded headers in requests proxied to the application may be impossible. +If the proxy enforces that all public external requests are HTTPS, the scheme can be manually set before using any middleware. +Configure it under the **OnApplicationInitialization** method of `AuthServerModule`: + +```csharp +app.Use((httpContext, next) => +{ + httpContext.Request.Scheme = "https"; + return next(); +}); +``` + +# FAQ + +- I see `Server Error 502!` + - Check your application logs under the *Logs* folder. A misconfiguration can prevent your application from starting up, and the easiest way is to pinpoint the problem by checking the logs. +- `System.IO.FileNotFoundException: Signing Certificate couldn't found!:` + - Ensure you have the **.pfx** file in the related location. The **.pfx** file should be marked as an embedded resource, and it should be in the publish directory when you publish your application. +- I can't see the login page! It shows an `HTTP 400` error. + - This is related to the generated URL from the application that tries to authenticate against the AuthServer. Check the AuthServer logs and make sure you have **valid redirect_uri** seeded from the *OpenIddictDataSeedContributor* and the application that redirects to AuthServer has the same configuration. From 533b43e53c12414abac360e0442f1ded7c00a2f0 Mon Sep 17 00:00:00 2001 From: selmankoc Date: Wed, 23 Oct 2024 15:47:03 +0300 Subject: [PATCH 2/4] Fixed docs-nav.json for deployment docs --- docs/en/docs-nav.json | 47 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 7d017e5ba1b..f8c8cb8eebb 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -1644,7 +1644,52 @@ }, { "text": "Layered Solution", - "path": "solution-templates/layered-web-application" + "path": "solution-templates/layered-web-application", + "items": [ + { + "text": "Deployment", + "path": "solution-templates/layered-web-application/deployment", + "items": [ + { + "text": "Docker Deployment", + "path": "solution-templates/layered-web-application/deployment/deployment-docker-compose.md" + }, + { + "text": "Azure Deployment", + "items": [ + { + "text": "Deploy to Azure Web App Service", + "path": "solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md" + }, + { + "text": "Creating an Azure Web App Service Environment", + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md" + }, + { + "text": "Customizing the Configuration of Your ABP Application", + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md" + }, + { + "text": "Deploying Application With GitHub Actions", + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md" + } + ] + }, + { + "text": "IIS Deployment", + "path": "solution-templates/layered-web-application/deployment/deployment-iis.md" + }, + { + "text": "IdentityServer Deployment", + "path": "solution-templates/layered-web-application/deployment/identityserver-deployment.md" + }, + { + "text": "OpenIddict Deployment", + "path": "solution-templates/layered-web-application/deployment/openiddict-deployment.md" + } + ] + } + ] }, { "text": "Microservice Solution", From 8cef69384be9f06e685afee4e43a21737784a949 Mon Sep 17 00:00:00 2001 From: selmankoc Date: Wed, 23 Oct 2024 15:59:43 +0300 Subject: [PATCH 3/4] Fixed paths of images --- .../step1-create-azure-resources.md | 36 +++++++++---------- .../step3-deployment-github-action.md | 16 ++++----- .../deployment/deployment-docker-compose.md | 4 +-- .../deployment/deployment-iis.md | 10 +++--- .../deployment/identityserver-deployment.md | 10 +++--- .../deployment/openiddict-deployment.md | 4 +-- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md index a818c1287d5..4a4601486c6 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md @@ -25,7 +25,7 @@ To create a new Azure Web App Service, choose one of the following options: 3. Search for **Web App** and select **Web App** from the results. - ![Create a resource](../../../images/azure-deploy-create-a-resource.png) + ![Create a resource](../../../../images/azure-deploy-create-a-resource.png) 4. Click the **Create** button. @@ -33,11 +33,11 @@ To create a new Azure Web App Service, choose one of the following options: 6. Click the **Create** button. - ![Create Web App](../../../images/azure-deploy-create-web-app-2.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-2.png) 7. Wait for the deployment to complete. - ![Create Web App](../../../images/azure-deploy-create-web-app-3.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-3.png) {{else}} @@ -51,7 +51,7 @@ To create a new Azure Web App Service, choose one of the following options: 3. Search for **Web App** and select **Web App** from the results. - ![Create a resource](../../../images/azure-deploy-create-a-resource.png) + ![Create a resource](../../../../images/azure-deploy-create-a-resource.png) 4. Click the **Create** button. @@ -59,11 +59,11 @@ To create a new Azure Web App Service, choose one of the following options: 6. Click the **Create** button. - ![Create Web App](../../../images/azure-deploy-create-web-app-2.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-2.png) 7. Wait for the deployment to complete. - ![Create Web App](../../../images/azure-deploy-create-web-app-3.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-3.png) {{ else if UI == 'NG' }} @@ -75,7 +75,7 @@ To create a new Azure Web App Service, choose one of the following options: 3. Search for **Static Web App** and select **Static Web App** from the results. - ![Create a resource angular](../../../images/azure-deploy-create-a-resource-angular.png) + ![Create a resource angular](../../../../images/azure-deploy-create-a-resource-angular.png) 4. Click the **Create** button. @@ -83,11 +83,11 @@ To create a new Azure Web App Service, choose one of the following options: 6. Click the **Create** button. - ![Create Web App](../../../images/azure-deploy-create-web-app-4.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-4.png) 7. Wait for the deployment to complete. - ![Create Web App](../../../images/azure-deploy-create-web-app-5.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-5.png) {{else}} @@ -99,7 +99,7 @@ To create a new Azure Web App Service, choose one of the following options: 3. Search for **Static Web App** and select **Static Web App** from the results. - ![Create a resource blazor](../../../images/azure-deploy-create-a-resource-angular.png) + ![Create a resource blazor](../../../../images/azure-deploy-create-a-resource-angular.png) 4. Click the **Create** button. @@ -107,11 +107,11 @@ To create a new Azure Web App Service, choose one of the following options: 6. Click the **Create** button. - ![Create Web App](../../../images/azure-deploy-create-web-app-7.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-7.png) 7. Wait for the deployment to complete. - ![Create Web App](../../../images/azure-deploy-create-web-app-8.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-8.png) {{end}} @@ -123,7 +123,7 @@ To create a new Azure Web App Service, choose one of the following options: 3. Search for **Web App** and select **Web App** from the results. - ![Create a resource](../../../images/azure-deploy-create-a-resource.png) + ![Create a resource](../../../../images/azure-deploy-create-a-resource.png) 4. Click the **Create** button. @@ -131,11 +131,11 @@ To create a new Azure Web App Service, choose one of the following options: 6. Click the **Create** button. - ![Create Web App](../../../images/azure-deploy-create-web-app-6.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-6.png) 7. Wait for the deployment to complete. - ![Create Web App](../../../images/azure-deploy-create-web-app-3.png) + ![Create Web App](../../../../images/azure-deploy-create-web-app-3.png) {{ if Tiered == "Yes" && (UI == "MVC" || UI == "BlazorServer")}} @@ -151,7 +151,7 @@ Same as above, but you only need to modify the name of the web app service to ** 2. Search for **Redis Cache** and select **Redis Cache** from the results. - ![Create a resource](../../../images/azure-deploy-create-redis.png) + ![Create a resource](../../../../images/azure-deploy-create-redis.png) 3. Click the **Create** button. @@ -159,11 +159,11 @@ Same as above, but you only need to modify the name of the web app service to ** 5. Click the **Create** button. - ![Create Redis](../../../images/azure-deploy-create-redis-2.png) + ![Create Redis](../../../../images/azure-deploy-create-redis-2.png) 6. Wait for the deployment to complete. - ![Create Redis](../../../images/azure-deploy-create-redis-3.png) + ![Create Redis](../../../../images/azure-deploy-create-redis-3.png) {{ end }} diff --git a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md index 32e51a2a58e..9aa9e5df83d 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md +++ b/docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md @@ -19,7 +19,7 @@ 4. Click the **set up a workflow yourself** button. - ![Set up this workflow](../../../images/azure-deploy-set-up-this-workflow.png) + ![Set up this workflow](../../../../images/azure-deploy-set-up-this-workflow.png) 5. Copy this content to the opened file and commit it. @@ -685,7 +685,7 @@ jobs: 9. Click the **New repository secret** button. - ![New repository secret](../../../images/azure-deploy-new-repository-secret.png) + ![New repository secret](../../../../images/azure-deploy-new-repository-secret.png) 10. Add the following secrets: @@ -693,17 +693,17 @@ jobs: Example of Azure SQL connection string: - ![Azure sql connection string](../../../images/azure-deploy-connection-string.png) + ![Azure sql connection string](../../../../images/azure-deploy-connection-string.png) - **AZUREAPPSERVICE_PUBLISHPROFILE**: The publish the profile of your Azure Web App Service. You can download it from the **Overview** tab of your Azure Web App Service. - ![Publish profile](../../../images/azure-deploy-publish-profile.png) + ![Publish profile](../../../../images/azure-deploy-publish-profile.png) {{ if UI == "NG" || UI == "Blazor"}} - **AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS**: The API token of your Azure Static Web App. You can get it from the **Overview** tab of your Azure Static Web App. - ![API token](../../../images/azure-deploy-api-token.png) + ![API token](../../../../images/azure-deploy-api-token.png) {{end}} @@ -711,15 +711,15 @@ jobs: 12. Click the **Deploy to Azure Web App** workflow. - ![Deploy to Azure Web App](../../../images/azure-deploy-deploy-to-azure-web-app.png) + ![Deploy to Azure Web App](../../../../images/azure-deploy-deploy-to-azure-web-app.png) 13. Click the **Run workflow** button. - ![Run workflow](../../../images/azure-deploy-run-workflow.png) + ![Run workflow](../../../../images/azure-deploy-run-workflow.png) 14. Navigate to the web app URL to see the deployed application. - ![Azure Web App](../../../images/azure-deploy-runtime-stack2.png) + ![Azure Web App](../../../../images/azure-deploy-runtime-stack2.png) > If deploying your application was unsuccessful, you can check the logs of the deployment by clicking the **Deploy to Azure Web App** workflow and then clicking the **deploy-to-webapp** job. diff --git a/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md b/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md index 6c9c7246387..9767beb3baa 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md +++ b/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md @@ -449,7 +449,7 @@ ENTRYPOINT ["dotnet", "Acme.BookStore.Blazor.dll"] You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. -![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) +![auth-server-pfx-generation-error](../../../images/auth-server-pfx-generation-error.png) Since it contains the OpenID-provider within, it also uses multi-stages to generate `authserver.pfx` file which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **BlazorModule**: @@ -794,7 +794,7 @@ ENTRYPOINT ["dotnet", "Acme.BookStore.HttpApi.Host.dll"] You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. -![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) +![auth-server-pfx-generation-error](../../../images/auth-server-pfx-generation-error.png) Since it contains the openid-provider within, it also uses multi-stages to generate `authserver.pfx` file which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **HttpApiHostModule**: diff --git a/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md b/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md index 5be87f85cbf..ee6f6667c2a 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md +++ b/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md @@ -134,7 +134,7 @@ Rename the created file extension to ".pfx" Import the certificate to IIS -![Import the certificate](../../images/iis-install-cert.gif) +![Import the certificate](../../../images/iis-install-cert.gif) ### Add domain names to hosts file @@ -240,19 +240,19 @@ You can add as website from IIS. > For {{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} we need to enable load user profile to true from application pool for created web site. -![Load User Profile](../../images/load-user-profile-iis.png) +![Load User Profile](../../../images/load-user-profile-iis.png) > For local deployment select the SSL certificate when you add the web site. -![SSL Certificate Selection](../../images/ssl-cert-selection-in-iis.png) +![SSL Certificate Selection](../../../images/ssl-cert-selection-in-iis.png) The final result should look like this (depending on your project type). -![IIS deployment](../../images/iis-sample-deployment.png) +![IIS deployment](../../../images/iis-sample-deployment.png) We can visit the websites from a browser. -![Tiered IIS deployment](../../images/iis-sample-tiered-deployment.gif) +![Tiered IIS deployment](../../../images/iis-sample-tiered-deployment.gif) ## What's next? diff --git a/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md b/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md index b73968c6325..8cb9438576a 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md +++ b/docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md @@ -24,7 +24,7 @@ This configuration must be done if **Angular** or **Blazor** (web assembly) is u Update DbMigrator project `appsettings.json` **IdentityServer.Clients.RootUrls** with production values: -![db-migrator-appsettings](../../images/db-migrator-appsettings.png) +![db-migrator-appsettings](../../../images/db-migrator-appsettings.png) Or, manually add production values to `IdentityServerClientRedirectUris`, `IdentityServerClientPostLogoutRedirectUris`, `IdentityServerClientCorsOrigins` tables in your database. @@ -42,7 +42,7 @@ Default development environment uses [developer signing certificates option](htt Update **IdentityServerModule** with using real certificate on `IIdentityServerBuilder` pre-configuration. -![idsrv-certificate](../../images/idsrv-certificate.png) +![idsrv-certificate](../../../images/idsrv-certificate.png) You can also [create self-signed certificate](https://docs.abp.io/en/commercial/5.0/startup-templates/microservice/tye-integration#create-developer-certificates) and use it. @@ -52,7 +52,7 @@ You can also [create self-signed certificate](https://docs.abp.io/en/commercial/ Update **IdentityServerModule** to [enfcore https](https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-6.0&tabs=visual-studio). Add `UseHsts` to add hsts headers to clients, add `UseHttpsRedirection` to redirect http requests to https. -![use-https](../../images/use-https.png) +![use-https](../../../images/use-https.png) ### Behind Load Balancer @@ -70,11 +70,11 @@ app.Use((httpContext, next) => A common scenario is running applications in kubernetes environment. While IdentityServer needs to face internet on https, internal requests can be done using http. -![idsrv-k8s](../../images/idsrv-k8s.png) +![idsrv-k8s](../../../images/idsrv-k8s.png) **HttpApi.Host** and **Web** applications authority should be set to http since token validations will done using http request. -![api-resource-internal-idsrv](../../images/api-resource-internal-idsrv.png) +![api-resource-internal-idsrv](../../../images/api-resource-internal-idsrv.png) > You can use different appsettings files like *appsettings.production.json* to override these values or directly override environment values from kubernetes. diff --git a/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md b/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md index 72608e5ccc0..65ac72719cb 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md +++ b/docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md @@ -22,7 +22,7 @@ If **Angular** or **Blazor** (Web Assembly) is used as a back-office web applica Update DbMigrator project `appsettings.json` **OpenIddict.Applications.RootUrls** with production values or override them: -![db-migrator-appsettings](../images/db-migrator-openiddict-appsettings.png) +![db-migrator-appsettings](../../../images/db-migrator-openiddict-appsettings.png) > If you are using microservice template self-migration and not using DbMigrator project, update **IdentityService** appsettings. @@ -39,7 +39,7 @@ The default development environment uses [developer signing certificates option] Update **AuthServerModule** by using a real certificate on `OpenIddictBuilder` pre-configuration. -![openiddict-certificate](../images/openiddict-certificate.png) +![openiddict-certificate](../../../images/openiddict-certificate.png) When you create a new application from the application template, ABP CLI automatically generates a new self-signed certificate with the name `openiddict.pfx` and a random password. This file and the password are provided in the `GetSigningCertificate` method. From 899245ae4649fd0526b8813880986770cec510ea Mon Sep 17 00:00:00 2001 From: selmankoc Date: Wed, 23 Oct 2024 16:30:08 +0300 Subject: [PATCH 4/4] Fix paths of some images --- .../deployment/deployment-docker-compose.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md b/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md index 9767beb3baa..a9e106221b6 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md +++ b/docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md @@ -306,7 +306,7 @@ ENTRYPOINT ["dotnet", "Acme.BookStore.Web.dll"] You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. -![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) +![auth-server-pfx-generation-error](../../../images/auth-server-pfx-generation-error.png) Since it contains the openid-provider within, it also uses multi-stages to generate `authserver.pfx` file which is **used by OpenIddict as signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **WebModule**: @@ -718,7 +718,7 @@ ENTRYPOINT ["dotnet", "Acme.BookStore.HttpApi.Host.dll"] You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This error is not important since we aim to generate the **authserver.pfx** file and discard the container it is built in. -![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) +![auth-server-pfx-generation-error](../../../images/auth-server-pfx-generation-error.png) Since it contains the OpenID-provider within, it also uses multi-stages to generate `authserver.pfx` file, which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **HttpApiHostModule**: @@ -872,7 +872,7 @@ ENTRYPOINT ["dotnet", "Acme.BookStore.AuthServer.dll"] You can come across an error when the image is being built. This occurs because of `dotnet dev-certs` command trying to list the existing certificates **inside the container** and unavailable to. This is not an important error since we aim to generate the **authserver.pfx** file and discard the container it is built in. -![auth-server-pfx-generation-error](../../../en/images/auth-server-pfx-generation-error.png) +![auth-server-pfx-generation-error](../../../images/auth-server-pfx-generation-error.png) The AuthServer docker image building process contains multi-stages to generate `authserver.pfx` file, which is **used by OpenIddict as a signing and encryption certificate**. This configuration is found under the `PreConfigureServices` method of the **AuthServerModule**: