I have one physical server with Docker, my docker run 2 containers, two web app in two différents ports
I also have two domains.
Can I link my domains one by web app ?
Thanks you !
Yes, you can. You can put a reverse proxy that routes traffic based on the domain name in front of the 2 containers.
As an example, let's create 2 simple Dockerfiles to simulate your 2 apps. I'll use Nginx as it's a very simple way to create a web server. Don't get hung up on the fact that I use Nginx here. This should be your web app containers.
Dockerfile1:
FROM nginx
RUN echo 'hello from container 1' > /usr/share/nginx/html/index.html
and Dockerfile2:
FROM nginx
RUN echo 'hello from container 2' > /usr/share/nginx/html/index.html
Then we'll create a docker-compose file to run the 2 containers, along with a reverse proxy.
docker-compose.yml:
version: '3'
services:
app1:
build:
context: .
dockerfile: ./Dockerfile1
app2:
build:
context: .
dockerfile: ./Dockerfile2
reverseproxy:
image: nginx
ports:
- 8080:80
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
And finally, the nginx.conf file that configures nginx to route traffic for 'domain1.com' to the 'app1' container and traffic for 'domain2.com' to 'app2'.
nginx.conf:
events { }
http {
server {
listen 80;
server_name domain1.com;
location / {
proxy_pass http://app1/;
}
}
server {
listen 80;
server_name domain2.com;
location / {
proxy_pass http://app2/;
}
}
}
Now you can start up all 3 containers using
docker-compose up -d
and send a request to each container using
curl -H "Host: domain1.com" http://localhost:8080
curl -H "Host: domain2.com" http://localhost:8080
And the responses will come from the two different containers.
Related
I want to host multiple Flask apps on my docker nginx image. I want each app to listen on a different port.
However, i am unable to do so.
nginx.conf
server {
listen 80;
location / {
include uwsgi_params;
uwsgi_pass flask1:8080;
}
}
server {
listen 81;
location / {
include uwsgi_params;
uwsgi_pass flask2:8081;
}
}
docker-compose.yml
version: "3.7"
services:
flask1:
build: ./flask1
container_name: flask1
restart: always
environment:
- APP_NAME=MyFlaskNginxDockerApp
expose:
- 8080
flask2:
build: ./flask2
container_name: flask2
restart: always
environment:
- APP_NAME=MyFlaskNginxDockerApp
expose:
- 8081
nginx:
build: ./nginx
container_name: nginx
restart: always
ports:
- "8080:80"
- "8081:81"
nginx - Dockerfile
# Use the Nginx image
FROM nginx
# Remove the default nginx.conf
RUN rm /etc/nginx/conf.d/default.conf
# Replace with our own nginx.conf
COPY nginx.conf /etc/nginx/conf.d/
When I built and run this docker-compose, my websites are not available.
I want flask1 to be accessible via localhost:8080 and flask 2 to be accessible via localhost:8081
Can someone please help point out what I did wrong ?
You should not be using the service name, instead use host.docker.internal which resolves request to the host. Make this change in your nginx.conf
I would suggest using docker networks instead..
What you've set up right now is that external clients can connect to your flask apps on :81 and :82. Other containers like nginx can connect on flask1:80 and flask2:80.
Nginx could also be set up with host network mode to go back out and connect to :81 and :82, but that's probably not what you want. In fact, my guess would be that exposing external ports on the flask apps at all is probably not what you want to do in the long term, although it can be helpful for debugging because it gives you a way bypass the proxy.
Oops, forgot to add, you need to set up Nginx to use docker's internal dns to resolve the service names to IPs as mentioned here:
https://stackoverflow.com/a/37656784/9194976
I have tried reading through the other stackoverflow questions here but I am either missing something or none of them are working for me.
Context
I have two docker containers setup on a DigitalOcean server running Ubuntu.
root_frontend_1 running on ports 0.0.0.0:3000->3000/tcp
root_nginxcustom_1 running on ports 0.0.0.0:80->80/tcp
If I connect to http://127.0.0.1, I get the default Nginx index.html homepage. If I http://127.0.0.1:3000 I am getting my react app.
What I am trying to accomplish is to get my react app when I visit http://127.0.0.1. Following the documentation and suggestions here on StackOverflow, I have the following:
docker-compose.yml in root of my DigitalOcean server.
version: "3"
services:
nginxcustom:
image: nginx
hostname: nginxcustom
ports:
- "80:80"
volumes:
- ./nginx.conf:/root/nginxcustom/conf/custom.conf
tty: true
backend:
build: https://github.com/Twitter-Clone/twitter-clone-api.git
ports:
- "8000:8000"
tty: true
frontend:
build: https://github.com/dougmellon/react-api.git
ports:
- "3000:3000"
stdin_open: true
tty: true
nginxcustom/conf/custom.conf :
server {
listen 80;
server_name http://127.0.0.1;
location / {
proxy_pass http://root_frontend_1:3000; # this one here
proxy_redirect off;
}
}
When I run docker-compose up, it builds but when I visit the ip of my server, it's still showing the default nginx html file.
Question
What am I doing wrong here and how can I get it so the main URL points to my react container?
Thank you for your time, and if there is anything I can add for clarity, please don't hesitate to ask.
TL;DR;
The nginx service should proxy_pass to the service name (customnginx), not the container name (root_frontend_1) and the nginx config should be mounted to the correct location inside the container.
Tip: the container name can be set in the docker-compose.yml for services setting the container_name however beware you can not --scale services with a fixed container_name.
Tip: the container name (root_frontend_1) is generated using the compose project name which defaults to using the current directory name if not set.
Tip: the nginx images are packaged with a default /etc/nginx/nginx.conf that will include the default server config from /etc/nginx/conf.d/default.conf. You can docker cp the default configuration files out of a container if you'd like to inspect them or use them as a base for your own configuration:
docker create --name nginx nginx
docker cp nginx:/etc/nginx/conf.d/default.conf default.conf
docker cp nginx:/etc/nginx/nginx.conf nginx.conf
docker container rm nginx
With nginx proxying connections for the frontend service we don't need to bind the hosts port to the container, the services ports definition can be replaced with an expose definition to prevent direct connections to http://159.89.135.61:3000 (depending on the backend you might want prevent direct connections as well):
version: "3"
services:
...
frontend:
build: https://github.com/dougmellon/react-api.git
expose:
- "3000"
stdin_open: true
tty: true
Taking it a step further we can configure an upstream for the
frontend service then configure the proxy_pass for the upstream:
upstream frontend {
server frontend:3000 max_fails=3;
}
server {
listen 80;
server_name http://159.89.135.61;
location / {
proxy_pass http://frontend/;
}
}
... then bind-mount the custom default.conf on top of the default.conf inside the container:
version: "3"
services:
nginxcustom:
image: nginx
hostname: nginxcustom
ports:
- "80:80"
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
tty: true
... and finally --scale our frontend service (bounce the services removing the containers to make sure changes to the config take effect):
docker-compose stop nginxcustom \
&& docker-compose rm -f \
&& docker-compose up -d --scale frontend=3
docker will resolve the service name to the IP's of the 3 frontend containers which nginx will proxy the connections for in a (by default) round robin manner.
Tip: you can not --scale a service that has ports mappings, only a single container can bind to the port.
Tip: if you've updated the config and can connect to your load balanced service then you're all set to create a DNS record to resolve a hostname to your public IP address then update your default.conf's server_name.
Tip: for security I maintain specs for building a nginx docker image with Modsecurity and Modsecurity-nginx pre-baked with the OWASP Core Rule Set.
In Docker when multiple services needs to communicate with each other, you can use the service name in the url (set in the docker-composer.yml instead of the ip (which is attributed from the available pool of the network, default by default), it will automatically be resolve to the right container ip due to network management by docker.
For you it would be http://frontend:3000
I have installed jenkins docker in my system and am able to access the jenkins console with the local host url like http://localhost:8080.
Now, I wanted to share the URL with group of people. Some one suggest the steps to configure.
I am not sure of your Jenkins config as you haven't shared an MRE. So, this is how you launch a new Jenkins service that can be accessed by others on the network through Nginx.
We will be using Docker and docker-compose to facilitate the process. We're using the official Nginx and Jenkins images from docker hub.
Create a folder that contains the needed config files :
mkdir ~/jenkins-docker
cd ~/jenkins-docker
touch docker-compose.yml
touch nginx.conf
Make a home directory for Jenkins :
mkdir ~/jenkins
Create Jenkins and Nginx docker-compose services (docker-compose.yml file content):
version: '3'
services:
jenkins:
image: jenkins
container_name: jenkins
privileged: true
user: root
volumes:
- ~/jenkins:/var/jenkins_home
restart: always
ports:
- 8080:8080
networks:
- jenkinsnet
server:
image: nginx:1.17.2
container_name: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf # your nginx config file
- /var/log/nginx:/var/log/nginx # log files
restart: always
command: nginx-debug -g 'daemon off;'
ports:
- 8000:80
networks:
- jenkinsnet
depends_on:
- jenkins
networks:
jenkinsnet:
Create an Nginx config to make Jenkins accessible on the network (nginx.conf file content)
events {}
http {
include mime.types;
## logging
log_format main '$remote_addr - $remote_user [$time_local] [$server_name] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# server config
server {
listen 80;
location / {
proxy_pass http://jenkins:8080;
}
}
}
Run your services :
cd ~/jenkins-docker
docker-compose up
Access Jenkins on your local machine on http://localhost:8080
Access Jenkins from other devices on your network on http://local-ip-address:8000 (ex: http://192.168.1.23:8000)
Access Jenkins from other devices connected to the internet http://public-ip-address:8000 (ex: http://56.137.222.112:8000) (Port Forwarding required if you're setting up on your home network. If you're using cloud providers, allow access to port 8000 for your instance)
Further Explanation
We are launching two docker containers. The jenkins container contains a Jenkins installation, accessible on port 8080 in the container. Consequently, we published that port in the jenkins service config, so that we can access it from the host machine using :
ports:
8080:8080
The nginx container contains a reverse proxy server that allows you to make the Jenkins server accessible by routing all incoming traffic on a certain port to it.
In order for the nginx service to route traffic to the jenkins service, we create and assign a single network to the services:
# network creation :
networks:
jenkinsnet:
# network assignement :
networks:
- jenkinsnet
When the two containers belong to the same network, We are able to use the container names as hostnames. So accessing localhost:1234 on the jenkins container can be done from the nginx container using jenkins:1234. So, in the nginx.conf file we route all traffic coming to Nginx to the Jenkins server using :
location / {
proxy_pass http://jenkins:8080;
}
Nginx is listening on port 80 :
server {
listen 80;
...etc
So we publish the port to the host machine so that Nginx can pick up the incoming requests :
ports:
- 8000:80
I chose port 8000 but you can use any port you like.
Nginx reverse proxy can't reach docker host. Hosting on amazon (EC2)
I want to load different apps depends on location.
nginx.conf
server {
listen 80 ;
server_name localhost;
location /web {
proxy_pass http://web:4000/;
}}
Location works and it means that nginx image builded correct either.
docker-compose file
services:
web:
image: web
container_name: web
ports:
- 4000:4000
hostname: web
networks:
- default
nginx:
image: nginx
container_name: nginx
ports:
- 80:80
depends_on:
- web
networks:
- default
networks:
default:
external:
name: my-network
I expect
- when I type in url /web it should show app from docker container
I've tried
Run single container - works fine (web or nginx)
Added 127.0.0.1 web in /etc/hosts (I can do 'curl web' but it shows localhost response)
Added index index.html in location section
Added resolver in the location section
Use links instead of network
When "docker-compose up" I can inspect docker container (web) and see IP - 192.168.10.2 . Then curl 192.168.10.2 shows me index.html. But I can't make curl http://web:4000 seems that hostname in unreachable, but I think that using IP in proxy_pass is a bad decision.
I wasn't able to handle those issues, so I've chose another approach.
Create network ipam
docker network create --gateway 172.20.0.1 --subnet 172.20.0.0/24 ipam
Assigned for each service ipv4address in docker-compose file
networks:
default:
ipv4_address: 172.20.0.5 for web
where
networks:
default:
external:
name: ipam
Add chmod for directory /var/www/html in my web docker image
chmod -R 755 /var/www/html
(seems this additional step required if you build LINUX container under windows docker)
I have an two containers running via docker-compose:
version: '3'
services:
web:
image: me/web
container_name: web
nginx:
image: me/nginx
container_name: nginx
ports:
- '80:80'
volumes:
- ../nginx:/etc/myapp/nginx
My nginx container copies in a new default.conf from the mapped volume from the entrypoint.sh:
#!/usr/bin/env bash
cp /etc/myapp/nginx/default.conf /etc/nginx/conf.d/default.conf
nginx -g 'daemon off;'
My custom default.conf looks like:
server {
listen 80;
server_name my.website.com;
location / {
proxy_pass http://web/;
}
}
With this configuration everything works as expected. After starting with docker-compose I can then navigate to http://my.website.com and access the web container instance properly.
However, now I want to change my port to something other than the default 80, such as 81 for example:
services:
..
nginx:
image: me/nginx
container_name: nginx
ports:
- '81:80'
..
Now this no longer works. Whenever I visit http://my.website.com:81 I get:
This site can’t be reached
my.website.com refused to connect.
ERR_CONNECTION_REFUSED
The other weird part is that if I use localhost rather than my.website.com, everything works just fine on port 81. Ex:
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web/;
}
}
Navigating to http://localhost:81 works correctly.
What am I doing wrong here? How do I configure nginx to something other than localhost (my domain) and proxy on a different port than 80 to my web container?
Check that port 81 is open on my.website.com i.e. check firewall rules are in place etc