'Host docker nginx multiple apps on same host Ubuntu
I want to manage reverse proxy (Nginx) with multiple Independent webapps on the same host. Means I have 4 webapps that are hosted on containers separately via docker-compose file and behind with Nginx. How I can handle this scenario, like I have 4 different environments (dev/qa/uat/prod) all are have septate apps, app1/app2/app3/app4 which have their own Nginx instances, all should be deployed on same Host Ubuntu(20.4)
When I run docker-compose-app1.yml its up and run as expected and I can browse (localhost --> https://localhost/login) same as host ip as well BUT
Problem statement: When I run docker-compose-app2.yml it gives following error
Container app2_nginx Starting
2.0s Error response from daemon: driver failed programming external connectivity on endpoint app2_nginx (18b62acf9312fd57cad9979bd0ebde963ff57f32a7489b11faacee4cf4b02b97): Bind for 0.0.0.0:443 failed: port is already allocated The terminal process "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command docker compose -f "docker-compose-app2.yml" up -d --build" terminated with exit code: 1.
app1 Docker file (same for all web app)
FROM node:lts-alpine
ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
RUN npm install --production --silent && mv node_modules ../
COPY . .
EXPOSE 3000
RUN chown -R node /usr/src/app
USER node
CMD ["npm", "start"]
Docker-compose-app1.yml (same for all except image/container/ssl certificates and app host port)
version: '3.4'
services:
nginx:
image: nginx:latest
restart: unless-stopped
ports:
- 80:80
- 443:443
volumes:
- ./site:/usr/share/nginx/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./nginx/app.com.crt:/etc/nginx/app1.com.crt
- ./nginx/app.com.key:/etc/nginx/app1.com.key
# environment:
# SITES: 'app.com=app_ssl:80'
# FORCE_HTTPS: "true"
depends_on:
- app1
container_name: app1_nginx
app1:
image: app1
build:
context: .
dockerfile: ./Dockerfile
environment:
NODE_ENV: production
restart: always
ports:
- 9200:3000
# - 801:80
container_name: app1
Default.conf for app1
server {
listen 80;
server_name www.app1.com;
index index.html;
# root /usr/share/nginx/html;
location / {
root /usr/share/nginx/html;
rewrite ^ https://$host$request_uri? permanent;
error_log /etc/nginx/app1_errors.log;
return 301 https://$server_name$request_uri;
}
}
server { # This new server will watch for traffic on 443
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name app1.com;
ssl_certificate /etc/nginx/app1.com.crt;
ssl_certificate_key /etc/nginx/app1.com.key;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
add_header Strict-Transport-Security max-age=500;
root /usr/share/nginx/html;
location / {
proxy_pass http://hosyip:9200;
error_log /etc/nginx/app1_errors.log;
proxy_set_header X-Forwarded-Proto https;
}
}
Folder structure for webapp1, same as reset of other 3 Webapps
- app1
- nginx
-- nginx.conf
- docker-compose.yml
Solution 1:[1]
The issue is that you publish all container ports to the same host port, thats what the error is saying
Bind for 0.0.0.0:443 failed: port is already allocated
When you run the for first time docker-compose up there is no issue, but its subsequent one requests the same host port
In these cases, you could tackle this by not explicitily binding the ports to a specific host port, but instead let the system find the free ones.
docker-compose.yml
version: '3.4'
services:
nginx:
image: nginx:latest
restart: unless-stopped
ports:
# NOT explicit bind
- 80
- 443
volumes:
- ./site:/usr/share/nginx/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./nginx/app.com.crt:/etc/nginx/app1.com.crt
- ./nginx/app.com.key:/etc/nginx/app1.com.key
# environment:
# SITES: 'app.com=app_ssl:80'
# FORCE_HTTPS: "true"
depends_on:
- app1
container_name: app1_nginx
app1:
image: app1
build:
context: .
dockerfile: ./Dockerfile
environment:
NODE_ENV: production
restart: always
# There is no need to expose these ports since you use nginx for load balancing
# ports:
# - 9200:3000
# - 801:80
container_name: app1
Since the containers are able to perform dns discovery you could alter your nginx default.conf to find the container
default.conf
server {
listen 80;
server_name www.app1.com;
index index.html;
# root /usr/share/nginx/html;
location / {
root /usr/share/nginx/html;
rewrite ^ https://$host$request_uri? permanent;
error_log /etc/nginx/app1_errors.log;
return 301 https://$server_name$request_uri;
}
}
server { # This new server will watch for traffic on 443
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name app1.com;
ssl_certificate /etc/nginx/app1.com.crt;
ssl_certificate_key /etc/nginx/app1.com.key;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
add_header Strict-Transport-Security max-age=500;
root /usr/share/nginx/html;
location / {
# proxy_pass http://hosyip:9200;
# Docker can resolve the hostname, you can use the container name
proxy_pass http://app1:3000;
error_log /etc/nginx/app1_errors.log;
proxy_set_header X-Forwarded-Proto https;
}
}
After docker-compose up your OS will assign random ports for the nginx container, so no conflict will arise. An example
To access app1 curl localhost:49155
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Tolis Gerodimos |

