Configure a PHP app for Azure App Service
Warning
PHP on Windows reached the end of support in November 2022. PHP is supported only for App Service on Linux. This article is for reference only.
This guide shows you how to configure your PHP web apps, mobile back ends, and API apps in Azure App Service.
This guide provides key concepts and instructions for PHP developers who deploy apps to App Service. If you've never used App Service, you should first follow the Create a PHP web app in Azure App Service quickstart and the Deploy a PHP, MySQL, and Redis app to Azure App Service tutorial.
Show the PHP version
To show the current PHP version, run the following command in Azure Cloud Shell:
az webapp config show --resource-group <resource-group-name> --name <app-name> --query phpVersion
Note
To address a development slot, include the parameter --slot
followed by the name of the slot.
To show all supported PHP versions, run the following command in Cloud Shell:
az webapp list-runtimes --os windows | grep PHP
This guide shows you how to configure your PHP web apps, mobile back ends, and API apps in Azure App Service.
This guide provides key concepts and instructions for PHP developers who deploy apps to App Service. If you've never used Azure App Service, you should first follow the Create a PHP web app in Azure App Service quickstart and the Deploy a PHP, MySQL, and Redis app to Azure App Service tutorial.
Show the PHP version
To show the current PHP version, run the following command in Azure Cloud Shell:
az webapp config show --resource-group <resource-group-name> --name <app-name> --query linuxFxVersion
Note
To address a development slot, include the parameter --slot
followed by the name of the slot.
To show all supported PHP versions, run the following command in Cloud Shell:
az webapp list-runtimes --os linux | grep PHP
Set the PHP version
Run the following command in Cloud Shell to set the PHP version to 8.1:
az webapp config set --resource-group <resource-group-name> --name <app-name> --php-version 8.1
Run the following command in Cloud Shell to set the PHP version to 8.1:
az webapp config set --resource-group <resource-group-name> --name <app-name> --linux-fx-version "PHP|8.1"
Run Composer
If you want App Service to run Composer at deployment time, the easiest way is to include Composer in your repository.
From a local terminal window, change the directory to your repository root. Then, follow the instructions at Download Composer to download composer.phar
to the directory root.
Run the following commands. To run them, you need npm installed.
npm install kuduscript -g
kuduscript --node --scriptType bash --suppressPrompt
Your repository root now has two additional files: .deployment
and deploy.sh
.
Open deploy.sh
and find the Deployment
section, which looks like this example:
##################################################################################################################################
# Deployment
# ----------
At the end of the Deployment
section, add the code section that you need to run the required tool:
# 4. Use composer
echo "$DEPLOYMENT_TARGET"
if [ -e "$DEPLOYMENT_TARGET/composer.json" ]; then
echo "Found composer.json"
pushd "$DEPLOYMENT_TARGET"
php composer.phar install $COMPOSER_ARGS
exitWithMessageOnError "Composer install failed"
popd
fi
Commit all your changes and deploy your code by using Git or by using ZIP deploy with build automation enabled. Composer should now be running as part of deployment automation.
Run Bower, Gulp, or Grunt
If you want App Service to run popular automation tools at deployment time (such as Bower, Gulp, or Grunt), you need to supply a custom deployment script. App Service runs this script when you deploy by using Git or by using ZIP deploy with build automation enabled.
To enable your repository to run these tools, you need to add them to the dependencies in package.json
. For example:
"dependencies": {
"bower": "^1.7.9",
"grunt": "^1.0.1",
"gulp": "^3.9.1",
...
}
From a local terminal window, change the directory to your repository root and run the following commands. To run them, you need npm installed.
npm install kuduscript -g
kuduscript --node --scriptType bash --suppressPrompt
Your repository root now has two additional files: .deployment
and deploy.sh
.
Open deploy.sh
and find the Deployment
section, which looks like this example:
##################################################################################################################################
# Deployment
# ----------
This section ends with running npm install --production
. At the end of the Deployment
section, add the code section that you need to run the required tool:
See an example in the MEAN.js sample, where the deployment script also runs a custom npm install
command.
Bower
This snippet runs bower install
:
if [ -e "$DEPLOYMENT_TARGET/bower.json" ]; then
cd "$DEPLOYMENT_TARGET"
eval ./node_modules/.bin/bower install
exitWithMessageOnError "bower failed"
cd - > /dev/null
fi
Gulp
This snippet runs gulp imagemin
:
if [ -e "$DEPLOYMENT_TARGET/gulpfile.js" ]; then
cd "$DEPLOYMENT_TARGET"
eval ./node_modules/.bin/gulp imagemin
exitWithMessageOnError "gulp failed"
cd - > /dev/null
fi
Grunt
This snippet runs grunt
:
if [ -e "$DEPLOYMENT_TARGET/Gruntfile.js" ]; then
cd "$DEPLOYMENT_TARGET"
eval ./node_modules/.bin/grunt
exitWithMessageOnError "Grunt failed"
cd - > /dev/null
fi
Customize build automation
If you deploy your app by using Git or by using ZIP packages with build automation enabled, the App Service build automation steps through the following sequence:
- Run a custom script if
PRE_BUILD_SCRIPT_PATH
specifies it. - Run
php composer.phar install
. - Run a custom script if
POST_BUILD_SCRIPT_PATH
specifies it.
PRE_BUILD_COMMAND
and POST_BUILD_COMMAND
are environment variables that are empty by default. To run pre-build commands, define PRE_BUILD_COMMAND
. To run post-build commands, define POST_BUILD_COMMAND
.
The following example specifies the two variables to a series of commands, separated by commas:
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings PRE_BUILD_COMMAND="echo foo, scripts/prebuild.sh"
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings POST_BUILD_COMMAND="echo foo, scripts/postbuild.sh"
For additional environment variables to customize build automation, see Oryx configuration.
For more information on how App Service runs and builds PHP apps in Linux, see the Oryx documentation on how PHP apps are detected and built.
Customize startup
If you want, you can run a custom command at the container startup time. Run the following command in Cloud Shell:
az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "<custom-command>"
Access environment variables
In App Service, you can set app settings outside your app code. You can then access those settings by using the standard getenv()
pattern. For example, to access an app setting called DB_HOST
, use the following code:
getenv("DB_HOST")
Change the site root
The web framework of your choice might use a subdirectory as the site root. For example, Laravel uses the public/
subdirectory as the site root.
To customize the site root, set the virtual application path for the app by using the az resource update
command. The following example sets the site root to the public/
subdirectory in your repository:
az resource update --name web --resource-group <group-name> --namespace Microsoft.Web --resource-type config --parent sites/<app-name> --set properties.virtualApplications[0].physicalPath="site\wwwroot\public" --api-version 2015-06-01
By default, Azure App Service points the root virtual application path (/
) to the root directory of the deployed application files (sites\wwwroot
).
The web framework of your choice might use a subdirectory as the site root. For example, Laravel uses the public/
subdirectory as the site root.
The default PHP image for App Service uses NGINX, and you change the site root by configuring the NGINX server with the root
directive. This example configuration file contains the following snippet that changes the root
directive:
server {
#proxy_cache cache;
#proxy_cache_valid 200 1s;
listen 8080;
listen [::]:8080;
root /home/site/wwwroot/public; # Changed for Laravel
location / {
index index.php index.html index.htm hostingstart.html;
try_files $uri $uri/ /index.php?$args; # Changed for Laravel
}
...
The default container uses the configuration file at /etc/nginx/sites-available/default
. Keep in mind that any edit you make to this file is erased when the app restarts. To make a change that's effective across app restarts, add a custom startup command like this example:
cp /home/site/wwwroot/default /etc/nginx/sites-available/default && service nginx reload
This command replaces the default NGINX configuration file with a file named default
in your repository root, and it restarts NGINX.
Detect an HTTPS session
In App Service, TLS/SSL termination happens at the network load balancers, so all HTTPS requests reach your app as unencrypted HTTP requests. If your app logic needs to check whether the user requests are encrypted, inspect the X-Forwarded-Proto
header:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
// Do something when HTTPS is used
}
Popular web frameworks let you access the X-Forwarded-*
information in your standard app pattern. In CodeIgniter, the is_https() function checks the value of X_FORWARDED_PROTO
by default.
Customize php.ini settings
If you need to make changes to your PHP installation, you can change any of the php.ini directives by using the following steps.
Note
The best way to see the PHP version and the current php.ini
configuration is to call phpinfo()
in your app.
Customize non-PHP_INI_SYSTEM directives
To customize PHP_INI_USER
, PHP_INI_PERDIR
, and PHP_INI_ALL
directives, add a .user.ini
file to the root directory of your app.
Add configuration settings to the .user.ini
file by using the same syntax that you would use in a php.ini
file. For example, if you wanted to turn on the display_errors
setting and set the upload_max_filesize
setting to 10M
, your .user.ini
file would contain this text:
; Example Settings
display_errors=On
upload_max_filesize=10M
; Write errors to d:\home\LogFiles\php_errors.log
; log_errors=On
Redeploy your app with the changes and restart it.
As an alternative to using a .user.ini
file, you can use ini_set()
in your app to customize these non-PHP_INI_SYSTEM
directives.
To customize PHP_INI_USER
, PHP_INI_PERDIR
, and PHP_INI_ALL
directives for Linux web apps, such as upload_max_filesize
and expose_php
, use a custom .ini file. You can create it in an SSH session. First, set up the directory:
- Go to your Kudu site:
https://<sitename>.scm.azurewebsites.net
. - On the top menu, select Bash or SSH.
- In Bash or SSH, go to your
/home/site/wwwroot
directory. - Create a directory called
ini
(for example,mkdir ini
). - Change the current working directory to the
ini
folder that you just created.
Now, create an .ini file where you'll add your settings. This example uses extensions.ini
. There are no file editors such as Vi, Vim, or Nano, so use Echo to add the settings to the file. Change the upload_max_filesize
value from 2M
to 50M
. Use the following command to add the setting and create an extensions.ini
file if one doesn't already exist:
/home/site/wwwroot/ini>echo "upload_max_filesize=50M" >> extensions.ini
/home/site/wwwroot/ini>cat extensions.ini
upload_max_filesize=50M
/home/site/wwwroot/ini>
In the Azure portal, add an application setting to scan the ini
directory that you just created to apply the change for upload_max_filesize
:
- Go to the Azure portal and select your App Service Linux PHP application.
- Under Application settings, select + Add new setting.
- For the app setting name, enter
PHP_INI_SCAN_DIR
. For the value, enter:/home/site/wwwroot/ini
. - Select Save.
Note
If you recompiled a PHP extension, such as GD, follow the steps at Recompiling PHP extensions.
Customize PHP_INI_SYSTEM directives
To customize PHP_INI_SYSTEM
directives, use the PHP_INI_SCAN_DIR
app setting.
First, run the following command in Cloud Shell to add an app setting called PHP_INI_SCAN_DIR
:
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings PHP_INI_SCAN_DIR="d:\home\site\ini"
Go to the Kudu console (https://<app-name>.scm.azurewebsites.net/DebugConsole
), and then go to d:\home\site
.
Create a directory in d:\home\site
called ini
. Then, create an .ini file in the d:\home\site\ini
directory (for example, settings.ini
) with the directives that you want to customize. Use the same syntax that you would use in a php.ini
file.
For example, to change the value of expose_php
, run the following commands:
cd /home/site
mkdir ini
echo "expose_php = Off" >> ini/setting.ini
For the changes to take effect, restart the app.
To customize PHP_INI_SYSTEM
directives, you can't use the .htaccess
approach. App Service provides a separate mechanism that uses the PHP_INI_SCAN_DIR
app setting.
First, run the following command in Cloud Shell to add an app setting called PHP_INI_SCAN_DIR
:
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings PHP_INI_SCAN_DIR="/usr/local/etc/php/conf.d:/home/site/ini"
The value /usr/local/etc/php/conf.d
is the default directory where php.ini
exists. The value /home/site/ini
is the custom directory in which you'll add a custom .ini file. You separate the values with a colon (:
).
Go to the web SSH session with your Linux container (https://<app-name>.scm.azurewebsites.net/webssh/host
).
Create a directory in /home/site
called ini
. Then, create an .ini file in the /home/site/ini
directory (for example, settings.ini
) with the directives that you want to customize. Use the same syntax that you would use in a php.ini
file.
Tip
The built-in Linux containers in App Service use /home
as persisted shared storage.
For example, to change the value of expose_php
, run the following commands:
cd /home/site
mkdir ini
echo "expose_php = Off" >> ini/setting.ini
For the changes to take effect, restart the app.
Enable PHP extensions
The built-in PHP installations contain the most commonly used extensions. You can enable additional extensions in the same way that you customize php.ini directives.
Note
The best way to see the PHP version and the current php.ini
configuration is to call phpinfo()
in your app.
To enable additional extensions, use the following steps:
Add a
bin
directory to the root directory of your app, and put the.dll
extension files in it (for example,mongodb.dll
). Make sure that the extensions are compatible with the PHP version in Azure, and that they're VC9 and non-thread-safe (NTS) compatible.Deploy your changes.
Follow the steps in Customize PHP_INI_SYSTEM directives, and add the extensions into the custom .ini file with the extension or zend_extension directive:
extension=d:\home\site\wwwroot\bin\mongodb.dll zend_extension=d:\home\site\wwwroot\bin\xdebug.dll
For the changes to take effect, restart the app.
The built-in PHP installations contain the most commonly used extensions. You can enable additional extensions in the same way that you customize php.ini directives.
Note
The best way to see the PHP version and the current php.ini
configuration is to call phpinfo()
in your app.
To enable additional extensions, use the following steps:
Add a
bin
directory to the root directory of your app, and put the.so
extension files in it (for example,mongodb.so
). Make sure that the extensions are compatible with the PHP version in Azure, and that they're VC9 and non-thread-safe (NTS) compatible.Deploy your changes.
Follow the steps in Customize PHP_INI_SYSTEM directives, and add the extensions into the custom .ini file with the extension or zend_extension directive:
extension=/home/site/wwwroot/bin/mongodb.so zend_extension=/home/site/wwwroot/bin/xdebug.so
For the changes to take effect, restart the app.
Access diagnostic logs
Use the standard error_log()
tool to make your diagnostic logs appear in Azure App Service.
To access the console logs generated from inside your application code in App Service, turn on diagnostic logging by running the following command in Cloud Shell:
az webapp log config --resource-group <resource-group-name> --name <app-name> --docker-container-logging filesystem --level Verbose
Possible values for --level
are Error
, Warning
, Info
, and Verbose
. Each subsequent level includes the previous level. For example, Error
includes only error messages. Verbose
includes all messages.
After you turn on diagnostic logging, run the following command to see the log stream:
az webapp log tail --resource-group <resource-group-name> --name <app-name>
If console logs don't appear immediately, check again in 30 seconds.
Note
You can also inspect the log files from the browser at https://<app-name>.scm.azurewebsites.net/api/logs/docker
.
To stop log streaming at any time, select Ctrl+C.
You can access the console logs generated from inside the container.
To turn on container logging, run the following command:
az webapp log config --name <app-name> --resource-group <resource-group-name> --docker-container-logging filesystem
Replace <app-name>
and <resource-group-name>
with names that are appropriate for your web app.
After you turn on container logging, run the following command to see the log stream:
az webapp log tail --name <app-name> --resource-group <resource-group-name>
If console logs don't appear immediately, check again in 30 seconds.
To stop log streaming at any time, select Ctrl+C.
You can also inspect the log files in a browser at https://<app-name>.scm.azurewebsites.net/api/logs/docker
.
Troubleshoot
When a working PHP app behaves differently in App Service or has errors, try the following solutions:
- Access the log stream.
- Test the app locally in production mode. App Service runs your app in production mode, so you need to make sure that your project works as expected in production mode locally. For example:
- Depending on your
composer.json
file, different packages might be installed for production mode (require
versusrequire-dev
). - Certain web frameworks might deploy static files differently in production mode.
- Certain web frameworks might use custom startup scripts when running in production mode.
- Depending on your
- Run your app in App Service in debug mode. For example, in Laravel, you can configure your app to output debug messages in production by setting the
APP_DEBUG
app setting totrue
.
Ignore the robots933456 message in logs
You might see the following message in the container logs:
2019-04-08T14:07:56.641002476Z "-" - - [08/Apr/2019:14:07:56 +0000] "GET /robots933456.txt HTTP/1.1" 404 415 "-" "-"
You can safely ignore this message. /robots933456.txt
is a dummy URL path that App Service uses to check if the container is capable of serving requests. A 404 response indicates that the path doesn't exist, and it signals to App Service that the container is healthy and ready to respond to requests.