22

I already tried to search for this issue, but it's all different from mine, so I'm posting this here. I'm trying to create a webserver using nginx to host multiple laravel projects in subfolders. It's my labs server. So I'd like to have my projects like this:

  • domain.com/project1
  • domain.com/project2
  • domain.com/project3

I'm copying the following nginx location block for each project (i don't know what's happening here, I just copied from the internet and it worked):

location ^~ /project1/ {
        alias /home/web/project1/public;
        try_files $uri $uri/ @project1;

    location ~ \.php {
        fastcgi_pass                    unix:/var/run/php5-fpm.sock;
        fastcgi_index                   index.php;
        include                         /etc/nginx/fastcgi_params;
        fastcgi_param                   SCRIPT_FILENAME "/home/web/project1/public/index.php";
    }

}

location @project1 {
     rewrite /avm/(.*)$ /project1/index.php?/$1 last;
}

And RESTful routes in my laravel app like this:

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/

Route::get('/', ['middleware' => 'auth','uses' => 'HomeController@index'])->name('home');

// Authentication
Route::get('auth/login', 'Auth\AuthController@getLogin');
Route::post('auth/login', 'Auth\AuthController@authenticate');
Route::get('auth/logout', 'Auth\AuthController@getLogout');

// Administração
Route::group(['prefix' => 'administracao', 'middleware' => 'auth'], function() {
    Route::resource('filiais', 'FiliaisController');
    Route::resource('precos', 'PrecosController');
    Route::resource('funcionarios', 'FuncionariosController');
    Route::resource('cargos', 'CargosController');
    Route::resource('vendedores', 'VendedoresController');
});

// Comercial
Route::group(['prefix' => 'comercial', 'middleware' => 'auth'], function() {
    Route::resource('clientes', 'ClientesController');
    Route::resource('fichas', 'FichasController');
});

// Operacional
Route::group(['prefix' => 'operacional', 'middleware' => 'auth'], function() {
    Route::resource('agenda', 'AgendaController');
    Route::resource('os', 'OsController');
    Route::resource('ambientes', 'AmbientesController');
    Route::resource('processos', 'ProcessosController');
    Route::get('relatorios', 'RelatoriosController@index');

    Route::group(['prefix' => 'processo', 'middleware' => 'auth'], function() {
        Route::get('create', 'ProcessoController@create');
        Route::get('index', 'ProcessoController@index');

        Route::post('{os}/parse', 'ProcessoController@parse');

        Route::get('{os}', 'ProcessoController@principal');
        Route::match(['get', 'post'], '{os}/detalhe', 'ProcessoController@detalhe');
        Route::get('{os}/duplicidades', 'ProcessoController@duplicidades');
        Route::get('{os}/restantes', 'ProcessoController@restantes');
        Route::match(['get', 'post'], '{os}/auditoria', 'ProcessoController@auditoria');
        Route::match(['get', 'post'], '{os}/operadores', 'ProcessoController@operadores');
        Route::match(['get', 'post'], '{os}/divergencia', 'ProcessoController@divergencia');
        Route::match(['get', 'post'], '{os}/finalizar', 'ProcessoController@finalizar');
        Route::get('{os}/excluir/{setor}', 'ProcessoController@destroy');
    });
});

Although it seems to work (the page appears, etc) when it goes into bussiness logic (save to database, etc.) it appears to have many bugs. For example when I try to create a new employee in url http://domain.com/project1/administracao/funcionarios it gives me the error: SQLSTATE[42S22]: Column not found: 1054 Unknown column '/administracao/funcionarios' in (it's kinda prepending some url routes)

And when I setup a subdomain like project1.domain.com everything works fine. But I don't want to create a subdomain for each project, I want it to work in subfolders url. Is it possible?

Rodrigo Souza
  • 7,162
  • 12
  • 41
  • 72
  • Look at the accepted answer here: http://stackoverflow.com/questions/16683046/how-to-install-laravel-4-to-a-web-host-subfolder-without-publicly-exposing-app – Angad Dubey Apr 04 '16 at 15:35
  • that's for Laravel 4.. I already tried – Rodrigo Souza Apr 04 '16 at 19:04
  • 1
    Can you show the controller code for posting to `project1/administracao/funcionarios`? I imagine you're using `Input::all()` or similar, I'd be interested in seeing a dump of the data sent to that function – Jeff Apr 07 '16 at 23:58

8 Answers8

2

Recently I had the exact same problem. I wanted to have

but I hated having to modify nginx conf every time I added a new project.

Here's what I came up with:

# Capture $project from /$projectname/controller/action
map $request_uri $project {

    ~^/(?<captured_project>[a-zA-Z0-9_-]+)/? $captured_project;
    default / ;
}

