Mulitple Docker Containers on Port 80 with Same Domain - nginx

My question is similar to this question but with only one domain.
Is it possible to run multiple docker containers on the same server, all of them on port 80, but with different URL paths?
For example:
Internally, all applications are hosted on the same docker server.
172.17.0.1:8080 => app1
172.17.0.2:8080 => app2
172.17.0.3:8080 => app3
Externally, users will access the applications with the following URLs:
www.mydomain.com (app1)
www.mydomain.com/app/app2 (app2)
www.mydomain.com/app/app3 (app3)

I solved this issue with an nginx reverse proxy.
Here's the Dockerfile for the nginx container:
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
And this is the nginx.conf:
http {
server {
listen 80;
location / {
proxy_pass http://app1:5001/;
}
location /api/ {
proxy_pass http://app2:5000/api/;
}
}
}
I then stood up the nginx, app1, and app2 containers inside the same docker network.
Make sure to include the trailing / in the location and proxy paths, otherwise nginx will return a '502: Bad Gateway'.
All requests go through the docker host on port 80, which hands them off to the nginx container, which then forwards them onto the app containers based on the url path.

Related

How can I keep port and url without updating Gitlab nginx?

nginx(ng1): 172.168.240.5
Gitlab includ nginx (ng2): 172.168.240.55
ng1 config
listen 81;
server_name ng1;
location /gitlab/ {
proxy_pass 172.168.240.55/
}
how can I keep port and url without updating ng2. // only modify ng1
url gitlab lost
it's login(POST) http://ng1:81/gitlab/users/sign_in
but it's show http://ng1:81/users/sign_in instead of http://ng1:81/gitlab/users/sign_in
it seems to be rewrite by ng2
url gitlab and port lost
click one file in http://ng1:81/gitlab/root/pg/
but it's http://ng1/root/pg/index.html instead of http://ng1:81/gitlab/root/pg/index.html
need nginx reverse proxy
/servername/port/ for dynamic servername and port
I find resolve (dns server + nginx)
Using nginx regex location matching to dynamically map URI's to different ports for multiple reverse proxies

Nginx proxy on kubernetes

I have a nginx deployment in k8s cluster which proxies my api/ calls like this:
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
location /api {
proxy_pass http://backend-dev/api;
}
}
This works most of the time, however sometimes when api pods aren't ready, nginx fails with error:
nginx: [emerg] host not found in upstream "backend-dev" in /etc/nginx/conf.d/default.conf:12
After couple of hours exploring internets, I found the article which pretty much the same issue. I've tried this:
location /api {
set $upstreamName backend-dev;
proxy_pass http://$upstreamName/api;
}
Now nginx returns 502.
And this:
location /api {
resolver 10.0.0.10 valid=10s;
set $upstreamName backend-dev;
proxy_pass http://$upstreamName/api;
}
Nginx returns 503.
What's the correct way to fix it on k8s?
If your API pods are not ready, Nginx wouldn't be able to route traffic to them.
From Kubernetes documentation:
The kubelet uses readiness probes to know when a Container is ready to start accepting traffic. A Pod is considered ready when all of its Containers are ready. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.
If you are not using liveness or readiness probes, then your pod will be marked as "ready" even if your application running inside the container has not finished it's startup process and is ready to accept traffic.
The relevant section regarding Pods and DNS records can be found here
Because A records are not created for Pod names, hostname is required for the Pod’s A record to be created. A Pod with no hostname but with subdomain will only create the A record for the headless service (default-subdomain.my-namespace.svc.cluster-domain.example), pointing to the Pod’s IP address. Also, Pod needs to become ready in order to have a record unless publishNotReadyAddresses=True is set on the Service.
UPDATE: I would suggest using NGINX as an ingress controller.
When you use NGINX as an ingress controller, the NGINX service starts successfully and whenever an ingress rule is deployed, the NGINX configuration is reloaded on the fly.
This will help you avoid NGINX pod restarts.

