A Laravel extension for using a laravel application on a multi domain setting

Overview

Laravel Laravel Laravel Laravel License

Laravel Multi Domain

An extension for using Laravel in a multi domain setting

Laravel Multi Domain

Description

This package allows a single Laravel installation to work with multiple HTTP domains.

There are many cases in which different customers use the same application in terms of code but not in terms of database, storage and configuration.

This package gives a very simple way to get a specific env file, a specific storage path and a specific database for each such customer.

Documentation

Version Compatibility

Laravel Multidomain
5.5.x 1.1.x
5.6.x 1.2.x
5.7.x 1.3.x
5.8.x 1.4.x
6.x 2.x
7.x 3.x
8.x 4.x

Further notes on Compatibility

Releases v1.1.x:

  • From v1.1.0 to v1.1.5, releases are fully compatibile with Laravel 5.5, 5.6, 5.7, 5.8 or 6.0.
  • From v1.1.6+ releases v1.1.x are only compatible with Laravel 5.5 in order to run tests correctly.

To date, releases v1.1.6+, v1.2.x, v1.3.x, v1.4.x, v2.x and v3.x are functionally equivalent. Releases have been separated in order to run integration tests with the corresponding version of the Laravel framework.

However, with the release of Laravel 8, releases v1.1.14, v1.2.8, v1.3.8 and v1.4.8 are the last releases including new features for the corresponding Laravel 5.x versions (bugfix support is still active for that versions). 2021-02-13 UPDATE: some last features for v1.1+ releases are still ongoing :)

v1.0 requires Laravel 5.1, 5.2, 5.3 and 5.4 (no longer maintained and not tested versus laravel 5.4, however the usage of the package is the same as for 1.1)

Installation

Add gecche/laravel-multidomain as a requirement to composer.json:

{
    "require": {
        "gecche/laravel-multidomain": "4.*"
    }
}

Update your packages with composer update or install with composer install.

You can also add the package using composer require gecche/laravel-multidomain and later specify the version you want (for now, dev-v1.1.* is your best bet).

This package needs to override the detection of the HTTP domain in a minimal set of Laravel core functions at the very start of the bootstrap process in order to get the specific environment file. So this package needs a few more configuration steps than most Laravel packages.

Installation steps:

  1. replace the whole Laravel container by modifying the following lines at the very top of the bootstrap/app.php file.
//$app = new Illuminate\Foundation\Application(
$app = new Gecche\Multidomain\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
  1. update the two application Kernels (HTTP and CLI).

At the very top of the app/Http/Kernel.php file , do the following change:

//use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Gecche\Multidomain\Foundation\Http\Kernel as HttpKernel;

Similarly in the app/Console/Kernel.php file:

//use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Gecche\Multidomain\Foundation\Console\Kernel as ConsoleKernel;
  1. Override the QueueServiceProvider with the extended one in the $providers array in the config/app.php file:
        //Illuminate\Queue\QueueServiceProvider::class,
        Gecche\Multidomain\Queue\QueueServiceProvider::class,
  1. publish the config file.
php artisan vendor:publish 

(This package makes use of the discovery feature.)

Following the above steps, your application will be aware of the HTTP domain in which is running, both for HTTP and CLI requests, including queue support.

Usage

This package adds three commands to manage your application HTTP domains:

domain.add artisan command

The main command is the domain:add command which takes as argument the name of the HTTP domain to add to the application. Let us suppose we have two domains, site1.com and site2.com, sharing the same code.

We simply do:

php artisan domain:add site1.com 

and

php artisan domain:add site2.com 

These commands create two new environment files, .env.site1.com and .env.site2.com, in which you can put the specific configuration for each site (e.g. databases configuration, cache configuration and other configurations, as usually found in an environment file).

The command also adds an entry in the domains key in config/domains.php file.

In addition, two new folders are created, storage/site1_com/ and storage/site2_com/. They have the same folder structure as the main storage.

Customizations to this storage substructure must be matched by values in the config/domain.php file.

domain.remove artisan command

The domain:remove command removes the specified HTTP domain from the application by deleting its environment file. E.g.:

php artisan domain:remove site2.com 

Adding the force option will delete the domain storage folder.

The command also removes the appropriate entry from, the domains key in config/domains.php file.

domain.update_env artisan command

The domain:update_env command passes a json encoded array of data to update one or all of the environment files. These values will be added at the end of the appropriate .env.

Update a single domain environment file by adding the domain option.

When the domain option is absent, the command updates all the environment files, including the standard .env one.

The list of domains to be updated is maintained in the domain.php config file.

E.g.:

php artisan domain:update_env --domain_values='{"TOM_DRIVER":"TOMMY"}' 

will add the line TOM_DRIVER=TOMMY to all the domain environment files.

domain.list artisan command

The domain:list command lists the currently installed domains, with their .env file and storage path dir.

The list is maintained in the domains key of the config/domain.php config file.

This list is automatically updated at every domain:add and domain:remove commands run.

config:cache artisan command

The config:cache artisan command can be used with this package in the same way as any other artisan command.

Note that this command will generate a file config.php file for each domain under which the command has been executed. I.e. the command

php artisan config:cache --domain=site2.com 

will generate the file

config-site2_com.php 

Further information

At run-time, the current HTTP domain is maintained in the laravel container and can be accessed by its domain() method added by this package.

A domainList() method is available. It returns an associative array containing the installed domains info, similar to the domain.list command above.

E.g.

[ 
   site1.com => [
       'storage_path' => <LARAVEL-STORAGE-PATH>/site1_com,
       'env' => '.env.site1.com'
   ]
] 

Distinguishing between HTTP domains in web pages

For each HTTP request received by the application, the specific environment file is loaded and the specific storage folder is used.

If no specific environment file and/or storage folder is found, the standard one is used.

The detection of the right HTTP domain is done by using the $_SERVER['SERVER_NAME'] PHP variable.

Customizing the detection of HTTP domains

Starting from release 1.1.15, the detection of HTTP domains can be customized passing a Closure as the domain_detection_function_web entry of the new domainParams argument of Application's constructor. In the following example, the HTTP domain detection relies upon $_SERVER['HTTP_HOST'] instead of $_SERVER['SERVER_NAME'].

$domainParams = [
    'domain_detection_function_web' => function() {
        return \Illuminate\Support\Arr::get($_SERVER,'HTTP_HOST');
    }
];

//$app = new Illuminate\Foundation\Application(
$app = new Gecche\Multidomain\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__), null, $domainParams
);

Using multi domains in artisan commands

In order to distinguishing between domains, each artisan command accepts a new option: domain. E.g.:

php artisan list --domain=site1.com 

The command will use the corresponding domain settings.

About queues

The artisan commands queue:work and queue:listen commands have been updated to accept a new domain option.

php artisan queue:work --domain=site1.com 

As usual, the above command will use the corresponding domain settings.

Keep in mind that if, for example, you are using the database driver and you have two domains sharing the same db, you should use two distinct queues if you want to manage the jobs of each domain separately.

For example, you could:

  • put in your .env files a default queue for each domain, e.g. QUEUE_DEFAULT=default1 for site1.com and QUEUE_DEFAULT=default2 for site2.com
  • update the queue.php config file by changing the default queue accordingly:
'database' => [
    'driver' => 'database',
    'table' => 'jobs',
    'queue' => env('QUEUE_DEFAULT','default'),
    'retry_after' => 90,
],
  • launch two distinct workers
 php artisan queue:work --domain=site1.com --queue=default1

and

 php artisan queue:work --domain=site1.com --queue=default2

Obviously, the same can be done for each other queue driver, apart from the sync driver.

storage:link command

If you make use of the storage:link command and you want a distinct symbolic link for each domain, you have to create them manually because to date such command always creates a link named storage and that name is hard coded in the command. Extending the storage:link command allowing to choose the name is outside the scope of this package (and I hope it will be done directly in future versions of Laravel).

A way to obtain multiple storage links could be the following. Let us suppose to have two domains, namely site1.com and site2.com with associated storage folders storage/site1_com and storage/site2_com.

  1. We manually create links for each domain:
ln -s storage/site1_com/app/public public/storage-site1_com 
ln -s storage/site2_com/app/public public/storage-site2_com 
  1. In .env.site1.com and .env.site2.com we add an entry, e.g., for the first domain:
APP_PUBLIC_STORAGE=-site1_com
  1. In the filesystems.php config file we change as follows:
'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage'.env('APP_PUBLIC_STORAGE'),
    'visibility' => 'public',
],

Furthermore, if you are using the package in a Single Page Application (SPA) setting, you could better handling distinct public resources for each domain via .htaccess or similar solutions as pointed out by Scaenicus in his .htaccess solution.

Storing environment files in a custom folder

Starting from version 1.1.11 a second argument has been added to the Application constructor in order to choose the folder where to place the environment files: if you have tens of domains, it is not very pleasant to have environment files in the root Laravel's app folder.

