# Production server provision configures Staging envs if hosts are the same - Bug or Intention?

**URL:** https://discourse.roots.io/t/production-server-provision-configures-staging-envs-if-hosts-are-the-same-bug-or-intention/6090
**Category:** trellis
**Created:** 2016-03-02T16:09:21Z
**Posts:** 10

## Post 1 by @craigpearson — 2016-03-02T16:09:22Z

I’m not sure if this is my misunderstanding of host files or whether this is a bug. Here’s my situation:

In trellis/hosts/ :  
**Staging**

```
[staging]
195.50.84.246

[web]
195.50.84.246
```

**Production**

```
[production]
195.50.84.246

[web]
195.50.84.246
```

The above configuration would assume that both staging and production are on the same server. With the latest HEAD version of Trellis, if I run a server provision for production using: `ansible-playbook server.yml -e env=production`

The above actually provisions the server for staging and not production. I.e. all my staging yaml configs are loaded and not my production files.

All other files are configured correctly as when I remove the IP decleration from the staging host file and run `ansible-playbook server.yml -e env=production` the production server is configured as expected using the production yaml files.

Is this expected behaviour?

---

## Post 2 by @fullyint — 2016-03-02T18:09:04Z

@craigpearson Thank you for reporting this! It is definitely not the intention that Trellis will load staging information when you specify `env=production`. It’s an ‘unexpected behavior’ resulting from an unexpected usage of including your host `195.50.84.246` in multiple environment groups (in `[staging]` and `[production]` simultaneously). Ansible sees multiple groups for the host and picks one; not always the one you want.

Your unexpected usage is to have both staging and production on the same server. I realize there may be some cases/arguments for it, but generally the recommendation is to put them on separate servers. The $5/month DigitalOcean droplets make it feasible. I like having the freedom to mess with a site’s staging server without constraints. I wouldn’t have this freedom and full ability to test things if the server were serving the production site. I couldn’t reprovision, reboot, rebuild as much as I like to do.

Thinking about Ansible internals, I’m not sure we can just make this issue silently fix itself in the background. However, I’m pretty sure we can detect that a host is in multiple environment groups, halt the playbook, and present a message suggesting a couple options. You can choose one of these options.

**Option 1 - Adjust host files, use same commands**  
I’d recommend this option. Adjust your hosts files like this:

```
# hosts/staging
my_staging_hostname ansible_host=195.50.84.246

[staging]
my_staging_hostname

[web]
my_staging_hostname
```

( **Edit** in file below, suggested by @dutchmichael [here](https://discourse.roots.io/t/production-server-provision-configures-staging-envs-if-hosts-are-the-same-bug-or-intention/6090/10): `[staging]` should be `[production]`)

```
# hosts/production
my_production_hostname ansible_host=195.50.84.246

[production]
my_production_hostname

[web]
my_production_hostname
```

You can edit `my_staging_hostname` and `my_production_hostname` to be whatever you want, so long as it is not an IP and the name is consistent across its three appearances in any given host file. This resolves the problem by assigning a hostname that differs between the `[staging]` group and the `[production]` group, even though the underlying `ansible_host` parameter is the same.

Then you can run `ansible-playbook` commands like normal.

**Option 2 - Adjust your commands**  
As you know, the [default inventory](https://github.com/roots/trellis/blob/2a1954b18b3d274d8a015a0f3b4f7ad7a27cfbb6/ansible.cfg#L4) Trellis loads is the entire `hosts` directory. You can override this and make it load just the `hosts/production` file by adding the `-i` option (inventory file) to your command:

```
ansible-playbook server.yml -i hosts/production -e env=production
```

or

```
ansible-playbook server.yml -i hosts/staging -e env=staging
```

---

## Post 3 by @craigpearson — 2016-03-03T01:11:46Z

Thanks a lot for getting back to me on this, I really appreciate the time you’ve taken to explain not only the issue but also two solutions. Although my gift may not amount to much… here’s some virtual beers :beer: :beer:

I ran into the issue on a dreaded rushed job really, I wouldn’t normally attempt to have a staging environment and production environment on the same server. There was a bit of cross over on content population and database migration issues so I was looking at this setup as an interim “fix” in the project. Your solutions worked and you saved my bacon!

---

## Post 4 by @jecko — 2016-04-05T18:30:29Z

Hi @craigpearson

Which options works for you 1 or 2?

Thank you

---

## Post 5 by @jecko — 2016-04-05T18:59:47Z

Hi @fullyint,

Not sure to understand what you mean here: [quote=“fullyint, post:2, topic:6090”]  
Option 2 - Adjust your commands As you know, the default inventory Trellis loads is the entire hosts directory.  
[/quote]

Would you mean the files loads for staging and production if we didn’t add -i param even if we only choose env=staging?

I am looking to put the two environments on same vm instance: [dev.site.com](http://dev.site.com) into a dev directory and [site.com](http://site.com). to another dir.

Is the 1rst option you suggest will do that?

@RiFi2k Did you try that setup?

Thank you

---

## Post 6 by @fullyint — 2016-04-05T21:31:55Z

@jecko

### Background

Ansible uses your local “control machine” to run commands on other machines. The other machines can be a Vagrant VM or remote servers (e.g., at DigitalOcean). When you run an Ansible command on your local control machine, you must inform Ansible which machines (servers, “hosts”) should be controlled. This involves two steps.

**1. Specify hosts.** Trellis follows a common Ansible practice of specifying the “hosts” (machines, servers) affected in the playbook [`hosts`](https://github.com/roots/trellis/blob/9527520e6647e4b7708689c48d42fe928a7e7c68/server.yml#L13) parameter.

**2. Specify inventory file(s) containing machine info (aka “hosts” file).** You inform Ansible about the machines to be controlled by listing them in an [“inventory” (aka “hosts”) file](http://docs.ansible.com/ansible/intro_inventory.html). You can have more than one inventory file. Trellis lists its inventory files in the [`hosts`](https://github.com/roots/trellis/tree/9527520e6647e4b7708689c48d42fe928a7e7c68/hosts) directory.

Ansible needs to know which inventory file(s) to use any time you run a playbook or command. The [Trellis default](https://github.com/roots/trellis/blob/9527520e6647e4b7708689c48d42fe928a7e7c68/ansible.cfg#L6) instructs Ansible to read all the inventory files in the `hosts` directory.

The Trellis inventory files group machines by environment, with `[group_name_in_brackets]`. This group membership determines the variables (`group_vars/environment`) used for the machine when you run a playbook. The recommended Trellis setup is for any given machine to be in only one environment group.

Although the Trellis default is to make Ansible aware of machines in all environments by loading all files in the `hosts` dir, a machine’s membership in only one environment group ensures that the right `group_vars` will be used for that machine.

The original issue discussed in this thread was that a machine/server was listed in multiple environment groups and thus the wrong set of `group_vars` was being applied on occasion.

> [@fullyint](#):
>
> Ansible sees multiple groups for the host and picks [the `group_vars` for] one; not always the one you want.

To get around the problem, **option 1** avoids the problem by assigning a single machine/IP a different nickname to use in the different environment groups. The unique name per group is the solution.

In **option 2** , the `-i` (inventory) option was added to the command to specify only the inventory file for a given environment, overriding the Trellis default of reading all inventory files. Then Ansible doesn’t even know that a machine/IP is in any other environment groups and has no trouble picking the correct `group_vars`.

### Your questions

> [@jecko](#):
>
> Would you mean the files loads for staging and production if we didn’t add -i param even if we only choose env=staging?

Unless you specify `-i` all inventory files in `hosts` will load. This is fine and would even be desirable for playbooks that need to coordinate between servers in multiple environments. It is only a problem if a machine is listed in multiple environment groups, as discussed above.

When you include the extra-var `env=staging`, you are instructing Ansible to affect the machine(s) in the `staging` group. If that machine is also in the production group, Ansible will have to pick between the `group_vars` for `production` and `staging` and may not pick the one you expect. Using `-i` to _only_ let Ansible know about the machine’s membership in `staging` is just one of the two options for getting around the problem.

> [@jecko](#):
>
> I am looking to put the two environments on same vm instance: [dev.site.com](http://dev.site.com) into a dev directory and [site.com](http://site.com). to another dir.

Try using the standard [`example.com`](https://github.com/roots/trellis/blob/9527520e6647e4b7708689c48d42fe928a7e7c68/group_vars/production/wordpress_sites.yml#L6) site key in production, but changing the [staging site key](https://github.com/roots/trellis/blob/9527520e6647e4b7708689c48d42fe928a7e7c68/group_vars/staging/wordpress_sites.yml#L6) to `staging.example.com` (also in [`vault.yml`](https://github.com/roots/trellis/blob/9527520e6647e4b7708689c48d42fe928a7e7c68/group_vars/staging/vault.yml#L11)). Then, you’ll find your two different sites/envs on your server in separate directories:

```
srv/
  www/
    example.com/
    staging.example.com/
```

Also see [this thread](https://discourse.roots.io/t/staging-and-production-on-same-vps/2440/23) for notes on challenges of putting staging and production on the same server.

Finally, with all that said, I simply would not recommend doing any of this. I recommend that you do not put staging and production on the same server. See earlier comments in this thread for why not, and [here](https://discourse.roots.io/t/staging-and-production-on-same-vps/2440/10) and elsewhere on Roots discourse.

---

## Post 7 by @craigpearson — 2016-04-05T21:52:12Z

This is by far the most comprehensive answer I’ve ever read! This is getting bookmarked!

---

## Post 8 by @jecko — 2016-04-06T13:17:51Z

Thank you for this great, detailed, complete answer, and for your time, I really appreciate.

---

## Post 9 by @nathanielks — 2016-08-02T21:32:15Z

For future reference, this also applies to web hosts that give an account one IP address, but individual stages are given separate port numbers to SSH into. For example, I’m using Trellis locally and Kinsta to host a client site. Each stage in Kinsta uses the same IP address, but different port number. Creating a custom host at the top of the hosts file like @fullyint demonstrated is the proper solution to this!

---

## Post 10 by @dutchmichael — 2017-06-05T23:58:55Z

> [@fullyint](#):
>
> # hosts/production
> 
> my\_production\_hostname ansible\_host=195.50.84.246
> 
> [staging]  
> my\_production\_hostname
> 
> [web]  
> my\_production\_hostname

Need to change [staging] to [production] in option 1 - Adjust your host file like this.
