Injecting environment variables into static websites using Nginx
innoq.com
innoq.com
<!--#include file="header.html"-->
and the header.html file would be just inlined into the page.
You could also write plugins for Netscape server in c to do whatever else you liked to the html page before serving it to the browser.
It was all blazingly fast, the compiled binary code was in memory and unix was doing a good job of keeping our frequent pages (out of about 30,000 in total) in memory too. We easily saturated our datacenter's networking with it. All with mid range for it's time but now hilariously puny server.
We had a set of static frontend apps (React) that were built in CI, and which had to support being served either out of S3 buckets in a variety of environments, or in walled-off on-prem environments, and therefore had to support a variety of API endpoint URLs. There was an 85% likelihood that the endpoint URL would be one main one (our primary distribution platform), but the other 15% could be anything.
I set up a global variable attached to `window` (gasp!) in the frontend's index.html that would point to the API endpoint, and by default our CI build would spit out the common scenario URL. When doing local development, the URL was supplied via an environment file, which worked perfectly.
For all other production scenarios we served the app out of a Docker container. At container launch, we passed in via env vars the proper endpoint URL, and a script would absorb the passed env var and embed it into the nginx config file using `envsubst` like the OP's article. This config file was configured using `subs_filter` to find our global variable in the index.html file and replace its contents with that of the env var, which was now hardcoded in a sense into the file.
This setup was a bit convoluted, but it allowed us to not have to change anything while in local development, be able to change the endpoint URL each time the container was launched without any rebuild, and didn't require any additional requests to a configuration script. It was the best fit in our situation to allow local development to continue unchanged while also supporting pretty much any future scenario.
Hope that might spur some ideas for someone.
1. Bundle the app image with a “container.json.template”
2. Have the UI request this file first, along with a preload in the head
3. Use Nginx envsubst to populate the config.json from env vars on container start
It’s an additional HTTP request and templating JSON via string interpolation isn’t fun but it was quite simple and kept the build clean with config injected at run time.
Given the interpolation problem (I.e chaos when someone uses a number value and it’s undefined), I’d probably ditch env subst and perhaps do something else to build the JSON.
Surely you can still find some old site from somewhere that uses it, but has someone actually used it even somewhat lately & what use case you had? For most cases where it made sense you would probably just use some static site generator and deploy different version if required. Or do the replacing during the publishing phase.
PHP is totally overkill, and even a site generator feels overkill for this purpose; now I can just throw together some html and upload, no need for running a script.
Also it's a bit of nostalgia (the reason I implemented it a cople of years ago) since ssi was my first contact with web development back in '96 or whenever :)
There is a pure static mode, when you pre-generate all the HTML.
Then there is a hybrid mode, with basic templating of time/clock. SSI can also be used to update pages.
When PHP is available, it can very closely approximate a dynamic site, with pages being pre-generated just in time, but then served to all subsequent requests.
Angular provides an environment mechanism at buildtime, so they expect us to create a docker image per environment, which is not our practice with other microservices in our pipeline. We’re used to kubernetes configMaps.
We used a docker docker runtime script + envsubst as above. However we used it to provide key/values to the window object (inside a template script tag), to be picked up by a proper Angular “AppConfig” service.
I’m not very happy with this solution as it might scare the next maintainers, specially if they don’t know about our ci/cd and backend. The source code is also peppered with little comments about this workaround, which is not ideal.
envsubst < template > parsed
executable $@
I've written more about it here: http://www.sheshbabu.com/posts/frontend-config-management/