How to override an HTTP header in Traefik 🐲
Tags: traefik, tooling, security, architecture
Published: 2021-08-07 13:33:25

---
title: How to override an HTTP header in Traefik 🐲
published: true
date: 2021-07-15 23:15:00 UTC
tags: traefik, tooling, security, architecture
canonical_url: https://www.benjaminrancourt.ca/how-to-override-an-http-header-in-traefik
cover_image: https://www.benjaminrancourt.ca/images/how-to-override-an-http-header-in-traefik.jpg
---
## Context

Recently, I installed **[Ghost](https://ghost.org/)** on my Docker architecture and I had to **override a default security HTTP header** that I had implemented for all services on **[Traefik](https://doc.traefik.io/traefik/)**, because a part of the application was not working as expected. 😱

![Screenshot of the error](https://www.benjaminrancourt.ca/images/frame-options-deny.jpg)<figcaption>Screenshot of the error, with the <a href="https://developer.chrome.com/docs/devtools/">Chrome DevTools</a> open.</figcaption>

> Refused to display '[https://www.mamaisonsherby.ca/](https://www.mamaisonsherby.ca/)' in a frame because it set 'X-Frame-Options' to 'deny'.

For those unfamiliar with the[**X-Frame-Options**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) HTTP response header, it is primarily used to indicate whether a browser can display a specific page in an [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). So in my case, if someone tries to embed one of my sites into another site, the browser will fail to load my website.

Unfortunately for me, Ghost is currently using iframes to display the site in the backend, so we can see what the posts will look like when they're published. So I had 3 choices:

1. I could **lose this functionality** (and keep the error page displayed);
2. I could **globally remove** the X-Frame-Options or **set it** to `SAMEORIGIN` to allow frames on the same origin;
3. I could try to **override this header** for my Ghost websites.

Naturally, as I try to have as much security as possible for my sites, I choose the third option. 😄

After some tries, I was finally able to get it working in just two easy steps. 🎉

## Step 1 – Define a new middleware

In our case, the [customFrameOptionsValue option](https://doc.traefik.io/traefik/middlewares/headers/#customframeoptionsvalue) allows us to override the [frameDeny](https://doc.traefik.io/traefik/middlewares/headers/#framedeny) option that we used in the default Traefik configuration (via default@file below).

> The `customFrameOptionsValue` allows the `X-Frame-Options` header value to be set with a custom value. This overrides the `FrameDeny` option.

So we just need to define a new [middleware](https://doc.traefik.io/traefik/middlewares/overview/) that sets this option to `SAMEORIGIN`:

```yaml
services:
  ghost:
    deploy:
      labels:
        traefik.http.middlewares.frameOptionsSameOrigin.headers.customFrameOptionsValue: "sameorigin"
```
<figcaption>The label added in a docker-compose.yml file.</figcaption>

If you need to use this middleware on multiple docker-compose.yml files, I'm pretty sure that you can set it directly in the Traefik configuration file. But this exercice is left to the reader. 😉

## Step 2 – Add the middleware to the router

Once the middleware is defined, we need to apply it on a [router](https://doc.traefik.io/traefik/routing/routers/). Since `.middlewares` is a list, its order is really important. In this case, they are applied in the [**same order**](https://doc.traefik.io/traefik/routing/routers/#middlewares) as their declaration in the router, so from left to right.

```yaml
# Add the new middleware to the router name ghost, after the others
services:
  ghost:
    deploy:
      labels:
        traefik.http.routers.ghost.middlewares: "default@file,frameOptionsSameOrigin"
```
<figcaption>Our new middleware has been added after the default@file middleware to take precedence over it.</figcaption>

In our case, since it is not the same option that is used, the order doesn't really matter. I'm assuming that the `customFrameOptionsValue` is still applied after the [`frameDeny` option](https://doc.traefik.io/traefik/middlewares/headers/#framedeny).

## Resume

So one way to override an HTTP header in Traefik is to simply:

1. Define a **new middleware** that defines your new HTTP headers.
2. Add the middleware to your router **after** the other middlewares.

Very easy when you know it, right? 😅