So, if you want to use a different folder simply add it at the very top of the bootstrap/app.php file. for example, if you want to add environment files to the envs subfolder, simply do:

//$app = new Illuminate\Foundation\Application(
$app = new Gecche\Multidomain\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__),
    dirname(__DIR__) . DIRECTORY_SEPARATOR . 'envs'
);

If you do not specify the second argument, the standard folder is assumed. Please note that if you specify a folder, also the standard .env file has to be placed in it

Default environment files and storage folders

If you try to run a web page or an shell command under a certain domain, e.g. sub1.site1.com and there is no specific environment file for that domain, i.e. the file .env.sub1.site1.com does not exist, the package will use the first available environment file by splitting the domain name with dots. In this example, the package searches for the the first environment file among the followings:

.env.site1.com
.env.com
.env

The same logic applies to the storage folder as well.

About Laravel's Scheduler, Supervisor and some limitation

If in your setting you make use of the Laravel's Scheduler, remember that also the command schedule:run has to be launched with the domain option. Hence, you have to launch a scheduler for each domain. At first one could think that one Scheduler instance should handle the commands launched for any domain, but the Scheduler itself is run within a Laravel Application, so the "env" under which it is run, automatically applies to each scheduled command and the --domain option has no effect at all.

The same applies to externals tools like Supervisor: if you use Supervisor for artisan commands, e.g. the queue:work command, please be sure to prepare a command for each domain you want to handle.

Due to the above, there are some cases in which the package can't work: in those settings where you don't have the possibility of changing for example the supervisor configuration rather than the crontab entries for the scheduler. Such an example has been pointed out here in which a Docker instance has been used.

