I am run a docker windows container on windows 10 anniversary edition and am looking to setup IIS as a reverse proxy to the container. Per https://blogs.technet.microsoft.com/virtualization/2016/05/25/windows-nat-winnat-capabilities-and-limitations/ it seems to suggest that it is an impossibility as it is impossible to reference the internal NAT range using local host. Which leaves a dynamically assigned IP address which can only be discover by running a docker inspect command after running the image. I am hoping there is a more efficient way that I am overlooking.
We also used a fixed ip address on our containers but we used another container with nginx to do the reverse proxy. The idea is that on our Container Host (Windows Server 2016) we only install Docker and nothing else. All configuration is done in the containers. This way we can easily migrate to another host.
This is the Dockerfile for the nginx proxy
FROM microsoft/windowsservercore
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ARG NgInxVersion="1.13.5"
ENV NgInxZipUrl="http://nginx.org/download/nginx-${NgInxVersion}.zip"
RUN Invoke-WebRequest -Uri $env:NgInxZipUrl -UseBasicParsing -Outfile c:\\nginx.zip
RUN Expand-Archive -Path c:\\nginx.zip -DestinationPath c:\\nginx
WORKDIR "c:\\nginx\\nginx-${NgInxVersion}"
COPY ./nginx.conf conf\\nginx.conf
ENTRYPOINT powershell .\\nginx.exe
Notice that the nginx.conf is copied to the nginx configuration folder. It contains the reverse proxy settings. Extract from http node for one of our sites:
server {
listen 80;
server_name somesite.mydomain.com;
location / {
proxy_pass http://172.22.108.6/;
}
}
The nginx container should be run with -p 80:80
When we add new containers we run a powershell script that updates the nginx.conf and reloads nginx. (this will be rare)
Example:
A user browses to http://somesite.mydomain.com
Our DNS redirects somesite.mydomain.com to ip of our Container Host
Since port 80 is exposed to nginx container, request goes there
nginx will proxy the request to 172.22.108.6
User sees the webpage running on container with ip 172.22.108.6
We solved this problem by assigning an IP address on the default subnet to each Windows container and exporting port 80 out of the container. This gave us a stable address to put into an ARR Reverse proxy rule. For example the following creates a container at the address 172.20.118.129 and then verifies the container is running at the requested address.
PS C:\WINDOWS\system32> docker run -d --name myservice --ip=172.20.118.129 microsoft/iis:nanoserver
7d20d8a131805727868ddf85f7c1f455fa2489bb2607b250e694a9e530a61302
PS C:\WINDOWS\system32> docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" myservice
172.20.118.129
Related
I am new to using docker and nginx together so i apologize in advance for my simple question which I am unable to get an answer to despite going through many resources on youtube.
I created an ubuntu server and ran the following command
sudo apt install nginx
Now I have a very simple flask application docker image(publicly available on docker hub and not developed by me) and I want to configure my nginx to work as a reverse proxy to my container running the said image.
My code for the reverse proxy in nginx configuration is as follows:
server{
listen 80;
location / {
proxy_pass "http://192.168.0.20:8000"
}
}
192.168.0.20 is my server ip and 8000 is the host port over which i am forwarding my docker container like
docker container run -p 8000:5000 <image>
But when I run http://192.168.0.20/ it opens default nginx index.html whereas I want it to forward to my app container to serve that static file because when i run http://192.168.0.20:8000/ it gives me desired output.
This might sound like a dumb question but i have been struggling to get a hang of nginx.
Thanks in advance for the help !!!
To reach the host from inside the container, you can't use 192.168.0.20, since that address isn't known inside the container. Depending on your host OS, you can use 172.17.0.1 (Linux) or host.docker.internal (Windows). If your OS is Linux, you should change your config to
server {
listen 80;
location / {
proxy_pass "http://172.17.0.1:8000/"
}
}
Rather than installing nginx yourself, you can use the nginx images that are available on docker hub. To get your config file into it, you copy it to /etc/nginx/conf.d/default.conf. Create a Dockerfile containing
FROM nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
Build and run it with
docker build -t mynginx .
docker run -d -p 80:80 mynginx
Now you should be able to go to http://192.168.0.20/ and get a response from the Flask app.
I have an application running on http://localhost:8000 using a docker image that was made by me.
Now I want to use NGINX as reverse proxy listening on port 80, to redirect to the localhost:8000.
Here my nginx.conf file
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
proxy_pass http://localhost:8000;
}
}
}
Here my Dockerfile:
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY index.html /usr/share/nginx/html
COPY nginx.conf /etc/nginx
CMD nginx
To build the image I use the command
docker build --no-cache -t mynginx .
To run it, I use
docker run -p 80:80 -d mynginx
Now, if I test from my local computer with curl localhost:8000 everything works, but if I try with curl localhost, I get a Bad Gateway error.
Moreover, I tried to serve static content and it works, but with the reverse proxy settings it does not work.
The reason you are getting a bad gateway is that from within your nginx container, localhost resolves to the container itself and not to the host system.
If you want to access your application container from your reverse proxy container, you need to put both containers into a network.
docker network create my-network
docker network connect --alias application my-network <application container id/name>
docker network connect --alias reverse-proxy my-network <reverse proxy container id/name>
--network can be an arbitrary name and --alias should be the hostnames you want to resolve to your containers.
In fact you do not need to provide an alias if you already assigned a (host)name (docker run --name ...) to your containers.
You can then change your proxy_pass directive to the (alias) name of your application container:
proxy_pass http://application:8000;
Also refer to the documentation: Container networking
curl localhost:8000 works => your application is running
curl localhost returns bad gateway means proxy_pass http://localhost:8000; does not work. This is because "localhost" is relative to its caller, in this case the nginx container, which does not have anything running on port 8000.
You need to point it to your application using proxy_pass http://your_app:8000; where "your_app" is the service name (docker-compose) or the container name or its network alias. Make sure they are in the same network.
I'am learning docker and start test simple project contains only index.php, but it not work.
I start docker in VirtualBox(CentOS) on my Windows OS.
I have index.php
<?php
echo "Hello world";
I have Dockerfile
FROM php:7.0-apache
COPY . /var/www/html
Then build image and start container:
docker build -t php-app .
docker run php-app
When I start container I see its ip
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4.
In VirtualBox I can see index.php using
curl 172.17.0.4/index.php
But in my Windows OS I type 192.168.1.194 (VirtualBox ip) in browser and I don't see my index.php. Apparently problem in ports. But what should I change to see index.php in Docker via my Windows browser?
You need to expose your port.
Run the container with this command:
docker run -p 80:80 php-app
This way your container's 80 port which is where your Apache instance is listening, will be bound to your host's (your virtual box vm in this case) 80 port and you should be able to reach it from outside.
You can read docker's all command line options' documentation in the official page here: https://docs.docker.com/engine/reference/run/#pid-equivalent
I want to run Nginx in a docker container, it listens to port 80 and I want it to proxy_pass to port 8080 when the url starts with word api, and I have some web app listening port 8080. This has been working for me without docker, but with docker, I couldn't get it to work.
My nginx.conf is like:
location /{
# serve static page
}
location /api {
proxy_pass http://0.0.0.0:8080;
}
I run my nginx container with docker run -d -p 80:80 -p 8080: 8080 nginx
My problem is now I can no longer run my web app because it can't listen to port 8080 since that container is already listening to it.
docker run -d --net host nginx
Try it!
Nginx container will share the host network with IP and all ports
First, you need to create a network to place both containers:
docker network create nginx_network
Then, you should specify Docker's DNS server in nginx configuration:
location /api {
#Docker DNS
resolver 127.0.0.11;
#my_api - name of container with your API, see below
proxy_pass http://my_api:8080;
}
Finally, run your containers:
docker run --network="nginx_network" -d --name my_api your_api_container
docker run --network="nginx_network" -d -p 80:80 nginx
Note:
--name parameter's value for API's container must match domain name in Nginx config
it's enough to specify only 80 port for your nginx container
first run your API's container and then Nginx's container (see below)
both containers must be in the same network
This should work.
In case if you run nginx container first, then nginx will try to resolve domain name my_api on startup and fail, because container with this name doesn't exist yet. In this case there is a following workaround (not sure if it is good solution). Modify nginx config:
location /api {
#Docker DNS
resolver 127.0.0.11;
#hack to prevent nginx to resolve domain on start up
set $docker_host "my_api";
#my_api - name of container with your API, see below
proxy_pass http://$docker_host:8080;
}
You can (or rather should) only have one process per docker container which means you will have nginx running in one container and your application on another. The old way is to create links between containers like this:
$ docker run --name my-app -d myself/myapp
$ docker run --name proxy --link my-app:my-app -d nginx
This will add a line in /etc/hosts in the nginx container so it will be able to call the other container by it's name.
And then in nginx.conf file:
location /api {
proxy_pass http://my-app:8080;
}
However according to official Docker docs this method is deprecated and you should only use it's "absolutely needed". Instead you should use the docker networking. Theoretically if both containers are in the same network and the local DNS server is working (embedded in docker) they should be able to see each other without the --link parameter. Unfortunately it didn't work for me for some reason. Nginx didn't have the correct DNS configured in /etc/resolv.conf, but read the article and play around it, I'm sure it will work.
I am trying to run Ubuntu inside of Docker, but my network has several restrictions:
must use network's DNS, when I set it, I do not get a response, I suspect it is because the return address is the docker IP 172 ...
must use network's Proxy, I can set an env, but it is useless without DNS working
I am trying this:
docker run --dns=10.69.114.61 -it ubuntu
docker run --dns=172.17.0.1 -it ubuntu (docker0 interface IP)
Docker containers will use docker host's dns settings by default.
In order to specify DNS server:
docker run --dns=10.69.114.61 -it debian:jessie /bin/bash
root#299849f13f21:/# cat /etc/resolv.conf
nameserver 10.69.114.61
Needless to say you must supply your network's DNS server IP address to the --dns flag.
docker run --dns=<your DNS server IP> -it debian:jessie /bin/bash
As you pointed out you should specify HTTP_PROXY variable to use your proxy server.