

I recently tried to deploy a statically generated site to an Azure Web App / App Service based on Linux. Because Linux Web Apps do not offer a runtime stack specifically for static files, I chose the PHP stack instead. It is the only runtime stack that can just serve files without any configuration… or so I thought. I immediately ran into trouble. My static pages would sometimes take seconds to load, redirecting to a URL with a port number in it: https://staticsite.com:8080/subfolder/
and displaying a ERR_CONNECTION_TIMED_OUT
error page.
After some testing, I discovered that this only happened for urls without trailing slash. For example: https://staticsite.com/subfolder/
would navigate to the intended page without problems. It was https://staticsite.com/subfolder
the problems occurred with. So what’s going on here? And how can it be fixed?
The PHP runtime stack can serve static files without configuration
Why this is happening
The problem occurs because of a (mis)configuration of Nginx. Nginx is the webserver that’s being used with the PHP 8 runtime stack. And it’s running / listening to traffic, using the 8080 port. You can check this out by opening the Web SSH Console from Azure and running nginx -T
. This will show the entire Nginx server configuration:
Using the Web SSH Console you can view the Nginx server configuration
The server configuration looks more or less as follows:
server {
listen 8080;
listen [::]:8080;
root /home/site/wwwroot;
index index.php index.html index.htm;
#...omitted for brevity
}
A great explanation of what is happening can be found here. It turns out that Nginx by default uses absolute urls for redirecting users. This is what happens when a user accesses a url without a trailing slash: Nginx tries to redirect the user, but uses an absolute url, even including the port number. This is apparently problematic on app services, possibly because they are running behind a load balancing mechanism by default and/or don’t open up port 8080 to the outside world.
However the precise mechanics of App Service Architecture, the absolute redirect fails.
Fortunately, this problem can be solved.
Solution #1
Of course this is more of a workaround, but you can configure the Linux app service to use the PHP 7 runtime stack. This runtime stack uses an Apache webserver instead of the Nginx one, and does not have this specific issue.
Solution #2
The more interesting solution would be to change the Nginx configuration itself. This is harder than it would seem. You cannot just add a config file to your site root, like you would add a web.config
or .htaccess
file.
You could get to the configuration file using SSH, but it’s located in a subfolder of the linux rootsystem /etc/nginx
, where changes to the files do not get persisted. Every time the app service restarts, the configuration files would be reset. (Changes are only persisted in the /home/
part, where the actual website files are stored.)
So how can we change the config? We can do so by letting the app service execute a script for us, on app service startup. This blog tought me how to do it..
So what I did was the following:
Step 1
I created a bash script in VS code that uses the sed
string replace tool to insert the absolute_redirect off;
statement into the Nginx configuration file. Next, it instructs Nginx to reload the configuration. The code looks as follows:
#!/bin/bash
echo "[CUSTOM STARTUP SCRIPT] Fixing trailing slash issue by adapting Nginx configuration file"
replace="server {"
replaceWith="server { absolute_redirect off;"
sed -i "s/${replace}/${replaceWith}/g" /etc/nginx/sites-available/default
echo "[CUSTOM STARTUP SCRIPT] Reloading nginx to apply new configuration"
service nginx reload
default
is the configuration file and sed -i
does an in place string replace. So it updates the file where it resides. As you can see, I’m updating the file in the sites-available
folder. When running nginx -T
in the SSH console, you’ll see the Nginx config file originating from the sites-enabled
folder. This folder is symlinked to the sites-available
folder, so the sites-enabled/default
file will show the updated config as well. Running nginx -T
after the startup confirms this.
Step 2
I then uploaded the script to the root folder of my site, using my existing Azure Pipeline.
Step 3
The last step was to reference the script as startup command:
My startup command:
/bin/bash /home/site/wwwroot/startup_script.sh
Using the Log stream in the Azure portal I could see that my script executed just fine, also when restarting the app service.
Conclusion
It’s a strange issue, and I hope the Azure team will fix it soon. But using the startup command is actually quite flexible, and gives you a lot of options to edit the configuration files a bit.
I can now safely use urls without trailing slashes! Plus I learned a lot diving into this.
Happy coding!
Sources
webapp linux nginx
Support me by sharing this
More
More blogs

Creating a beautiful documentation site with MkDocs
MkDocs is a great tool to create straightforward documentation sites. It's 1 of 2 static site generators I've recently worked with.
Read more
Fixing an Azure web app zip deployment issue
My Azure DevOps pipeline recently stopped zipdeploying to Azure App Service. This is how I fixed it.
Read more
Quick tip: how to deploy to web app subfolders
A quick tip on the possibilities of deploying to web app subfolders in Azure DevOps pipelines.
Read moreThanks
Thanks for reading

Thanks for reading my blog, I hope you got what you came for. Blogs of others have been super important during my work. This site is me returning the favor. If you read anything you do not understand because I failed to clarify it enough, please drop me a post using my socials.
Warm regards,
Martin
Microsoft MVP | Microsoft 365 Architect