Multiple production environments with multiple configs - php

For the first time I'm making a new web app in Laravel 7 which is going to be deployed on more than one server. Every server has it's own environment variables.
From my previous experiences in Zend framework, all variables were in one config file under some kind of paragraphs. First, there were variables that are common for all environments. After that, every environment have their own overwritten variables. Specific environment was set in index.php and index.php was not deployed. So it's very easy to use and to constantly deploy changes.
My question is, what is the best solution for this purpose in Laravel. So, I need some kind of basic configuration that can be inherited and possibly overwritten in some parts. If there is no something similar, what do you advise me?

Typically, configuration inheritance is a tricky thing to do. If you do not have complete overview over the configurations used, you can end up like one of the companies that send a push notification to the wrong users.
Laravel is built in a way where the default configuration can be set in the config folder and overridden using the .env file. This is how Laravel is intended to be used, so I suggest doing that.
Or, if you prefer, you can have a folder of .env files and then moving the correct one to the root on deployment.

Related

What are the advantages of storing info on .env files as opposed to .php files?

Considering storing settings information on a .env file, outside the document root folder, as the best practices suggest... What would be the advantages of using .env files as opposed to .php files?
.env files would be parsed by a library and stored on ENV variables.
.php files don't need parsing and will store info on ENV variables.
Thanks!
When developing you will have a set of keys that you configure on your local environment or whichever other enviroment you are developing. These keys (password to databases, email services, etc) you do not wish to share with other developers that work along side you. Neither if you are sharing the code with the world.
.env files where created in order for you to have a working environment without having to share those keys with the world or the rest of your team. They are supposed to be singular to the environment the project is settled.
When you create keys that are going to be used across the project, besides of adding them to your .env file you also should add them to the .env.example which is pushed to the repository. Leave the keys present in there while keeping the values empty for the .env.example so other developers understand what are the required keys for the project to work and what they should add in there while not giving a hint of what your local passwords are.
Also when you are working on local environments you normally use local passwords. A problem arises when you are deploying to a production server where real passwords that contain sensitive information will exist. So you do not want these to exist on your repository and definitely you do not desire these to be permanently stored in your repository (this comes with profession responsibility, specially when you are tagged just as a developer and not a sys admin, in the case where the sysadmin will add the keys once the project is deployed on the production environment).
It is a elegant way to bypass these problems above
In response to your second question in the comments
To be honest you can do it both ways if you end up following what I explained above. The main goal is to keep your variables protected. But you can just refuse to push the php file to repo.
In my opinion on why you should use .env instead of .php goes as follow:
1. with .env you immediately know it is a environment variable holder. .php regardless of how you name it is not as direct in understanding;
2. .env will be an ocult file when listing a directory;
3. It is easier, when working whit other developers in the same repo, to quickly identify and understand something should not be pushed on that commit (think even on the case of adding extra layer of security on a hook to make sure .env is not pushed on the commit. It is harder and you have to hardcode this for .php files);
I guess in your argument level these will be a few of the Go Tos when deciding between files. I would leave the .php files to be precisely that, php programming files instead of configs;
Now if you ask me between .env or .yml etc, I would say go with the one you are familiar/feel comfortable. At the end you avoided the .php the same :)
PS: Also, if you think on how you will reference them within the code whenever you need one of the environment variables it jumps way quicker to the eye when you see something like:
getenv('YOUR_VARIABLE_HERE');
.env files were created to make development more easy, and is not only used in PHP, as example in ruby you can use .env files https://github.com/bkeepers/dotenv.
If we take a look at the twelve factor principles. The following is stated:
The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.
https://12factor.net/config
So dotenv is just a tool to make this easy for the developers

How to keep CodIgniter application and config in their own in git repos?

Can anybody tell me what kind of workflow should I follow to keep my application source and configuration tracked in Git? I want to keep my config separate from my source is because there is one config for development, another for production enviroment and, and a third for local testing.
It's not unheard of to have a repo just for configuration files (just make sure that git repo does NOT HAVE PUBLIC ACCESS (so, not github unless you have private repos enabled). You end up with a repo for code, and a repo for configuration files, sometimes maintained by a different team (say, the deployment team).
The problem you have is that as far as I'm aware, git doesn't particularly like having multiple repos at the same level.
I don't know anything about CI, but I think it stores its configuration files in application/config.
Two options I can think of:
You can convert all application/config to a git repo and gitignore that folder from the main development repo.
If converting the whole folder into a repo is not feasible (say, some of the configuration files actually belong to the application repo), maintain a separate repo folder somewhere else in the system and symlink your necessary configuration files to application/config (and gitignore those symlinks in your code repo)
There is no need to use separate Git repositories. CodeIgniter supports the idea of environments:
Developers often desire different system behavior depending on whether an application is running in a development or production environment. For example, verbose error output is something that would be useful while developing an application, but it may also pose a security issue when "live".
The ENVIRONMENT Constant
By default, CodeIgniter comes with the environment constant set to use the value provided in $_SERVER['CI_ENV'], otherwise defaults to 'development'.
Set the CI_ENV environment variable for each server process to tell CodeIgniter which environment you're on. Depending on your stack this could involve using Apache's SetEnv, a shell export, or other mechanism.
Then you can set up environment-specific configuration files:
To create an environment-specific configuration file, create or copy a configuration file in application/config/{ENVIRONMENT}/{FILENAME}.php
For example, to create a production-only config.php, you would:
Create the directory application/config/production/
Copy your existing config.php into the above directory
Edit application/config/production/config.php so it contains your production settings
When you set the ENVIRONMENT constant to ‘production’, the settings for your new production-only config.php will be loaded.
Additionally, you may want to load certain settings directly from the environment, as described by the The Twelve-Factor App. (This isn't something that I've seen people do with CodeIgniter before, but it's a useful idea in general.)
For example, it might make sense to keep API keys or database connection information out of your config files, or to leave development-friendly values in your config files and override them with values loaded from environment variables.
An answer from a similar question will help you, it is answer by SO user #dwilkins.
Mr dwikins answer is simple, clear and effective. He suggest gitignore any conf you don't want, but remember to create "conf.sample" sample file.
Mr #alex-stuckey comment to add README file to guide other team member to use the "sample" file.
The following workflow was used back when i was a system administrator and we made scripts that depended on a config preset.
Basically, the main script was always the same, and the script's actions would depend on a config file that would hang from the master branch as so:
Master
|----Script.py
|----config_template.cfg
From Master we would take a branch that looked like so
Mimulation_machine
|----Script.py
|----simulation.cfg-------------->this was the modified config file
The workflow was to switch to master and create a new branch, that would eventually hold the configuration files. It is important that the branches would never merge back to master though. This may not be the best answer nor the most correct but it worked, and allowed us to switch to different configurations with a simple checkout.
Mind you that is an oversimplified verion of what we really had going on, we had a complex structure made out of gitignores and so.

How to better setup production env settings for a Laravel project?

As stated in the documentation, Laravel 5 uses a cool system called DotEnv. It enables us to configure all sorts of environment variables which will be available inside the project. As it may contain keys, it should be ignored in the source code.
Also, as its name is default, each machine/developer should have its own .env file.
Here comes the trouble: first, this is a private project. So I don't really mind stashing keys in the repository. Second, from other frameworks (Symfony? Yii?), I'm used to having separate settings for prod/stg/dev environments. But as the file is unique, this is not possible. Finally, I didn't want to mess with the production machine.
What's the best way to set those things up?
It's typical to exclude the .env file from your repository using a .gitignore file so that they may be configured differently for different environments.
You can create multiple .env files and manually upload them to your staging/testing/production environments. You would only need to do this once and change your settings depending on your environment.
Once in place, future deployments from your repository will not deploy your .env files and your environments will have separate configurations.
Years passed and after some more experience, I can still say both approaches (ignored and non-ignored) env files have their good points.
The best approach on Laravel, for private projects, is to keep the shared keys in .env.example, together with sane defaults (such as APP_ENV=prod or APP_DEBUG=false) and leave to the developer installing the project the task to configure some of those variables, and those that are empty (i.e. logging channels or personal keys).

The point of Yii2 environments folder

I am trying to work what the point of the environments folder is.
Originally I had the idea that you could point the webserver to the different dev and prod folders in the environment folder but after reading up a bit I realise this is not the case.
In Yii 1 you would solve this by just having multiple index.php's i.e.:
index.php
index-local.php
So the question is what benefit does this new environment structure actually give me over the old way?
I've found environments very useful in allowing me to keep a common code base for multiple client projects (based on Yii App Advanced) and setting up a different environment for each specific client, keeping their custom code private and separate.
To do this I store the environments folder in a separate git repo from the rest of the code and pull down the relevant folder on a client/project basis.
This lets me use a base common code for all projects and add/override any file for a specific client or project whilst still allowing separate dev/prod config settings. If the client uses other developers too, they are also catered for. In this way, only common code I choose will be shared amongst clients and custom code will be kept private.
I've also moved the composer.json file into the environments folder so I can pull in different extensions per client/project keeping those private too.
That init command can be a very powerful tool and you don't have to limit yourself to the template provided by the core developers.
If you don't need environments, then don't use them, but I assure you some people will find it very useful.
Yii2 documentation in WIP, but you should read this :
https://github.com/yiisoft/yii2/blob/master/docs/guide/apps-advanced.md#configuration-and-environments
You need to use yii init command to switch between these environments.
EDIT :
This new environment feature is more than just use different config file. You can use different folder structure, different entry script...etc
Personnaly I won't use this feature, I don't need it (I will use a different entry script as with Yii 1), but I think this is not useless.
I think you didn't get the real purpose of environments introduced in Yii2.
I'll try to explain what was the main purpose of adding environments to yii from the developers point of view on an example and hope you will really appreciate its usefulness.
Let's suppose for a moment that you are a team of developers (e.g. 5-7 person) working on mid-to-large project implemented in Yii. To effectively work on that project your team decides to use some CVS or SVN (e.g. GIT) and keep all the files of the project in repository in cloud for the whole team. That's de facto standard while working on mid-to-large projects in teams and nobody will resist that it's the only comfortable and easy way.
Ok, now let's suppose you use Yii 1.x or Yii2 with the approach of different entry scripts to differentiate between local (development) and production environments to connect to db or set some other environment specific configs. Everything is ok and working. But suppose your team members implemented something new on the project and you check out repository to work on updated version and you suddenly find out that your local config file (in this case entry script with config) is overwritten with other team member's file who pulled the changes to repository (because each of you is using your local machine db with other database name or OS, or config, or simply because your team uses one local development server db, but you are on vacation and can't use anything except your local machine).
So generally Yii2 environment adds more flexibility for using different environments each with it's own specific configurations while using also general (common) configs when working in teams on mid-to-large projects hence why the example in guide is given on advanced app project.
Surely you can overcome everything stated above with some solutions or .gitignore which is used by default to overcome the problem stated in Yii2 with environments. But:
Why bother if everything is already done?
and
It was just one little example of usefulness of Yii2 environments. More depends on the project and your imagination.
Overall Yii2 is great product. Not only it adds many new features to already great framework, but it also is more robust and flexible than Yii 1.x (despite the fact that Yii 1.x was already very robust).
As for Laravel or any other PHP framework, it really depends... Everyone will find his/her own favorite.
For those who are tired of copying files around, I created a useful script that you can run in background to keep the files in sync on your dev environment:
File sync-env-files.sh
#!/bin/bash
ENVIRONMENT_DIR="/var/www/example.com/environments/dev/"
DIR="/var/www/example.com/"
while [ true ]; do
for envFile in `find $ENVIRONMENT_DIR -type f`
do
file=${envFile/$ENVIRONMENT_DIR/$DIR}
if [ `stat -c "%Y" $file` -gt `stat -c "%Y" $envFile` ]; then
#echo "copying modified file $file to $envFile"
/bin/cp -f $file $envFile
fi
done
sleep 2
done
Then run the script in background or add to cron with flock
nohup server/sync-env-files.sh >/dev/null 2>&1 &
I would like to mention in addition to #AngelCoding, since this question still gets seen, that I use the environments folder lots now and definitely see the point of it.
The very first things I do in any open source project is create one project for the code base on GitHub and then another, private, one on Bitbucket for the configuration, in other words the environments folder.
Having this folder has made it a lot easier for me to separate my configuration into a private repository.
So the environments folder has a lot of uses and really helps to separate configuration for easier usage even if it does not seem like it initially.

Production, development, staging configs in ZF2?

I've read several tutorial on the subject, but still don't completely get what's expected from the developer wanting to make ZF2 app environment aware:
http://blog.evan.pro/environment-specific-configuration-in-zend-framework-2
http://www.spiffyjr.me/2012/06/17/how-does-configuration-work-in-zf2/comment-page-1/
ZF2 s not aware of environment concept by design - it's left to a developer to implement. I'm not entirely clear on how it's supposed to be done...
Reading through Evan's post it seems like there are 2 mechanism - and preferred one is not to use APPLICATION_ENV constant, just .local, .global files?
How should that work? Could someone describe a process they go though to make ZF2 environment aware? And what you do when code is to be pushed to different environment?
It seems like the idea is right now to have for ex: module1.local.php.dist-testing, module1.local.php.dist-production, module1.local.php.dist-development and when code is moved to different environment the idea is that these should be copy-renamed for that environment and passwords filled in manually? Am I correct?
The idea is that you provide some sensible default configuration with your application, but you do not store anything for a concrete environment with your code, nor in your version control system.
If you have for example two servers, one for production, one for development, you provide only the configuration details for one single environment in such a .local file. This way, your development server cannot know e.g. the master password for the production database. So it cannot accidentally happen that you get a new development server, and somebody forgets to set APPLICATION_ENV, and you start developing and mess up your production database, because the application knew the passwords.
Or the other way around, a new production server cannot accidentally access the development database.
So your application is aware of the environment automatically by reading the file that is present - and there is only one file per environment present that has all the details.
This puts the burden of ensuring that the correct file is present to the administrator - or the puppet script that configures everything. But the environment specific configuration will not be deployed within the application.

Categories