C
C#3w ago
Filomeon

How should my ng-app communicate with API?

Hi every one ! I am really confused. I am trying to deploy an Angular application on my Virtual Private Server (in the cloud). My ultimate goal is to make my ng app communicate with my .Net Api that itself communicates with a PostgreSQL database. I use docker for everything, on my VPS. Problem is, I understand so little about docker and nginx configurations 😅 . I have nginx installed on my VPS and I installed SSL certificates, so the connection is already "secure". But I deploy my angular application in a docker container with another nginx configuration, as "unprivileged". I did 99% the same as here https://docs.docker.com/guides/angular/containerize/. And my .NET API is 99% the .NET API with docker preinstalled, its basically a hello world application with a health check endpoint (I really try to advance step by step). My first question would be : How should my ng app communicate with my .Net API ? Should I also include the API in the nginx configuration that is used for the angular application, and make it a reverse proxy to communicate with the API? I thought that it would not be a good idea, since I already did that once and it kind of made my API "public". I mean, if I wrote in a browser the address https://mysite.be/api/health for example (my Domain is not "mysite", but that's the idea), it would display the healthcheck response from the api ("Healthy") on the page, pure string. So 100% public, right ? Is it not a bad idea ? How should I do ? Thanks in advance for any answer. I will obviously stay here to answer further questions, in case I didn't provide enough details ! I wanted to provide more information, like the Dockerfiles of my API and ng app, or the nginx.conf and docker compose files, but I would need to be sure that nothing is "secret". Idk if I should post them here ?
Docker Documentation
Containerize
Learn how to containerize an Angular application with Docker by creating an optimized, production-ready image using best practices for performance, security, and scalability.
22 Replies
kurumi
kurumi3w ago
nginx is not neccesary for internal network. Docker creates it's own network with its domain name system resolver. So when you deploy your stack, each application can communicate with others if they are on same network the nginx for internal communication only adds a bit complexity for communication. You can ask yourself, if you your frontend trust your backend - it's fine to communicate over HTTP (not HTTPs) and remove nginx. If it is smth like 0 trust network, it is recommended to keep nginx as layer between your frontend and backend take a look at this compose
services:
users_service:
build: ./users.service/src
container_name: users_service
networks:
- appnet

auth_service:
build: ./auth.service/src
container_name: auth_service
networks:
- appnet

prompt_service:
build: ./prompt.service/src
container_name: prompt_service
environment:
- PROMPT_BIND_ADDR=0.0.0.0
- PROMPT_BIND_PORT=22
- PROMPT_THREADS=4
- PROMPT_SSH_RSA_HOST_PUBLIC_KEY_PATH=/run/configs/prompt_ssh_rsa_pubkey
- PROMPT_SSH_RSA_HOST_PRIVATE_KEY_PATH=/run/secrets/prompt_ssh_rsa_key
ports:
- "2222:22"
secrets:
- prompt_ssh_rsa_key
configs:
- source: prompt_ssh_rsa_pubkey
target: /run/configs/prompt_ssh_rsa_pubkey
networks:
- appnet

secrets:
prompt_ssh_rsa_key:
file: ./prompt.service/dev-artifacts/host_rsa

configs:
prompt_ssh_rsa_pubkey:
file: ./prompt.service/dev-artifacts/host_rsa.pub

networks:
appnet:
driver: bridge
services:
users_service:
build: ./users.service/src
container_name: users_service
networks:
- appnet

auth_service:
build: ./auth.service/src
container_name: auth_service
networks:
- appnet

prompt_service:
build: ./prompt.service/src
container_name: prompt_service
environment:
- PROMPT_BIND_ADDR=0.0.0.0
- PROMPT_BIND_PORT=22
- PROMPT_THREADS=4
- PROMPT_SSH_RSA_HOST_PUBLIC_KEY_PATH=/run/configs/prompt_ssh_rsa_pubkey
- PROMPT_SSH_RSA_HOST_PRIVATE_KEY_PATH=/run/secrets/prompt_ssh_rsa_key
ports:
- "2222:22"
secrets:
- prompt_ssh_rsa_key
configs:
- source: prompt_ssh_rsa_pubkey
target: /run/configs/prompt_ssh_rsa_pubkey
networks:
- appnet

