Framework: Loading different env files using loadEnvironmentFrom is not working.

Created on 13 Mar 2018  路  5Comments  路  Source: laravel/framework

  • Laravel Version: 5.5.37
  • PHP Version: 7.0.13
  • Database Driver & Version: MySql [ 5.6.34 ]

Description:

Hi Laravel,

I want a functionality like loading different .env files based upon the subdomain of the website let me give you an example,

I have a domain like https://[subdomain].websitename.com and on every request i'm extracting the subdomain from the request url and trying to load the different env files which are stored at the root of the application just aside of .env with the name like .[subdomain].env

for loading the env file i'm using the below code in index.php

$tmp = explode('.', $request->getHost());
$subdomain = count($tmp) === 3 ? current($tmp) : '';
if (empty($subdomain) || realpath(__DIR__ . "/../.{$subdomain}.env") === false) {
die("Sorry, I think you are at wrong place, you shouldn't be here :).");
}
$app->loadEnvironmentFrom(".{$subdomain}.env");
$response = $kernel->handle($request)
$response->send();
$kernel->terminate($request, $response);

here, I have empty .env file which will not have any content inside because i don't want any default environment setup. i want subdomain specific settings for the application which will have different db, email & other settings that's why i have different .[subdomain].env files for each subdomains.

I have tried to see the loaded application setting which will show the correct env file loaded but the values are referenced from the old env which was loaded on the last request so, i thought loadEnvironmentFrom is not working as expected to work.

Steps To Reproduce:

  1. Install the laravel using installer or any other method
  2. setup multiple subdomains on your system and their env files with different setting for databases.
  3. write above code in index.php at the end of the file before processing the request.
  4. then try to load the database connections or any other config using the config('app').
  5. you will see that old values are loading.

thanks in advance,

Most helpful comment

I've implemented this at bootstrap/app.php just after $app creation:

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

switch(array_shift(explode(".",$_SERVER['HTTP_HOST']))){
    case 'sub1':
        $app->loadEnvironmentFrom('.env.sub1');     
        break;
    default:
    $app->loadEnvironmentFrom('.env');
    break;
};

And it works!!!

All 5 comments

Hi!

The loadEnvironmentFrom method is only setting the environment filename you hand over to it. It doesn't load the file directly. This happens in the bootstrapping part of the application by the DotEnv class.

Did you think about handling all that stuff in the bootstrap() method of the Kernel.php file? This would be the right place for it, I think, as this is one of the first places that is being loaded (as stated in the docs under https://laravel.com/docs/5.5/lifecycle ). IMHO the index.php file is the wrong place for that.

A possible solution for your problem:
Set your environment for every subdomain in your webserver vhost, so you don't need to write/extend any php code and just create environment files like eg. .env.subdomain1environment, .env.subdomain2environment, .env.subdomain3environment, ...
For more information please refer to the last paragraph above the blue information box in the docs: https://laravel.com/docs/5.5/configuration#environment-configuration

So, when using Apache2 for example, you could set your environment in your httpd.conf of apache or in your Laravel .htaccess file, with a check for the subdomains you have.

Sample code:

<If "req('Host') == 'sub1.yourdomain.com'">
    SetEnv APP_ENV=sub1
</If>

Or

SetEnvIf Host "^sub1\.yourdomain\.com$" APP_ENV=sub1

which will result in filenames like .env.sub1

OR

If the SetEnvIf is not dynamically enough for you and you don't want to specify every single subdomain, you can also try something like this:

SetEnvIf Host "^([^.]*)\.yourdomain\.com$" APP_ENV=$1

which will result in filenames like .env.sub1.yourdomain.com

You can find more information about the possibilities to switch configurations in the following part of the Laravel docs: https://laravel.com/docs/5.6/configuration#environment-configuration
Please have a special look at the blue boxes, there is more information about switching environments based on the APP_ENV environment variable.

I hope this helps. Feel free to ask if you have any further questions.

Best wishes
Tom

For Laravel 5.6, you can do this in public/index.php

I have different DB credentials for different servers; some are live, some are staging, some are dev. This makes it very easy to have a central area for storing configs for all the servers, without getting confused. Still avoid storing this in the repo though!

It also ensures I NEVER overwrite on .env with another incorrect one, destined for a different server.

You can easily adapt this to load for different subdomains.

/*
 * Let's make sure we load an environment appropriate for the server the code is running on
 */
$hostname = gethostname();
if (($d = strpos($hostname, '.')) !== false) {
  $hostname = substr($hostname, 0, $d);
}
putenv('APP_ENV=' . $hostname);

vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php checks if APP_ENV is set in line 52, and if it is, the value in APP_ENV is appended to the .env file name in line 57.

So a homestead .env file would be called:
/.env.homestead

My Windows dev server has a Windows name of WINDEV, and the .env filename becomes:
/.env.WINDEV

I've implemented this at bootstrap/app.php just after $app creation:

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

switch(array_shift(explode(".",$_SERVER['HTTP_HOST']))){
    case 'sub1':
        $app->loadEnvironmentFrom('.env.sub1');     
        break;
    default:
    $app->loadEnvironmentFrom('.env');
    break;
};

And it works!!!

I've implemented this at bootstrap/app.php just after $app creation:

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

switch(array_shift(explode(".",$_SERVER['HTTP_HOST']))){
    case 'sub1':
        $app->loadEnvironmentFrom('.env.sub1');       
        break;
    default:
  $app->loadEnvironmentFrom('.env');
  break;
};

And it works!!!

it does not work in Lumen5.6

i try other like this,
my vm or container set environment SERVICE_TAGS, and my local mac not set it.

``` = php
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);

$tag = getenv('SERVICE_TAGS');

if ($tag != null) {
switch($tag){
case 'staging':
$app->loadEnvironmentFrom('./env/.env.staging');
break;
case 'production':
$app->loadEnvironmentFrom('./env/.env');
break;
default:
$app->loadEnvironmentFrom('./env/.env.local');
break;
};
} else {
$app->loadEnvironmentFrom('./env/.env.local');
}
```

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments

JamborJan picture JamborJan  路  3Comments

gabriellimo picture gabriellimo  路  3Comments

Fuzzyma picture Fuzzyma  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments