Skip to content

aaronpowell/keystone-6-azure-example

Repository files navigation

Deploying Keystone 6 on Azure

This article will cover how to deploy Keystone to Azure using Platform-as-a-Service (PaaS).

You will need an Azure account for this, you can sign up for a free trial if you don't already have one.

Required Resources

There are three resources in Azure that are required to run Keystone in a PaaS model, AppService to host the Keystone web application, Storage to store images/uploaded assets, and a managed Postgres database.

Table of Contents


Creating Resources via the Azure Portal

In this section we'll use the Azure Portal to create the required resources to host Keystone.

  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-keystone-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-keystone-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 fo 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 - mykeystoneapp
    • 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 PostgreSQL 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-keystone-db
    • Data source - None (unless you're wanting to import from a backup)
    • Location - Select an appropriate region
    • Version - 11
    • Compute + storage - Select an appropriate scale for your requirements (Basic is adequate for many Keystone 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 Postgres and Storage account to the Web App (App Service), 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, keystone-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 (App Service) you created and go to Settings - Configuration
  5. Create three New application settings:
    • AZURE_STORAGE_ACCOUNT as the Storage account name value you copied above.
    • AZURE_STORAGE_KEY as the key1 value you copied above.
    • AZURE_STORAGE_CONTAINER as the name of the container, which you specified as keystone-uploads above.
  6. These will become the environment variables available to Keystone, click Save.

Configure Postgres

  1. Navigate to the Azure Database for PostgreSQL server 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 psql cli:

    • psql --host <server> --user <username> --port=5432 --dbname postgres
  5. Create a database for Keystone to use CREATE DATABASE keystone; then close the Cloud Shell

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

  7. Create a New application setting named DATABASE_URL, which contains the connection string, encoded per Prisma's requirements (this will become the environment variables available to Keystone) and click Save, it will look something like:

    • postgres://$username%40$serverName:$password@$serverName.postgres.database.azure.com:5432/$dbName

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

    rgName=my-keystone-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)

    appPlanName=keystone-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 (App Service) running Node.js 14

    webAppName=my-keystone-app
    az webapp create --resource-group $rgName --name $webAppName --plan $appPlanName --runtime "NODE|14-lts"
  4. Create a Storage Account

    saName=mykeystoneapp
    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=keystone-uploads
    az storage container create --name $container --public-access blob --access-key $saKey --account-name $saName
  5. Create a Postgres database

    serverName=my-keystone-db
    dbName=keystone
    username=keystone
    password=...
    
    # Create the server
    az postgres server create --resource-group $rgName --name $serverName --location $location --admin-user $username --admin-password $password --version 11 --sku-name B_Gen5_1
    
    # Create the database
    az postgres db create --resource-group $rgName --name $dbName --server-name $serverName
    
    # Allow Azure resources through the firewall
    az postgres 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 (App Service)

    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting AZURE_STORAGE_ACCOUNT=$saName
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting AZURE_STORAGE_KEY=$saKey
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting AZURE_STORAGE_CONTAINER=$container
    az webapp config appsettings set --resource-group $rgName --name $webAppName --setting DATABASE_URL=postgres://$username%40$serverName:$password@$serverName.postgres.database.azure.com:5432/$dbName

Deploy with an Azure Resource Manager template

A Resource Manager template has been created that will provision all the resources that are required, as well as setup the appropriate settings across the AppService. Click the button below and fill out the parameters as required to create the resources. Alternatively, you can create a custom template deployment via the portal and upload the template file, or run the template form the Azure CLI.

Deploy to Azure

The template is located at .azure/azuredeploy.json


Storing files and images

As AppService is a PaaS hosting model, it is not possible to store files on disk, as it is not persisted between deployments nor is it shared between scale-out machines. The solution for this in Keystone is to use a custom field type https://github.com/keystonejs-contrib/k6-contrib/tree/main/packages/fields-azure.

Local development

For local development, you can either use the standard Keystone file/image field types (which stored on the local disk), or the Azurite emulator.

Deploying and running Keystone

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:

"scripts": {
    "start": "node ./node_modules/@keystone-6/core/bin/cli.js start"
}

Optional - Using Azure AD B2C for user accounts

Keystone provides built in authentication but this can be replaced with a custom provider that supports Azure AD B2C. For this, you'll need the https://github.com/OpenSaasAU/keystone-nextjs-auth auth package and then follow the NextAuth docs on setting up Azure AD B2C.

Once Azure is configured, update your auth provider with nextjs-auth to use AzureADB2C like so:

const auth = createAuth({
  listKey: "User",
  identityField: "subjectId",
  sessionData: `id name email`,
  autoCreate: true,
  userMap: { subjectId: "id", name: "name" },
  accountMap: {},
  profileMap: { email: "mail" },
  providers: [
    Providers.AzureADB2C({
      clientId: process.env.AZURE_CLIENT_ID,
      clientSecret: process.env.AZURE_CLIENT_SECRET,
      scope: "offline_access User.Read",
      tenantId: process.env.AZURE_TENANT_ID,
    }),
  ],
});

Running the sample locally

To run the sample locally, you will need to use a Postgres database (either locally hosted, or hosted on Azure) and provide an Azure storage account (either an emulator like Azurite or an Azure resource).

This connection information will need to be made available as environment variables:

AZURE_STORAGE_ACCOUNT=...
AZURE_STORAGE_KEY=...
AZURE_STORAGE_CONTAINER=...
DATABASE_URL=...
AZURE_STORAGE_ACCOUNT_HOST=http://127.0.0.1:10000/

About

A sample application for running Keystone 6 on Azure

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages