1
0
mirror of https://github.com/thib8956/nginx-proxy synced 2025-02-24 09:48:14 +00:00

Merge pull request #1609 from pini-gh/pini-1132

Honor VIRTUAL_PORT + DEBUG flag + fallback entry
This commit is contained in:
Nicolas Duchon 2021-05-28 12:07:32 +02:00 committed by GitHub
commit 49b2b5cd97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 159 additions and 28 deletions

View File

@ -82,17 +82,21 @@ NginX does not support scoped IPv6 resolvers. In [docker-entrypoint.sh](./docker
By default, docker uses IPv6-to-IPv4 NAT. This means all client connections from IPv6 addresses will show docker's internal IPv4 host address. To see true IPv6 client IP addresses, you must [enable IPv6](https://docs.docker.com/config/daemon/ipv6/) and use [ipv6nat](https://github.com/robbertkl/docker-ipv6nat). You must also disable the userland proxy by adding `"userland-proxy": false` to `/etc/docker/daemon.json` and restarting the daemon.
### Multiple Ports
If your container exposes multiple ports, nginx-proxy will default to the service running on port 80. If you need to specify a different port, you can set a VIRTUAL_PORT env var to select a different one. If your container only exposes one port and it has a VIRTUAL_HOST env var set, that port will be selected.
[1]: https://github.com/jwilder/docker-gen
[2]: http://jasonwilder.com/blog/2014/03/25/automated-nginx-reverse-proxy-for-docker/
### Multiple Hosts
If you need to support multiple virtual hosts for a container, you can separate each entry with commas. For example, `foo.bar.com,baz.bar.com,bar.com` and each host will be setup the same.
### Virtual Ports
When your container exposes only one port, nginx-proxy will default to this port, else to port 80.
If you need to specify a different port, you can set a `VIRTUAL_PORT` env var to select a different one. This variable cannot be set to more than one port.
For each host defined into `VIRTUAL_HOST`, the associated virtual port is retrieved by order of precedence:
1. From the `VIRTUAL_PORT` environment variable
1. From the container's exposed port if there is only one
1. From the default port 80 when none of the above methods apply
### Wildcard Hosts
You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [xip.io](http://xip.io), using `~^foo\.bar\..*\.xip\.io` will match `foo.bar.127.0.0.1.xip.io`, `foo.bar.10.0.2.2.xip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html).
@ -424,6 +428,33 @@ will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRT
#### Per-VIRTUAL_HOST `server_tokens` configuration
Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details.
### Troubleshooting
In case you can't access your VIRTUAL_HOST, set `DEBUG=true` in the client container's environment and have a look at the generated nginx configuration file `/etc/nginx/conf.d/default`:
```
$ docker exec <nginx-proxy-instance> cat /etc/nginx/conf.d/default
```
Especially at `upstream` definition blocks which should look like:
```
# foo.example.com
upstream foo.example.com {
## Can be connected with "my_network" network
# Exposed ports: [{ <exposed_port1> tcp } { <exposed_port2> tcp } ...]
# Default virtual port: <exposed_port|80>
# VIRTUAL_PORT: <VIRTUAL_PORT>
# foo
server 172.18.0.9:<Port>;
# Fallback entry
server 127.0.0.1 down;
}
```
The effective `Port` is retrieved by order of precedence:
1. From the `VIRTUAL_PORT` environment variable
1. From the container's exposed port if there is only one
1. From the default port 80 when none of the above methods apply
### Contributing

View File

@ -2,6 +2,7 @@
{{ $external_http_port := coalesce $.Env.HTTP_PORT "80" }}
{{ $external_https_port := coalesce $.Env.HTTPS_PORT "443" }}
{{ $debug_all := $.Env.DEBUG }}
{{ define "upstream" }}
{{ if .Address }}
@ -17,9 +18,9 @@
{{ else if .Network }}
# {{ .Container.Name }}
{{ if .Network.IP }}
server {{ .Network.IP }} down;
server {{ .Network.IP }}:{{ .VirtualPort }};
{{ else }}
server 127.0.0.1 down;
# /!\ No IP for this network!
{{ end }}
{{ end }}
@ -180,29 +181,32 @@ server {
upstream {{ $upstream_name }} {
{{ range $container := $containers }}
{{ $addrLen := len $container.Addresses }}
{{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }}
{{/* If only 1 port exposed, use that as a default, else 80 */}}
{{ $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }}
{{ range $knownNetwork := $CurrentContainer.Networks }}
{{ range $containerNetwork := $container.Networks }}
{{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }}
## Can be connected with "{{ $containerNetwork.Name }}" network
{{/* If only 1 port exposed, use that */}}
{{ if eq $addrLen 1 }}
{{ $address := index $container.Addresses 0 }}
{{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }}
{{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}}
{{ else }}
{{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }}
{{ $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }}
{{ $address := where $container.Addresses "Port" $port | first }}
{{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }}
{{ if $debug }}
# Exposed ports: {{ $container.Addresses }}
# Default virtual port: {{ $defaultPort }}
# VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }}
{{ if not $address }}
# /!\ Virtual port not exposed
{{ end }}
{{ end }}
{{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork "VirtualPort" $port) }}
{{ else }}
# Cannot connect to network of this container
# Cannot connect to network '{{ $containerNetwork.Name }}' of this container
{{ end }}
{{ end }}
{{ end }}
{{/* nginx-proxy/nginx-proxy#1105 */}}
# Fallback entry
server 127.0.0.1 down;
{{ end }}
{{ end }}
{{ end }}
{{ end }}
}

View File

@ -0,0 +1,12 @@
import pytest
import re
def test_debug_info_is_present_in_nginx_generated_conf(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII')
assert re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \}\]", conf) or \
re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \}\]", conf)
assert re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+82\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+83\s+tcp \}\]", conf) or \
re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+83\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+82\s+tcp \}\]", conf)
assert "# Default virtual port: 80" in conf
assert "# VIRTUAL_PORT: 82" in conf
assert conf.count("# /!\ Virtual port not exposed") == 1

