How to Run a Laravel Application With Reverb in an Azure Web App

We’ve been building a lot more Laravel applications over the past few years at Cypress North. Our software engineers find the platform to be very efficient and robust, and it’s increasingly becoming a good fit for our clients' custom software development needs.
When it’s time to deploy a Laravel application to production, we frequently work within our clients' preferred cloud hosting provider, and Microsoft Azure is a common landing spot. Whenever possible, we try to deploy applications to a managed app service rather than a virtual machine in order to gain cost savings and increased scalability. This also helps avoid having to manage and maintain an underlying operating system.
Deploying a Laravel application to an Azure web app (formerly named App Service) works great, but the necessary configuration is a little non-obvious, especially when considering the Laravel worker queue and Laravel Reverb.
Let me walk you through how to configure an Azure web app to host your Laravel + Reverb application with an Azure Flexible MySQL Database.
Table of Contents
Configure Your Web App for Laravel and Reverb
- Deploy Your Code
- Configure Your .env File
- Install PHP Composer
- Run Composer Install On Your Project
- Scaffold Your Database
- Configure Nginx for Laravel
- Configure Reverb
- Configure a Startup Script
Create Azure Resources
Start by creating a new resource group for your project (if needed.) Resource groups are a way to bundle services together for billing and organizational purposes.
- In your resource group, click on + Create to add services to the group
- From the Marketplace screen, search for "web app" (filter to Azure services only if you don’t see it) and choose create
- Fill in an instance name, which will form the Azure URL for your application
- Under Publish, choose the Code option
- Under Runtime stack, choose PHP 8.3 or whatever the current fit is for your application
- Under Operating System, choose Linux
- Set your Region for Azure deployment
- Under Pricing Plans -> Linux Plan, click Create New and give your plan a name
- Under Pricing Plans -> Pricing Plan, choose your app service power/plan
- Click Next: Database >
- Click on Create a Database and choose MySQL - Flexible Server
- Set your MySQL Server name, and set your Database name to the name of the database you want to use for your app
- Click Next: Deployment >
- Enable Basic Authentication, and optionally configure Continuous Deployment. (In this example, I will use a local Git deployment. But in production, we often use Continuous Deployment, which will automatically deploy your project from GitHub when you commit to your selected branch.)
- Click Next: Networking >
- Enable public access
- Click Review & Create >
- Scroll to the bottom and copy your database username and password into a notepad for use in your application
- Click Create
Once your resources have deployed, you should be able to reach your app server using the <app-name>.azurewebsites.net domain name and get the default webpage.
Configure your Web App for Laravel and Reverb
Next, you want to hop into the terminal. When running an Azure web app, the easiest way to access SSH is using the web terminal that you can launch from the development tools menu of your web app resource. If you prefer, you can use the Azure CLI and TCP tunneling to connect using your local system.
Pay attention to this note! Anything you change that is not inside the /home directory will be reverted to its default state any time the web app is restarted. An Azure web app can restart randomly, and will also restart if you set up Continuous Deployment and a deployment occurs.
You cannot count on ANY changes to the system persisting until you have completed the automated startup configurations which I’ll cover.
The default site directory (which will be persisted) is at /home/site/wwwroot
Deploy Your Code
The first thing we’ll do is load our Laravel project into the /home/site/wwwroot directory. For this example, I’m going to clone my project using Git. But first, we have to install Git.
Run the following commands to install Git:
apt update
apt install git
Move to the web directory and clone your project:
cd /home/site/wwwroot
git clone <your repository url>
This will clone your project into a new directory, so you need to move the files up a level so they are in the wwwroot directory.
mv <your project folder>/{.,}* ../
Confirm all of your files have been moved (including hidden files) then clean up:
rmdir <your project folder>
rm hostingstart.html
Configure Your .env File
Now that your code is deployed, you’ll need to set up your .env file for this environment. Open or create your .env file and update the necessary app settings to match your new Azure environment.
For the moment, set your APP_URL (and ASSET_URL if needed) to your new Azure hostname which you can find on the overview page of the web app.
Then update your database app settings to match your new Azure MYSQL flexible server. You can get the hostname from the overview tab of your DB server resource, and the username and password that you saved when you created the database and server.
Install PHP Composer
While it's not technically necessary if you take the right steps, or depending on your workflow, you’ll often need composer on the server to install the project dependencies.
I like to create a folder inside the /home/site directory called ext which will hold my system files that I’ll need to set up the web app instance on each startup.
mkdir /home/site/ext
cd /home/site/ext
Now we’ll pull down the composer installer and execute it.
wget https://getcomposer.org/installer
php installer
This will create the composer.phar file in your ext directory. It’s not currently findable by the system in this location, however, so we need to copy it into the /usr/local/bin directory.
cp composer.phar /usr/local/bin/composer
Now you can run composer like you normally would.
Run Composer Install on Your Project (If Needed)
Now that we’ve installed composer on the system, you can run it on your project to install any dependencies.
cd /home/site/wwwroot
composer install
Scaffold Your Database
Scaffold your database using artisan, seeding it with data if you need to.
php artisan migrate –seed
When doing this you may get the following error:
Connections using insecure transport are prohibited while –require_secure_transport=ON.
To get past this quickly, you can go to your MYSQL resource, and go to the Settings -> Server Parameters page. On page 2 of the parameters, you’ll find the setting “require_secure_transport” which you can set to OFF and then save. Running the migrate command again will succeed.
Configure Nginx for Laravel
The default Nginx configuration is set up for generic PHP but not for Laravel specifically. You’ll need to modify the default host file for Nginx, but since this is a system file, we’ll want to do this in a copy of the host file inside our ext directory.
First, we’ll copy the default host file from the system Nginx directory to our ext folder.
cp /etc/nginx/sites-enabled/default /home/site/ext
Now we can edit our copy to look like the following (replacing your specific hostname in the server_name)
server {
#proxy_cache cache;
#proxy_cache_valid 200 1s;
listen 8080;
listen [::]:8080;
root /home/site/wwwroot/public;
index index.php index.html index.htm;
server_name laravel-demo.azurewebsites.net;
port_in_redirect off;
location / {
index index.php index.html index.htm hostingstart.html;
try_files $uri $uri/ /index.php?$args;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /html/;
}
# Disable .git directory
location ~ /\.git {
deny all;
access_log off;
log_not_found off;
}
# Add locations of phpmyadmin here.
location ~* [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.[Pp][Hh][Pp])(|/.*)$;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 3600;
fastcgi_read_timeout 3600;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
}
Copy this host file back into the system directory and restart Nginx.
cp /home/site/ext/default /etc/nginx/sites-enabled
service nginx restart
You should now be able to load your Laravel application on your Azure domain, although Reverb will not be working yet.
Configure Reverb
This is where things can get frustrating without some guidance. The Laravel Reverb Docs give you some instructions that work great for a virtual machine but do not work on an Azure web app. This has to do with the nature of an Azure app service, and the fact that you aren’t in control of fully managing it.
Problem 1: You can’t use port 8080 because that is reserved for your actual website
Problem 2: It’s unclear what is happening in Azure with the ports and reverse proxy
Problem 3: The .env app settings can be confusing
Reverb has two parts:
- A client script that runs on the browser and creates a WebSocket connection to your server
- A server process that listens for WebSocket requests from the client, usually on a non-public port
In an Azure web app, the ONLY ports that a client can connect to are 80 and 443. This means that you have to proxy WebSocket requests to the internal port that Reverb is listening on, but only for the specific requests that matter to Reverb.
The first thing we need to do is set our application .env file with the right app settings for Reverb.
The first set of app settings is for the client.
You’ll want to set the REVERB_HOST to your application hostname (without a protocol)
Set the REVERB_PORT=443
Set the REVERB_SCHEME=https
Then we need to set the Reverb Server settings.
Set the REVERB_SERVER_HOST=127.0.0.1
Set the REVERB_SERVER_PORT=8123
The port can be different as long as it’s available and is not a reserved port [80,443,8080]
Now we need to figure out how to proxy a Reverb request from port 443, which is automatically proxied to port 8080 already, to Reverb on port 8123.
To do this, we need to modify our Nginx host file again and add two new location blocks. I was thankful to have found the location block configurations needed thanks to a blog post by Arifia Kasastra on Medium: How to set up Nginx for Laravel Reverb — The Laravel’s Websocket Server
Open up the Nginx configuration file at /home/site/ext/default for editing. Update the file to look like the following (adjusting your server_name and Reverb port if needed):
server {
#proxy_cache cache;
#proxy_cache_valid 200 1s;
listen 8080;
listen [::]:8080;
root /home/site/wwwroot/public;
index index.php index.html index.htm;
server_name laravel-demo.azurewebsites.net;
port_in_redirect off;
location / {
index index.php index.html index.htm hostingstart.html;
try_files $uri $uri/ /index.php?$args;
}
# Laravel Reverb
# The Websocket Client/Laravel Echo would connect and listen to this
location ~ /app/(?<reverbkey>.*) { # variable reverbkey
proxy_pass http://127.0.0.1:8123/app/$reverbkey;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
# The Laravel Backend would broadcast to this
location ~ ^/apps/(?<reverbid>[^/]+)/events$ { # variable reverbid
proxy_pass http://127.0.0.1:8123/apps/$reverbid/events;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /html/;
}
# Disable .git directory
location ~ /\.git {
deny all;
access_log off;
log_not_found off;
}
# Add locations of phpmyadmin here.
location ~* [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.[Pp][Hh][Pp])(|/.*)$;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 3600;
fastcgi_read_timeout 3600;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
}
Because Reverb listens for WebSocket requests at /app and for API requests at /apps we need to capture requests to those locations, which also contain a reverbkey or reverbid, and proxy pass them to our Reverb server, which is what the two new blocks do.
Save the file, then copy it into the system Nginx directory and restart Nginx.
cp /home/site/ext/default /etc/nginx/sites-enabled
service nginx restart
You now have a working Laravel + Reverb application on an Azure web app! 🤖 But we’re not done yet.
Great, we’ve got everything up and running. The last thing we need to do is automate our configuration so that it persists through reboots.
Configure a Startup Script
By configuring a startup shell script, we can reconfigure our app server after a reboot to work in the way we just set up.
First, create a new file called startup.sh inside the /home directory and edit it.
nano /home/startup.sh
We need to do 5 things, but you can add any operation you want to execute on startup to this script:
- Copy composer into the /usr/local/bin directory
- Copy our Nginx config into the system Nginx directory
- Restart Nginx
- Start the Laravel Queue
- Start Reverb
Add these commands to your startup.sh file and save it:
cp /home/site/ext/composer.phar /usr/local/bin/composer
cp /home/site/ext/default /etc/nginx/sites-enabled
service nginx restart
/usr/local/bin/php /home/site/wwwroot/artisan queue:work --daemon &
/usr/local/bin/php /home/site/wwwroot/artisan reverb:start &
And the final thing we need to do is tell our web app to execute this script on boot.
Go to your web app resource in Azure and navigate to the Settings -> Configuration page. In the Startup Command field, enter the path to your script (/home/startup.sh) and press save.
Done!🥳
Your application will now be in a working state that persists through reboots. You can test this by restarting your web app and making sure everything is working as expected.
If you need help with your Laravel applications, or any other software development needs, contact us!
1 Comment
Leave a Reply
Meet the Author

Matthew Mombrea
Matt is our Chief Technology Officer and one of the founders of our agency. He started Cypress North in 2010 with Greg Finn, and now leads our Buffalo office. As the head of our development team, Matt oversees all of our technical strategy and software and systems design efforts.
With more than 19 years of software engineering experience, Matt has the knowledge and expertise to help our clients find solutions that will solve their problems and help them reach their goals. He is dedicated to doing things the right way and finding the right custom solution for each client, all while accounting for long-term maintainability and technical debt.
Matt is a Buffalo native and graduated from St. Bonaventure University, where he studied computer science.
When he’s not at work, Matt enjoys spending time with his kids and his dog. He also likes to golf, snowboard, and roast coffee.
Great blog! I loved that you mentioned all the steps in detail.