I know this is an old question, but I faced the exact same problem and it took me a while to solve. May this be of help to those coming from search engines.
I found 2 solutions (I ended up choosing the second one). Both allow you to use environment variables in docker to configure your API URL.
Solution 1 ("client"-side): env.js asset + sed
The idea is to have your Angular client load an env.js
file from your HTTP server. This env.js
will contain the API URL, and will be modifiable by your container when it starts. This is what you discussed in the question comments.
Add an env.js
in your angular app assets folder (src/assets
for me with angular-cli):
var MY_APP_ENV = {
apiUrl: 'http://localhost:9400',
}
In your index.html
, you will load your env:
<head>
<meta charset="utf-8">
<base href="/">
<script src="env.js"></script>
</head>
In your environment.ts, you can use the variable:
declare var MY_APP_ENV: any;
export const environment = {
production: false,
apiUrl: MY_APP_ENV.apiUrl
};
In your NGINX Dockerfile do:
FROM nginx:1.11-alpine
COPY tmp/dist /usr/share/nginx/html
COPY run.sh /run.sh
CMD ["sh", "/run.sh"]
The run.sh script is where the sed magic happens:
#!/bin/sh
# API
/bin/sed -i "s|http://localhost:9400|${MY_API_URL}|" /usr/share/nginx/html/env.js
nginx -g 'daemon off;'
In your angular services, use environment.apiUrl
to connect to the API (you need to import environment, see Angular 2 docs).
Solution 2 (purely server side): nginx proxy config + envsubst
I wasn't happy with the previous solution because the API URL needed to be from the host point of view, it couldn't use another container hostname in my docker-compose setup.
So I thought: many people use NGINX as a proxy server, why not proxy /api
to my other container this way.
Dockerfile:
FROM nginx:1.11-alpine
COPY tmp/dist /usr/share/nginx/html
COPY frontend.conf.template /etc/nginx/conf.d/frontend.conf.template
COPY run.sh /run.sh
CMD ["/bin/sh", "/run.sh"]
frontend.conf.template:
server {
listen 80;
server_name myserver;
# API Server
location /api/ {
proxy_pass ${MY_API_URL}/;
}
# Main
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri$args $uri$args/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
run.sh:
#!/bin/sh
# Substitute env vars
envsubst '$MY_API_URL' \
< /etc/nginx/conf.d/frontend.conf.template \
> /etc/nginx/conf.d/default.conf
# Start server
nginx -g 'daemon off;'
envsubt
allows you to substitute environment variables in a string with a shell-like syntax.
Then use /api/xyz
to connect to the API from the Angular app.
I think the second solution is much cleaner. The API URL can be the API docker container name in a docker-compose setup, which is nice. The client is not involved, it is transparent. However, it depends on NGINX.