diff --git a/README.md b/README.md index 7228d3a..aa9e491 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,12 @@ docker network connect my-other-network my-nginx-proxy In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks. +### Host networking + +`nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself. + +Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers. + ### Custom external HTTP/HTTPS ports If you want to use `nginx-proxy` with different external ports that the default ones of `80` for `HTTP` traffic and `443` for `HTTPS` traffic, you'll have to use the environment variable(s) `HTTP_PORT` and/or `HTTPS_PORT` in addition to the changes to the Docker port mapping. If you change the `HTTPS` port, the redirect for `HTTPS` traffic will also be configured to redirect to the custom port. Typical usage, here with the custom ports `1080` and `10443`: diff --git a/nginx.tmpl b/nginx.tmpl index e7b5914..fc6bca8 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -67,6 +67,24 @@ # {{ .Name }} (ignored) {{- continue }} {{- end }} + {{- if eq .Name "host" }} + {{- /* Handle containers in host nework mode */}} + {{- if (index $.globals.networks "host") }} + # both container and proxy are in host network mode, using localhost IP + {{- $ip = "127.0.0.1" }} + {{- continue }} + {{- end }} + {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }} + {{- if and . .Gateway }} + # container is in host network mode, using {{ .Name }} gateway IP + {{- $ip = .Gateway }} + {{- break }} + {{- end }} + {{- end }} + {{- if $ip }} + {{- continue }} + {{- end }} + {{- end }} {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} # {{ .Name }} (unreachable) {{- continue }} diff --git a/test/conftest.py b/test/conftest.py index 8e32650..f73b7c0 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -160,6 +160,10 @@ def container_ip(container: Container): net_info = container.attrs["NetworkSettings"]["Networks"] if "bridge" in net_info: return net_info["bridge"]["IPAddress"] + + # container is running in host network mode + if "host" in net_info: + return "127.0.0.1" # not default bridge network, fallback on first network defined network_name = list(net_info.keys())[0] @@ -173,6 +177,10 @@ def container_ipv6(container): net_info = container.attrs["NetworkSettings"]["Networks"] if "bridge" in net_info: return net_info["bridge"]["GlobalIPv6Address"] + + # container is running in host network mode + if "host" in net_info: + return "::1" # not default bridge network, fallback on first network defined network_name = list(net_info.keys())[0] diff --git a/test/test_host-network-mode/test_host-network-mode.py b/test/test_host-network-mode/test_host-network-mode.py new file mode 100644 index 0000000..0c21348 --- /dev/null +++ b/test/test_host-network-mode/test_host-network-mode.py @@ -0,0 +1,13 @@ +import pytest + + +def test_forwards_to_bridge_network_container(docker_compose, nginxproxy): + r = nginxproxy.get("http://bridge-network.nginx-proxy.tld/port") + assert r.status_code == 200 + assert r.text == "answer from port 80\n" + + +def test_forwards_to_host_network_container(docker_compose, nginxproxy): + r = nginxproxy.get("http://host-network.nginx-proxy.tld/port") + assert r.status_code == 200 + assert r.text == "answer from port 8080\n" diff --git a/test/test_host-network-mode/test_host-network-mode.yml b/test/test_host-network-mode/test_host-network-mode.yml new file mode 100644 index 0000000..1f2769c --- /dev/null +++ b/test/test_host-network-mode/test_host-network-mode.yml @@ -0,0 +1,31 @@ +version: "2" + +networks: + net1: + internal: true + net2: + +services: + bridge-network: + image: web + environment: + WEB_PORTS: "80" + VIRTUAL_HOST: "bridge-network.nginx-proxy.tld" + networks: + - net2 + + host-network: + image: web + environment: + WEB_PORTS: "8080" + VIRTUAL_HOST: "host-network.nginx-proxy.tld" + VIRTUAL_PORT: "8080" + network_mode: host + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + networks: + - net1 + - net2 diff --git a/test/test_host-network-mode/test_proxy-host-network-mode.py b/test/test_host-network-mode/test_proxy-host-network-mode.py new file mode 100644 index 0000000..330334b --- /dev/null +++ b/test/test_host-network-mode/test_proxy-host-network-mode.py @@ -0,0 +1,13 @@ +import pytest + + +def test_forwards_to_host_network_container_1(docker_compose, nginxproxy): + r = nginxproxy.get("http://host-network-1.nginx-proxy.tld:8888/port") + assert r.status_code == 200 + assert r.text == "answer from port 8080\n" + + +def test_forwards_to_host_network_container_2(docker_compose, nginxproxy): + r = nginxproxy.get("http://host-network-2.nginx-proxy.tld:8888/port") + assert r.status_code == 200 + assert r.text == "answer from port 8181\n" diff --git a/test/test_host-network-mode/test_proxy-host-network-mode.yml b/test/test_host-network-mode/test_proxy-host-network-mode.yml new file mode 100644 index 0000000..32106e2 --- /dev/null +++ b/test/test_host-network-mode/test_proxy-host-network-mode.yml @@ -0,0 +1,26 @@ +version: "2" + +services: + host-network-1: + image: web + environment: + WEB_PORTS: "8080" + VIRTUAL_HOST: "host-network-1.nginx-proxy.tld" + VIRTUAL_PORT: "8080" + network_mode: host + + host-network-2: + image: web + environment: + WEB_PORTS: "8181" + VIRTUAL_HOST: "host-network-2.nginx-proxy.tld" + VIRTUAL_PORT: "8181" + network_mode: host + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTP_PORT: 8888 + network_mode: host