server {

    listen 11.22.33.44:80;

    server_name customerdemo.example.com www.customerdemo.example.com;

    # Use $project/public as root
    root /sites/customerdemo.example.com/$project/public;

    # Use index.php as directory index
    index index.php;

    # Include the basic h5bp config set (see https://github.com/h5bp/server-configs-nginx)
    include h5bp/basic.conf;

    # Process /projectname/the/rest/of/the/url
    location ~ ^/([^/]+)/(.*) {

        # Save the rest of the URL after project name as $request_url
        set $request_url /$2;


        # If the saved url refers to a file in public folder (a static file), serve it,
        # else redirect to index.php, passing along any ?var=val URL parameters
        try_files $request_url /index.php?$is_args$args;

    }

    # Process any URL containing .php (we arrive here through previous location block)
    # If you don't need to serve any other PHP files besides index.php, use location /index.php here
    # instead, to prevent possible execution of user uploaded PHP code
    location ~ [^/]\.php(/|$) {

        # Define $fastcgi_script_name and $fastcgi_path_info
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;

        # Immediately return 404 when script file does not exist
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }

        # Mitigate https://httpoxy.org/ vulnerabilities
        fastcgi_param HTTP_PROXY "";

        # Define PHP backend location (find yours by grepping "listen ="
        # from your PHP config folder, e.g. grep -r "listen =" /etc/php/)
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;

        # Set SCRIPT_FILENAME to execute
        fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;

        # Include the default fastcgi parameters
        include fastcgi_params;

        # Overwrite REQUEST_URI (default is $request_uri) with $request_url we saved earlier
        fastcgi_param  REQUEST_URI        $request_url;
    }

}

The result is that I don't have to do ANYTHING other than git clone in /sites/customerdemo.example.com/ folder and run composer install and php artisan migrate to add a new project.

Actually, I have developed myself a control panel where I can click on "Add project" and specify project details and a new bitbucket repo, mysql user and database will be created and customerdemo server will be given deploy access to this bitbucket repo and a webhook is set up in this new repo which will call a deployment script on customerdemo server each time someone commits to master on this repo which will trigger either git clone or git pull and composer install and database migration. That's why I needed dynamic Nginx configuration. ;-)

Henno
  • 1,448
  • 4
  • 18
  • 30
  • Hello @Henno , thanks for your answer. It works good in dynamic way. Only issue I have faced that then I use asset('/resources/dist/css/public.css') or url('/') with some /image/path in public folder, the result is there is a part containing project name is missing. So if I have example.com/myProject, the desired URL to image is example.com/myProject/images/image.jpg but instead is example.com/images/image.jpg. Do you know how to solve this issue? – Johnczek Jul 19 '23 at 20:12
2

Check this Nginx configuration I believe it will helps you

server {
server_name main-app.dev;
root /var/www/projects/main/public;


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;
# sub_directory
location ^~ /sub-app {
  alias /var/www/projects/sub/public;
  try_files $uri $uri/ @sub;

    location ~ \.php {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_read_timeout 30000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/projects/sub/public/index.php;
    }
    access_log off;
    error_log  /var/www/projects/sub/storage/log/error.log error;
}

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

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

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

access_log off;
error_log  /var/www/projects/main/storage/log/error.log error;

error_page 404 /index.php;

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_read_timeout 30000;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
}

location ~ /\.(?!well-known).* {
    deny all;
}}
Hamza Alayed
  • 635
  • 5
  • 17
  • I will update it, but this is wired, the link is an official website "GitHub", if github dies mean development world die with it :). I believe you should add some exception for famous websites. Anyway, I will update my answer . – Hamza Alayed Jan 31 '19 at 12:58
1

I have successfully run a Laravel 5.4 project in a "subfolder" of another site by using a simple symlink.

There was no funky special rewrite rules in the Nginx configuration. No copy & paste of sections of the project. No mention of the subfolder in the routes. Just a regular Laravel 5 project neatly contained somewhere on the server and a symlink to it's public folder from the main site's document root.

/var/www/domain.com/public/project1 --> /var/www/project1/public

All the routes just work!

When writing your views you do have to wrap the paths for client-side assets in asset() helper function so the paths in the HTML will contain the subfolder and the browser can find them.

<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">

But doing that does not make your code less flexible, because if you do run the site in an environment where it is not accessed via a subfolder, it works because asset() works with what the address bar contains.

Martin Joiner
  • 3,529
  • 2
  • 23
  • 49
0

I think the problem might be in your nginx.conf file. Try this:

location ^~ /project1 {
        alias /home/web/project1/public;
        try_files $uri $uri/ @project1;

    location ~ \.php {
        fastcgi_pass     unix:/var/run/php5-fpm.sock;
        fastcgi_index    index.php;
        include          /etc/nginx/fastcgi_params;
    }

}

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

Also, please be sure that /home/web/project1/ is outside of your web root.

This being said, it is really not recommended to run Laravel in a subfolder. Much easier in a subdomain.

I got the basic idea for this suggestion from this gist.

