Tutorial: Build a PHP (Laravel) and Azure Database for MySQL - Flexible Server app on Azure App Service

Azure App Service provides a highly scalable, self-patching web hosting service using the Linux operating system. This tutorial shows how to create a secure PHP app in Azure App Service that's connected to a MySQL database (using Azure Database for MySQL flexible server). When you're finished, you'll have a Laravel app running on Azure App Service on Linux.

Screenshot of the Azure app example titled Task List showing new tasks added.

In this tutorial, you learn how to:

  • Create a secure-by-default PHP and MySQL app in Azure
  • Configure connection secrets to MySQL using app settings
  • Deploy application code using GitHub Actions
  • Update and redeploy the app
  • Run database migrations securely
  • Stream diagnostic logs from Azure
  • Manage the app in the Azure portal

Prerequisites

Sample application

To follow along with this tutorial, clone or download the sample application from the repository:

git clone https://github.com/Azure-Samples/laravel-tasks.git

If you want to run the application locally, do the following:

  • In .env, configure the database settings (like DB_DATABASE, DB_USERNAME, and DB_PASSWORD) using settings in your local Azure Database for MySQL flexible server database. You need a local Azure Database for MySQL flexible server instance to run this sample.

  • From the root of the repository, start Laravel with the following commands:

    composer install
    php artisan migrate
    php artisan key:generate
    php artisan serve
    

1 - Create App Service and Azure Database for MySQL flexible server resources

In this step, you create the Azure resources. The steps used in this tutorial create an App Service and Azure Database for MySQL flexible server configuration that's secure by default. For the creation process, you'll specify:

  • The Name for the web app. It's the name used as part of the DNS name for your webapp in the form of https://<app-name>.azurewebsites.net.
  • The Runtime for the app. It's where you select the version of PHP to use for your app.
  • The Resource Group for the app. A resource group lets you group (in a logical container) all the Azure resources needed for the application.

Sign in to the Azure portal and follow these steps to create your Azure App Service resources.

Instructions Screenshot
In the Azure portal:
  1. Enter "web app database" in the search bar at the top of the Azure portal.
  2. Select the item labeled Web App + Database under the Marketplace heading.
You can also navigate to the creation wizard directly.
Screenshot showing how to use the search box in the top tool bar to find the Web App + Database creation wizard.
In the Create Web App + Database page, fill out the form as follows.
  1. Resource Group → Select Create new and use a name of msdocs-laravel-mysql-tutorial.

  2. Region → Any Azure region near you.

  3. Namemsdocs-laravel-mysql-XYZ where XYZ is any three random characters. This name must be unique across Azure.

  4. Runtime stackPHP 8.0.

    MySQL - Flexible Server is selected for you by default as the database engine. Azure Database for MySQL is a fully managed MySQL database as a service on Azure, compatible with the latest community editions.

  5. Note the database name that's generated for you (<app-name>-database). You'll need it later.

  6. Select Review + create.

After validation completes, select Create.
Screenshot showing how to configure a new app and database in the Web App + Database wizard.
The deployment takes a few minutes to complete, and creates the following resources:
  • Resource group → The container for all the created resources.
  • App Service plan → Defines the compute resources for App Service. A Linux plan in the P1v2 tier is created.
  • App Service → Represents your app and runs in the App Service plan.
  • Virtual network → Integrated with the App Service app and isolates back-end network traffic.
  • Azure Database for MySQL - Flexible Server → Accessible only from the virtual network. A database and a user are created for you on the server.
  • Private DNS zone → Enables DNS resolution of the MySQL database server in the virtual network.
Once deployment completes, select the Go to resource button. You're taken directly to the App Service app.
Screenshot showing the form to fill out to create a web app in Azure.

2 - Set up database connectivity

The creation wizard generated app settings for you to use to connect to the database, but not in a format that's useable for your code yet. In this step, you edit and update app settings to the format that your app needs.

Instructions Screenshot
In the App Service page, in the left menu, select Configuration. Screenshot showing how to open the configuration page in App Service.
In the Application settings tab of the Configuration page, for each of the following settings, select Edit, update the Name field with new values and select OK.
Current Name New Name
AZURE_MYSQL_DBNAME DB_DATABASE
AZURE_MYSQL_HOST DB_HOST
AZURE_MYSQL_USERNAME DB_USERNAME
AZURE_MYSQL_PASSWORD DB_PASSWORD
Screenshot showing how to see the autogenerated connection string.
Create a new MYSQL_ATTR_SSL_CA database setting:
  1. Select New application setting.

  2. In the Name field, enter MYSQL_ATTR_SSL_CA.

  3. In the Value field, enter /home/site/wwwroot/ssl/DigiCertGlobalRootCA.crt.pem.

    This app setting points to the path of the TLS/SSL certificate you need to access the MySQL server. It's included in the sample repository for convenience.

  4. Select OK.

