# Host Identification

Using the mesh to communicate to upstream hosts can sometimes require additional setup. Primarily, this happens when the upstream is behind some sort of load balancer (openshift routes, AWS lambda functions, etc). In these circumstances, a small number of IP addresses actual route to a large number of virtual hosts. To get to the proper endpoint, you will need to either setup `Server Name Identification` (SNI) or utilize the `Host` header.

## Table of Contents

* [SNI](#sni)
* [Host Header](#host-header)

## Configuration Reference

| Attribute               | Description                                                                   | Type     | Default |
| ----------------------- | ----------------------------------------------------------------------------- | -------- | ------- |
| `cluster.instances`     | The location of instances of this cluster                                     | `array`  | `[]`    |
| `cluster.sni`           | The server name of the intended target.                                       | `string` | `""`    |
| `domain.custom_headers` | An array of user-specified headers added to upstream requests to the cluster. | `array`  | `[]`    |

## Detailed Configuration and Usage

### Custom Headers

Objects in the `domain.custom_headers` array have two fields:

| Attribute | Description                                        | Type     | Default |
| --------- | -------------------------------------------------- | -------- | ------- |
| `key`     | The key of the header added to upstream requests   | `string` | `""`    |
| `value`   | The value of the header added to upstream requests | `string` | `""`    |

When specified, the given values are applied to upstream requests. For example, in the following domain:

```javascript
{
  "zone_key": "default-zone",
  "domain_key": "trek",
  "name": "*",
  "port": 8080,
  "redirects": null,
  "gzip_enabled": false,
  "cors_config": null,
  "aliases": null,
  "force_https": false,
  "custom_headers": [
    {
      "key": "hello",
      "value": "world!"
    }
  ]
}
```

the headers `"hello" : "world"` will be added to add requests going to the upstream host.

### Cluster Instances

Objects in the `cluster.instances` array have the following schema:

| Attribute | Description                                          | Type     | Default                                                                                                                       |
| --------- | ---------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `host`    | The default host name used to make upstream requests | `string` | `""`, or the value from [service discovery](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/discovery) |
| `port`    | The default port used to make upstream requests      | `int`    | `0`, or the value from [service discovery](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/discovery)  |

In most cases, these values are automatically populated by gm-control during service discovery, but they can also be manually specified if needed. For more information, see this information on [service discovery](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/discovery).

## SNI

SNI will be used when also performing SSL connections. During the SSL handshake, the intended upstream is given, which the router uses to forward along the request.

The cluster below is appropriate to forward requests to a GreyMatter edge node behind an Openshift router. Note the `sni` section that specifies this should go to the named server. Though this can seem redundant given the `host` section, Envoy actually resolves `greymatter.development.deciphernow.com` into a host:port pair which it uses to send the request. Attempting to send a request (without `sni`) to just the host:port will fail, as the router doesn't know the intended target.

```javascript
{
  "zone_key": "default-zone",
  "cluster_key": "service",
  "name": "service",
  "instances": [
    {
      "host": "greymatter.development.deciphernow.com",
      "port": 443
    }
  ],
  "require_tls": true,
  "ssl_config": {
    "cipher_filter": "",
    "protocols": null,
    "cert_key_pairs": [
      {
        "certificate_path": "/app/certs/justin.ely.crt",
        "key_path": "/app/certs/justin.ely.key"
      }
    ],
    "sni": "greymatter.development.deciphernow.com"
  }
}
```

## Host Header

When doing non-TLS requests, adding the header `"HOST"` on upstream requests can be used set a host name identification similar to TLS requests. Rather than having the router/load balancer identify the correct server from the SSL connection, it can read the `HOST` header of the plaintext http request, and route correctly.

An example of this is shown below, which was used to send traffic to an AWS lambda function. The `domain` below will append the HOST header keyword to all requests, making sure the router will know where to send them. Note this can ONLY be done on the `domain` object right now, so these headers will apply to all attached routes.

```javascript
{
  "zone_key": "default-zone",
  "domain_key": "trek",
  "name": "*",
  "port": 8080,
  "redirects": null,
  "gzip_enabled": false,
  "cors_config": null,
  "aliases": null,
  "force_https": false,
  "custom_headers": [
    {
      "key": "Host",
      "value": "3duly5keff.execute-api.us-east-1.amazonaws.com"
    }
  ]
}
```

If testing/verifying behavior like this with other means; tools like `curl` will accept header arguments, and the proxy will propagate them with requests. E.g. `curl -H "host: 3duly5keff.execute-api.us-east-1.amazonaws.com" http://localhsot:8080/` would accomplish the same thing as the domain above.
