Skip to content

Instantly share code, notes, and snippets.

@tsolar
Last active October 9, 2024 01:24
Show Gist options
  • Save tsolar/8d45ed05bcff8eb75404 to your computer and use it in GitHub Desktop.
Save tsolar/8d45ed05bcff8eb75404 to your computer and use it in GitHub Desktop.
Laravel in subdirectory nginx example
server {
client_body_in_file_only clean;
client_body_buffer_size 32K;
client_max_body_size 300M;
sendfile on;
send_timeout 300s;
# Port that the web server will listen on.
#listen 80;
# Host that will serve this project.
server_name tsolar.com;
# Useful logs for debug.
access_log /var/log/nginx/tsolar.com-access.log;
error_log /var/log/nginx/tsolar.com-error.log;
rewrite_log on;
# The location of our projects public directory.
root /home/tom/public_html/demos/;
# Point index to the Laravel front controller.
index index.php;
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
access_log off;
expires max;
}
location / {
# URLs to attempt, including pretty ones.
try_files $uri $uri/ /index.php?q=$uri&$args;
}
# Remove trailing slash to please routing system.
if (!-d $request_filename) {
rewrite ^/(.+)/$ /$1 permanent;
}
# version 1
location ^~ /demo1 {
alias /home/tom/public_html/demos/demo1/public;
try_files $uri $uri/ @demo1;
location ~* \.php {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(.*)$;
include /etc/nginx/fastcgi_params;
}
}
location @demo1 {
rewrite ^/demo1/(.*)$ /demo1/index.php/$1 last; # THIS IS THE IMPORTANT LINE
}
# end version 1
# version 2
# this is with `ln -s /home/tom/public_html/demos/demo1/public <document root>/demo1`
location ~ /demo1 {
try_files /demo1/$uri /demo1/$uri/ /demo1/index.php?q=$uri&$args;
}
# end version 2
# PHP FPM configuration.
location ~* \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# We don't need .ht files with nginx.
location ~ /\.ht {
deny all;
}
# Set header expirations on per-project basis
location ~* \.(?:ico|css|js|jpe?g|JPG|png|svg|woff)$ {
expires 365d;
}
}
@iwangrp
Copy link

iwangrp commented Oct 14, 2016

`server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /var/www/html;
# root /var/www/html/laravel/learn_laravel/public;
index index.php index.html index.htm;

server_name localhost;

# version 1
location ^~ /laravel/laravel {
    alias /var/www/html/laravel/laravel/public;
    try_files $uri $uri/ @demo1;

    location ~* \.php {
        # fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        # include /etc/nginx/fastcgi_params;
        include snippets/fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

location @demo1 {
    rewrite ^/laravel/laravel/(.*)$ /laravel/laravel/index.php/$1 last; # THIS IS THE IMPORTANT LINE
}
# end version 1


location / {
    try_files $uri $uri/ =404;
    # try_files $uri $uri/ /index.php?$query_string;
    # include /etc/nginx/naxsi.rules
}

error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
    root /usr/share/nginx/html;
}

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

location ~ /\.ht {
    deny all;
}

}`
if i go to http://blablabla.com/laravel/laravel/public , why output downloading index.php on my public folder laravel

@quetool
Copy link

quetool commented Feb 13, 2017

there is a way to do that with apache??

@phrfpeixoto
Copy link

This causes redirect loop

@manjufy
Copy link

manjufy commented Nov 26, 2017

Yes, causes redirect loop

@SuryaElite
Copy link

I have done that by using below configuration and its working. The above mentioned gist was displaying 404 "Not Found".

  # sub_directory
  location ^~ /sub_directory {  
      alias /var/www/choppies/sub_directory/public;  
      try_files $uri $uri/ @sub_directory;  

      location ~ \.php {  
          include snippets/fastcgi-php.conf;
          fastcgi_pass unix:/run/php/php7.0-fpm.sock; 
          fastcgi_param SCRIPT_FILENAME /var/www/choppies/sub_directory/public/index.php;
      }  
  }  

  location @sub_directory {
      rewrite /sub_directory/(.*)$ /sub_directory/index.php?/$1 last;  
  }
  # end sub_directory

@ucandoit1010
Copy link

@SuryaElite
thank you for your example ! my website is working now !

@CreativeWolf
Copy link

Heya, I tried this, the application works as such, but the routes aren't still pointing to the base directory.

Example:
https://dev.example.com/isms/ - This points to the application correctly

I have this code in the view

<li class="nav-item"><a class="nav-link" href="/about">About</a></li>

and this code in the web.php for the route

Route::get('/about', function () {
        return view('pages.about');
});

When I hover on the browser, instead of pointing to https://dev.example.com/isms/about it points to https://dev.example.com/about

Appreciate any pointers in fixing this.

Thanks

@Loetfi
Copy link

Loetfi commented Oct 27, 2018

good reference

