- part 1: Injecting environment variables into static websites using NGINX (this post)
- part 2: Customer-specific documentation with Jekyll
- part 3: Rich code documentation with Jekyll
Naturally, when using an SSO mechanism other than HTTP Basic Authentication, we need to display a “Sign Out” button to users. But when combined with static site generation (SSG), we do not know the sign out URI yet, since it may depend on the particular configuration of the deployment.
In order to actually render the button, we were faced with two choices:
- Run the SSG tool not in CI, but when the Docker container is started.
- Render the link without an URI and let the web server inject it at runtime.
In our case, the SSG tool is Jekyll, so adding its entire Ruby toolchain would defeat the purpose of using NGINX: being as lightweight as possible. Additionally, this huge image would create more attack surface. So, we quickly eliminated this option.
But how could the second choice be implemented? Fortunately, Server Side Includes can help here. In a nutshell, the generated pages contain almost all content, plus some small instructions to the web server to additionally insert more content. SSI can be used to fetch content from other servers, conditionally enable or disable areas in a page, or merely to print the contents of a variable somewhere (like the current date and time).
NGINX supports SSI after enabling the configuration option:
In the Jekyll template file, we can now add the following snippet:
When browsing the page locally with
jekyll serve, this will produce invalid HTML markup (although it does not break the page because browsers are lenient), so I recommend only rendering it in production mode (i.e. in CI):
Other SSG tools have similar means to distinguish between different environments.
Now the only open issue is that NGINX does not pass through environment variables that are set for the process to the SSI engine. To make matters worse, NGINX decidedly does not even support reading environment variables in the configuration file.
According to the official NGINX Docker image, the way to pass such variables into the running container is by using templates.
The image contains a startup script that runs
envsubst on the configuration files that are marked as “templates”.
When starting the container, the template is processed and the environment variables are copied into the actual NGINX configuration.
In order to leverage this mechanism, move the relevant part of your NGINX configuration into a template file called
default.conf.template (or any other name ending in
Dockerfile is adapted accordingly:
This is necessary so that the startup scripts pick up the file and run it through
Now, in the NGINX configuration, you can access the variables:
When the container is started without further ado, the script generates the following configuration:
This is because our
Dockerfile specifies a default value for
It is very important that in the NGINX template, the SSI variable name (
ssisignouturl) differs from the environment variable name (
SIGN_OUT_URL), because otherwise
envsubst would substitute both occurences.
The scripts leave undefined variable occurences unchanged.
Finally, after changing the configuration as above, the SSI engine can substitute the URL. Build and start the Docker image as follows:
This will render the following HTML:
What we found surprising here is that NGINX has no built-in mechanism to pass through environment variables and that we had to instead rely on the startup scripts provided by the Docker image.
In situations where the official Docker image cannot be used, I would recommend generating the sign out link as a text file and including the file via
include, instead of printing a variable with
Further documentation can be found on the NGINX site.
Kubernetes Init Containers could help here, but we wanted to avoid moving work from CI to runtime. ↩