42

I have two docker containers with nginx. container1 is linked to container2. Docker then adds an entry to /etc/hosts which I entered into the nginx configuration like so:

server {
    location ~ ^/some_url/(.*)$ {
        proxy_pass http://container1/$1;
    }
}

I can ping container1 from container2, but nginx cannot resolve it:

*1 no resolver defined to resolve container1

How can I proxy_pass a request to another docker container?

Tim
  • 1,315
  • 1
  • 14
  • 35
  • Can you share your hosts file? How did you link the two containers? (What name does the link have?) Also gotcha: In case you `rm`d one of the containers and restart it later, the IP will have changed (hosts are not updated) – wpp Jan 19 '15 at 17:53
  • I just tried configuration similar to yours and it worked fine for me with `nginx:1.7.9`. Can you start bash at *container2* and curl *container1* ? You are not using the same configurations both container1 and 2, are you? – Mykola Gurov Jan 20 '15 at 12:12
  • 1
    @MykolaGurov I can ping and curl and what not container1 from container2. My problem is, that nginx doesn't seem to be able to resolve it. I'm not using the same configurations, no (if you're referring to nginx config). – Tim Jan 21 '15 at 22:32

4 Answers4

63

Use an upstream block instead of the container name directly

upstream backend {
    server container1;
}
server {
    location ~ ^/some_url/(.*)$ {
        proxy_pass http://backend/$1;
    }
}

This should allow normal name resolution to occur providing a way to easily use docker links with nginx.

Bruce Stringer
  • 654
  • 6
  • 4
  • 1
    Best answer when you aren't wanting to mess around with any external dependencies. – Xaero Degreaz Apr 21 '16 at 18:56
  • 7
    The problem I had with this solution is that `container1` must be up and running before you can start your nginx container, otherwise it won't start – Marc-Alexandre Bérubé May 12 '16 at 17:21
  • 1
    Write a script that waits until the backend is up. Something like this should work: `bash -c "while ! curl -s container1:8080 > /dev/null; do echo waiting for container1; sleep 3; done; start_nginx.sh"` where `start_nginx.sh` actually starts the nginx service. – threejeez Jun 29 '16 at 16:50
  • 1
    @Marc-AlexandreBérubé Shouldn't be an issue though - if you're using `--link` that's a requirement anyhow. – TJ Biddle Aug 10 '17 at 22:06
  • only really clean and safe solution. kudos! – Jarema Oct 07 '18 at 12:22
  • Does not work, throws the same error with the upstream name defined. Alpine image nginx/1.23.2 – Marc Dec 03 '22 at 10:49
51

I believe, Nginx is using its own DNS resolver implementation,

You could use embedded Docker DNS service, if enabled, check your container resolver:

cat /etc/resolv.conf

Should be:

nameserver 127.0.0.11

Use this IP as resolver:

server {
    location ~ ^/some_url/(.*)$ {
        resolver 127.0.0.11;
        proxy_pass http://container1/$1;
    } }

There is plenty of Docker image with such hack in the entrypoint:

https://github.com/jetbrains-infra/docker-nginx-resolver

entrypoint.sh:

...
echo resolver $(awk 'BEGIN{ORS=" "} $1=="nameserver" {print $2}' /etc/resolv.conf) ";" > /etc/nginx/includes/resolver.conf
...

nginx.conf:

http {
    include       /etc/nginx/includes/resolver.conf;
....
Thomas Decaux
  • 21,738
  • 2
  • 113
  • 124
  • 3
    Hmm, maybe the hard coded IP 127.0.0.11 could bring some issues – Thomas Decaux Mar 13 '17 at 16:10
  • I think yes. The ideal way would be to parse the `etc/resolv.conf` for the nameserver IP. – psiyumm Mar 14 '17 at 05:43
  • 3
    I just came across this: http://stackoverflow.com/questions/35744650/docker-network-nginx-resolver#comment68472082_37656784. Hardcoding IP address in user-defined networks won't be a problem. – psiyumm Mar 14 '17 at 05:50
  • 2
    Why Nginx dont parse resolv.conf btw ? – Thomas Decaux Mar 14 '17 at 08:59
  • It looks like it does but not sure why it specifically fails in the case of docker. – psiyumm Mar 15 '17 at 20:49
  • Maybe resolv.conf is changed after the image is started, hence nginx didnt get it – Thomas Decaux Mar 16 '17 at 12:50
  • I am running nginx in kubernetes. cat: /etc/resolve.conf: No such file or directory – Arrow_Raider Mar 29 '21 at 15:52
  • for future google visitors looking for a solution in openshift: https://stackoverflow.com/a/66857955/1143392 – Max Mar 29 '21 at 18:17
  • What's the point of having the nameserver set in /etc/resolv.conf if you hardcode the 127.0.0.11 in the nginx conf? SO is full of questions about this issue but there is still no answer other than hardcoding that sucks because the config becomes docker-specific. There is no answer why ping works but nginx does not. And this answer just puts together two random advices with no explanation. – Nakilon Jul 03 '21 at 09:21
  • I agree, I really prefer answer with real explanation, but here, nginx have its own resolver implementation, you can make a PR on nginx code source, or use the hack (ex: https://github.com/jetbrains-infra/docker-nginx-resolver ) – Thomas Decaux Jul 06 '21 at 08:27
9

You should take a look at this answer about using /etc/hosts as your resolver: Using /etc/hosts as resolver for url rewriting

Basically, your dns or resolver does not use /etc/hosts to resolve names during a lookup, but you can work around this by installing dnsmasq and using 127.0.0.1 as your resolver. You can add 127.0.0.1 as the resolver directly in your nginx config:

server {
    location ~ ^/some_url/(.*)$ {
        resolver 127.0.0.1;
        proxy_pass http://container1/$1;
    }
}
Community
  • 1
  • 1
Michael
  • 10,124
  • 1
  • 34
  • 49
  • That's something I actually already tried, but since dnsmasq did not start up without errors I gave up. Maybe too quickly. Will try again and let you know. – Tim Jan 19 '15 at 22:25
  • I tried again, simply added dnsmasq to my entrypoint. If you're running your container inside a VM make sure to run dnsmasq as root, it won't work otherwise. – Tim Jan 26 '15 at 13:48
0

In my case, it seem that using $request_uri get me this error. So I finally use this and Docker resolver is taken

server {
    location /api/ {
        proxy_pass http://backend/api/;
    }
}
alexandre-rousseau
  • 2,321
  • 26
  • 33