secrets:
prompt_ssh_rsa_key:
file: ./prompt.service/dev-artifacts/host_rsa

configs:
prompt_ssh_rsa_pubkey:
file: ./prompt.service/dev-artifacts/host_rsa.pub

networks:
appnet:
driver: bridge
here prompt_service can call users_service with domain name users_service. This happens bcs I defined a network, so all services share this specific network appnet
Filomeon
FilomeonOP3w ago
I think I see So I could get 100% rid of the docker-nginx configuration and use the docker network itself to let the apps communicate with each other ?
kurumi
kurumi3w ago
if it is for internal use - yes
Filomeon
FilomeonOP3w ago
I think my biggest regret is to find only tutorials for docker that use "best practice", but the best practice are really not that simple for a beginner
kurumi
kurumi3w ago
Your Angular app should be descovered externally?
Filomeon
FilomeonOP3w ago
What would you define as internal use ?
kurumi
kurumi3w ago
means everyone in web can access it, or it just for smth internal?
Filomeon
FilomeonOP3w ago
yes it is on the web, every one should be able to access it. The angular application
kurumi
kurumi3w ago
so it is discoverable, I see. So things are changed so in this case don't use service name in request
fetch(`http://users_service/users`, {
method: 'GET',PUT, DELETE
headers: {
'Content-Type': 'application/json',
},
})
fetch(`http://users_service/users`, {
method: 'GET',PUT, DELETE
headers: {
'Content-Type': 'application/json',
},
})
here the problem - your clients are outside your docker network, so they don't know what is http://users_service/users. You have to use public (exposed) endpoint (discoverable domain name or ip address) so rewrite it as
fetch(`http://backend.application.com/users`, {
method: 'GET',PUT, DELETE
headers: {
'Content-Type': 'application/json',
},
})
fetch(`http://backend.application.com/users`, {
method: 'GET',PUT, DELETE
headers: {
'Content-Type': 'application/json',
},
})
where backend.application.com points to VPS ip (via Cloudflare for example), and it resolves with reverse proxy (nginx in your case) to your backend or use IP address and expose your backend port let me rewrite with Angular + Dotnet example to you
Filomeon
FilomeonOP3w ago
Could i maybe send you the files that I already have, if I check that there is no secret in it ? It would be a starting point ? By files, I mean docker compose, dockerfiles for api and ng, and also nginx.conf ?
kurumi
kurumi3w ago
proxy + frontend + backend
version: "3.9"

services:
backend:
build: ./backend
container_name: backend
networks:
- appnet
expose:
- "5000" # internal port

frontend:
build: ./frontend
container_name: frontend
networks:
- appnet
expose:
- "80" # internal port

nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- appnet
depends_on:
- backend
- frontend

networks:
appnet:
driver: bridge
version: "3.9"

services:
backend:
build: ./backend
container_name: backend
networks:
- appnet
expose:
- "5000" # internal port

frontend:
build: ./frontend
container_name: frontend
networks:
- appnet
expose:
- "80" # internal port

nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- appnet
depends_on:
- backend
- frontend

networks:
appnet:
driver: bridge
nginx could be set to proxy frontend.my-appication.com to your frontend and backend.my-application.com. In this example you are not exposing your services outside. You use proxy for that. So entrypoint of entire stack is nginx with it's 80 or 443 ports here you just can do
fetch(https://backend.my-application.com/users);
fetch(https://backend.my-application.com/users);
or without nginx:
version: "3.9"

services:
backend:
build: ./backend
container_name: backend
ports:
- "5000:5000"
networks:
- appnet

frontend:
build: ./frontend
container_name: frontend
ports:
- "4200:80"
networks:
- appnet

networks:
appnet:
driver: bridge
version: "3.9"

services:
backend:
build: ./backend
container_name: backend
ports:
- "5000:5000"
networks:
- appnet

frontend:
build: ./frontend
container_name: frontend
ports:
- "4200:80"
networks:
- appnet

networks:
appnet:
driver: bridge
frontend can communicate both 1. raw ip address with no SSL
fetch(http://192.168.0.1/users);
fetch(http://192.168.0.1/users);
2. domain name (if you are using DNS, for example Cloudflare)
fetch(https://backend.my-application.com/users);
fetch(https://backend.my-application.com/users);
not in DMs, and I am not nginx expert
Filomeon
FilomeonOP3w ago
Ok I think your example is already too advanced for me
kurumi
kurumi3w ago
the key difference is how you are communicating - what is your entrypoint (in 1st example it is nginx) or entrypoints (frontend and backend separately) the best way is to have a single entrypoint which decides where routes traffic: 1. to frontend by subdomain frontend 2. to backend by subdomain backend Why it is better? You can handle some security vulnerabilities in one place. So nginx will decide to block or to pass your requests. If malicious traffic is sent it can abort it note that you are not pinned to use nginx only, there are dozen of entrypoint technologies which handles traffic, logging, load balancing, security
Filomeon
FilomeonOP3w ago
i see
kurumi
kurumi3w ago
there is a much easier way for reverse proxing - Nginx Proxy Manager. You can take a look at this https://www.youtube.com/watch?v=P3imFC7GSr0 https://nginxproxymanager.com/ and it is also avaliable in docker (and it is free)
Christian Lempa
YouTube
Nginx Proxy Manager - How-To Installation and Configuration
In this Nginx Proxy Manager How-To, I'll show you how to install and configure Nginx Proxy Manager in Docker. #Docker #NginxProxyManager #HomeLab DOCS: https://github.com/christianlempa/videos/tree/main/nginxproxymanager-tutorial Follow me: TWITTER: https://twitter.com/christianlempa INSTAGRAM: https://instagram.com/christianlempa DISCORD: h...
Nginx Proxy Manager
Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt
kurumi
kurumi3w ago
nice UI over nginx configs, it is not so advanced, but still...
Filomeon
FilomeonOP3w ago
I think the situation at the moment is like this : - I have a VPS, with SSL and nginx installed, that redirects the localhost:8080 of my angular applicatio as a "https". - On this VPS, there is a docker compose that runs the ng application and the .net api. - The docker compose starts two images, one for app and one for api. - In the app image, there is another nginx "unprivileged" that redirects all /api calls to the :80 port where my API is. Would that seem adequate, or is it a bad idea / practice / design ? Is it considered as a single entry point, since I have the "basic" nginx at the root of my VPS that redirects everything to the 8080 ? Thank you, I m checking that right now
kurumi
kurumi3w ago
I suggest to make nginx redirections not by /api route, but by api subdomain Redirects everything to the 8080 you mean only backend to its container under 8080 port? Everything would be not correct, caz nginx has to do same for frontend
Filomeon
FilomeonOP3w ago
I m not sure I totally understand what I did, but I think that the nginx installed on my VPS redirects traffic to my front end, and then my front end has a second nginx configuration that is inside the docker container and that redirects the /api calls to my actual api the nginx that is really installed on my VPS has something like server { listen 80} and server { listen 443 } and location { proxy pass localhost:8080 }
kurumi
kurumi3w ago
it's fine, but what I mean is to make not your-domain-name.com/api/some-endpoint, but api.your-domain-name.com/some-endpoint just what I prefer and what's easier for me but your approach is fine 👍
Filomeon
FilomeonOP3w ago
oh, ok, I see now I will check if I can do that without paying another DNS domain name haha
kurumi
kurumi3w ago
You are not creating new domain, but subdomain. It is free unless you end up with some extraordinary DNS provider

Did you find this page helpful?