1
0
mirror of https://github.com/thib8956/nginx-proxy synced 2025-08-23 07:51:56 +00:00

Merge pull request #2279 from Knapoc/network-segregation-seperate-containers

feat: allow nginx / docker-gen network segregation
This commit is contained in:
Nicolas Duchon
2025-05-15 13:18:29 +02:00
committed by GitHub
6 changed files with 217 additions and 32 deletions

View File

@@ -1136,25 +1136,65 @@ I'm 5b129ab83266
To run nginx proxy as a separate container you'll need to have [nginx.tmpl](https://github.com/nginx-proxy/nginx-proxy/blob/main/nginx.tmpl) on your host system.
First start nginx with a volume:
First start nginx with a volume mounted to `/etc/nginx/conf.d`:
```console
docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx
docker run --detach \
--name nginx \
--publish 80:80 \
--volume /tmp/nginx:/etc/nginx/conf.d \
nginx
```
Then start the docker-gen container with the shared volume and template:
```console
docker run --volumes-from nginx \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
-v $(pwd):/etc/docker-gen/templates \
-t nginxproxy/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
docker run --detach \
--name docker-gen \
--volumes-from nginx \
--volume /var/run/docker.sock:/tmp/docker.sock:ro \
--volume $(pwd):/etc/docker-gen/templates \
nginxproxy/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
```
Finally, start your containers with `VIRTUAL_HOST` environment variables.
```console
docker run -e VIRTUAL_HOST=foo.bar.com ...
docker run --env VIRTUAL_HOST=foo.bar.com ...
```
### Network segregation
To allow for network segregation of the nginx and docker-gen containers, the label `com.github.nginx-proxy.nginx-proxy.nginx` must be applied to the nginx container, otherwise it is assumed that nginx and docker-gen share the same network:
```console
docker run --detach \
--name nginx \
--publish 80:80 \
--label "com.github.nginx-proxy.nginx-proxy.nginx" \
--volume /tmp/nginx:/etc/nginx/conf.d \
nginx
```
Network segregation make it possible to run the docker-gen container in an [internal network](https://docs.docker.com/reference/cli/docker/network/create/#internal), unreachable from the outside.
You can also customise the label being used by docker-gen to find the nginx container with the `NGINX_CONTAINER_LABEL`environment variable (on the docker-gen container):
```console
docker run --detach \
--name docker-gen \
--volumes-from nginx \
--volume /var/run/docker.sock:/tmp/docker.sock:ro \
--volume $(pwd):/etc/docker-gen/templates \
--env "NGINX_CONTAINER_LABEL=com.github.foobarbuzz" \
nginxproxy/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
docker run --detach \
--name nginx \
--publish 80:80 \
--label "com.github.foobarbuzz" \
--volume "/tmp/nginx:/etc/nginx/conf.d" \
nginx
```
⬆️ [back to table of contents](#table-of-contents)

View File

@@ -10,10 +10,10 @@
{{- $_ := set $globals "containers" $ }}
{{- $_ := set $globals "Env" $.Env }}
{{- $_ := set $globals "Docker" $.Docker }}
{{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }}
{{- $config := dict }}
{{- $_ := set $config "nginx_proxy_version" $.Env.NGINX_PROXY_VERSION }}
{{- $_ := set $config "nginx_container_label" ($.Env.NGINX_CONTAINER_LABEL | default "com.github.nginx-proxy.nginx-proxy.nginx") }}
{{- $_ := set $config "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
{{- $_ := set $config "external_http_port" ($globals.Env.HTTP_PORT | default "80") }}
{{- $_ := set $config "external_https_port" ($globals.Env.HTTPS_PORT | default "443") }}
@@ -44,26 +44,29 @@
{{- $_ := set $globals "vhosts" (dict) }}
{{- $_ := set $globals "networks" (dict) }}
# Networks available to the container running docker-gen (which are assumed to
# match the networks available to the container running nginx):
{{- $currentContainer := where $globals.containers "ID" $globals.Docker.CurrentContainerID | first }}
{{- $labeledContainer := whereLabelExists $globals.containers $globals.config.nginx_container_label | first }}
{{- $_ := set $globals "NetworkContainer" ($labeledContainer | default $currentContainer) }}
# Networks available to the container labeled "{{ $globals.config.nginx_container_label }}" or the one running docker-gen
# (which are assumed to match the networks available to the container running nginx):
{{- /*
* Note: $globals.CurrentContainer may be nil in some circumstances due to
* <https://github.com/nginx-proxy/docker-gen/issues/458>. For more context
* see <https://github.com/nginx-proxy/nginx-proxy/issues/2189>.
* Note:
* $globals.NetworkContainer may be nil in some circumstances due to https://github.com/nginx-proxy/docker-gen/issues/458.
* For more context see https://github.com/nginx-proxy/nginx-proxy/issues/2189.
*/}}
{{- if $globals.CurrentContainer }}
{{- range sortObjectsByKeysAsc $globals.CurrentContainer.Networks "Name" }}
{{- if $globals.NetworkContainer }}
{{- range sortObjectsByKeysAsc $globals.NetworkContainer.Networks "Name" }}
{{- $_ := set $globals.networks .Name . }}
# {{ .Name }}
{{- else }}
# (none)
{{- end }}
{{- else }}
# /!\ WARNING: Failed to find the Docker container running docker-gen. All
# upstream (backend) application containers will appear to be
# unreachable. Try removing the -only-exposed and -only-published
# arguments to docker-gen if you pass either of those. See
# <https://github.com/nginx-proxy/docker-gen/issues/458>.
# /!\ WARNING: Failed to find the Docker container labeled "{{ $globals.config.nginx_container_label }}" or the one running docker-gen.
# All upstream (backend) application containers will appear to be unreachable.
# Try removing the -only-exposed and -only-published arguments to docker-gen if you pass either of those.
# See https://github.com/nginx-proxy/docker-gen/issues/458.
{{- end }}
{{- /*
@@ -97,7 +100,7 @@
{{- $ipv4 = "127.0.0.1" }}
{{- continue }}
{{- end }}
{{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }}
{{- range sortObjectsByKeysAsc $.globals.NetworkContainer.Networks "Name" }}
{{- if and . .Gateway (not .Internal) }}
# container is in host network mode, using {{ .Name }} gateway IP
{{- $ipv4 = .Gateway }}
@@ -114,7 +117,7 @@
{{- end }}
{{- /*
* Do not emit multiple `server` directives for this container if it
* is reachable over multiple networks or multiple IP stacks. This avoids
* is reachable over multiple networks or multiple IP stacks. This avoids
* accidentally inflating the effective round-robin weight of a server due
* to the redundant upstream addresses that nginx sees as belonging to
* distinct servers.
@@ -397,7 +400,7 @@ upstream {{ $vpath.upstream }} {
{{- $debug_vpath := deepCopy $vpath | merge (dict "ports" $tmp_ports) }}
{{- $_ := set $debug_paths $path $debug_vpath }}
{{- end }}
{{- $debug_vhost := deepCopy .VHost }}
{{- /* If it's a regexp, do not render the Hostname to the response to avoid rendering config breaking characters */}}
{{- $_ := set $debug_vhost "hostname" (.VHost.is_regexp | ternary "Hostname is a regexp and unsafe to include in the debug response." .Hostname) }}
@@ -606,7 +609,7 @@ proxy_set_header Proxy "";
{{- $path_port_containers := get $path_ports $port | default (list) | concat $containers }}
{{- $_ := set $path_ports $port $path_port_containers }}
{{- $_ := set $path_data "ports" $path_ports }}
{{- if (not (hasKey $path_data "dest")) }}
{{- $_ := set $path_data "dest" $dest }}
{{- end }}
@@ -614,7 +617,7 @@ proxy_set_header Proxy "";
{{- if (not (hasKey $path_data "proto")) }}
{{- $_ := set $path_data "proto" $proto }}
{{- end }}
{{- $_ := set $paths $path $path_data }}
{{- end }}
{{- $_ := set $vhost_data "paths" $paths }}
@@ -666,7 +669,7 @@ proxy_set_header Proxy "";
{{- if (not (hasKey $path_data "proto")) }}
{{- $_ := set $path_data "proto" $proto }}
{{- end }}
{{- $_ := set $paths $path $path_data }}
{{- end }}
{{- $_ := set $vhost_data "paths" $paths }}
@@ -708,7 +711,7 @@ proxy_set_header Proxy "";
{{- end }}
{{- $userIdentifiedCert := groupByKeys $vhost_containers "Env.CERT_NAME" | first }}
{{- $vhostCert := "" }}
{{- if exists (printf "/etc/nginx/certs/%s.crt" $hostname) }}
{{- $vhostCert = $hostname }}
@@ -721,10 +724,10 @@ proxy_set_header Proxy "";
{{- $parentVhostCert = $parentHostname }}
{{- end }}
{{- end }}
{{- $trust_default_cert := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.trust-default-cert" | keys | first | default $globals.config.trust_default_cert | parseBool }}
{{- $defaultCert := and $trust_default_cert $globals.config.default_cert_ok | ternary "default" "" }}
{{- $cert := or $userIdentifiedCert $vhostCert $parentVhostCert $defaultCert }}
{{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }}
@@ -738,10 +741,10 @@ proxy_set_header Proxy "";
{{- $https_method = "noredirect" }}
{{- end }}
{{- $non_get_redirect := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.non-get-redirect" | keys | first | default $globals.config.non_get_redirect }}
{{- $http2_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable" | keys | first | default $globals.config.enable_http2 | parseBool }}
{{- $http3_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http3.enable" | keys | first | default $globals.config.enable_http3 | parseBool }}
{{- $acme_http_challenge := groupByKeys $vhost_containers "Env.ACME_HTTP_CHALLENGE_LOCATION" | first | default $globals.config.acme_http_challenge }}
{{- $acme_http_challenge_legacy := eq $acme_http_challenge "legacy" }}
{{- $acme_http_challenge_enabled := false }}
@@ -903,7 +906,7 @@ server {
break;
}
{{- end }}
{{- if $vhost.enable_debug_endpoint }}
{{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }}
{{- end }}

View File

@@ -0,0 +1,45 @@
networks:
proxy:
private:
internal: true
volumes:
nginx_conf:
services:
nginx-proxy-nginx:
image: nginx
container_name: nginx
volumes:
- nginx_conf:/etc/nginx/conf.d:ro
ports:
- "80:80"
- "443:443"
networks:
- proxy
labels:
- "com.github.nginx-proxy.nginx-proxy.foobarbuzz"
nginx-proxy-dockergen:
image: nginxproxy/docker-gen
command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../../nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl
- nginx_conf:/etc/nginx/conf.d
environment:
NGINX_CONTAINER_LABEL: "com.github.nginx-proxy.nginx-proxy.foobarbuzz"
networks:
- private
web:
image: web
container_name: whoami2
expose:
- "80"
environment:
WEB_PORTS: "80"
VIRTUAL_HOST: whoami2.nginx.container.docker
networks:
- proxy

View File

@@ -0,0 +1,27 @@
import docker
import pytest
from packaging.version import Version
raw_version = docker.from_env().version()["Version"]
pytestmark = pytest.mark.skipif(
Version(raw_version) < Version("1.13"),
reason="Docker compose syntax v3 requires docker engine v1.13 or later (got {raw_version})"
)
def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
r = nginxproxy.get("http://unknown.nginx.container.docker/")
assert r.status_code == 503
def test_forwards_to_whoami(docker_compose, nginxproxy):
r = nginxproxy.get("http://whoami2.nginx.container.docker/")
assert r.status_code == 200
whoami_container = docker_compose.containers.get("whoami2")
assert r.text == f"I'm {whoami_container.id[:12]}\n"
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@@ -0,0 +1,43 @@
networks:
proxy:
private:
internal: true
volumes:
nginx_conf:
services:
nginx-proxy-nginx:
image: nginx
container_name: nginx
volumes:
- nginx_conf:/etc/nginx/conf.d:ro
ports:
- "80:80"
- "443:443"
networks:
- proxy
labels:
- "com.github.nginx-proxy.nginx-proxy.nginx"
nginx-proxy-dockergen:
image: nginxproxy/docker-gen
command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../../nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl
- nginx_conf:/etc/nginx/conf.d
networks:
- private
web:
image: web
container_name: whoami2
expose:
- "80"
environment:
WEB_PORTS: "80"
VIRTUAL_HOST: whoami2.nginx.container.docker
networks:
- proxy

View File

@@ -0,0 +1,27 @@
import docker
import pytest
from packaging.version import Version
raw_version = docker.from_env().version()["Version"]
pytestmark = pytest.mark.skipif(
Version(raw_version) < Version("1.13"),
reason="Docker compose syntax v3 requires docker engine v1.13 or later (got {raw_version})"
)
def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
r = nginxproxy.get("http://unknown.nginx.container.docker/")
assert r.status_code == 503
def test_forwards_to_whoami(docker_compose, nginxproxy):
r = nginxproxy.get("http://whoami2.nginx.container.docker/")
assert r.status_code == 200
whoami_container = docker_compose.containers.get("whoami2")
assert r.text == f"I'm {whoami_container.id[:12]}\n"
if __name__ == "__main__":
import doctest
doctest.testmod()