How to setup Nginx to run PHP/Laravel API with frontend app on same domain
There are multiple ways of deploying this kind of applications and here I will describe my way of doing it. Lately, many applications separate frontend and backend parts so we can observe them as two projects. We could have Laravel API and Angular/React/Vue on the other side. If we have this project structure then our frontend (eg. Vue) is purely static app. Running npm run build
is going to generate dist
directory which contains our entire application which we can then serve using Web server.
As for the PHP part, we want to use FastCGI Process Manager (FPM). This is a topic in itself but in short FPM will handle PHP files much more efficiently and thus improve performance and enable a higher load.

Many developers will serve frontend part on www.example.com and backend part on www.api-example.com. This is pretty simple to configure but when I wanted to serve Vue app on www.example.com and my API on www.example.com/api I ran into some problems. If you just bought server and don’t have a domain yet, this is the way you can deploy your app. After some time this is the configuration I decided to use
server {
listen 80;
server_name 147.242.153.77; # fake IP address
root /home/myfolder/example/html; #path to static directory add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff"; index index.html index.htm index.php;
charset utf-8; location / {
try_files $uri $uri/ /index.html;
} location /api {
alias /home/myfolder/example-api/public;
try_files $uri $uri/ @laravelapi;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}location @laravelapi {
rewrite /api/(.*)?$ /api/index.php?$is_args$args last;
}location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }error_page 404 /index.php;location ~ /\.(?!well-known).* {
deny all;
}
}
We set root directive to our frontend app. Every request is going to hit our first location block if it doesn’t start with /api
and it is going to execute index.html
from Vue static directory.
Request made for /api/users
is a little bit more complicated. It is going to hit second location block. Then we are using alias to set correct path to our API.
Note: alias
directive doesn’t append the location part. If we used root
instead it would try to access /home/myfolder/example-api/public/api
and that is not what we want.
The try_files
means when you receive a URI that's matched by this block try $uri
first, eg. /api/images/image.jpg
, Nginx will try to serve image.jpg
file inside /home/myfolder/example-api/public/images
. Then it will try to serve whole folder /images
.
Last option is a fallback option which will redirect request to the named location @laravelapi
. Inside this block we will rewrite /api/users
into /api/index.php
.
Flag last
stops processing the current set of ngx_http_rewrite_module
directives and starts a search for a new location matching the changed URI.
Because of the new URI /api/index.php
, this time we will finally hit regex location block ~ \.php$
that is going to pass processing of the /home/myfolder/example-api/public/index.php
script to FPM.
IMPORTANT: With this configuration our Laravel application is deployed on 147.242.153.77/api
so we can remove route prefix /api
from Laravel’s RouteServiceProvider.php
. If we hadn’t done that we would need to send requests to /api/api/users
to get a response, otherwise we would get 404.