I am trying to deploy an Angular 10 web app in Docker using NGINX, but I cannot get it to be served by it. Googling around I found a lot of sparse information, but I came up with this procedure:
normally build the Angular app for production (
--prod
), outside Docker. The result gets saved into thedist
folder of the project, which then will be copied into a container. I found other examples which use multi-stage build inside the container; but this is discouraged for scalability purposes. At any rate, building the app manually gives me easier control on the result, so to me this is the way to go.provide a Dockerfile using
nginx:alpine
, where I just copy a custom configuration and my compiled app to the container, and then run it as an executable viaENTRYPOINT
:
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
WORKDIR /usr/share/nginx/html
COPY dist/myapp/ .
ENTRYPOINT ["nginx", "-g", "daemon off;"]
This way, NGINX log should be redirected to the console, and thus shown in the container's terminal.
- the meat here is in the NGINX configuration file. I don't know much about it, but from the evidence at https://blog.codecentric.de/en/2019/03/docker-angular-dockerize-app-easily/ and https://denys.dev/2018-03-02/your-angular-apps-as-docker-containers/, I came up with this, which should correctly take HTML 5 routing into account (
nginx.conf
, saved in the same folder of theDockerfile
):
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
try_files $uri $uri/ /index.html;
}
}
}
(I also found this other post, but it has a less complete configuration for Angular's purposes).
- build the image (
docker build . -t myrepo/myapp:tag
). When doing so, it took a lot of time for sending useless content outside thedist
folder. Thus, following a tip at https://denys.dev/2018-03-02/your-angular-apps-as-docker-containers/ ("optimizing the build"), I added a .dockerignore with:
e2e
node_modules
src
This time, the build was much faster. In both cases it was successfully built.
I can now run the container, either directly (docker run -d -p 4200:80 myrepo/myapp:tag
), or from a docker compose script. In both cases, I will need to redirect the container's port 80 (NGINX) to the host port 4200 (the usual Angular app localhost port).
The problem: I'd expect to see my app served by NGINX at localhost:4200
. Instead, what I find is just the default welcome NGINX page, telling me that the NGINX server is successfully installed and working, but further configuration is required.
I looked for something in the logs, but docker logs mycontainer
displayed nothing.
I tried to inspect the container's filesystem to see if the Angular app is in its place (usr/share/nginx/html
). To this end, I followed the advice at Exploring Docker container's file system: for the alpine image there is no bash, so I dumped the filesystem into a TAR file with docker export mycontainer > mydump.tar
. By looking at the TAR's content I can see that my app files are there: index.html
, JS files, assets, and the like.
What am I missing here to complete the NGINX configuration and get my app served?
UPDATE
I followed @Derek's directions: deleted .gitignore
, replaced my nginx.conf
with the suggested one, rebuilt the app, and run it. This time the build took about 15 minutes, and sent 1.134 GB of build context to the Docker daemon.
To quickly run it in my test machine I published the image in the Docker Hub. The whole project is open source, so if anyone wants to diagnose something in a repro environment there is both the binary image and its source:
- image:
vedph2020/cadmus_web:1.0.5
(1.0.4
is the one with my nginx). Just use thedocker-compose.yml
there, with tag1.0.5
for thecadmus-web
service. There is some backend stuff there, but I am sure it works because I can connect to its endpoint at localhost:60380/swagger. - repository: https://github.com/vedph/cadmus_web (the real app name is
cadmus_web
; thus the build wasdocker build . -t vedph2020/cadmus_web:1.0.5
).
Meantime I tried to create an empty dummy Angular app, and use my original Dockerfile and nginx files. To my surprise it worked. The only difference is that the dummy Angular app had no routing, whereas mine has it with hash location strategy. Supposing some hash-related config issue in NGINX, I tried to access mine from http://localhost:4200/#/home, with no luck: same welcome page.