Until nginx v1.19, you had to either bake in the image a ready configuration file or mount it at runtime.
Often, you would need to template the nginx config file. This was made possible since v1.19 in a convenient way using environment variables.
First, you need a template to copy. Create default.conf.template file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| server {
listen 80;
server_name ${NGINX_PORT};
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
root /usr/share/nginx/html;
index index.html index.htm;
}
}
|
In the Dockerfile, we need to place the *.template file in a specific location, /etc/nginx/templates.
On startup, the nginx entrypoint script scans this directory for files with *.template suffix by default, and it runs envsubst
.
The envsubst parse the template using the shell interpolation and replaces shell variables with values from environment variables.
It outputs to a file in /etc/nginx/conf.d/
.
If you’re using $var
, and there’s no such env-var, it will stay as is in the output file.
In the above file, $host
and $remote_addr
are such examples. We want them to stay as parameters in the output file, as they are parameters used by nginx.
Let’s look at a complete example.
1
2
3
4
5
6
7
8
9
10
| # docker-compose.yml
version: '3.7'
services:
nginx:
build:
context: nginx/
ports:
- "80:80"
environment:
- NGINX_HOST
|
1
2
3
4
5
6
| # Dockerfile
FROM nginx:1.19.6-alpine
RUN mkdir /etc/nginx/templates
COPY default.conf.template /etc/nginx/templates
COPY index.html /usr/share/nginx/html/
|
Running the docker-compose with NGINX_HOST=1.1.1.1 docker-compose up -d
and the generated default.conf
would look:
1
2
3
4
5
6
| server {
listen 80;
server_name "1.1.1.1";
..
..
|
If you’re interested, these are the internal scripts nginx uses in its image at startup:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| #!/bin/sh
# docker-entrypoint.sh
set -e
if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
exec 3>&1
else
exec 3>/dev/null
fi
if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then
if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then
echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration"
echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/"
find "/docker-entrypoint.d/" -follow -type f -print | sort -n | while read -r f; do
case "$f" in
*.sh)
if [ -x "$f" ]; then
echo >&3 "$0: Launching $f";
"$f"
else
# warn on shell scripts without exec bit
echo >&3 "$0: Ignoring $f, not executable";
fi
;;
*) echo >&3 "$0: Ignoring $f";;
esac
done
echo >&3 "$0: Configuration complete; ready for start up"
else
echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration"
fi
fi
exec "$@"
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| #!/bin/sh
# docker-entrypoint.d/20-envsubst-on-templates.sh
set -e
ME=$(basename $0)
auto_envsubst() {
local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}"
local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}"
local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}"
local template defined_envs relative_path output_path subdir
defined_envs=$(printf '${%s} ' $(env | cut -d= -f1))
[ -d "$template_dir" ] || return 0
if [ ! -w "$output_dir" ]; then
echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable"
return 0
fi
find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do
relative_path="${template#$template_dir/}"
output_path="$output_dir/${relative_path%$suffix}"
subdir=$(dirname "$relative_path")
# create a subdirectory where the template file exists
mkdir -p "$output_dir/$subdir"
echo >&3 "$ME: Running envsubst on $template to $output_path"
envsubst "$defined_envs" < "$template" > "$output_path"
done
}
auto_envsubst
exit 0
|
Resources
https://github.com/docker-library/docs/tree/master/nginx#using-environment-variables-in-nginx-configuration-new-in-119