Due to the EOL of PHP 7.4 and older Laravel versions like the 8.x branch, an upgrade of the runtime and libraries is required. As we have written elsewhere, the Azure App Service runtime stack for PHP 8.x uses nginx instead of the Apache web server. With the change to nginx, the rewrite rules provided by Laravel for mod_rewrite are no longer working. Away from that, there were serious errors until the end of 2022, once composer has been run. However, this issue has been fixed in the meantime.

Changing the minor version of PHP to PHP 8.2

In your Azure App Service instance, navigate to Configuration > General settings and select 8.2 as Minor version:

Minor Version PHP 8.2

Custom configuration for nginx

To deploy Laravel 10 apps in an nginx webserver, you have to use a custom nginx configuration. In the context of an Azure App Service, it is important that

  • the nginx configuration's root directory is /home/site/wwwroot/public
  • and everything below the / URI is forwarded to index.php.
server {
	# set root directory
    root /home/site/wwwroot/public;
	
	# ...

    location / {
		# forward to index.php
        try_files $uri $uri/ /index.php?$query_string;
    }
	
	# ...
}

You can use this gist, which contains all necessary modifications. Either download the gist directly into your Azure App Service instance or store it in your Git repository.

Download nginx.conf into the Azure App Service instance

In your Azure App Service navigate to Development Tools > SSH > Go

Execute the following command:

cd site && curl -L -O https://gist.githubusercontent.com/schakko/8076888f98fed2b1f4cc2448d44a3057/raw/a3f8ee3f4caeef73e7d9a6cc4ee04c41ba8d078c/nginx.conf

Minor Version PHP 8.2

Store nginx.conf in your Git repository

In your Laravel's source code repository create a directory azure-app-service and download the gist mentioned above into it.

Startup script to apply custom nginx.conf

When your Azure App Service instance starts, it has to overwrite the default nginx configuration file with the recently downloaded nginx.conf.

The script startup.sh is pretty simple:

#!/bin/bash

cp /home/site/nginx.conf /etc/nginx/sites-available/default
# or -if you are storing the nginx.conf in your Git repository-:
# cp /home/site/repository/azure-app-service/nginx.conf /etc/nginx/sites-available/default

service nginx reload

Either store that script directly in Azure App Service below /home/site/startup.sh or save it in your Git repository below /azure-app-service/startup.sh

Activate the startup script

In Azure App Service, navigate to Configuration > General settings and modify the Startup Command setting: Either set it to /home/site/startup.sh or -if you are managing the script in your Git repository- /home/site/repository/azure-app-service/startup.sh.

Startup command

Restart the app service afterwards.

Deploying the Laravel 10 application

When deploying your Laravel 10 application, you will see an output like this - depending upon your deployment method:

Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Deploy Async
remote: Updating branch 'main'.
remote: Updating submodules.
remote: Preparing deployment for commit id 'XXX'.
remote: PreDeployment: context.CleanOutputPath False
remote: PreDeployment: context.OutputPath /home/site/wwwroot
remote: Repository path is /home/site/repository
remote: Running oryx build...
remote: Operation performed by Microsoft Oryx, https://github.com/Microsoft/Oryx
remote: You can report issues at https://github.com/Microsoft/Oryx/issues
remote:
remote: Oryx Version: 0.2.20220825.1, Commit: 24032445dbf7bf6ef068688f1b123a7144453b7f, ReleaseTagName: 20220825.1
remote:
remote: Build Operation ID: |XXX
remote: Repository Commit : XXX
remote:
remote: Detecting platforms...
remote: .....
remote: Detected following platforms:
remote:   nodejs: 16.19.0
remote:   php: 8.2.2
remote: Version '16.19.0' of platform 'nodejs' is not installed. Generating script to install it...
remote: Version '8.2.2' of platform 'php' is not installed. Generating script to install it...
remote:
remote: Using intermediate directory '/tmp/8db1ee7c99d449f'.
remote:
remote: Copying files to the intermediate directory...
remote: Done in 1 sec(s).
remote:
remote: Source directory     : /tmp/8db1ee7c99d449f
remote: Destination directory: /home/site/wwwroot
remote:
remote:
remote: Downloading and extracting 'nodejs' version '16.19.0' to '/tmp/oryx/platforms/nodejs/16.19.0'...
remote: Detected image debian flavor: bullseye.
remote: Downloaded in 5 sec(s).
remote: Verifying checksum...
remote: Extracting contents...
remote: performing sha512 checksum for: nodejs...
remote: Done in 11 sec(s).
remote:
remote:
remote: Downloading and extracting 'php' version '8.2.2' to '/tmp/oryx/platforms/php/8.2.2'...
remote: Detected image debian flavor: bullseye.
remote: Downloaded in 1 sec(s).
remote: Verifying checksum...
remote: Extracting contents...
remote: performing sha512 checksum for: php...
remote: Done in 3 sec(s).
remote:
remote:
remote: Downloading and extracting 'php-composer' version '2.0.8' to '/tmp/oryx/platforms/php-composer/2.0.8'...
remote: Detected image debian flavor: bullseye.
remote: Downloaded in 0 sec(s).
remote: Verifying checksum...
remote: Extracting contents...
remote: performing sha512 checksum for: php-composer...
remote: Done in 1 sec(s).
remote:
remote: PHP executable: /tmp/oryx/platforms/php/8.2.2/bin/php
remote: Composer archive: /tmp/oryx/platforms/php-composer/2.0.8/composer.phar
remote: Running 'composer install --ignore-platform-reqs --no-interaction'...

# composer output ...
remote: Preparing output...
remote:
remote: Copying files to destination directory '/home/site/wwwroot'...

remote: ........................................................................................................................................................................
remote: Done in 173 sec(s).
remote:
remote: Removing existing manifest file
remote: Creating a manifest file...
remote: Manifest file created.
remote: Copying .ostype to manifest output directory.
remote:
remote: Done in 208 sec(s).
remote: Running post deployment command(s)...
remote:
remote: Generating summary of Oryx build
remote: Parsing the build logs
remote: Found 0 issue(s)
remote:
remote: Build Summary :
remote: ===============
remote: Errors (0)
remote: Warnings (0)
remote:
remote: Triggering recycle (preview mode disabled).
remote: Deployment successful. deployer =  deploymentPath =