@subtronic
Copy link

@CreativeWolf, for the set link in view, set name for the route and use global function route().
Route::get('/about', function () { return view('pages.about'); })->name('about-page');
And in the view
<li class="nav-item"><a class="nav-link" href="{{route('about-page')}}">About</a></li>

@legoheld
Copy link

legoheld commented Mar 3, 2020

I had one small annoying issue with # version 1:

rewrite ^/demo1/(.*)$ /demo1/index.php/$1 last; # THIS IS THE IMPORTANT LINE

will always pass the matched path in the regex as a query argument to the index.php.
But in laravel this will always add the path as a query string like this: /demo/my/test

// in laravel
url()->full()
// returns 
/demo/my/test?%2Fmy%2Ftest

The laravel index.php does not need the path as an argument. It looks on the Server Request_URI for the path information.
So a routing like this should be enough:

// if you include fastcgi_params;
rewrite ^/demo1/(.*)$ /demo1/index.php last;

// or if you dont have fastcgi_params included
rewrite ^/demo1/(.*)$ /demo1/index.php?$query_string last;

@Verron
Copy link

Verron commented Jul 6, 2020

I had one small annoying issue with # version 1:

rewrite ^/demo1/(.*)$ /demo1/index.php/$1 last; # THIS IS THE IMPORTANT LINE

will always pass the matched path in the regex as a query argument to the index.php.
But in laravel this will always add the path as a query string like this: /demo/my/test

// in laravel
url()->full()
// returns 
/demo/my/test?%2Fmy%2Ftest

The laravel index.php does not need the path as an argument. It looks on the Server Request_URI for the path information.
So a routing like this should be enough:

// if you include fastcgi_params;
rewrite ^/demo1/(.*)$ /demo1/index.php last;

// or if you dont have fastcgi_params included
rewrite ^/demo1/(.*)$ /demo1/index.php?$query_string last;

This comment is so underrated. Just to explain the difference between having the ? and not, fastcgi_params adds a QUERY_STRING for you and it is set to the $query_string variable (found in $_SERVER if you're using PHP), so if you use it, you don't need index.php?. In my case, I was using index.php?/$1 from a serversforhackers.com guide.

Also, make sure the APP_URL has your subdirectory in the path so your url functions like assets/url work properly. My nginx config just in case it helps someone. I am using laravel homestead with a pretty complex app with multiple sub applications.

listen 80;
listen 443 ssl http2;
server_name .example.test;
root "/home/vagrant/code/";

index index.html index.htm index.php;

charset utf-8;

location /app1 {
    alias /home/vagrant/app1/public;
    access_log /var/log/nginx/example.test.app1-access.log;
    error_log /var/log/nginx/example.test.app1-error.log error;

    try_files $uri $uri/ @app1;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $request_filename;
    }
}

location @app1 {
    rewrite /app1/(.*)$ /app1/index.php last; # Remove ?/$1 since fastcgi_params adds query string
}

location /app2 {
    alias /home/vagrant/app2/public;
    access_log /var/log/nginx/example.test.app2-access.log;
    error_log /var/log/nginx/example.test.app2-error.log error;

    try_files $uri $uri/ @app2;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $request_filename;
    }
}

location @app2 {
    rewrite /app2/(.*)$ /app2/index.php last; # Remove ?/$1 since fastcgi_params adds query string
}

# Redirect all other traffic to app1
location / {
    rewrite ^/(.*) /app1/$1 permanent;
}

location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt  { access_log off; log_not_found off; }

access_log /var/log/nginx/example.test-access.log;
error_log  /var/log/nginx/example.test-error.log error;

sendfile off;

location ~ /\.ht {
    deny all;
}

ssl_certificate     /etc/nginx/ssl/example.test.crt;
ssl_certificate_key /etc/nginx/ssl/example.test.key;

@japita-se
Copy link

@Verron
I get
rewrite or internal redirection cycle while internally redirecting to "/index.php",

@ggalvez92
Copy link

I have done that by using below configuration and its working. The above mentioned gist was displaying 404 "Not Found".

  # sub_directory
  location ^~ /sub_directory {  
      alias /var/www/choppies/sub_directory/public;  
      try_files $uri $uri/ @sub_directory;  

      location ~ \.php {  
          include snippets/fastcgi-php.conf;
          fastcgi_pass unix:/run/php/php7.0-fpm.sock; 
          fastcgi_param SCRIPT_FILENAME /var/www/choppies/sub_directory/public/index.php;
      }  
  }  

  location @sub_directory {
      rewrite /sub_directory/(.*)$ /sub_directory/index.php?/$1 last;  
  }
  # end sub_directory

It worked perfectly :) thanks you so much

@n0099
Copy link

n0099 commented Jun 8, 2023

You might need an extra line

fastcgi_param  HTTP_PROXY "";