Screenshot showing how to create an app setting.
Create the following extra app settings by following the same steps, then select Save.
  • APP_DEBUG: Use true as the value. This is a Laravel debugging variable.

  • APP_KEY: Use base64:Dsz40HWwbCqnq0oxMsjq7fItmKIeBfCBGORfspaI1Kw= as the value. This is a Laravel encryption variable.

    Important

    This APP_KEY value is used here for convenience. For production scenarios, it should be generated specifically for your deployment using php artisan key:generate --show in the command line.

Screenshot showing all the required app settings in the configuration page.

3 - Deploy sample code

In this step, you'll configure GitHub deployment using GitHub Actions. It's just one of many ways to deploy to App Service, but also a great way to have continuous integration in your deployment process. By default, every git push to your GitHub repository will kick off the build and deploy action. You'll make some changes to your codebase with Visual Studio Code directly in the browser, then let GitHub Actions deploy automatically for you.

Instructions Screenshot
In a new browser window:
  1. Sign in to your GitHub account.

  2. Navigate to https://github.com/Azure-Samples/laravel-tasks.

  3. Select Fork.

  4. Select Create fork.

Screenshot showing how to create a fork of the sample GitHub repository.
In the GitHub page, open Visual Studio Code in the browser by pressing the . key. Screenshot showing how to open the Visual Studio Code browser experience in GitHub.
In Visual Studio Code in the browser, open config/database.php in the explorer.In the mysql connection, see that the app settings you created earlier for the MySQL connection are already used (DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD, MYSQL_ATTR_SSL_CA). Screenshot showing Visual Studio Code in the browser and an opened file.
Back in the App Service page, in the left menu, select Deployment Center. Screenshot showing how to open the deployment center in App Service.
In the Deployment Center page:
  1. In Source, select GitHub. By default, GitHub Actions is selected as the build provider.

  2. Sign in to your GitHub account and follow the prompt to authorize Azure.

  3. In Organization, select your account.

  4. In Repository, select laravel-tasks.

  5. In Branch, select main.

  6. In the top menu, select Save.

App Service commits a workflow file into the selected GitHub repository, in the .github/workflows directory.
Screenshot showing how to configure CI/CD using GitHub Actions.
In the Deployment Center page:
  1. Select Logs. A deployment run is already started.

  2. In the log item for the deployment run, select Build/Deploy Logs.

    You're taken to your GitHub repository and see that the GitHub action is running. The workflow file defines two separate stages, build and deploy.

Screenshot showing how to open deployment logs in the deployment center.
To make any changes to your code, go to Visual Studio Code in the browser:
  1. Select the Source Control extension.

  2. Next to the changed file, for example database.php, select + to stage your changes.

  3. In the textbox, type a commit message, for example add certificate.

  4. Select the checkmark to commit and push to GitHub.

If you go back to the Deployment Center page, you'll see a new log entry because another run is started. Wait for the run to complete. It takes about 15 minutes.

Tip

The GitHub action is defined by the file in your GitHub repository, in .github/workflow. You can make it faster by customizing the file.

Screenshot showing how to commit your changes in the Visual Studio Code browser experience.

4 - Generate database schema

The creation wizard puts the Azure Database for MySQL flexible server instance behind a private endpoint, so it's accessible only from the virtual network. Because the App Service app is already integrated with the virtual network, the easiest way to run database migrations with your database is directly from within the App Service container.

Instructions Screenshot
In the App Service page:
  1. From the left menu, select SSH.

  2. Select Go.

An SSH session with your App Service container is opened in the browser. If you want, you can navigate directly to https://<app-name>.scm.azurewebsites.net/webssh/host instead.
Screenshot showing how to open the SSH shell for your app from the Azure portal.
In the SSH terminal:
  1. CD to the root of your application code:

    cd /home/site/wwwroot
    
  2. Run database migrations from your application root.

    php artisan migrate --force
    

    Note

    Only changes to files in /home can persist beyond app restarts. Changes outside of /home are not persisted.

