Host Strapi 3 on Azure

Thursday, Oct 14, 2021 7 minute read Tags: javascript azure graphql
Hey, thanks for the interest in this post, but just letting you know that it is over 3 years old, so the content in here may not be accurate.

I originally contributed the following as a guide for the official Strapi docs, but as they are working on v4 of Strapi at the moment, I figured it would still be good to include somewhere, so here it is on my blog! As a result, the layout of the content won’t be my normal blog style, it’s more documtation-esq, but it should still do the job.

If you’re new to Strapi, Strapi is a headless CMS that you would host somewhere and use their API to pull the content into an application, be it a SPA in your favourite JavaScript framework, a mobile app, or something else.

These guides are tested against the v3 release of Strapi, as v4 is in beta at the time of writing. It’s likely that much of the content covered here will be applicable for v4, the only thing I expect to change is how to use the file upload provider, I’m unsure if the existing plugin will work with v4.

Azure Install Requirements

Table of Contents

Required Resources

There are three resources in Azure that are required to run Strapi in a PaaS model, AppService to host the Strapi web application, Storage to store images/uploaded assets, and a database, Azure has managed MySQL and Postgres to choose from (for this tutorial, we’ll use MySQL, but the steps are the same for MySQL).

Creating Resources via the Azure Portal

In this section we’ll use the Azure Portal to create the required resources to host Strapi.

  1. Navigate to the Azure Portal

  2. Click Create a resource and search for Resource group from the provided search box

  3. Provide a name for your Resource Group, my-strapi-app, and select a region

  4. Click Review + create then Create

  5. Navigate to the Resource Group once it’s created, click Create resources and search for Web App

  6. Ensure the Subscription and Resource Group are correct, then provide the following configuration for the app:

    • Name - my-strapi-app
    • Publish - Code
    • Runtime stack - Node 14 LTS
    • Operating System - Linux
    • Region - Select an appropriate region
  7. Use the App Service Plan to select the appropriate Sku and size for the level of scale your app will need (refer to the Azure docs for more information on the various Sku and sizes)

  8. Click Review + create then Create

  9. Navigate back to the Resource Group and click Create then search for Storage account and click Create

  10. Ensure the Subscription and Resource Group are correct, then provide the following configuration for the storage account:

    • Name - my-strapi-app
    • Region - Select an appropriate region
    • Performance - Standard
    • Redundancy - Select the appropriate level of redundancy for your files
  11. Click Review + create then Create

  12. Navigate back to the Resource Group and click Create then search for Azure Database for MySQL and click Create

  13. Select Single server for the service type

  14. Ensure the Subscription and Resource Group are correct, then provide the following configuration for the storage account:

    • Name - my-strapi-db
    • Data source - None (unless you’re wanting to import from a backup)
    • Location - Select an appropriate region
    • Version - 5.7
    • Compute + storage - Select an appropriate scale for your requirements (Basic is adequate for many Strapi workloads)
  15. Enter a username and password for the Administrator account, click Review + create then Create

Configuring the Resources

Once all the resources are created, you will need to get the connection information for the MySQL and Storage account to the Web App, as well as configure the resources for use.

Configure the Storage Account
  1. Navigate to the Storage Account resource, then Data storage - Containers
  2. Create a new Container, provide a Name, strapi-uploads, and set Public access level to Blob, then click Create
  3. Navigate to Security + networking - Access keys, copy the Storage account name and key1
  4. Navigate to the Web App you created and go to Settings - Configuration
  5. Create new application settings for the Storage account, storage account key and container name (these will become the environment variables available to Strapi) and click Save
Configure MySQL
  1. Navigate to the MySQL resource then Settings - Connection security

  2. Set Allow access to Azure services to Yes and click Save

  3. Navigate to Overview and copy Server name and Server admin login name

  4. Open the Azure Cloud Shell and log into the mysql cli:

    • mysql --host <server> --user <username> -p
  5. Create a database for Strapi to use CREATE DATABASE strapi; then close the Cloud Shell

    • Optional - create a separate non server admin user (see this doc for guidance)
  6. Navigate to the Web App you created and go to Settings - Configuration

  7. Create new application settings for the Database host, username and password (these will become the environment variables available to Strapi) and click Save