View File

@ -0,0 +1,27 @@
web1:
image: web
expose:
- "80"
- "81"
environment:
WEB_PORTS: "80 81"
VIRTUAL_HOST: "web1.nginx-proxy.tld"
VIRTUAL_PORT: "82"
web2:
image: web
expose:
- "82"
- "83"
environment:
WEB_PORTS: "82 83"
VIRTUAL_HOST: "web2.nginx-proxy.tld"
VIRTUAL_PORT: "82"
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
environment:
DEBUG: "true"

View File

@ -0,0 +1,8 @@
import pytest
import re
def test_debug_info_is_present_in_nginx_generated_conf(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII')
assert re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \}\]", conf) or \
re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \}\]", conf)
assert conf.count("# Exposed ports: [{") == 1

View File

@ -0,0 +1,26 @@
web1:
image: web
expose:
- "80"
- "81"
environment:
WEB_PORTS: "80 81"
VIRTUAL_HOST: "web1.nginx-proxy.tld"
VIRTUAL_PORT: "82"
DEBUG: "true"
web2:
image: web
expose:
- "82"
- "83"
environment:
WEB_PORTS: "82 83"
VIRTUAL_HOST: "web2.nginx-proxy.tld"
VIRTUAL_PORT: "82"
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -0,0 +1,8 @@
import pytest
import re
def test_answer_is_served_from_virtual_port_which_is_ureachable(docker_compose, nginxproxy):
r = nginxproxy.get("http://web.nginx-proxy.tld/port")
assert r.status_code == 502
assert re.search(r"\n\s+server \d+\.\d+\.\d+\.\d+:90;\n", nginxproxy.get_conf().decode('ASCII'))

View File

@ -0,0 +1,15 @@
web:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
VIRTUAL_HOST: "web.nginx-proxy.tld"
VIRTUAL_PORT: "90"
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro