{"id":13589007,"url":"https://github.com/gecche/laravel-multidomain","last_synced_at":"2025-10-26T03:03:53.995Z","repository":{"id":3881031,"uuid":"51210102","full_name":"gecche/laravel-multidomain","owner":"gecche","description":"A Laravel extension for using a laravel application on a multi domain setting","archived":false,"fork":false,"pushed_at":"2024-04-01T19:32:55.000Z","size":500,"stargazers_count":800,"open_issues_count":9,"forks_count":99,"subscribers_count":28,"default_branch":"master","last_synced_at":"2024-05-02T19:17:39.251Z","etag":null,"topics":["laravel","laravel-multidomain","multi-domains","multi-env","multi-tenancy","php","tenancy"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gecche.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-06T16:24:55.000Z","updated_at":"2024-06-18T14:05:36.764Z","dependencies_parsed_at":"2023-01-13T12:48:21.618Z","dependency_job_id":"fb383660-7280-4072-b59d-60cf0863e92f","html_url":"https://github.com/gecche/laravel-multidomain","commit_stats":{"total_commits":106,"total_committers":10,"mean_commits":10.6,"dds":0.4811320754716981,"last_synced_commit":"6fe02124ec7d58eb3098d7752713b0c61275961f"},"previous_names":[],"tags_count":73,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gecche%2Flaravel-multidomain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gecche%2Flaravel-multidomain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gecche%2Flaravel-multidomain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gecche%2Flaravel-multidomain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gecche","download_url":"https://codeload.github.com/gecche/laravel-multidomain/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247796158,"owners_count":20997522,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["laravel","laravel-multidomain","multi-domains","multi-env","multi-tenancy","php","tenancy"],"created_at":"2024-08-01T16:00:20.349Z","updated_at":"2025-10-26T03:03:48.947Z","avatar_url":"https://github.com/gecche.png","language":"PHP","funding_links":[],"categories":["Laravel 扩展","PHP","Packages"],"sub_categories":["Helpers/General"],"readme":"[![License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://tldrlegal.com/license/mit-license)\n[![Laravel](https://img.shields.io/badge/Laravel-12.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-11.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-10.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-9.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-8.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-7.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-6.x-orange.svg?style=flat-square)](http://laravel.com)\n[![Laravel](https://img.shields.io/badge/Laravel-5.x-orange.svg?style=flat-square)](http://laravel.com)\n\n# Laravel Multi Domain\nAn extension for using Laravel in a multi domain setting\n\n![Laravel Multi Domain](laravel-multidomain.png)\n\n## Description\nThis package allows a single Laravel installation to work with multiple HTTP domains.\n\nThere are many cases in which different customers use the same application in terms of code but not in terms of \ndatabase, storage and configuration.\n\nThis package gives a very simple way to get a specific env file, a specific storage path and a specific database \nfor each such customer.\n\n## Documentation\n\n### Version Compatibility\n\n Laravel   | Multidomain\n:----------|:-----------\n 12.x      | 12.x\n 11.x      | 11.x\n 10.x      | 10.x\n  9.x      |  5.x\n  8.x      |  4.x\n  7.x      |  3.x\n  6.x      |  2.x\n  5.8.x    |  1.4.x\n  5.7.x    |  1.3.x\n  5.6.x    |  1.2.x\n  5.5.x    |  1.1.x\n\n#### Further notes on Compatibility\n\nReleases v1.1.x:\n- 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. \n- From v1.1.6+ releases v1.1.x are only compatible with Laravel 5.5 in order to run tests correctly.\n\nTo date, releases v1.1.6+, v1.2.x, v1.3.x, v1.4.x, v2.x and v3.x are functionally equivalent.\nReleases have been separated in order to run integration tests with the corresponding version of the \nLaravel framework.\n\nHowever, with the release of Laravel 8, releases v1.1.14, v1.2.8, v1.3.8 and v1.4.8 are the last releases \nincluding new features for the corresponding Laravel 5.x versions (bugfix support is still active for that versions). \n**2021-02-13 UPDATE**: some last features for v1.1+ releases are still ongoing :)\n\nv1.0 requires Laravel 5.1, 5.2, 5.3 and 5.4 (no longer maintained and not tested versus laravel 5.4, \nhowever the usage of the package is the same as for 1.1)\n\n**2023-02-20 UPDATE**: From Laravel 10.x up, the package versions follow the same numbering.\n\n### Installation\n\nAdd gecche/laravel-multidomain as a requirement to composer.json:\n\n```javascript\n{\n    \"require\": {\n        \"gecche/laravel-multidomain\": \"12.*\"\n    }\n}\n```\n\nUpdate your packages with composer update or install with composer install.\n\nYou can also add the package using `composer require gecche/laravel-multidomain` and later \nspecify the version you want.\n\nThis package needs to override the detection of the HTTP domain in a minimal set of Laravel core functions \nat the very start of the bootstrap process in order to get the specific environment file. So this package \nneeds a few more configuration steps than most Laravel packages. \n\nInstallation steps:\n1. replace the whole Laravel container by modifying the following lines\nat the very top of the `bootstrap/app.php` file.\n\n```php\n//use Illuminate\\Foundation\\Application\nuse Gecche\\Multidomain\\Foundation\\Application\n```\n\n2. Override the `QueueServiceProvider` with the extended \none in the `config/app.php` file as follows:\n\n```php\n    'providers' =\u003e \\Illuminate\\Support\\ServiceProvider::defaultProviders()-\u003emerge([\n        // Package Service Providers...\n    ])-\u003ereplace([\n      \\Illuminate\\Queue\\QueueServiceProvider::class =\u003e \\Gecche\\Multidomain\\Queue\\QueueServiceProvider::class,\n    ])-\u003emerge([\n        // Added Service Providers (Do not remove this line)...\n    ])-\u003etoArray(),\n```\n\nPlease note that if you changed the `config/app.php` file due to other reasons, probably there is already \nthe above `providers` entry in that file and the only important line is the one which replaces the `QueueServiceProvider`.\n        \n3. Publish the config file.\n\n```\nphp artisan vendor:publish \n```\n\n(This package makes use of the discovery feature.)\n\nFollowing the above steps, your application will be aware of the HTTP domain\nin which is running, both for HTTP and CLI requests, including queue support.\n\nNOTE: in Laravel 11 the installation is simpler than before: if you use a \nprevious version of Laravel, please check in the documentation the installation steps.\n\n#### Laravel Horizon installation: \n\nThe package is compatible with Horizon, thatnks to community contributions. If you need to use \nthis package together with Horizon you have to follow other two installation steps:\n\n1. Install Laravel Horizon as usual\n\n2. Replace the Laravel Horizon import at the very top of the app/Providers/HorizonServiceProvider.php file.\n\n```php\n//use Laravel\\Horizon\\HorizonApplicationServiceProvider;\nuse Gecche\\Multidomain\\Horizon\\HorizonApplicationServiceProvider;\n```\n\n### Usage\n\nThis package adds three commands to manage your application HTTP domains:\n\n#### `domain.add` artisan command\n\nThe main command is the `domain:add` command which takes as argument the name of the \nHTTP domain to add to the application. Let us suppose we have two domains, `site1.com` \nand `site2.com`, sharing the same code.\n\nWe simply do:\n\n```\nphp artisan domain:add site1.com \n```\n\nand \n\n```\nphp artisan domain:add site2.com \n```\n\nThese commands create two new environment files, `.env.site1.com` and `.env.site2.com`, \nin which you can put the specific configuration for each site (e.g. databases configuration, \ncache configuration and other configurations, as usually found in an environment file).\n\nThe command also adds an entry in the `domains` key in `config/domains.php` file.\n\nIn addition, two new folders are created, `storage/site1_com/` and `storage/site2_com/`. \nThey have the same folder structure as the main storage.\n\nCustomizations to this `storage` substructure must be matched by values in the `config/domain.php` file.\n \n#### `domain.remove` artisan command\nThe  `domain:remove` command removes the specified HTTP domain from the \napplication by deleting its environment file.  E.g.:\n\n```\nphp artisan domain:remove site2.com \n```\nAdding the `force` option will delete the domain storage folder.\n\nThe command also removes the appropriate entry from, the `domains` key in `config/domains.php` file.\n\n#### `domain.update_env` artisan command\nThe  `domain:update_env` command passes a json encoded array of data to update one or all of the environment files. \nThese values will be added at the end of the appropriate .env.\n\nUpdate a single domain environment file by adding the `domain` argument. \n\nWhen the `domain` argument is absent, the command updates all the environment files, including the standard `.env` one.\n\nThe list of domains to be updated is maintained in the `domain.php` config file. \n\nE.g.:\n  \n```\nphp artisan domain:update_env --domain_values='{\"TOM_DRIVER\":\"TOMMY\"}' \n```  \n \nwill add the line `TOM_DRIVER=TOMMY` to all the domain environment files.\n\n#### `domain.list` artisan command\nThe  `domain:list` command lists the currently installed domains, with their .env file and storage path dir.\n\nThe list is maintained in the `domains` key of the `config/domain.php` config file.\n\nThis list is automatically updated at every `domain:add` and `domain:remove` commands run.\n\n#### `config:cache` artisan command\nThe config:cache artisan command can be used with this package in the same way as any other \nartisan command. \n\nNote that this command will generate a file config.php file for each domain under which the command has been executed.\nI.e. the command\n ```\n php artisan config:cache --domain=site2.com \n ```\nwill generate the file\n ```\n config-site2_com.php \n ```\n\n### Further information\nAt run-time, the current HTTP domain is maintained in the laravel container \nand can be accessed by its `domain()` method added by this package.\n\nA `domainList()` method is available. It returns an associative array \ncontaining the installed domains info, similar to the `domain.list` command above.\n\nE.g.\n ```\n [ \n    site1.com =\u003e [\n        'storage_path' =\u003e \u003cLARAVEL-STORAGE-PATH\u003e/site1_com,\n        'env' =\u003e '.env.site1.com'\n    ]\n ] \n ```\n\n#### Distinguishing between HTTP domains in web pages\n\nFor each HTTP request received by the application, the specific environment file is \nloaded and the specific storage folder is used.\n \nIf no specific environment file and/or storage folder is found, the standard one is used.\n\nThe detection of the right HTTP domain is done by using the `$_SERVER['SERVER_NAME']` \nPHP variable. \n\nIMPORTANT NOTE: in some execution environments $_SERVER['SERVER_NAME'] is not instantiated, so \nthis package does not work properly until you customize the detection of HTTP domains \nas described below.\n \n#### Customizing the detection of HTTP domains\n\nStarting from release 1.1.15, the detection of HTTP domains can be customized passing a `Closure` \nas the `domain_detection_function_web` entry of the new `domainParams` argument of `Application`'s \nconstructor. In the following example, the HTTP domain detection relies upon `$_SERVER['HTTP_HOST']` \ninstead of `$_SERVER['SERVER_NAME']`.\n\n```php\n//use Illuminate\\Foundation\\Application;\nuse Gecche\\Multidomain\\Foundation\\Application;\nuse Illuminate\\Foundation\\Configuration\\Exceptions;\nuse Illuminate\\Foundation\\Configuration\\Middleware;\n\n$environmentPath = null;\n\n$domainParams = [\n    'domain_detection_function_web' =\u003e function() {\n        return \\Illuminate\\Support\\Arr::get($_SERVER,'HTTP_HOST');\n    }\n];\n\nreturn Application::configure(basePath: dirname(__DIR__),\n    environmentPath: $environmentPath,\n    domainParams: $domainParams)\n    -\u003ewithRouting(\n        web: __DIR__.'/../routes/web.php',\n        commands: __DIR__.'/../routes/console.php',\n        health: '/up',\n    )\n    -\u003ewithMiddleware(function (Middleware $middleware) {\n        //\n    })\n    -\u003ewithExceptions(function (Exceptions $exceptions) {\n        //\n    })-\u003ecreate();\n```\n\n\n#### Using multi domains in artisan commands\n \nIn order to distinguishing between domains, each artisan command accepts a new option: `domain`. E.g.:\n\n```\nphp artisan list --domain=site1.com \n```\n\nThe command will use the corresponding domain settings.\n\n#### About queues\n \n The artisan commands `queue:work` and `queue:listen` commands have been updated\n to accept a new `domain` option.\n ```\n php artisan queue:work --domain=site1.com \n ```\nAs usual, the above command will use the corresponding domain settings.\n\nKeep in mind that if, for example, you are using the `database` driver and you have two domains sharing the same db,\nyou should use two distinct queues if you want to manage the jobs of each domain separately.\n\nFor example, you could: \n- put in your .env files a default queue for each domain, e.g. \n`QUEUE_DEFAULT=default1` for site1.com and `QUEUE_DEFAULT=default2` for site2.com\n- update the `queue.php` config file by changing the default queue accordingly: \n```\n'database' =\u003e [\n    'driver' =\u003e 'database',\n    'table' =\u003e 'jobs',\n    'queue' =\u003e env('QUEUE_DEFAULT','default'),\n    'retry_after' =\u003e 90,\n],\n```\n        \n- launch two distinct workers \n```\n php artisan queue:work --domain=site1.com --queue=default1\n ```\n and\n```\n php artisan queue:work --domain=site1.com --queue=default2\n ```\n\nObviously, the same can be done for each other queue driver, apart from the `sync` driver.\n\n#### `storage:link` command\n \nIf you make use of the `storage:link` command and you want a distinct symbolic link for each domain, you have to create \nthem manually because to date such command always creates a link named `storage` and that name is hard coded in the \ncommand. Extending the `storage:link` command allowing to choose the name is outside the scope of this package \n(and I hope it will be done directly in future versions of Laravel).\n\nA way to obtain multiple storage links could be the following.\nLet us suppose to have two domains, namely `site1.com` and `site2.com` with associated storage folders \n`storage/site1_com` and `storage/site2_com`.\n\n1. We manually create links for each domain: \n\n```\nln -s storage/site1_com/app/public public/storage-site1_com \nln -s storage/site2_com/app/public public/storage-site2_com \n```\n\n2. In `.env.site1.com` and `.env.site2.com` we add an entry, e.g., for the first domain: \n\n```\nAPP_PUBLIC_STORAGE=-site1_com\n```\n\n3. In the `filesystems.php` config file we change as follows:\n\n```\n'public' =\u003e [\n    'driver' =\u003e 'local',\n    'root' =\u003e storage_path('app/public'),\n    'url' =\u003e env('APP_URL').'/storage'.env('APP_PUBLIC_STORAGE'),\n    'visibility' =\u003e 'public',\n],\n```\n\nFurthermore, if you are using the package in a Single Page Application (SPA) setting, you could better handling distinct \npublic resources for each domain via .htaccess or similar solutions as pointed out by [Scaenicus](https://github.com/Scaenicus) in his \n[.htaccess solution](https://github.com/gecche/laravel-multidomain/issues/11#issuecomment-559822284).\n\n#### Storing environment files in a custom folder\n\nStarting from version 1.1.11 a second argument has been added to the Application constructor in order to choose the \nfolder where to place the environment files: if you have tens of domains, it is not very pleasant to have environment \nfiles in the root Laravel's app folder. \n\nSo, if you want to use a different folder simply add it at the very top of the `bootstrap/app.php` file. for example, \nif you want to add environment files to the `envs` subfolder, simply do:\n\n```php\n//use Illuminate\\Foundation\\Application;\nuse Gecche\\Multidomain\\Foundation\\Application;\nuse Illuminate\\Foundation\\Configuration\\Exceptions;\nuse Illuminate\\Foundation\\Configuration\\Middleware;\n\n$environmentPath = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'envs';\n\n$domainParams = [];\n\nreturn Application::configure(basePath: dirname(__DIR__),\n    environmentPath: $environmentPath,\n    domainParams: $domainParams)\n    -\u003ewithRouting(\n        web: __DIR__.'/../routes/web.php',\n        commands: __DIR__.'/../routes/console.php',\n        health: '/up',\n    )\n    -\u003ewithMiddleware(function (Middleware $middleware) {\n        //\n    })\n    -\u003ewithExceptions(function (Exceptions $exceptions) {\n        //\n    })-\u003ecreate();\n```\n\nIf you do not specify the second argument, the standard folder is assumed. Please note that if you specify a folder, \nalso the standard `.env` file has to be placed in it\n\n#### Default environment files and storage folders\n\nIf 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 \nenvironment file for that domain, i.e. the file `.env.sub1.site1.com` does not exist, the package will use the first \navailable environment file by splitting the domain name with dots. In this example, the package searches for the \nthe first environment file among the followings:\n\n```\n.env.site1.com\n.env.com\n.env\n```\n\nThe same logic applies to the storage folder as well.\n\n#### About Laravel's Scheduler, Supervisor and some limitation\n \nIf in your setting you make use of the Laravel's Scheduler, remember that also the command `schedule:run` has to be \nlaunched with the domain option. Hence, you have to launch a scheduler for each domain. \nAt first one could think that one Scheduler instance should handle the commands launched for any domain, but the \nScheduler itself is run within a Laravel Application, so the \"env\" under which it is run, automatically applies to \neach scheduled command and the `--domain` option has no effect at all.\n\nThe same applies to externals tools like Supervisor: if you use Supervisor for artisan commands, e.g. the `queue:work` \ncommand, please be sure to prepare a command for each domain you want to handle.\n\nDue to the above, there are some cases in which the package can't work: in those settings where you don't have the \npossibility of changing for example the supervisor configuration rather than the `crontab` entries for the scheduler. \nSuch an example has been pointed out [here](https://github.com/gecche/laravel-multidomain/issues/21#issuecomment-600469868) \nin which a Docker instance has been used. \n\nLastly, be aware that some Laravel commands call other Artisan commands from the inside, \nobviously without the `--domain` option. The above situation does not work properly because the subcommand will work with \nthe standard environment file. An example is the `migrate` command when using the `--seed` option.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgecche%2Flaravel-multidomain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgecche%2Flaravel-multidomain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgecche%2Flaravel-multidomain/lists"}