How to set up continuous deployment for a Web App on Azure App Service
This tutorial shows how to configure continuous deployment for a Web App on Azure App Service using GitHub Actions. Having automatic deploys is useful to reduce manual errors, speed up deliveries and allow simple rollback when something goes wrong.
Prerequisites
- Azure account with permissions to create a Resource Group and an App Service.
- GitHub account with a repository containing a small application (for example, Node.js or Python).
- Azure CLI installed and authenticated (az login) or access to the Azure Portal.
- Basic knowledge of CI/CD and YAML files.
Step 1: Create a Resource Group and an App Service Plan
The App Service needs a Plan that defines the resources. Here we create a Resource Group and an App Service Plan at a free/shared tier for testing.
# escolher nome e região
az group create --name rg-webapp-demo --location westeurope
# criar App Service Plan (SKU: B1, S1, F1, etc. - para teste usar F1 ou B1)
az appservice plan create --name plan-webapp-demo --resource-group rg-webapp-demo --sku B1 --is-linux
Step 2: Create a Web App
Create the Web App that will receive the continuous deployment. If your app is Node.js, specify the runtime; for Python, adjust the --runtime parameter.
# exemplo para Node.js numa app Linux
az webapp create --resource-group rg-webapp-demo --plan plan-webapp-demo --name webapp-demo-UNIQUE --runtime "NODE|18-lts"
Step 3: Create a Service Principal and assign role for GitHub Actions
To allow GitHub Actions to deploy to the Web App securely, create a Service Principal and give it the Contributor role on the Web App resource (or only on the Web Plan and the App).
# criar service principal e capturar output em JSON
az ad sp create-for-rbac --name "gh-actions-webapp-demo" --role contributor --scopes /subscriptions//resourceGroups/rg-webapp-demo --sdk-auth
Save the JSON that the command returns: it contains clientId, clientSecret, tenantId and subscriptionId. We will use it as a secret in GitHub.
Step 4: Add secret in the GitHub repository
In GitHub, go to Settings > Secrets & variables > Actions and create a secret named AZURE_CREDENTIALS with the JSON returned in the previous step. This allows the workflow to authenticate to Azure.
Step 5: Create GitHub Actions workflow for continuous deployment
Create a YAML file in the .github/workflows folder that builds and deploys the app to the Azure Web App. This example is minimal for Node.js; adapt it to your stack.
name: CI-CD to Azure WebApp
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Build
run: npm run build --if-present
- name: 'Login to Azure'
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: 'Deploy to Azure WebApp'
uses: azure/webapps-deploy@v2
with:
app-name: 'webapp-demo-UNIQUE'
slot-name: 'production'
package: '.'
Step 6: Test and troubleshoot common errors
When pushing to the main branch, the workflow is triggered. Common errors include incorrect credentials (check AZURE_CREDENTIALS), wrong app name (check app-name) or incompatible runtime. Open the Action log to see build and deploy messages.
Verify the result
To confirm that continuous deployment works:
- Push a simple change to the repository (for example, modify index.html or a route).
- In GitHub Actions check if the workflow ran successfully.
- Open the Web App URL (https://webapp-demo-UNIQUE.azurewebsites.net) and confirm the change.
- If something fails, check the logs in GitHub Actions and the application logs in the Azure Portal > Web App > Log Stream.
Conclusion
You now have a simple continuous deployment pipeline with GitHub Actions for a Web App on Azure App Service. Possible next steps: use deployment slots for A/B testing, configure health checks, automate rollback, or add unit tests to the workflow. Tip: use a staging slot to validate deployments before promoting to production — have you tried that?