3. Deploy PHP Blob Storage App to Azure Virtual Machine
Introduction
In this tutorial, we’ll deploy the PHP web application from Exercise 2 to an Azure Virtual Machine. This exercise builds on the previous one where we created a PHP app to display images from Azure Blob Storage. Now we’ll provision an Azure VM and deploy our application to make it accessible over the internet.
Prerequisites
- Completed Exercise 2 (PHP Blob Storage App)
- An Azure account with an active subscription
- Basic understanding of Linux and SSH
- Your PHP application code from Exercise 2
Step 1: Prepare Your Application for Deployment
First, ensure your PHP application is ready for deployment with proper environment configuration.
Configure environment variables
In your local blob-storage-php directory, update your .env file with your actual Azure Storage
connection string:
# Azure Blob Storage Configuration
AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=yourstorageaccount;AccountKey=yourkey;EndpointSuffix=core.windows.net"
AZURE_STORAGE_CONTAINER_NAME="imagerepository"
Important: Replace the connection string with your actual values from Exercise 2.
Create cloud-init configuration
Create a cloud-init file that will automatically configure the VM during provisioning:
cloud-init.yaml
#cloud-config
package_update: true
package_upgrade: true
packages:
- php
- php-cli
- php-curl
- php-json
- php-mbstring
- php-xml
- php-fpm
- nginx
- curl
write_files:
- path: /etc/nginx/sites-available/blobapp
content: |
server {
listen 80;
server_name _;
root /var/www/blobapp;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
runcmd:
# Wait for package manager to finish and ensure PHP is available
- until command -v php >/dev/null 2>&1; do sleep 5; done
- systemctl start php8.1-fpm || systemctl start php-fpm
# Install Composer with proper environment
- cd /tmp && curl -sS https://getcomposer.org/installer | COMPOSER_HOME=/root php
- mv /tmp/composer.phar /usr/local/bin/composer
- chmod +x /usr/local/bin/composer
# Create web directory
- mkdir -p /var/www/blobapp
- chown -R www-data:www-data /var/www/blobapp
- chmod -R 755 /var/www/blobapp
# Configure Nginx
- rm /etc/nginx/sites-enabled/default
- ln -s /etc/nginx/sites-available/blobapp /etc/nginx/sites-enabled/blobapp
- systemctl restart nginx
- systemctl enable nginx
- systemctl restart php8.1-fpm
- systemctl enable php8.1-fpm
Step 2: Create Azure Virtual Machine via Portal
Create a Virtual Machine
Navigate to Virtual Machines
- Go to the Azure Portal
- Search for “Virtual machines” and select it
Create new VM
- Click + Create → Virtual machine
Configure Basic Settings
- Subscription: Select your subscription
- Resource group: Create new →
blob-app-rg - Virtual machine name:
blob-app-vm - Region: Choose a region close to you
- Image:
Ubuntu Server 22.04 LTS - x64 Gen2 - Size:
Standard_B1s(1 vCPU, 1 GB RAM - sufficient for demo)
Configure Administrator Account
- Authentication type: SSH public key
- Username:
azureuser - SSH public key source: Use existing public key stored in Azure
- SSH public key: Paste your existing public key (from
~/.ssh/id_rsa.pub)
Configure Inbound Port Rules
- Public inbound ports: Allow selected ports
- Select inbound ports: SSH (22), HTTP (80)
Advanced Settings
- Click Advanced tab
- Custom data: Copy and paste the contents of your
cloud-config.yamlfile
Review and Create
- Click Review + create
- Click Create
Wait for Deployment
The VM creation process will take 3-5 minutes. Cloud-init will automatically install and configure all required software. Once complete:
- Note the Public IP address from the VM overview page
- Wait an additional 2-3 minutes for cloud-init to complete the setup
Alternative: Create VM with Azure CLI
If you prefer using the command line, you can create the VM using Azure CLI instead of the portal.
Prerequisites for CLI deployment
Ensure you have:
- Azure CLI installed (
az --versionto check) - Logged in to Azure (
az login) - SSH key pair generated (
ssh-keygen -t rsaif needed)
Create deployment script
Create a file called deploy-blob-vm.sh:
#!/bin/bash
# Configuration
RESOURCE_GROUP="blob-app-rg"
LOCATION="northeurope"
VM_NAME="blob-app-vm"
ADMIN_USER="azureuser"
echo "Creating resource group..."
az group create \
--name $RESOURCE_GROUP \
--location $LOCATION
echo "Creating virtual machine..."
az vm create \
--resource-group $RESOURCE_GROUP \
--name $VM_NAME \
--image Ubuntu2204 \
--size Standard_B1s \
--admin-username $ADMIN_USER \
--generate-ssh-keys \
--custom-data cloud-init.yaml
echo "Opening HTTP port 80..."
az vm open-port \
--resource-group $RESOURCE_GROUP \
--name $VM_NAME \
--port 80
echo "Getting public IP address..."
PUBLIC_IP=$(az vm show \
--resource-group $RESOURCE_GROUP \
--name $VM_NAME \
--show-details \
--query 'publicIps' \
--output tsv)
echo "Deployment completed!"
echo "Website: http://$PUBLIC_IP"
echo "SSH: ssh $ADMIN_USER@$PUBLIC_IP"
echo ""
echo "Note: Wait 2-3 minutes for cloud-init to complete setup"
echo "To cleanup: az group delete --name $RESOURCE_GROUP --yes"
Run the deployment
Make the script executable and run it:
chmod +x deploy-blob-vm.sh
./deploy-blob-vm.sh
The script will:
- Create a resource group
- Create the VM with cloud-init configuration
- Open HTTP port 80
- Display the public IP address
Step 3: Verify VM Configuration
Check cloud-init status
Connect to your VM to verify the automatic setup completed successfully:
ssh azureuser@YOUR_VM_PUBLIC_IP
Check cloud-init status:
# Check if cloud-init finished
sudo cloud-init status
# View cloud-init logs if needed
sudo tail -f /var/log/cloud-init-output.log
Step 4: Deploy Your PHP Application
Create local deployment script
Create a local deployment script that will copy files and execute all commands remotely. On your local machine, create deploy-app.sh:
#!/bin/bash
# Configuration
VM_IP="YOUR_VM_PUBLIC_IP"
VM_USER="azureuser"
echo "Starting application deployment to $VM_IP..."
# Copy application files directly to VM /tmp directory
echo "Copying application files to VM..."
scp composer.json index.php .env $VM_USER@$VM_IP:/tmp/
# Execute deployment commands on VM via SSH
echo "Executing deployment commands on VM..."
ssh $VM_USER@$VM_IP << 'EOF'
echo "Verifying staged files in /tmp..."
ls -la /tmp/{composer.json,index.php,.env}
echo "Copying files to web directory..."
sudo cp /tmp/composer.json /tmp/index.php /tmp/.env /var/www/blobapp/
echo "Installing PHP dependencies..."
cd /var/www/blobapp
sudo COMPOSER_ALLOW_SUPERUSER=1 composer install --no-interaction --optimize-autoloader
echo "Setting file permissions..."
sudo chown -R www-data:www-data /var/www/blobapp
sudo chmod -R 755 /var/www/blobapp
echo "Cleaning up temporary files..."
rm -f /tmp/composer.json /tmp/index.php /tmp/.env
echo "Restarting web services..."
sudo systemctl restart nginx
sudo systemctl restart php8.1-fpm
echo "Application deployment completed!"
echo "Your app should now be available at: http://$(curl -s ifconfig.me)"
EOF
echo "Deployment script finished!"
Execute the deployment
Update the script with your VM IP:
# Edit the script and replace YOUR_VM_PUBLIC_IP with actual IP nano deploy-app.shMake script executable and run it:
chmod +x deploy-app.sh ./deploy-app.sh
Manual deployment alternative
If you prefer to run commands manually:
# Upload files to VM using scp
scp composer.json index.php .env azureuser@YOUR_VM_PUBLIC_IP:/tmp/
# Connect to VM
ssh azureuser@YOUR_VM_PUBLIC_IP
# Create application directory and copy files
sudo mkdir -p /var/www/blobapp
sudo cp /tmp/composer.json /tmp/index.php /tmp/.env /var/www/blobapp/
# Install dependencies and set permissions
cd /var/www/blobapp
sudo COMPOSER_ALLOW_SUPERUSER=1 composer install --no-interaction --optimize-autoloader
sudo chown -R www-data:www-data /var/www/blobapp
sudo chmod -R 755 /var/www/blobapp
# Clean up and restart services
rm -f /tmp/composer.json /tmp/index.php /tmp/.env
sudo systemctl restart nginx
sudo systemctl restart php8.1-fpm
exit
Note: Your .env file already contains the correct Azure Storage connection string from Step 1.
Step 5: Test Your Deployment
Verify the application
Test locally on the VM:
ssh azureuser@YOUR_VM_PUBLIC_IP "php -f /var/www/blobapp/index.php"Access via web browser:
- Open your browser
- Navigate to
http://YOUR_VM_PUBLIC_IP - You should see your image gallery displaying images from Azure Blob Storage
Troubleshooting
If the application doesn’t work:
Check Nginx logs:
ssh azureuser@YOUR_VM_PUBLIC_IP "sudo tail -f /var/log/nginx/error.log"Check PHP-FPM logs:
ssh azureuser@YOUR_VM_PUBLIC_IP "sudo tail -f /var/log/php8.1-fpm.log"Test PHP processing:
ssh azureuser@YOUR_VM_PUBLIC_IP "echo '<?php phpinfo(); ?>' | sudo tee /var/www/blobapp/info.php" # Visit: http://YOUR_VM_PUBLIC_IP/info.phpVerify file permissions:
ssh azureuser@YOUR_VM_PUBLIC_IP "ls -la /var/www/blobapp/"
Step 6: Test and Verify
Verify all components
- VM is running: Check in Azure Portal
- Nginx is serving:
curl http://YOUR_VM_PUBLIC_IP - PHP is processing: Visit your app URL
- Images are loading: Check that images from Azure Blob Storage display correctly
Performance check
Test your application:
- Load time of the main page
- Image loading from Azure Blob Storage
- Responsive design on different devices
Conclusion
You’ve successfully deployed a PHP web application to an Azure Virtual Machine! This exercise demonstrated:
- VM provisioning through Azure Portal
- Linux server configuration and software installation
- PHP application deployment with Nginx
- Integration with Azure Blob Storage from a cloud-hosted application
Your application is now running on Azure infrastructure and accessible via the internet, displaying images stored in Azure Blob Storage.
Don’t Forget
Azure VMs incur costs while running. Delete resources when not needed to avoid unexpected charges.