A simple nginx docker image that has the ability to insert environment variables. Created so I could re-use an image between prod and staging environments for my frontend builds. It replaces environment variables on container startup, so you don´t have to rebuild your Docker image or use a server-side language to change some settings.
This repository generates the images available on the Docker hub. Using this image for your own project is as simple as creating a Dockerfile with the two lines below:
FROM nstapelbroek/static-webserver:5
COPY ./your-static-content /var/www
A more modern example where you build your frontend project and ship it:
FROM node:21 as build
WORKDIR /opt/project
COPY package.json package-lock.json /opt/project/
RUN npm ci
COPY . /opt/project
RUN npm run build
FROM nstapelbroek/static-webserver:5
COPY --from=build --chown=nginx:nginx /opt/project/dist /var/www
When this container starts, a script will replace all occurrences of ${VARIABLE_NAME} in /var/www
with
their matching environment variable.
For example, given this HTML in a file located at /var/www/index.html
<p>
My backend is located at ${BACKEND_URL}
</p>
And building & running this with an environment variable passed in docker run (docker run -p 8080:80 -e BACKEND_URL=https://api.someproject.com myimage:latest
), you'll end up with:
Note: Please make sure your environment keys do not contain special characters. Only a-z
, A-Z
, 0-9
and _
are recommended.
By default, the script only changes files located in /var/www
. You can change this by setting the NGINX_ENVSUBST_WWW_DIR
environment variable.
Using es6 template literals can cause issues. You can fine-tune the replacement by configuring a filter with the NGINX_ENVSUBST_FILTER
environment variable. This should allow you to set a prefix like CONFIG_
.
Here's a table that should help you understand the behavior:
text value in file | passed environment variable | passed nginx filter | result | why |
---|---|---|---|---|
$MY_PROJECT_URL |
MY_PROJECT_URL=123 |
PROJECT |
123 |
the passed filter matches we have an environment variable to replace |
${MY_PROJECT_URL} |
MY_PROJECT_URL=123 |
PROJECT |
123 |
the passed filter matches and we have an environment variable to replace |
`${MY_PROJECT_URL}` | MY_PROJECT_URL=123 |
PROJECT |
`123` | the passed filter matches we have an environment variable to replace |
MY_PROJECT_URL |
MY_PROJECT_URL=123 |
PROJECT |
MY_PROJECT_URL |
this is not a valid form for envsubst |
$MY_PROJECT_URL |
YOUR_PROJECT_URL=123 |
PROJECT |
MY_PROJECT_URL |
the filter matches, but we have no environment variable to replace |
$MY_PROJECT_URL |
MY_PROJECT_URL=123 |
PUBLIC_ |
MY_PROJECT_URL |
the variable does match the allowed filter |
The project is not meant as a development environment. Don´t mount your code in here as it will only change environment variables on the first container startup.
To prevent sudden BC-breaks you should avoid using the latest
tag when building upon this image (or any image for that reason).
I'm using Semver as a base for versioning schematics. Due to the small functionality of this container I'm considering the following changes as "incompatible API changes":
- Altered behavior at clients, for example due to changes in cache-headers
- Altered behavior in the find & replace script
- Altered behavior in the file locations
You should use the latest available tag in at in the registry.
This project is licensed under the MIT License - see the LICENSE file for details
- nginx dockerfiles for creating a stable base image
- h5bp server configs for providing the nginx config
- html5up for providing the template used in the placeholder page
- envsubst for doing the replacements