Creating Resources via the Azure CLI

In this section, we’ll use the Azure CLI to create the required resources. This will assume you have some familiarity with the Azure CLI and how to find the right values.

  1. Create a new Resource Group

    1
    2
    3
    
    rgName=my-strapi-app
    location=westus
    az group create --name $rgName --location $location
    
  2. Create a new Linux App Service Plan (ensure you change the number-of-workers and sku to meet your scale requirements)

    1
    2
    
    appPlanName=strapi-app-service-plan
    az appservice plan create --resource-group $rgName --name $appPlanName --is-linux --number-of-workers 4 --sku S1 --location $location
    
  3. Create a Web App running Node.js 14

    1
    2
    
    webAppName=my-strapi-app
    az webapp create --resource-group $rgName --name $webAppName --plan $appPlanName --runtime "node|10.14"
    
  4. Create a Storage Account

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    saName=mystrapiapp
    az storage account create --resource-group $rgName --name $saName --location $location
    
    # Get the access key
    saKey=$(az storage account keys list --account-name $saName --query "[?keyName=='key1'].value" --output tsv)
    
    # Add a container to the storage account
    container=strapi-uploads
    az storage container create --name $container --public-access blob --access-key $saKey --account-name $saName
    
  5. Create a MySQL database

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    serverName=my-strapi-db
    dbName=strapi
    username=strapi
    password=...
    
    # Create the server
    az mysql server create --resource-group $rgName --name $serverName --location $location --admin-user $username --admin-password $password --version 5.7 --sku-name B_Gen5_1
    
    # Create the database
    az mysql db create --resource-group $rgName --name $dbName --server-name $serverName
    
    # Allow Azure resources through the firewall
    az mysql server firewall-rule create --resource-group $rgName --server-name $serverName --name AllowAllAzureIps --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
    
  6. Add configuration values to the Web App

    1
    2
    3
    4
    5
    6
    
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting STORAGE_ACCOUNT=$saName
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting STORAGE_ACCOUNT_KEY=$saKey
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting STORAGE_ACCOUNT_CONTAINER=$container
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting DATABASE_HOST=$serverName.mysql.database.azure.com
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting DATABASE_USERNAME=$username@$serverName
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting DATABASE_PASSWORD=$password
    

Deploy with an Azure Resource Manager template

To deploy using an Azure Resource Manager template, use the button below, or upload this template as a custom deployment in Azure.

Deploy to Azure

Storing files and images

As AppService is a PaaS hosting model, an upload provider will be required to save the uploaded assets to Azure Storage. Check out https://github.com/jakeFeldman/strapi-provider-upload-azure-storage for more details on using Azure Storage as an upload provider.

Local development

For local development, you can either use the standard Strapi file/image upload provider (which stored on the local disk), or the Azurite emulator.

Deploying and running Strapi

Azure AppService can be deployed to using CI/CD pipelines or via FTPS, refer to the Azure docs on how to do this for your preferred manner.

To start the Node.js application, AppService will run the npm start command. As there is no guarantee that the symlinks created by npm install were preserved (in the case of an upload from a CI/CD pipeline) it is recommended that the npm start command directly references the Keystone entry point:

1
2
3
"scripts": {
    "start": "node node_modules/strapi/bin/strapi.js start"
}

Conclusion

This has been a look at how we can use the different PaaS features of Azure to host Strapi, and the different ways in which you can setup those resources. I prefer to use the Resource Manager template myself, and then configure GitHub Actions as the CI/CD pipeline so that deployments all happen smoothly in the future.

Hopefully this makes it easier for you to also get your Strapi sites running in Azure, and once Strapi 4 is out, I’ll get some updated content on the differences that you need to be aware of when hosting in Azure.