Comments
  • Run Migrate and Seeder on new domain

    Run Migrate and Seeder on new domain

    Hi there,

    I am really glad you created this package. It mostly solves all of my problems. But, let's say, I created a new domain tenant1.site.com.

    How do I run the migrations and seeders on this tenant1 database?

    I would really appreciate it If you could add some command to migrate to a new domain database.

    like: php artisan domain:migrate tenant1

    Thanks & Regards Bilal Younas

    opened by collectiveconscious 19
  • cant read .env on multisite

    cant read .env on multisite

    hi, i try to make a laravel apps with multi site and multi domain with different database in single code base. i try to config .env each site. but when i try to config:cache it still using one database. im using laravel 5.8

    opened by buruhsd 14
  • Issue with ngnix wildcard sub domain

    Issue with ngnix wildcard sub domain

    First of all thanks for the nice package.

    When I try to use wildcard domain setup in ngnix like below

    server_name ~^(?.+).domain.com$;

    OR

    server_name *.domain.com

    The environment variable $_SERVER[SERVER_NAME] => ~^(?.+).domain.com$ is passed as this to php. As the package relying on $_SERVER[SERVER_NAME], it is not able to detect correct environment. But the $_SERVER[HTTP_HOST] is passed properly in this case.

    Not sure it is an issue with the package or is there any work around to pass the server name properly from ngnix?

    Thanks in advance.

    opened by satheesh365 10
  • VueJs Mixed Variables?

    VueJs Mixed Variables?

    Hello together,

    first i want to thank you for the great repository. I really like the concept and it opens me alot of doors. 👍

    I'm using Laravel and using some mixed variables in my code. I access them through process.env.MIX_ANY_VARIABLE. Unfortunately, i'm getting always the variable from .ENV and not DOMAIN.ENV. Is there any way to handle this proper?

    Thanks in advance

    opened by christoph-werker 8
  • artisan domain:add command issue

    artisan domain:add command issue

    Hello,

    I am using Laravel 8.12 and gecche/laravel-multidomain 4.0

    When I run command php artisan domain:add mysite.com it throw below error message

    cannot use a scalar value as an array at vendor/gecche/laravel-multidomain/src/Foundation/Console/AddDomainCommand.php:135

    Please help how can I fix this issue?

    Thanks, Asif

    opened by asifu5057 7
  • Run commands with the --domain option from another command

    Run commands with the --domain option from another command

    Hi, i'm trying to create the command domains:migrate in order to run the artisan migrate command on all domains.

    My command handle function is as follows:

    public function handle()
    {
        $domains = config('domain.domains');
    
        foreach($domains as $domain) {
            $this->call('migrate', ['--domain' => $domain]);
        }
    
        return true;
    }
    

    When i run the command, i expect it to migrate to all 3 of my domains. But it fails and returns "nothing to migrate":

    $ php artisan domains:migrate
    Nothing to migrate.
    Nothing to migrate.
    Nothing to migrate.
    

    How can i create a command to execute migration on all my domains? Thanks

    opened by andrecolza 7
  • Storage:link to Public

    Storage:link to Public

    Hi there,

    When I upload the file goes to storage/domain/app/public. I tried to create a symlink for this directory but it says. public/storage already exists for default linking.

    I used php artisan storage:link --domain=domain-address

    How do I create a symlink for each domain? or How do I use the default storage directory for all domains?

    Regards, Bilal Younas

    opened by collectiveconscious 7
  • Not working with 2nd domain

    Not working with 2nd domain

    Hello @gecche , How are you?

    I followed all the steps from first to last but when I run the last command " php artisan queue:work --domain=site1.com --queue=default1" so it's stuck nothing to any process and when I try to run the domain so it's showing 404 error.

    I am doing this all process into cPanel.

    Can you please guide me with that?

    Thank you and Regards, Tarun Vataliya

    opened by tuvataliya2141 5
  • Updating env of a specific domain seems to update all .env files

    Updating env of a specific domain seems to update all .env files

    Hi,

    this code has been really helpful in bridging the gap in our product however, looking at the documentation, either I am missing something or the parameter to specify which env file to update seems to get ignored and proceeds to update all files?

    php artisan domain:update_env --domain=testdomain.com --domain_values='{"TOM_DRIVER":"TOMMY"}' is how i assumed this would be structured, so am I missing something?

    Many thanks!

    opened by ccargill-ewx 5
  • Domain specific migration and seeders

    Domain specific migration and seeders

    Hi, first of all, this is an amazing package, able to get it up and working.

    I am a little puzzled with the migrations and seeding for specific DB/Domain. I created database/migrations/site_test folder to store site_test specific files. However, when I run the command "php artisan migrate --domain=site.test" - the system loads the migration tables from the migrations folder and not the site_test folder. Why this is happening?

    Also, how do I run seeders for a specific domain? Do I have to create a subfolder sites_test under /seeders/ folder - just like /migrations/ - will that work?

    Thank you for your help.

    Regards

    opened by newlaravelcoder 5
  • View and controller

    View and controller

    Hello I have a question or maybe two. I don't understand how to give blade files (where I should put them) to the different domains and how to put the view in controller? With folder path?

    opened by StrangerGithuber 5
  • Brilliant concept

    Brilliant concept

    I don't have an issue, just wanted to drop a line and tell you this is one of those simple and clever things. I have been fiddling with multi-tenant Laravel stuff for ages, I wish I had found this long ago. Downloaded it last night, I am 100% impressed.

    opened by nettsite 1
  • artisan schedule:work --domain problem

    artisan schedule:work --domain problem

    Hi,

    I am using Laravel 8 and gecche/laravel-multidomain 4.2. The command schedule:work not passing the domain to the next level command. But schedule:run works fine.

    Thank you for your time,

    Regards, Satheesh365

    opened by satheesh365 1
  • Models

    Models

    How should I use this tool if I have an application that shares the same database on all domains?

    For example,

    If i have this tables

    Products Settings Menus

    Would I need to add the domain as an id in each model and add a global scope to filter by domain?

    opened by maganius 2
  • is it able to work with Octane?

    is it able to work with Octane?

    Hey Folks,

    I was able to put my project (which use laravel-multidomain) to work with octane (swoole), with no additional effort it is able to run cli commands. But when I try from web looks like only use the original .env file no matter the domain I use. Any suggestion to solve it?

    Thank in advance

    opened by arivelli 3
  • Wrong Log path from job dispatched

    Wrong Log path from job dispatched

    Hi, first thanks for this package. I'm making some tests and i found maybe an issue.

    I'm connected on my site a. I write a log info from a http request, the log write into log file domain (storage/site_a/logs/laravel.log), all good.

    But when i write a log inside a job and dispatch this job, the log write in storage/logs/laravel.log and not in storage/site_a/logs/laravel.log.

    Any idea why ?

    opened by TheOneWhoKnokks 10
Owner
null
Run multiple websites using the same Laravel installation while keeping tenant specific data separated for fully independent multi-domain setups.

Tenancy for Laravel Enabling awesome Software as a Service with the Laravel framework. This is the successor of hyn/multi-tenant. Feel free to show su