morphatic
  • 7,677
  • 4
  • 47
  • 61
  • why should it be outside my web root? – Rodrigo Souza Apr 11 '16 at 19:01
  • If your web root is, say, `/home/web/` and you put your entire laravel project inside there, then all of the private laravel files will become visible to everyone on the web. They would be able to browse to http://yourdomain.com/project1/config/ and see the files there. – morphatic Apr 13 '16 at 07:11
0

Not completely sure about the solution, but I think you should try these ones:

  • Firstly: setting the url properly in config/app.php file.
  • Secondly: reviewing public/web.config file. The problem might be these configuration overwriting your nginx. consider changing <action type="Rewrite" url="project1/index.php" /> and see what it returns.

In last instance, var_dump the model and look for where it comes from.

henriale
  • 1,012
  • 9
  • 21
0

have you tried this configuration ?

https://gist.github.com/tsolar/8d45ed05bcff8eb75404

I will test tomorrow as soon I have time to replicate your situation in my env.

Pietro
  • 988
  • 10
  • 19
0

There is a simple solution to " I want it to work in subfolders url. Is it possible?".

Steps
1. make folder inside of your main domain public folder. you need to create 3 folders
home/web/public/project1
home/web/public/project2
home/web/public/project3

2. Inside each project folder you need to paste the content of the public folder of your laravel app

(from your Laravel Project) project1/public/{contents} -- copy this to -->(hosted server) home/web/public/project1/{contents}

  1. Upload the rest of laravel project outside the public root directory and give write access to the folder.

  2. Now open (hosted server) public/project1/index.php update these two fields

require __DIR __.'/../../PROJECTONE/bootstrap/autoload.php';

$app = require_once __DIR __.'/../../PROJECTONE/bootstrap/app.php';

  • sorry for the late reply.. this seems to work.. but now, how do I fix my route to support subdirectories? when I access: http://avminventarios.com.br/sts4/auth/login it gives me NotFoundHttpException in RouteCollection.php – Rodrigo Souza May 01 '16 at 17:53
  • can you share the (file structure) folders location and content of project/index.php soi can help you out with this. – Ashutosh Barthwal May 04 '16 at 17:55
  • can you share how your folder are managed/placed on the server. – Ashutosh Barthwal May 05 '16 at 17:40
  • `/avminventarios.com.br/laravel` has everything but the public folder. And the public folder contents are in `/avminventarios.com.br/web/sts2` – Rodrigo Souza May 05 '16 at 23:54
  • all you need to do is edit /avminventarios.com.br/web/sts2/[index.php](https://github.com/rasouza/avm/blob/master/public/index.php) require __DIR __.'/../../laravel/bootstrap/autoload.php'; $app = require_once __DIR __.'/../../laravel/bootstrap/app.php'; make sure laravel folder has read write permissions – Ashutosh Barthwal May 06 '16 at 04:46
  • That was already done.. the index.php can reach the autoload.php and app.php, but the way it handles the URL is the problem. That was the only modification I did in comparison of what you saw in my github repository – Rodrigo Souza May 07 '16 at 17:35
  • /avminventarios.com.br/web/.htaccess may be causing the problem can you share the content. – Ashutosh Barthwal May 08 '16 at 06:35
  • there's no .htaccess in this folder.. only in `/avminventarios.com.br/laravel` and `/avminventarios.com.br/web/sts2` – Rodrigo Souza May 09 '16 at 07:36
  • create a .htaccess file on the base web folder with this content ----------------------Content---------------------------------------- Options -MultiViews RewriteEngine On # Redirect Trailing Slashes... RewriteRule ^(.*)/$ /$1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] – Ashutosh Barthwal May 13 '16 at 04:48
0

try something like this .... I'm using following .conf for my server :

server {
    listen  80;
    root /vagrant;
    index index.html index.htm index.php app.php app_dev.php;

    server_name 192.168.33.10.xip.io;

    access_log /var/log/nginx/vagrant.com-access.log;
    error_log  /var/log/nginx/vagrant.com-error.log error;

    charset utf-8;

    location ~project(\d*)/((.*)\.(?:css|cur|js|jpg|jpeg|gif|htc|ico|png|html|xml))$ {
        rewrite project(\d*)/((.*)\.(?:css|cur|js|jpg|jpeg|gif|htc|ico|png|html|xml))$ /project$1/public/$2 break;
    }

    location /project1{
         rewrite ^/project1/(.*)$ /project1/public/index.php?$1 last;
    }

     location /project2 {
        rewrite ^/project2/(.*)$ /project2/public/index.php?$1 last;
    }

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

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        set $laravel_uri $request_uri;
        if ($laravel_uri ~ project(\d*)(/?.*)$) {
            set $laravel_uri $2;
        }
        fastcgi_param REQUEST_URI $laravel_uri;
        fastcgi_param LARA_ENV local; # Environment variable for Laravel
        fastcgi_param HTTPS off;
    }
    location ~ /\.ht {
        deny all;
    }
}
Arash Hatami
  • 5,297
  • 5
  • 39
  • 59