What is multi-sites with laravel?

If you are an advance laravel developer and want to know how you can run multiple website using single laravel repositry or project then we will cover how to do that in this tutorial.

By default laravel does not allow you to run multiple sites with single codebase however making small changes to your AppProvider file you can achieve this task.

We have to create a new folder called Sites in app directory. We will create two different website however we will put our website logic in single laravel project.

First of all create a new laravel project. If you don't know how to create a laravel project follow the link below:

Install Laravel5

Add multiple sites to laravel code

We have to make changes to our new laravel app so that it will allow us to create multiple sites with single code. Following will be our new directory structure:

Now, whenever we create a new site we have to create a folder in app/Sites folder with site code for example SITE1, SITE2, SITE3 and on.

Make sure to use unique uppercase code and site related controllers, view, models, migrations, config and route file will be placed in that new site folder as shown above.

Now, we have to tell laravel to follow this new structure. We have to place some sort of logic in our AppServiceProvider.php class.

Open app/Providers/AppServiceProvider.php file and add following logic to boot method:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // get current site path
        $site_name = strtoupper(getenv('SITE_CODE'));
        $namespace = "\\App\\Sites\\{$site_name}\\Controllers";
        $site_path = app_path(). '/Sites/' .$site_name;

        if (file_exists($site_path)) {
            $this->loadMigrationsFrom($site_path.'/Migrations');
            $this->loadViewsFrom($site_path. '/Views', strtolower($site_name));
            $this->mergeConfigFrom($site_path. '/config.php', strtolower($site_name));
            $this->loadTranslationsFrom($site_path.'/Translations', strtolower($site_name));
            \Route::namespace($namespace)->middleware('web')->group($site_path. '/routes.php');
        }
    }
}

When laravel app loads it will call above boot method where we get SITE_CODE constant from apache env variable.

When we create our virtual host configurations for apache we have to define SITE_CODE for each of our domain name so that we load appropriate site code.

Update Kernel to identify sites correctly

Once we are done with AppServiceProvider.php file changes next we need to let laravel know about env variable that we are going to use for our project.

Open app/Http/Kernel.php file modify it so that it points to correct .env file:

namespace App\Http;

use Illuminate\Routing\Router;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    public function __construct(Application $app, Router $router)
    {
        $env_path = strtoupper(getenv('SITE_CODE'));
        if($env_path) {
            $app->useEnvironmentPath(app_path('Sites/' .$env_path. '/'));
        }

        parent::__construct($app, $router);
    }

    // existing code will go here
}

Virtual host settings for Apache

Let's say that we have two websites:

  • www.site1.com
  • www.site2.com

Let's create a virtual host config for our site1:

<VirtualHost *:80>

    # variable that identify which 
    # project to use from multi-site project
    SetEnv SITE_CODE SITE1

    ServerName www.site1.com
    DocumentRoot /var/www/laravel-project/public

    <Directory /var/www/laravel-project/public>
        DirectoryIndex index.php
        AllowOverride All
        Require all granted
        Order allow,deny
        Allow from all
    </Directory>

</VirtualHost>

Let's create another virtual host config for our site2:

<VirtualHost *:80>

    # variable that identify which 
    # project to use from multi-site project
    SetEnv SITE_CODE SITE2

    ServerName www.site1.com
    DocumentRoot /var/www/laravel-project/public

    <Directory /var/www/laravel-project/public>
        DirectoryIndex index.php
        AllowOverride All
        Require all granted
        Order allow,deny
        Allow from all
    </Directory>

</VirtualHost>

If you note in above two apache configurations you will see that both of them are identical as they use the same laravel project however we set an additional variable to identify which site code to use for particular domain.

Start your apache server and navigate to both sites and you will see they are loaded from single laravel project however they are different sites.

Whenever you create a new project you have to remember following file structure:

|-- app
     |-- Sites
          |-- SITE1
                 |-- routes.php   -> routes for www.test1.com site
                 |-- .env         -> site configurations for www.site1.com
                 |-- config.php   -> config variables specific to www.site1.com
                 |-- Controllers  -> controllers specific to www.site1.com 
                 |-- Views        -> views specific to www.site1.com
                 |-- Migrations   -> Migrations specific to www.site1.com
                 |-- Translations -> Translations specific to www.site1.com

That is it, we have successfully created multi-sites using single laravel codebase.