in the location .php { block to mitigate https://httpoxy.org vulnerabilities.

@jamel3oy
Copy link

thanks you so much

@h136799711
Copy link

h136799711 commented Jan 15, 2024

@Verron
Works For me ,
Laravel 10

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

    root /var/www/html/v2api;
    index index.php index.html;


    location /v2api {
        alias /var/www/html/v2api/public/;
        try_files $uri $uri/  @v2api;

        # location ~* ^/v2api/(.*\.php)$  {
        location ~ \.php$  {
            # fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            fastcgi_param  PATH_INFO $fastcgi_path_info;

            fastcgi_pass v2api:9001;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            # fastcgi_param SCRIPT_FILENAME $request_filename;
            # include fastcgi_params;
        }
    }

    location @v2api {
        rewrite /v2api/(.*)$ /v2api/index.php last;
    }

    location / {
        try_files $uri $uri/ /index.php?s=$uri&$args;
    }

    location ~ \.php {
       add_header 'Access-Control-Allow-Origin' $allow_origin;
       add_header 'e-flag' $allow_origin;
       add_header 'Access-Control-Allow-Credentials' 'true';
       add_header Access-Control-Allow-Methods 'PUT,DELETE,GET, POST, OPTIONS';
       add_header Access-Control-Allow-Headers 'DNT,XO,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';


       if ($request_method = 'OPTIONS') {
         return 204;
       }
        fastcgi_pass v1api:9000;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
        fastcgi_buffer_size 64k;
        fastcgi_buffers 4 64k;
        fastcgi_busy_buffers_size 128k;
        fastcgi_temp_file_write_size 256k;

        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

qapi/api/uptime?a=b

"REQUEST_URI": "/qapi/api/uptime?a=b",
"QUERY_STRING": "a=b",

@susanBuck
Copy link

susanBuck commented Feb 16, 2024

The following config worked for me. Here's a video of it in action: Run Laravel via subdirectories on a Nginx server

server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com;

    root /var/www/main/public;

    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location /admin {
 
        alias /var/www/admin/public;

        try_files $uri $uri/ @admin;

        location ~ \.php$ {
            fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /var/www/admin/public/index.php;
        }
    }

    location @admin {
        # Take any requests that start with /admin/ and rewrite them to /admin/index.php (Laravel’s front controller)
        rewrite /admin/(.*)$ /admin/index.php last;
    }

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    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;
    charset utf-8;
}

@dhanyn10singapay
Copy link

I have done that by using below configuration and its working. The above mentioned gist was displaying 404 "Not Found".

  # sub_directory
  location ^~ /sub_directory {  
      alias /var/www/choppies/sub_directory/public;  
      try_files $uri $uri/ @sub_directory;  

      location ~ \.php {  
          include snippets/fastcgi-php.conf;
          fastcgi_pass unix:/run/php/php7.0-fpm.sock; 
          fastcgi_param SCRIPT_FILENAME /var/www/choppies/sub_directory/public/index.php;
      }  
  }  

  location @sub_directory {
      rewrite /sub_directory/(.*)$ /sub_directory/index.php?/$1 last;  
  }
  # end sub_directory

worked for me, thanks @SuryaElite

@phrfpeixoto
Copy link

As of Aug'24, this worked for me:

server {
    listen       443;
    server_name  www.example.com example.com;

    charset utf-8;

    root /var/www/www.example.com;
    access_log /var/log/nginx/ssl-access.log;
    error_log /var/log/nginx/ssl-error.log;
    rewrite_log on;

    # development settings
    client_max_body_size 50M;
    fastcgi_buffers 8 1600k;
    fastcgi_buffer_size 3200k;
    fastcgi_connect_timeout 300s;
    fastcgi_send_timeout 300s;
    fastcgi_read_timeout 300s;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot
    include snippets/ssl-params.conf;

    location ~ /.well-known {
        allow all;
    }

    location ^~ /laravel {
        alias /application/laravel/public;
        access_log /var/log/nginx/laravel-access.log;
        error_log /var/log/nginx/laravel-error.log error;

        try_files $uri $uri/ @laravel;

        location ~ \.php$ {
            fastcgi_split_path_info ^\/laravel\/((?U).+\.php)(.*)$;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param HTTP_PROXY "";
            fastcgi_param SCRIPT_FILENAME /app/public/$fastcgi_script_name;
            fastcgi_param SCRIPT_NAME /laravel/$fastcgi_script_name;
        }
    }

    location @laravel {
        rewrite /laravel/(.*)$ /laravel/index.php last; # Remove ?/$1 since fastcgi_params adds query string
    }

    ... other stuff for my website ...
}

I had to adapt the examples posted by other users because the FPM daemon is running within a docker container, but nginx is not
And nginx does need access to the files to serve them, hence:

  • The need to use an alias where the app files are present.
  • The need to set the container path (/app) on the SCRIPT_FILENAME fastcgi_param

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment