# Custom Nginx Includes in Trellis

The Nginx site conf generated by Trellis is designed to work with a wide range of WordPress installations, but your sites may require customization. For example, perhaps you use custom `rewrite`s to redirect legacy URLs, or maybe you would like to proxy some requests to another server. You may create custom Nginx `include` files or use child templates to extend the Trellis Nginx conf templates.

## `include` files

You may put your Nginx customizations in Ansible/Jinja2 templates, making full use of variables and logic. Store your template files in a new `nginx-includes` directory in your project's `trellis/` directory (e.g., sibling to `server.yml` playbook). If you prefer to name this directory `some-other-name`, you may define `nginx_includes_templates_path: some-other-name` in your `group_vars/all/main.yml`.

Trellis will recurse `nginx-includes` and template any files ending in `*.conf.j2` to the `/etc/nginx/includes.d/` directory on the remote, preserving the subdirectory structure. If you want to edit, add to, or delete your Nginx include files, edit them on the local machine and re-run the playbook.

::: tip
Append `--tags nginx-includes` to your command to run only the relevant portion of the playbook.
:::

### Default

By default in Trellis, a WordPress site's Nginx conf will include any `nginx-includes` files found in a subdirectory named after the site. Only the directories that match sites in your `wordpress_sites.yml` will be templated to the remote by default, with the addition of `all/`.

To illustrate, suppose you have two sites managed by Trellis, defined in `wordpress_sites` as follows:

```yaml
wordpress_sites:
  site1: ...
  site2: ...
```

You could organize your `nginx-includes` templates in corresponding subdirectories:

```plaintext
trellis/
  nginx-includes/
    site1/
      rewrites.conf.j2
      proxy.conf.j2
    site2/
      rewrites.conf.j2
```

You could also have an "all" directory, which would apply conf to all sites:

```plaintext
trellis/
  nginx-includes/
    all/
      rewrites.conf.j2
```

The above directory structure would be templated to the remote server as follows:

```plaintext
/
  etc/
    nginx/
      includes.d/
        site1/
          rewrites.conf
          proxy.conf
        site2/
          rewrites.conf
```

To explicitly walk through the example, consider just the `site1` site key in the `wordpress_sites` list. The corresponding `nginx-includes/site1/` directory contains two confs which are templated to the remote's `/etc/nginx/includes.d/site1/`. The primary Nginx conf for `site1` will have a statement `include includes.d/site1/*.conf;`, thus including `rewrites.conf` and `proxy.conf`.

This `include` directive is located inside the primary `server` block, just before the primary `location` block. Explore the [Child templates](#child-templates) section below for more options if this default does not satisfy your needs.

::: warning Note
This default `include` directive per site will not recurse subdirectories within `includes.d/site1` so if you place templates in `nginx-includes/site1/somedir/*.conf.j2`, they will be templated to the remote's `includes.d/site1/somedir/*.conf` but will not be included by default. See the [Child templates](#child-templates) section below for how you could include such confs.
:::

### File cleanup

By default, Trellis will remove from the remote's `includes.d` directory any `*.conf` file that lacks a corresponding template in your local machine's `nginx-includes`. If removing config files results in an empty directory, that directory is not removed. If you prefer to leave all conf files on the remote, you may disable this file cleanup by defining `nginx_includes_d_cleanup: false` in `group_vars/all/main.yml`.

### Deprecated templates directory

The original implementation of Trellis Nginx includes required template files to be stored in `roles/wordpress-setup/templates/includes.d`. That directory is now deprecated and will no longer function beginning with Trellis 1.0. Please move your templates to a directory named `nginx-includes` in the root of this project. It is preferable to store user-created templates separate from Trellis core files.

Trellis Nginx includes were originally made possible thanks to @chriszarate in [#242](https://github.com/roots/trellis/pull/242).

## Child templates

You may use child templates to override any `block` in the two Nginx conf templates:

- [`roles/nginx/templates/nginx.conf.j2`](https://github.com/roots/trellis/blob/master/roles/nginx/templates/nginx.conf.j2) is templated to the server as `/etc/nginx/nginx.conf`
- [`roles/wordpress-setup/templates/wordpress-site.conf.j2`](https://github.com/roots/trellis/blob/master/roles/wordpress-setup/templates/wordpress-site.conf.j2) is templated to the server as `/etc/nginx/sites-available/example.com.conf` (per each site)

Create your child templates following the [Jinja template inheritance](https://jinja.palletsprojects.com/en/stable/templates/#template-inheritance) docs and the guidelines below.

::: tip
Once you have set up your child templates, append `--tags nginx-includes` to your command to run only the Nginx conf portions of the playbook.
:::

### Designate a child template

You will need to inform Trellis of the child templates you have created.

#### `nginx_conf`

Use the `nginx_conf` variable to designate your child template for `nginx.conf.j2`. Given that this template applies to all sites, it would be appropriate to define the variable in a `group_vars/<environment>/main.yml` file (including `group_vars/all/main.yml`).

```yaml
nginx_conf: nginx-includes/nginx.conf.child
```

The example above designates a child template in the `nginx-includes` path on your local machine (i.e., the default path for `nginx_includes_templates_path` variable; see [`include` files](#include-files) section above). You may choose a different path and assign the template any name and file extension you wish. When using the `nginx-includes` path, however, avoid using a filename that matches the `*.conf.j2` pattern required for `include` files described above.

#### `nginx_wordpress_site_conf`

Use the `nginx_wordpress_site_conf` variable to designate your child template for `wordpress-site.conf.j2`, which is used for each of your sites. To designate a global child template for all your sites, you could define the variable in a `group_vars/<environment>/main.yml` file.

```yaml
nginx_wordpress_site_conf: nginx-includes/wordpress-site.conf.child
```

You may designate a child template per site by defining the variable in `group_vars/<environment>/wordpress_sites.yml`.

```yaml
wordpress_sites:
  example.com:
    ...
    nginx_wordpress_site_conf: nginx-includes/example.com.conf.child
    ...
```

### Create a Child Template

Create your child templates at the paths you designated in the `nginx_conf` and `nginx_wordpress_site_conf` variables described above. [Child templates](https://jinja.palletsprojects.com/en/stable/templates/#child-template) must include two elements:

- an `{% extends 'base_template' %}` statement
- one or more `{% block block_name %}` blocks

#### Child Template Example – Simple

Here is an example child template that replaces the `http_begin` block in the `nginx.conf.j2` base template.

```jinja
{% extends 'roles/nginx/templates/nginx.conf.j2' %}

{% block http_begin -%}
  server_names_hash_bucket_size 128;
  server_names_hash_max_size 512;
{% endblock %}
```

The path for your base template – referenced in your `extends` statement – must be relative to the `server.yml` playbook (i.e., relative to the Trellis root directory).

#### Child Template Example – Complex

The first block in the example child template below augments the content of the `fastcgi_basic` block from the `wordpress-site.conf.j2` base template. It inserts <code>{{ super() }}</code>, which represents the original block content from the base template, then adds an extra `fastcgi_param`. The second block in the example rewrites the `redirects_https` block, omitting the `ssl_enabled` conditional and adding a new `listen 8080` directive.

```jinja
{% extends 'roles/wordpress-setup/templates/wordpress-site.conf.j2' %}

    {% block fastcgi_basic -%}
    {{ super() }}
    fastcgi_param HTTPS on;
    {%- endblock %}

{% block redirects_https %}

# Redirect to https
server {
  listen 80;
  listen 8080;
  server_name {{ site_hosts | join(' ') }}{% if item.value.multisite.subdomains | default(false) %} *.{{ site_hosts_canonical | join(' *.') }}{% endif %};

  {{ self.acme_challenge() -}}

  location / {
    return 301 https://$host$request_uri;
  }
}

{% endblock -%}
```

You'll notice that these blocks use indentation and [whitespace control](https://jinja.palletsprojects.com/en/stable/templates/#whitespace-control) (e.g., `-%}`) parallel to their counterparts in the base template `wordpress-site.conf.j2`. This will achieve the best formatting of templated conf files on the server.

## Sites templates

You may use sites templates to add new sites confs to Nginx in addition to the standard WordPress confs. They are also Ansible/Jinja2 templates and thus can make full use of variables and logic.

Create your sites templates following the guidelines below.

::: tip
Once you have set up your sites templates, append `--tags nginx-sites` to your command to run only the Nginx sites portions of the playbook.
:::

### Default

By default in Trellis, a "no-default" site Nginx conf is included. Its purpose is to drop requests to unknown server names, preventing host header attacks and other potential problems.

The `nginx_sites_confs` variable contains the list of confs to be templated to the server's `sites-available` folder.

Its default value only registers the default site (whose template resides in `roles/nginx/templates/no-default.conf.j2`):

```yaml
nginx_sites_confs:
  - src: no-default.conf.j2
```

Each entry to this variable also has an `enabled` parameter, which can be omitted, and defaults to `true`.

It controls whether the conf is linked to the server's `sites-enabled` folder, and thus activated.

The above default is equivalent to:

```yaml
nginx_sites_confs:
  - src: no-default.conf.j2
    enabled: true
```

However, you might want to add other sites for specific purposes.

### Designate a site template

You will need to inform Trellis of the sites templates you have created.

#### `nginx_sites_confs`

Use the `nginx_sites_confs` variable to designate your new site template. Given that this template applies to all environments, it would be appropriate to define the variable in a `group_vars/<environment>/main.yml` file (including `group_vars/all/main.yml`).
Remember to keep the default site for security purposes if you don't have a specific reason to override it.

```yaml
nginx_sites_confs:
  - src: no-default.conf.j2
  - src: nginx-includes/example.conf.site.j2
```

The example above designates a site template in the `nginx-includes` path on your local machine (i.e., the default path for `nginx_includes_templates_path` variable; see [`include` files](#include-files) section above). You may choose a different path and assign the template any name and file extension you wish. When using the `nginx-includes` path, however, avoid using a filename that matches the `*.conf.j2` pattern required for `include` files described above.

### Create a site template

Create your site templates at the paths you designated in the `nginx_sites_confs` variable described above. Templates should start with an <code># {{ ansible_managed }}</code> statement to indicate that the file is [managed by ansible](https://docs.ansible.com/projects/ansible/latest/reference_appendices/config.html).

#### Template example

Here is an example site template that hosts nginx default page, listening on `example.com` non-standard port 8080.

```nginx
# {{ ansible_managed }}

server {
  listen 8080;
  server_name example.com;

  root /var/www/html;
  index index.html index.htm index.nginx-debian.html;

  location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
  }
}
```

### File cleanup

By default, Trellis will remove from the remote's `site-enabled` directory any link to a site conf file that has its `enabled` attribute set to `false`.
There is no cleanup of the confs in `sites-available`, they're only made mute by being disabled.

This example shows the addition of the above site template, while also disabling Trellis' default site.

```yaml
nginx_sites_confs:
  - src: no-default.conf.j2
    enabled: false
  - src: nginx-includes/example.conf.site.j2
```