Deploying Umbraco 9 to Azure App Service for Linux
Tags: umbraco, dotnet, azure, aspnet
Published: 2021-11-08 16:08:45

---
title: Deploying Umbraco 9 to Azure App Service for Linux
published: true
date: 2021-11-07 00:00:00 UTC
tags: umbraco, dotnet, azure, aspnet
canonical_url: https://swimburger.net/blog/umbraco/deploying-umbraco-9-to-azure-app-service-for-linux
cover_image: https://swimburger.net/media/ok1hpb11/umbraco-9-to-azure-app-service-for-linux-social.png?anchor=center&mode=crop&width=1000&height=420
---

Umbraco 9 has been built on top of .NET 5 (.NET Core). This means you are not limited to hosting Umbraco on Windows anymore, but you can now also host Umbraco on macOS and many popular Linux distributions.  
If you were hosting Umbraco on Azure App Service previously, you had to host it using App Service for Windows, but now you can also host it on **App Service for Linux**.

In this blog post, you will learn how to provision the infrastructure to host your Umbraco 9 instance using Azure SQL and Azure App Service for Linux. After provisioning the infrastructure, you will learn how to deploy your Umbraco 9 website to Azure App Service for Linux.

## Prerequisites

You will need these items to follow along:

- .NET 5 SDK ([install](https://dotnet.microsoft.com/download/dotnet/5.0))
- PowerShell ([install](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.1))
- Azure subscription ([start free](https://azure.microsoft.com/en-us/free/))
- Azure CLI ([install](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli))

## Create Azure infrastructure for Umbraco 9

You need at least 2 pieces of infrastructure to host Umbraco: Microsoft SQL Server and a web server.  
There are many services in Azure that can run SQL Server, and many services to run web servers. For this tutorial, you will use Azure SQL and Azure App Service for Linux.

You will use the Azure CLI to provision these resources in a PowerShell script. To keep things organized, start with initializing some variables that you'll use later on. Run the following PowerShell and adjust the variables as needed:

```powershell
$ResourceBaseName = 'your-umbraco9-site';
# assuming everything will be in the same resource location, 
# but may not be possible if Azure services aren't available in your desired region.
$Location = 'eastus';
$GroupName = "$($ResourceBaseName)-rg";

$AppServicePlanName = "$($ResourceBaseName)-asp";
# Enter web app name (has to be globally unique, will be used as subdomain xxx.azurewebsites.net)
$AppServiceName = 'nswimberghe-umbraco9-app';

# Enter sql server name (has to be globally unique, will be used as subdomain xxx.database.windows.net)
$SqlServerName = 'nswimberghe-umbraco9-sqlserver';
$SqlDbName = "$($ResourceBaseName)-sqldb";
$SqlAdminUser = 'YourSqlAdminUser';
# Must be complex enough or error will be thrown, use uppercase, lowercase, special symbols, and numbers
$SqlAdminPwd = '[Your SQL Admin User Password]'; 
```

Here's what the variables will be used for:

- **ResourceBaseName** : the prefix for multiple Azure resources
- **Location** : the location of all the Azure resources. The Azure services may not be available in the Azure region you wish to use. In that case, use a supported region.  
You can use this [Azure website to figure out in which region an Azure service is supported](https://azure.microsoft.com/en-us/global-infrastructure/services/).
- **GroupName** : the name of the Azure resource group.
- **AppServicePlanName** : the name of the App Service Plan. The App Service Plan is the set of servers (1 or more) on which your App Services will be run.
- **AppServiceName** : the name of your App Service. This name will be used to create a DNS entry like 'xxx.azurewebsites.net' where 'xxx' will be the name of your App Service. The name of your App Service has to be globally unique.
- **SqlServerName** : the name of your SQL Server. This name will be used to create a DNS entry like 'xxx.database.windows.net' where 'xxx' will be the name of your SQL Server. The name of your SQL server has to be globally unique.
- **SqlDbName** : the name of the database which will be created on your SQL Server. This is where the Umbraco CMS will store its content.
- **SqlAdminUser** : the username of the SQL Server admin user.
- **SqlAdminPwd** : the password of the SQL Server admin user.

The SQL Server admin credentials will be used to have the Umbraco CMS authenticate with the SQL server. It would be better to create a separate user and use alternatives methods to authenticate, but in this tutorial, you'll stick to using the admin credentials to keep things simple.

Create a new folder on your machine:

```powershell
mkdir Umbraco9ToAzureAppServiceForLinux
cd Umbraco9ToAzureAppServiceForLinux
```

You will use this folder to store configuration and your new Umbraco 9 website.

Run the following command:

```powershell
az config set --local `
    defaults.group=$GroupName `
    defaults.location=$Location `
    defaults.appserviceplan=$AppServicePlanName `
    defaults.web=$AppServiceName;
```

This will store some configuration at _.azure/config_ which will look like this:

```
[defaults]
group = your-umbraco9-site-rg
location = eastus
appserviceplan = your-umbraco9-site-asp
web = nswimberghe-umbraco9-app
```

Certain Azure CLI commands will require you to pass this information in as arguments, but if you don't, the commands will look at this configuration and use that instead. You'll run some commands to deploy your Umbraco 9 website later which will rely on this configuration.

Next, create your Azure resource group:

```powershell
az group create --location $Location --resource-group $GroupName;
```

Run this command to create an Azure SQL Server:

```powershell
az sql server create `
    --location $Location `
    --resource-group $GroupName `
    --name $SqlServerName `
    --admin-user $SqlAdminUser `
    --admin-password $SqlAdminPwd;
```

Run the following command to create a database in your Azure SQL Server:

```powershell
az sql db create `
    --server $SqlServerName `
    --name $SqlDbName;
```

Run this command to create a firewall rule which allows Azure services to have network access to your SQL Server. In the Azure Portal, there's a toggle to enable this, but in the CLI, you have to use start and stop IP address as 0.0.0.0 which Azure will interpret as the same thing.

```powershell
# this allows Azure services to communicate with the Sql Server (there are more secure alternatives)
az sql server firewall-rule create `
    --resource-group $GroupName `
    --server $SqlServerName `
    --name AllowAzureServices `
    --start-ip-address 0.0.0.0 `
    --end-ip-address 0.0.0.0;
```

Now all Azure services will be able to reach your SQL Server. There are better ways to secure your SQL Server such as using a Virtual Network, but this is the simplest way to get started.

You can use the `az sql db show-connection-string` command to get an 'ado.net' compatible connection string. This connection string will have not have the actual username and password included, but instead have the value '<username>' as the username and the value '<password>' as the password.  
Use the following Azure CLI command and use PowerShell to replace the dummy credentials with the actual admin credentials:

```powershell
$ConnectionString = $(az sql db show-connection-string `
    --server $SqlServerName `
    --name $SqlDbName `
    --client ado.net `
    --auth-type SqlPassword) `
    -replace "<username>",$SqlAdminUser -replace "<password>",$SqlAdminPwd;
```

You now have created an Azure SQL Server with a database and stored the connection string to connect to the SQL server into the `ConnectionString` variable. It is time to provision the Azure App Service for Linux.

Run the following command to create the Azure App Service Plan:

```powershell
az appservice plan create `
    --location $Location `
    --resource-group $GroupName `
    --name $AppServicePlanName `
    --is-linux;
```

By passing in the `--is-linux` argument, Azure will create an App Service plan based on Linux instead of Windows.

Run the following command to create the App Service:

```powershell
az webapp create `
    --name $AppServiceName `
    --plan $AppServicePlanName `
    --runtime '"DOTNET|5.0"'; #'" and "' is used to escape the | character in PowerShell
```

The `--runtime` argument specifies that the App Service should use the .NET 5 runtime to host your application.

Lastly, your Umbraco 9 site will need to connect to the SQL server, so you need to configure the connection string on your App Service to do that. Run the following command to add the connection string to your App Service configuration:

```powershell
az webapp config connection-string set `
    --resource-group $GroupName `
    --name $AppServiceName `
    --settings umbracoDbDSN=$ConnectionString `
    --connection-string-type SQLAzure;
```

**Here are all the steps in a single PowerShell script:**

```powershell
$ResourceBaseName = 'umbraco9';
$Location = 'eastus';
$GroupName = "$($ResourceBaseName)-rg";

$AppServicePlanName = "$($ResourceBaseName)-asp";
Write-Host "Enter web app name (has to be globally unique, will be used as subdomain xxx.azurewebsites.net)";
$AppServiceName = Read-Host "(name has to be globally unique, can only contain lowercase characters, numbers, and dashes)";

Write-Host "Enter sql server name (has to be globally unique, will be used as subdomain xxx.database.windows.net)";
$SqlServerName = Read-Host "(name has to be globally unique, can only contain lowercase characters, numbers, and dashes)";
$SqlDbName = "$($ResourceBaseName)-sqldb";
$SqlAdminUser = "SqlAdmin";
$SqlAdminPwd = Read-Host -AsSecureString "Enter a password for Sql Server admin";

az config set --local `
    defaults.group=$GroupName `
    defaults.location=$Location `
    defaults.appserviceplan=$AppServicePlanName `
    defaults.web=$AppServiceName;

az group create --location $Location --resource-group $GroupName;

az sql server create `
    --location $Location `
    --resource-group $GroupName `
    --name $SqlServerName `
    --admin-user $SqlAdminUser `
    --admin-password $($SqlAdminPwd | ConvertFrom-SecureString -AsPlainText);

az sql db create `
    --server $SqlServerName `
    --name $SqlDbName;

# this allows Azure services to communicate with the Sql Server (there are more secure alternatives)
az sql server firewall-rule create `
    --resource-group $GroupName `
    --server $SqlServerName `
    --name AllowAzureServices `
    --start-ip-address 0.0.0.0 `
    --end-ip-address 0.0.0.0;

$ConnectionString = $(az sql db show-connection-string `
    --server $SqlServerName `
    --name $SqlDbName `
    --client ado.net `
    --auth-type SqlPassword) `
    -replace "<username>",$SqlAdminUser -replace "<password>",$($SqlAdminPwd | ConvertFrom-SecureString -AsPlainText) `
    | ConvertTo-SecureString -AsPlainText;

az appservice plan create `
    --location $Location `
    --resource-group $GroupName `
    --name $AppServicePlanName `
    --is-linux;

az webapp create `
    --name $AppServiceName `
    --plan $AppServicePlanName `
    --runtime '"DOTNET|5.0"'; #'" and "' is used to escape the | character in PowerShell

az webapp config connection-string set `
    --resource-group $GroupName `
    --name $AppServiceName `
    --settings umbracoDbDSN=$($ConnectionString | ConvertFrom-SecureString -AsPlainText) `
    --connection-string-type SQLAzure;
```

Instead of hardcoding some of the values, the script will prompt you for them. The script also uses `SecureString` to store the admin password and connection string instead of storing it as plain text.

## Deploy Umbraco 9 to Azure App Service for Linux

Run these commands to create a new Umbraco 9 website locally in case you don't have an Umbraco 9 website yet:

```powershell
dotnet new -i Umbraco.Templates::\*;
dotnet new umbraco;
```

Run this command to publish the Umbraco 9 site to the _publish_ folder:

```powershell
dotnet publish . -c Release -o publish;
```

Run the following PowerShell cmdlet to zip the publish folder:

```powershell
Compress-Archive -Path publish/\* -DestinationPath publish.zip;
```

Run this command to deploy the zip file to your App Service:

```powershell
az webapp deploy `
    --clean true `
    --restart true `
    --src-path publish.zip `
    --type zip;
```

This command will

- upload your zip file to Azure
- delete any existing files in your App Service (`--clean`)
- deploy the contents of the zip file to your App Service
- restart your App Service

Normally, you need to also pass in the resource group and app service name, but in this case, it pulled that information from the _.azure/config_ file.

You can use the following command to quickly browse to your website:

```powershell
az webapp browse
```

By default, it'll take you to the website with the HTTP protocol instead of the HTTPS protocol. Make sure to switch to HTTPS, or even better, update your website to redirect all HTTP requests to HTTPS and add the HSTS security header.

To make the deployment more repeatable, you can use the following PowerShell script:

```powershell
If (Test-Path -Path './publish') {
    Remove-Item -Path './publish' -Recurse;
}
If (Test-Path -Path './publish.zip') {
    Remove-Item -Path './publish.zip' -Recurse;
}

dotnet publish . -c Release -o publish;
Compress-Archive -Path publish/* -DestinationPath publish.zip;
az webapp deploy `
    --clean true `
    --restart true `
    --src-path publish.zip `
    --type zip;
```

This updated script makes sure any previous publish folder or publish.zip file is removed before running the commands to publish and deploy the website.

## Summary

Now that Umbraco 9 is built on top of .NET 5 (.NET Core), you can host Umbraco on macOS and many popular Linux distributions. This also means you can now use Azure App Service for Linux instead of for Windows. You learned how to create the Azure infrastructure for an Umbraco website using the Azure CLI and how to deploy your Umbraco site to Azure App Service for Linux.