So I am developing an application that has two kinds of deployments. One is they host everything and there is one application / one database and no issues. The second (the one this question will center around) will have one application but different database connections per client.
Access to each domain will be white-listed so we don't have to worry about one client popping another clients domain in and their is other authentication on top of that.
What I need is two-fold:
a way to determine the client that is accessing the application (request headers? domain driven?)
grab the configurations for said client so they only access their databases information (use a certain .env file based on client?).
One idea I have thought of is using apache to set env variables based on the domain requested. However, I would prefer to keep this handling inside of laravel. Any ideas?
We do this very thing. As you noted, you need some authority that can map domains to clients, and then a away to fetch the client-specific settings.
Here is how we set it up:
We have different Apache vhost per client, with all the domains/aliases the client has setup. In the vhost file, Apache gives us one single env variable CLIENT_ID. That way we know who the client is, no matter which domain alias is being used at any one time.
We have a Laravel service provider then that looks at env('CLIENT_ID') and sets up a number of config options. One of the things that gets set is a client-specific path, where we store a number of client-specific resources and files. So we're doing something like this:
Config::set("paths.client", "/var/www/clients/" . env("CLIENT_ID"));
Now that we have the client-specific paths setup, we can use Dotenv to go load a client-specific .env file for this client. Note we still have a root .env file in our app directory (Laravel expects it) which sets up common config. The client-specific .env file sets up client-specific stuff like SMTP settings, and of course database connection settings.
Dotenv::load(Config::get("paths.client"));
Now that the client-specific .env is loaded, we can easily write to the database.connections config array. And from there on out, eloquent and everything else just work.
Config::set('database.connections.mysql', [
'database' => env('DB_DATABASE'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
]);
You wouldn't have to do it this way of course. We chose Apache vhosts as our authority for mapping domains to clients, but you could have a master database or just a config file. Then in your service provider, you just need to ask the master db (or the config file) what client needs to be setup.
From there your client settings could even be in the master database or config file, if you didn't want to store separate .env files. Whole lot of ways you can skin this cat.
Ultimately, however you get there, you once you set the database config connection array, you're good to go.
Update:
For anyone reading this in the future, there is another very simple way to load alternate .env files as mentioned in the comments below:
If you set APP_ENV somehow before you get to Laravel (SetEnv in virtualhost etc) it will by default look for .env.APP_ENV (Ex: .env.demo) file. I am using SetEnv to set APP_ENV and then creating .env files for each client.
For our purposes, we didn't want client-specific .env files sitting in the root of our app. But it could work quite well for other situations.
Related
I got a legacy code in symphony, but the systems works like this for each client has a system and one database, but the both are same for all of them, so i have "twenty" same systems "folders" for each client and each client has a database.
So, I'm trying to change this to one folder for all clients, but I've been having a problem with the databases, because the file .env we can set only one database for .env file, so, in this case i think to create a folder inside the system "envs" and i created for each client one .env with their names
Example: .envtest, .envgoogle, .envfacebook and etc...
And i use this function on public/index.php to set the corret .env
(new Dotenv())->load(DIR.'/../envs/.env'.explode(".", $_SERVER['HTTP_HOST'])[0]);
and when client trying to access the system i get from the $_SERVER the URL how i can concat and get the corret .env
but i think that i'm doing too wrong, there is other way to do this?
I can understand your problem. You can ask the creaters of symfony and they can help you. Just write your question in thier website here (choose any course and then put your question):
https://symfonycasts.com/
In my case, I have so many databases for my clients but in diffrent servers (LDAP and Soap) so it was easy for me. but in your case it is better to ask Symfony creater themselves.
I want to remove the CMS of my silverstripe web system and host it separately in a different server. What is the best way to do this?
As with all web application, back up the source code, assets and database... then restore them on the target server. There is a utility to aid you with this called sspak. I think you still need to handle .env files manually as these contain the most sensitive information (i.e. database passwords).
Other considerations might be if you have crons installed to ensure they are migrated. Also be sure to watch for anything whitelisted/authorised by the existing servers IP.
I know that my credentials could be stored in var/ directory but it doesn't feel right to me. How can I add an extra layer of security in order to keep the credentials safe?
Credentials should be stored in a file. This could either be a php file, or a .env file for example.
Credentials can be stored in plain text.
Your first line of defense is to store these files in a folder which is not accessible through your webserver.
For example:
/home/you/www/public -> public files go here, e.g your index.php
/home/you/www -> all other files, including vendor libs etc, and your config files
(The public folder should be defined as your serving folder in your virtual host configuration)
Your second line of defense is happening on your system. For example, maybe you have a special user with a strong password for your specific site. Basically, in this second line of defense you really specify who can access your files, who has SSH Access, etc.
Your third line of defense is configuring your database correctly. You might only need to allow local access for example?
Now, your fourth line of defense is making sure your credentials are never ever ever printed in error messages or logs, especially not in errors to web users. Differentiate between develop and production status in your scripts.
And there's more (monitoring incorrect logins, fail2ban, etc), but these are the basics. Most of them are handled when you use a php framework, like Laravel. Laravel differentiates between public and non public, uses .env files, allows you to define production status, and will limit error output to users.
I am running a Symfony 2.8.6 application on nginx/php-fpm.
There are multiple domains that are resolved into this server, and basically what I want to do is change RDB configuration according to which domain was used to access.
So my nginx.conf has lines like fastcgi_param SYMFONY__SOME__PARAM $host, but I have a problem.
This parameter injection is cached and not working as intended.
For example, there are two domains a.example.com and b.example.com, and they point to my server.
I want it to connect to different MySQL server when accessed through different domain, but it ignores the domain and connects to the same server always.
What I've confirmed:
Nginx passes the variable correctly.
The output of var_dump($_SERVER['SYMFONY__SOME__PARAM']) changes as expected.
The parameter is stored in app/cache/prod/appProdProjectContainer.php
AFAIS there are two options: disabling configuration cache totally, or disabling caching environment variables.
I think the latter option is more preferrable, but I even don't know how to disable the cache, whether totally or partially.
Using dynamic environment variables in service definitions is not possible in Symfony (see symfony/symfony#16403 (comment) why). You can try to use Incenteev/DynamicParametersBundle, but I have no experience with it.
How about changing cache directory for each environemnt.
fastcgi_param SYMFONY__CACHE_DIR /path/to/cache
I've developed a Web application with Laravel and everything is ok.
This should be a multi-tenant application, so I would like to share the same code but to use a different database for each tenant (I decided for this architecture as according to me it is too complex to share database schema or records among tenants).
Every tenant is accessing the application with its own third level domain (tenant1.xxxx.com, tenant2.xxxx.com, etc)
I would like then to create n. databases (tenant1, tenant2, etc) and to create n. database config file in Laravel (database.tenant1.php, database.tenant2.php, etc)
The problem now is that I cannot find an elegant way to alter the database config file loading system in Laravel.
I should select the config file, based on the host name used by the customer.
Any help would be appreciated.
Thank you,
Michele
in your config folder, there is a 'database.php' file. in that file you can see an array called 'connection' .
'connection' array manages different configuration for multiple database connections.
you can define your configuration for each of tenants in 'connection' array and based on the scenario you are in it, you can choose the appropriate connection to handle your query with a syntax like this:
DB::connection('tenant1')->select('where...');
or
DB::connection('tenant2')->select('where...');