How to use Nginx to connect to my app in Docker image?

My Nginx is not in docker image. My app is in docker image. They both live on the same server.
I don't want Nginx in a docker image, since it looks awful complex for me to configure. But my app is running in a docker container.
How to configure Nginx to use the docker image which my app is running in?
Here is my Nginx config file:
server {
listen 80;
server_name my.domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name www.nicolasxu.space nicolasxu.space;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";
ssl_certificate /root/.ssh/nicolasxu.space.cert;
ssl_certificate_key /root/nicolasxu.space.key;
[....]
}
To easily setup nginx (in docker host) as a reverse proxy in front of a dockerized webapp you could just --publish the port of your webapp and route the trafic to this port:
Run your docker container with --publish argument to bind host port with container's webapp port, for instance with a jenkins container I would do:
docker run --publish 127.0.0.1:8080:8080 --name jenkins jenkins
This binds port 8080 of the container to port 80 on localhost's 127.0.0.1 of the host machine (this avoids port 8080 to be opened to anyone if you don't use any firewall). The Docker User Guide explains in detail how to manipulate ports in Docker.
Forward all incoming trafic as a reverse proxy to the local container your port (8080 in my example)
server {
...
listen 443 ssl;
server_name www.nicolasxu.space nicolasxu.space;
...
ssl_certificate ...
location / {
# forward all the trafic to docker container's published port
proxy_pass http://localhost:8080;
}
}
Setting SSL on nginx and routing the trafic as HTTP to dockerized webapp is a good practice and will work like a charm.
Edit
For maximum performances, you can also use :
docker run --network=host ...
When using --network=host, docker will instruct the container to use the hosts networking stack. You won't have to --publish ports on host as it is the same network stack, and web application will be available on it's native port.

docker swarm mode nginx between 2 swarm clusters

I'm trying to create a proxy in front of a swarm cluster.
This proxy is inside of another swarm cluster, to provide HA.
This is the current structure:
Proxy cluster (ip range 192.168.98.100 ~ 192.168.98.102)
proxy-manager1;
proxy-worker1;
proxy-worker2;
App cluster (ip range 192.168.99.100 ~ 192.168.99.107)
app-manager1;
app-manager2;
app-manager3;
app-worker1;
app-worker2;
app-worker3;
app-worker4;
app-worker5;
When I configure nginx with the app-manager's IP address, the proxy redirection works good.
But when I configure nginx with the app-manager's hostname or DNS, the proxy service does not find the server to redirect.
This is the working config file:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
upstream app {
server 192.168.99.100:8080;
server 192.168.99.101:8080;
server 192.168.99.102:8080;
}
server {
listen 80;
location / {
proxy_pass http://app;
}
}
}
Is that a good practice?
Or maybe I'm doing wrong?
You have to make sure that nginx can resolve the hostnames to ip addresses. Check this out for more information: https://www.nginx.com/blog/dns-service-discovery-nginx-plus/
Check how nginx is resolving the hostnames or check the hosts files on the nginx servers.
On a side note, I sometimes will run this for the local dns https://cr.yp.to/djbdns.html and then makes sure that all the nginx servers use that dns service running on a server. It is easier to configure djbdns than to keep all the host files updated.

How to rewrite URL to match a server using nginx?

I'm new to nginx. I have two projects, and the one is django web app which is running localhost 8000, and another is tornado which used to provide api service and running localhost 8888.
How do I config the nginx that redirects all the url requests(from 80 port) to localhost:8000 but /api requests to localhost:8888(tornado app)?
Edit your nginx config file. Add a server block and use proxy_pass in location blocks to proxy (redirect) the request.
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:8000;
}
location /api {
proxy_pass http://127.0.0.1:8888;
}
}
Save it, and reload nginx.
nginx -s reload
https://gist.github.com/soheilhy/8b94347ff8336d971ad0

Resources