Screenshot showing the commands to run in the SSH shell and their output.

5 - Change site root

Laravel application lifecycle begins in the /public directory instead. The default PHP 8.0 container for App Service uses Nginx, which starts in the application's root directory. To change the site root, you need to change the Nginx configuration file in the PHP 8.0 container (/etc/nginx/sites-available/default). For your convenience, the sample repository contains a custom configuration file called default. As noted previously, you don't want to replace this file using the SSH shell, because your changes will be lost after an app restart.

Instructions Screenshot
In the App Service page:
  1. From the left menu, select Configuration.

  2. Select the General settings tab.

Screenshot showing how to open the general settings tab in the configuration page of App Service.
In the General settings tab:
  1. In the Startup Command box, enter the following command: cp /home/site/wwwroot/default /etc/nginx/sites-available/default && service nginx reload.

    It replaces the Nginx configuration file in the PHP 8.0 container and restarts Nginx. This configuration ensures that this change is made to the container each time it starts.

  2. Select Save.

Screenshot showing how to configure a startup command in App Service.

6 - Browse to the app

Instructions Screenshot
In the App Service page:
  1. From the left menu, select Overview.

  2. Select the URL of your app.

    You can also navigate directly to https://<app-name>.azurewebsites.net.

Screenshot showing how to launch an App Service from the Azure portal.
Add a few tasks to the list.Congratulations, you're running a data-driven PHP app in Azure App Service. Screenshot of the Laravel app running in App Service.

7 - Stream diagnostic logs

Instructions Screenshot
In the App Service page:
  1. From the left menu, select App Service logs.

  2. Under Application logging, select File System.

Screenshot showing how to enable native logs in App Service in the Azure portal.
From the left menu, select Log stream.You see the logs for your app, including platform logs and logs from inside the container. Screenshot showing how to view the log stream in the Azure portal.

Clean up resources

When you're finished, you can delete all of the resources from your Azure subscription by deleting the resource group.

Instructions Screenshot
In the search bar at the top of the Azure portal:
  1. Enter the resource group name.

  2. Select the resource group.

Screenshot showing how to search for and navigate to a resource group in the Azure portal.
In the resource group page, select Delete resource group. Screenshot showing the location of the Delete Resource Group button in the Azure portal.
  1. Enter the resource group name to confirm your deletion.

  2. Select Delete.

Screenshot of the confirmation dialog for deleting a resource group in the Azure portal.

Frequently asked questions

How much does this setup cost?

Pricing for the create resources is as follows:

How do I connect to an Azure Database for MySQL flexible server database that's secured behind a virtual network?

To connect to an Azure Database for MySQL flexible server database, you can use several methods based on the tools and environments at your disposal:

  • Command-line tool access:
    • Use the mysql command from the app's SSH terminal for basic access.
  • Desktop tools (for example, MySQL Workbench):
    • Using SSH tunneling with Azure CLI:
      • Create an SSH session to the web app by using the Azure CLI.
      • Use the SSH session to tunnel the traffic to MySQL.
    • Using site-to-site VPN or Azure VM:
      • Your machine must be part of the virtual network.
      • Consider using:
        • An Azure VM linked to one of the subnets.
        • A machine in an on-premises network that has a site-to-site VPN connection to the Azure virtual network.
  • Azure Cloud Shell integration:

How does local app development work with GitHub Actions?

Take the autogenerated workflow file from App Service as an example, each git push kicks off a new build and deployment run. From a local clone of the GitHub repository, you make the desired updates push it to GitHub. For example:

git add .
git commit -m "<some-message>"
git push origin main

Why is the GitHub Actions deployment so slow?

The autogenerated workflow file from App Service defines build-then-deploy, two-job run. Because each job runs in its own clean environment, the workflow file ensures that the deploy job has access to the files from the build job:

Most of the time taken by the two-job process is spent uploading and download artifacts. If you want, you can simplify the workflow file by combining the two jobs into one, which eliminates the need for the upload and download steps.

Summary

In this tutorial, you learned how to:

  • Create a secure-by-default PHP and Azure Database for MySQL flexible server app in Azure
  • Configure connection secrets to Azure Database for MySQL flexible server using app settings
  • Deploy application code using GitHub Actions
  • Update and redeploy the app
  • Run database migrations securely
  • Stream diagnostic logs from Azure
  • Manage the app in the Azure portal