Tenancy 1.1k Dec 30, 2022
Run multiple websites using the same Laravel installation while keeping tenant specific data separated for fully independent multi-domain setups, previously

Run multiple websites using the same Laravel installation while keeping tenant specific data separated for fully independent multi-domain setups, previously

Tenancy 2.4k Jan 3, 2023
An example of multi-domain/subdomain app in Laravel.

?? UPDATE A better example with online demo: https://github.com/laravel-101/multi-domain-laravel-app Multi-Domain Laravel App An example of multi-doma

DigitalWheat 204 Dec 27, 2022
A Laravel package that allows you to use multiple ".env" files in a precedent manner. Use ".env" files per domain (multi-tentant)!

Laravel Multi ENVs Use multiple .envs files and have a chain of precedence for the environment variables in these different .envs files. Use the .env

Allyson Silva 48 Dec 29, 2022
Setting up the a docker + building a simple project on Mac-book using laravel sail

Sailing on mac-book Setting up the a docker + building a simple project on Mac-book with Laravel sail Installing Docker Well, installing docker is the

AmirH.Najafizadeh 3 Jul 31, 2022
Taskpm - Run multi tasks by PHP multi process

php-pkg-template Run multi tasks by PHP multi process Install composer composer require phppkg/taskpm Usage github: use the template for quick create

PHPPkg 2 Dec 20, 2021
⚙️Laravel Nova Resource for a simple key/value typed setting

Laravel Nova Resource for a simple key/value typed setting Administer your Laravel Simple Setting in Nova Pre-requisites This Nova resource package re

elipZis 5 Nov 7, 2022
Laravel Setting - Easily save, update and get titles, descriptions, and more. it is very easy to use.

Laravel Setting Easily save, update and get titles, descriptions, and more. it is very easy to use. This is great for storing and receiving general si

Ali Ranjbar 2 Aug 23, 2022
Multi theme support for Laravel application

Multi theme support for Laravel application This Laravel package adds multi-theme support to your application. It also provides a simple authenticatio

QiroLab 287 Dec 29, 2022
Support multi theme for Laravel application

Very short description of the package This is where your description should go. Try and limit it to a paragraph or two, and maybe throw in a mention o

Ephraïm SEDDOR 1 Dec 1, 2021
Bring multi themes support to your Laravel application with a full-featured Themes Manager

Introduction hexadog/laravel-themes-manager is a Laravel package which was created to let you developing multi-themes Laravel application. Installatio

hexadog 86 Dec 15, 2022
A Multi User Chat Application With Laravel and Livewire

A Multi User Chat Application With Laravel and Livewire. where you can chat with multiple frinds at the same time. i build this with php Laravel and Livewire.

Tauseed 15 Oct 22, 2022
Easily integrate single-database multi tenant features into your Laravel application

Laravel Tenant Aware Easily integrate single-database multi tenant features into your Laravel application. Installation You can install the package vi

H-FARM Innovation 9 Dec 21, 2022
Source Code for 'Domain-Driven Laravel' by Jesse Griffin

Apress Source Code This repository accompanies Domain-Driven Laravel by Jesse Griffin (Apress, 2020). Download the files as a zip using the green butt

Apress 63 Dec 17, 2022
Create and manage A Domain Driven Design (DDD) in your Laravel app, simply and efficiently.

Create and manage A Domain Driven Design (DDD) in your Laravel app, simply and efficiently.

Lucas Nepomuceno 4 Jun 11, 2022
A lightweight domain event pattern implementation for Doctrine2.

Knp Rad Domain Event A lightweight domain event pattern implementation for Doctrine2. Official maintainers: @Einenlum Installation With composer : $ c

KNP Labs 5 Sep 23, 2022
Chrome extension to generate Laravel integration tests while using your app.

Laravel TestTools Check out the introduction post about the chrome extension. Installation git clone [email protected]:mpociot/laravel-testtools.git # i

Marcel Pociot 473 Nov 1, 2022
Backend application using Laravel 9.x REST APIs for games topup from digiflazz.com and payment gateway using xendit.co

TOPUP - Laravel 9.x REST API Documentation is still on progress. For now, you can fork this postman collection Installation Clone this project git clo

Muhammad Athhar Kautsar 46 Dec 17, 2022
Automatic multi-tenancy for Laravel. No code changes needed.

Tenancy for Laravel — stancl/tenancy Automatic multi-tenancy for your Laravel app. You won't have to change a thing in your application's code. ✔️ No

Samuel Štancl 2.7k Jan 3, 2023