浏览代码

Merge branch 'main' into remove_scoped

Nicolas Duchon 4 年之前
父节点
当前提交
65a88a0291
共有 62 个文件被更改,包括 513 次插入309 次删除
  1. 0 4
      .github/ISSUE_TEMPLATE.md
  2. 11 0
      .github/dependabot.yml
  3. 114 0
      .github/workflows/dockerhub.yml
  4. 37 0
      .github/workflows/test.yml
  5. 0 22
      .travis.yml
  6. 52 11
      Dockerfile
  7. 52 11
      Dockerfile.alpine
  8. 10 6
      Makefile
  9. 42 43
      README.md
  10. 1 1
      docker-compose.yml
  11. 8 10
      docker-entrypoint.sh
  12. 8 7
      generate-dhparam.sh
  13. 3 2
      nginx.tmpl
  14. 7 13
      test/README.md
  15. 55 53
      test/conftest.py
  16. 3 1
      test/pytest.ini
  17. 1 4
      test/requirements/Dockerfile-nginx-proxy-tester
  18. 1 1
      test/requirements/README.md
  19. 0 6
      test/requirements/build.sh
  20. 5 5
      test/requirements/python-requirements.txt
  21. 3 3
      test/requirements/web/webserver.py
  22. 1 1
      test/stress_tests/test_deleted_cert/docker-compose.yml
  23. 2 2
      test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py
  24. 1 1
      test/stress_tests/test_unreachable_network/README.md
  25. 1 1
      test/stress_tests/test_unreachable_network/docker-compose.yml
  26. 1 1
      test/test_DOCKER_HOST_unix_socket.yml
  27. 1 1
      test/test_composev2.yml
  28. 1 1
      test/test_custom/test_defaults-location.yml
  29. 1 1
      test/test_custom/test_defaults.yml
  30. 1 1
      test/test_custom/test_location-per-vhost.py
  31. 1 1
      test/test_custom/test_location-per-vhost.yml
  32. 1 1
      test/test_custom/test_per-vhost.yml
  33. 1 1
      test/test_custom/test_proxy-wide.yml
  34. 1 1
      test/test_default-host.yml
  35. 16 12
      test/test_dockergen/test_dockergen_v2.py
  36. 22 32
      test/test_dockergen/test_dockergen_v3.py
  37. 1 1
      test/test_events.py
  38. 1 1
      test/test_events.yml
  39. 1 1
      test/test_headers/test_http.yml
  40. 1 1
      test/test_headers/test_https.yml
  41. 1 1
      test/test_ipv6.yml
  42. 1 1
      test/test_multiple-hosts.yml
  43. 1 1
      test/test_multiple-networks.yml
  44. 1 1
      test/test_multiple-ports/test_VIRTUAL_PORT.yml
  45. 1 1
      test/test_multiple-ports/test_default-80.yml
  46. 1 1
      test/test_multiple-ports/test_single-port-not-80.yml
  47. 1 1
      test/test_nominal.yml
  48. 9 9
      test/test_ssl/test_dhparam.py
  49. 1 1
      test/test_ssl/test_dhparam.yml
  50. 4 4
      test/test_ssl/test_dhparam_generation.py
  51. 1 1
      test/test_ssl/test_dhparam_generation.yml
  52. 2 2
      test/test_ssl/test_hsts.py
  53. 1 1
      test/test_ssl/test_hsts.yml
  54. 1 1
      test/test_ssl/test_nohttp.yml
  55. 1 1
      test/test_ssl/test_nohttps.yml
  56. 1 1
      test/test_ssl/test_noredirect.yml
  57. 4 4
      test/test_ssl/test_wildcard.py
  58. 1 1
      test/test_ssl/test_wildcard.yml
  59. 1 1
      test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml
  60. 6 6
      test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py
  61. 3 3
      test/test_wildcard_host.py
  62. 1 1
      test/test_wildcard_host.yml

+ 0 - 4
.github/ISSUE_TEMPLATE.md

@@ -1,9 +1,5 @@
 # !!!PLEASE READ!!!
 
-## Questions
-
-If you have a question, DO NOT SUBMIT a new issue.  Please ask the question on the Q&A Group: https://groups.google.com/forum/#!forum/nginx-proxy
-
 ## Bugs or Features
 
 If you are logging a bug or feature request, please search the current open issues to see if there is already a bug or feature opened.

+ 11 - 0
.github/dependabot.yml

@@ -0,0 +1,11 @@
+version: 2
+updates:
+
+  # Maintain dependencies for Docker
+  - package-ecosystem: "docker"
+    directory: "/"
+    schedule:
+      interval: "daily"
+    labels:
+      - "area/chore"
+      - "area/dockerfile"

+ 114 - 0
.github/workflows/dockerhub.yml

@@ -0,0 +1,114 @@
+name: DockerHub
+
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: '0 0 * * 1'
+  push:
+    branches:
+      - main
+    tags:
+      - '*.*.*'
+    paths-ignore:
+      - 'test/*'
+      - '.gitignore'
+      - '.travis.yml'
+      - 'docker-compose-separate-containers.yml'
+      - 'docker-compose.yml'
+      - 'LICENSE'
+      - 'Makefile'
+      - '*.md'
+
+jobs:
+  multiarch-build-debian:
+    runs-on: ubuntu-latest
+    steps:
+
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Get Docker tags for Debian based image
+        id: docker_meta_debian
+        uses: crazy-max/ghaction-docker-meta@v2
+        with:
+          images: |
+            nginxproxy/nginx-proxy
+            jwilder/nginx-proxy
+          tags: |
+            type=semver,pattern={{version}}
+            type=semver,pattern={{major}}.{{minor}}
+            type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
+
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
+
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v1
+
+      - name: Login to DockerHub
+        uses: docker/login-action@v1 
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+      - name: Build and push the Debian based image
+        id: docker_build_debian
+        uses: docker/build-push-action@v2
+        with:
+          file: Dockerfile
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+          push: true
+          tags: ${{ steps.docker_meta_debian.outputs.tags }}
+          labels: ${{ steps.docker_meta_debian.outputs.labels }}
+
+      - name: Images digests
+        run: echo ${{ steps.docker_build_debian.outputs.digest }}
+
+  multiarch-build-alpine:
+    runs-on: ubuntu-latest
+    steps:
+
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Get Docker tags for Alpine based image
+        id: docker_meta_alpine
+        uses: crazy-max/ghaction-docker-meta@v2
+        with:
+          images: |
+            nginxproxy/nginx-proxy
+            jwilder/nginx-proxy
+          tags: |
+            type=semver,suffix=-alpine,pattern={{version}}
+            type=semver,suffix=-alpine,pattern={{major}}.{{minor}}
+            type=raw,value=alpine,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
+          flavor: latest=false
+
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
+
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v1
+
+      - name: Login to DockerHub
+        uses: docker/login-action@v1 
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+      - name: Build and push the Alpine based image
+        id: docker_build_alpine
+        uses: docker/build-push-action@v2
+        with:
+          file: Dockerfile.alpine
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+          push: true
+          tags: ${{ steps.docker_meta_alpine.outputs.tags }}
+          labels: ${{ steps.docker_meta_alpine.outputs.labels }}
+
+      - name: Images digests
+        run: echo ${{ steps.docker_build_alpine.outputs.digest }}

+ 37 - 0
.github/workflows/test.yml

@@ -0,0 +1,37 @@
+name: Test
+
+on: [push, pull_request]
+
+jobs:
+  unit:
+    name: Unit Test
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: true
+      matrix:
+        base_docker_image: [alpine, debian]
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Set up Python 3.9
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.9
+
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install -r python-requirements.txt
+        working-directory: test/requirements
+
+      - name: Build Docker web server image
+        run: make build-webserver
+
+      - name: Build Docker nginx proxy test image
+        run: make build-nginx-proxy-test-${{ matrix.base_docker_image }}
+
+      - name: Run tests
+        run: pytest
+        working-directory: test

+ 0 - 22
.travis.yml

@@ -1,22 +0,0 @@
-dist: trusty
-sudo: required
-
-env:
-  matrix:
-  - TEST_TARGET: test-debian
-  - TEST_TARGET: test-alpine
-
-before_install:
-  - sudo apt-get -y remove docker docker-engine docker-ce
-  - sudo rm /etc/apt/sources.list.d/docker.list
-  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
-  - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
-  - sudo apt-get update
-  - sudo apt-get -y install docker-ce
-  - docker version
-  - docker info
-  # prepare docker test requirements
-  - make update-dependencies
-
-script:
-  - make $TEST_TARGET

+ 52 - 11
Dockerfile

@@ -1,5 +1,46 @@
-FROM nginx:1.19.3
-LABEL maintainer="Jason Wilder mail@jasonwilder.com"
+# setup build arguments for version of dependencies to use
+ARG DOCKER_GEN_VERSION=0.7.6
+ARG FOREGO_VERSION=0.16.1
+
+# Use a specific version of golang to build both binaries
+FROM golang:1.15.10 as gobuilder
+
+# Build docker-gen from scratch
+FROM gobuilder as dockergen
+
+ARG DOCKER_GEN_VERSION
+
+RUN git clone https://github.com/jwilder/docker-gen \
+   && cd /go/docker-gen \
+   && git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \
+   && go mod download \
+   && CGO_ENABLED=0 GOOS=linux go build -ldflags "-X main.buildVersion=${DOCKER_GEN_VERSION}" ./cmd/docker-gen \
+   && go clean -cache \
+   && mv docker-gen /usr/local/bin/ \
+   && cd - \
+   && rm -rf /go/docker-gen
+
+# Build forego from scratch
+# Because this relies on golang workspaces, we need to use go < 1.8. 
+FROM gobuilder as forego
+
+# Download the sources for the given version
+ARG FOREGO_VERSION
+ADD https://github.com/jwilder/forego/archive/v${FOREGO_VERSION}.tar.gz sources.tar.gz
+
+# Move the sources into the right directory
+RUN tar -xzf sources.tar.gz && \
+   mkdir -p /go/src/github.com/ddollar/ && \
+   mv forego-* /go/src/github.com/ddollar/forego
+
+# Install the dependencies and make the forego executable
+WORKDIR /go/src/github.com/ddollar/forego/
+RUN go get -v ./... && \
+   CGO_ENABLED=0 GOOS=linux go build -o forego .
+
+# Build the final image
+FROM nginx:1.19.10
+LABEL maintainer="Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag)"
 
 # Install wget and install/updates certificates
 RUN apt-get update \
@@ -12,17 +53,17 @@ RUN apt-get update \
 
 # Configure Nginx and apply fix for very long server names
 RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
- && sed -i 's/worker_processes  1/worker_processes  auto/' /etc/nginx/nginx.conf
-
-# Install Forego
-ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego
-RUN chmod u+x /usr/local/bin/forego
+ && sed -i 's/worker_processes  1/worker_processes  auto/' /etc/nginx/nginx.conf \
+ && sed -i 's/worker_connections  1024/worker_connections  10240/' /etc/nginx/nginx.conf
 
-ENV DOCKER_GEN_VERSION 0.7.4
+# Install Forego + docker-gen
+COPY --from=forego /go/src/github.com/ddollar/forego/forego /usr/local/bin/forego
+COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen
 
-RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
- && tar -C /usr/local/bin -xvzf docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
- && rm /docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz
+# Add DOCKER_GEN_VERSION environment variable
+# Because some external projects rely on it
+ARG DOCKER_GEN_VERSION
+ENV DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION}
 
 COPY network_internal.conf /etc/nginx/
 

+ 52 - 11
Dockerfile.alpine

@@ -1,5 +1,46 @@
-FROM nginx:1.19.3-alpine
-LABEL maintainer="Jason Wilder mail@jasonwilder.com"
+# setup build arguments for version of dependencies to use
+ARG DOCKER_GEN_VERSION=0.7.6
+ARG FOREGO_VERSION=0.16.1
+
+# Use a specific version of golang to build both binaries
+FROM golang:1.15.10-alpine as gobuilder
+RUN apk add --no-cache git
+
+# Build docker-gen from scratch
+FROM gobuilder as dockergen
+
+ARG DOCKER_GEN_VERSION
+
+RUN git clone https://github.com/jwilder/docker-gen \
+   && cd /go/docker-gen \
+   && git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \
+   && go mod download \
+   && CGO_ENABLED=0 go build -ldflags "-X main.buildVersion=${DOCKER_GEN_VERSION}" ./cmd/docker-gen \
+   && go clean -cache \
+   && mv docker-gen /usr/local/bin/ \
+   && cd - \
+   && rm -rf /go/docker-gen
+
+# Build forego from scratch
+FROM gobuilder as forego
+
+# Download the sources for the given version
+ARG FOREGO_VERSION
+ADD https://github.com/jwilder/forego/archive/v${FOREGO_VERSION}.tar.gz sources.tar.gz
+
+# Move the sources into the right directory
+RUN tar -xzf sources.tar.gz && \
+   mkdir -p /go/src/github.com/ddollar/ && \
+   mv forego-* /go/src/github.com/ddollar/forego
+
+# Install the dependencies and make the forego executable
+WORKDIR /go/src/github.com/ddollar/forego/
+RUN go get -v ./... && \
+   CGO_ENABLED=0 GOOS=linux go build -o forego .
+
+# Build the final image
+FROM nginx:1.19.10-alpine
+LABEL maintainer="Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag)"
 
 # Install wget and install/updates certificates
 RUN apk add --no-cache --virtual .run-deps \
@@ -9,17 +50,17 @@ RUN apk add --no-cache --virtual .run-deps \
 
 # Configure Nginx and apply fix for very long server names
 RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
- && sed -i 's/worker_processes  1/worker_processes  auto/' /etc/nginx/nginx.conf
-
-# Install Forego
-ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego
-RUN chmod u+x /usr/local/bin/forego
+ && sed -i 's/worker_processes  1/worker_processes  auto/' /etc/nginx/nginx.conf \
+ && sed -i 's/worker_connections  1024/worker_connections  10240/' /etc/nginx/nginx.conf
 
-ENV DOCKER_GEN_VERSION 0.7.4
+# Install Forego + docker-gen
+COPY --from=forego /go/src/github.com/ddollar/forego/forego /usr/local/bin/forego
+COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen
 
-RUN wget --quiet https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
- && tar -C /usr/local/bin -xvzf docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
- && rm /docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz
+# Add DOCKER_GEN_VERSION environment variable
+# Because some external projects rely on it
+ARG DOCKER_GEN_VERSION
+ENV DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION}
 
 COPY network_internal.conf /etc/nginx/
 

+ 10 - 6
Makefile

@@ -2,15 +2,19 @@
 .PHONY : test-debian test-alpine test
 
 
-update-dependencies:
-	test/requirements/build.sh
+build-webserver:
+	docker build -t web test/requirements/web
 
-test-debian: update-dependencies
-	docker build -t jwilder/nginx-proxy:test .
+build-nginx-proxy-test-debian:
+	docker build -t nginxproxy/nginx-proxy:test .
+
+build-nginx-proxy-test-alpine:
+	docker build -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test .
+
+test-debian: build-webserver build-nginx-proxy-test-debian
 	test/pytest.sh
 
-test-alpine: update-dependencies
-	docker build -f Dockerfile.alpine -t jwilder/nginx-proxy:test .
+test-alpine: build-webserver build-nginx-proxy-test-alpine
 	test/pytest.sh
 
 test: test-debian test-alpine

+ 42 - 43
README.md

@@ -1,5 +1,9 @@
-![latest 0.8.0](https://img.shields.io/badge/latest-0.8.0-green.svg?style=flat)
-![nginx 1.19.3](https://img.shields.io/badge/nginx-1.19.3-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub')
+[![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml)
+[![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases)
+![nginx 1.19.10](https://img.shields.io/badge/nginx-1.19.10-brightgreen.svg)
+[![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub")
+[![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub')
+[![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub')
 
 
 nginx-proxy sets up a container running nginx and [docker-gen][1].  docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped.
@@ -10,7 +14,7 @@ See [Automated Nginx Reverse Proxy for Docker][2] for why you might want to use
 
 To run it:
 
-    $ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
 
 Then start any containers you want proxied with an env var `VIRTUAL_HOST=subdomain.youdomain.com`
 
@@ -24,17 +28,17 @@ Provided your DNS is setup to forward foo.bar.com to the host running nginx-prox
 
 The nginx-proxy images are available in two flavors.
 
-#### jwilder/nginx-proxy:latest
+#### nginxproxy/nginx-proxy:latest
 
-This image uses the debian:jessie based nginx image.
+This image uses the debian:buster based nginx image.
 
-    $ docker pull jwilder/nginx-proxy:latest
+    $ docker pull nginxproxy/nginx-proxy:latest
 
-#### jwilder/nginx-proxy:alpine
+#### nginxproxy/nginx-proxy:alpine
 
-This image is based on the nginx:alpine image. Use this image to fully support HTTP/2 (including ALPN required by recent Chrome versions). A valid certificate is required as well (see eg. below "SSL Support using letsencrypt" for more info).
+This image is based on the nginx:alpine image. Use this image to fully support HTTP/2 (including ALPN required by recent Chrome versions). A valid certificate is required as well (see eg. below "SSL Support using an ACME CA" for more info).
 
-    $ docker pull jwilder/nginx-proxy:alpine
+    $ docker pull nginxproxy/nginx-proxy:alpine
 
 ### Docker Compose
 
@@ -43,7 +47,7 @@ version: '2'
 
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy
+    image: nginxproxy/nginx-proxy
     ports:
       - "80:80"
     volumes:
@@ -51,8 +55,11 @@ services:
 
   whoami:
     image: jwilder/whoami
+    expose:
+      - "8000"
     environment:
       - VIRTUAL_HOST=whoami.local
+      - VIRTUAL_PORT=8000
 ```
 
 ```shell
@@ -65,7 +72,7 @@ I'm 5b129ab83266
 
 You can activate the IPv6 support for the nginx-proxy container by passing the value `true` to the `ENABLE_IPV6` environment variable:
 
-    $ docker run -d -p 80:80 -e ENABLE_IPV6=true -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -e ENABLE_IPV6=true -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
 
 #### Scoped IPv6 Resolvers
 
@@ -98,7 +105,7 @@ If you want your `nginx-proxy` container to be attached to a different network,
 
 ```console
 $ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro \
-    --name my-nginx-proxy --net my-network jwilder/nginx-proxy
+    --name my-nginx-proxy --net my-network nginxproxy/nginx-proxy
 $ docker network connect my-other-network my-nginx-proxy
 ```
 
@@ -119,7 +126,7 @@ allow 172.16.0.0/12;
 deny all;
 ```
 
-When internal-only access is enabled, external clients with be denied with an `HTTP 403 Forbidden`
+When internal-only access is enabled, external clients will be denied with an `HTTP 403 Forbidden`
 
 > If there is a load-balancer / reverse proxy in front of `nginx-proxy` that hides the client IP (example: AWS Application/Elastic Load Balancer), you will need to use the nginx `realip` module (already installed) to extract the client's IP from the HTTP request headers.  Please see the [nginx realip module configuration](http://nginx.org/en/docs/http/ngx_http_realip_module.html) for more details.  This configuration can be added to a new config file and mounted in `/etc/nginx/conf.d/`.
 
@@ -150,8 +157,11 @@ If you use fastcgi,you can set `VIRTUAL_ROOT=xxx`  for your root directory
 
 To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example
 
-    $ docker run -d -p 80:80 -e DEFAULT_HOST=foo.bar.com -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -e DEFAULT_HOST=foo.bar.com -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
 
+nginx-proxy will then redirect all requests to a container where `VIRTUAL_HOST` is set to `DEFAULT_HOST`, if they don't match any (other) `VIRTUAL_HOST`. Using the example above requests without matching `VIRTUAL_HOST` will be redirected to a plain nginx instance after running the following command:
+
+    $ docker run -d -e VIRTUAL_HOST=foo.bar.com nginx
 
 ### Separate Containers
 
@@ -168,7 +178,7 @@ $ curl -H "Host: whoami.local" localhost
 I'm 5b129ab83266
 ```
 
-To run nginx proxy as a separate container you'll need to have [nginx.tmpl](https://github.com/jwilder/nginx-proxy/blob/master/nginx.tmpl) on your host system.
+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:
 
@@ -187,9 +197,9 @@ $ docker run --volumes-from nginx \
 Finally, start your containers with `VIRTUAL_HOST` environment variables.
 
     $ docker run -e VIRTUAL_HOST=foo.bar.com  ...
-### SSL Support using letsencrypt
+### SSL Support using an ACME CA
 
-[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allows the creation/renewal of Let's Encrypt certificates automatically.
+[acme-companion](https://github.com/nginx-proxy/acme-companion) is a lightweight companion container for the nginx-proxy. It allows the automated creation/renewal of SSL certificates using the ACME protocol.
 
 Set `DHPARAM_GENERATION` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`.
 The default value is `true`
@@ -202,7 +212,7 @@ certificates or optionally specifying a cert name (for SNI) as an environment va
 
 To enable SSL:
 
-    $ docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
 
 The contents of `/path/to/certs` should contain the certificates and private keys for any virtual
 hosts in use.  The certificate and keys should be named after the virtual host with a `.crt` and
@@ -226,7 +236,7 @@ at startup.  Since it can take minutes to generate a new `dhparam.pem`, it is do
 background.  Once generation is complete, the `dhparam.pem` is saved on a persistent volume and nginx
 is reloaded.  This generation process only occurs the first time you start `nginx-proxy`.
 
-> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 2048 bits for A+ security.  Some
+> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 4096 bits for A+ security.  Some
 > older clients (like Java 6 and 7) do not support DH keys with over 1024 bits.  In order to support these
 > clients, you must either provide your own `dhparam.pem`, or tell `nginx-proxy` to generate a 1024-bit
 > key on startup by passing `-e DHPARAM_BITS=1024`.
@@ -234,7 +244,7 @@ is reloaded.  This generation process only occurs the first time you start `ngin
 In the separate container setup, no pregenerated key will be available and neither the
 [jwilder/docker-gen](https://hub.docker.com/r/jwilder/docker-gen) image nor the offical
 [nginx](https://registry.hub.docker.com/_/nginx/) image will generate one. If you still want A+ security
-in a separate container setup, you'll have to generate a 2048 bits DH key file manually and mount it on the
+in a separate container setup, you'll have to generate a 2048 or 4096 bits DH key file manually and mount it on the
 nginx container, at `/etc/nginx/dhparam/dhparam.pem`.
 
 #### Wildcard Certificates
@@ -276,7 +286,7 @@ and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalan
 `AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`.
 
 Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container generates
-a 2048 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing
+a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing
 this, either globally or per virtual-host.
 
 The default behavior for the proxy when port 80 and 443 are exposed is as follows:
@@ -317,7 +327,7 @@ $ docker run -d -p 80:80 -p 443:443 \
     -v /path/to/htpasswd:/etc/nginx/htpasswd \
     -v /path/to/certs:/etc/nginx/certs \
     -v /var/run/docker.sock:/tmp/docker.sock:ro \
-    jwilder/nginx-proxy
+    nginxproxy/nginx-proxy
 ```
 
 You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html)
@@ -359,7 +369,7 @@ To add settings on a proxy-wide basis, add your configuration file under `/etc/n
 This can be done in a derived image by creating the file in a `RUN` command or by `COPY`ing the file into `conf.d`:
 
 ```Dockerfile
-FROM jwilder/nginx-proxy
+FROM nginxproxy/nginx-proxy
 RUN { \
       echo 'server_tokens off;'; \
       echo 'client_max_body_size 100m;'; \
@@ -368,7 +378,7 @@ RUN { \
 
 Or it can be done by mounting in your custom configuration in your `docker run` command:
 
-    $ docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
 
 #### Per-VIRTUAL_HOST
 
@@ -378,7 +388,7 @@ In order to allow virtual hosts to be dynamically configured as backends are add
 
 For example, if you have a virtual host named `app.example.com`, you could provide a custom configuration for that host as follows:
 
-    $ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
     $ { echo 'server_tokens off;'; echo 'client_max_body_size 100m;'; } > /path/to/vhost.d/app.example.com
 
 If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink:
@@ -398,7 +408,7 @@ just like the previous section except with the suffix `_location`.
 
 For example, if you have a virtual host named `app.example.com` and you have configured a proxy_cache `my-cache` in another custom file, you could tell it to use a proxy cache as follows:
 
-    $ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
+    $ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
     $ { echo 'proxy_cache my-cache;'; echo 'proxy_cache_valid  200 302  60m;'; echo 'proxy_cache_valid  404 1m;' } > /path/to/vhost.d/app.example.com_location
 
 If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink:
@@ -417,26 +427,15 @@ Before submitting pull requests or issues, please check github to make sure an e
 
 #### Running Tests Locally
 
-To run tests, you need to prepare the docker image to test which must be tagged `jwilder/nginx-proxy:test`:
-
-    docker build -t jwilder/nginx-proxy:test .  # build the Debian variant image
-
-and call the [test/pytest.sh](test/pytest.sh) script.
-
-Then build the Alpine variant of the image:
-
-    docker build -f Dockerfile.alpine -t jwilder/nginx-proxy:test .  # build the Alpline variant image
-
-and call the [test/pytest.sh](test/pytest.sh) script again.
-
-
-If your system has the `make` command, you can automate those tasks by calling:
+To run tests, you just need to run the command below:
 
     make test
 
+This commands run tests on two variants of the nginx-proxy docker image: Debian and Alpine.
 
-You can learn more about how the test suite works and how to write new tests in the [test/README.md](test/README.md) file.
+You can run the tests for each of these images with their respective commands:
 
-### Need help?
+    make test-debian
+    make test-alpine
 
-If you have questions on how to use the image, please ask them on the [Q&A Group](https://groups.google.com/forum/#!forum/nginx-proxy)
+You can learn more about how the test suite works and how to write new tests in the [test/README.md](test/README.md) file.

+ 1 - 1
docker-compose.yml

@@ -1,7 +1,7 @@
 version: '2'
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy
+    image: nginxproxy/nginx-proxy
     container_name: nginx-proxy
     ports:
       - "80:80"

+ 8 - 10
docker-entrypoint.sh

@@ -4,10 +4,10 @@ set -e
 # Warn if the DOCKER_HOST socket does not exist
 if [[ $DOCKER_HOST = unix://* ]]; then
 	socket_file=${DOCKER_HOST#unix://}
-	if ! [ -S $socket_file ]; then
+	if ! [ -S "$socket_file" ]; then
 		cat >&2 <<-EOT
 			ERROR: you need to share your Docker host socket with a volume at $socket_file
-			Typically you should run your jwilder/nginx-proxy with: \`-v /var/run/docker.sock:$socket_file:ro\`
+			Typically you should run your nginxproxy/nginx-proxy with: \`-v /var/run/docker.sock:$socket_file:ro\`
 			See the documentation at http://git.io/vZaGJ
 		EOT
 		socketMissing=1
@@ -15,26 +15,24 @@ if [[ $DOCKER_HOST = unix://* ]]; then
 fi
 
 # Generate dhparam file if required
-# Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default
-# Note2: if $DHPARAM_GENERATION is set to false in environment variable, dh param generator will skip completely
-/app/generate-dhparam.sh $DHPARAM_BITS $DHPARAM_GENERATION
+/app/generate-dhparam.sh
 
 # Compute the DNS resolvers for use in the templates - if the IP contains ":", it's IPv6 and must be enclosed in []
-export RESOLVERS=$(awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g')
+RESOLVERS=$(awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g'); export RESOLVERS
 
 SCOPED_IPV6_REGEX="\[fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}\]"
 
-if [ "x$RESOLVERS" = "x" ]; then
+if [ "$RESOLVERS" = "" ]; then
 	echo "Warning: unable to determine DNS resolvers for nginx" >&2
 	unset RESOLVERS
 elif [[ $RESOLVERS =~ $SCOPED_IPV6_REGEX ]]; then
 	echo -n "Warning: Scoped IPv6 addresses removed from resolvers: " >&2
-	echo $RESOLVERS | grep -Eo $SCOPED_IPV6_REGEX | paste -s -d ' ' >&2
-	export RESOLVERS=$(echo $RESOLVERS | sed -r "s/$SCOPED_IPV6_REGEX//g" | xargs echo -n)
+	echo "$RESOLVERS" | grep -Eo "$SCOPED_IPV6_REGEX" | paste -s -d ' ' >&2
+	RESOLVERS=$(echo "$RESOLVERS" | sed -r "s/$SCOPED_IPV6_REGEX//g" | xargs echo -n); export RESOLVERS
 fi
 
 # If the user has run the default command and the socket doesn't exist, fail
-if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then
+if [ "$socketMissing" = 1 ] && [ "$1" = forego ] && [ "$2" = start ] && [ "$3" = '-r' ]; then
 	exit 1
 fi
 

+ 8 - 7
generate-dhparam.sh

@@ -1,8 +1,9 @@
 #!/bin/bash -e
 
-# The first argument is the bit depth of the dhparam, or 4096 if unspecified
-DHPARAM_BITS=${1:-4096}
-GENERATE_DHPARAM=${2:-true}
+# DHPARAM_BITS is the bit depth of the dhparam, or 4096 if unspecified
+DHPARAM_BITS=${DHPARAM_BITS:-4096}
+# DHPARAM_GENERATION=false skips dhparam generation
+DHPARAM_GENERATION=${DHPARAM_GENERATION:-true}
 
 # If a dhparam file is not available, use the pre-generated one and generate a new one in the background.
 # Note that /etc/nginx/dhparam is a volume, so this dhparam will persist restarts.
@@ -14,7 +15,7 @@ GEN_LOCKFILE="/tmp/dhparam_generating.lock"
 PREGEN_HASH=$(md5sum $PREGEN_DHPARAM_FILE | cut -d" " -f1)
 if [[ -f $DHPARAM_FILE ]]; then
     CURRENT_HASH=$(md5sum $DHPARAM_FILE | cut -d" " -f1)
-    if [[ $PREGEN_HASH != $CURRENT_HASH ]]; then
+    if [[ $PREGEN_HASH != "$CURRENT_HASH" ]]; then
         # There is already a dhparam, and it's not the default
         echo "Custom dhparam.pem file found, generation skipped"
         exit 0
@@ -26,7 +27,7 @@ if [[ -f $DHPARAM_FILE ]]; then
     fi
 fi
 
-if [[ $GENERATE_DHPARAM =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then
+if [[ $DHPARAM_GENERATION =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then
     echo "Skipping Diffie-Hellman parameters generation and Ignoring pre-generated dhparam.pem"
     exit 0
 fi
@@ -43,10 +44,10 @@ touch $GEN_LOCKFILE
 # Generate a new dhparam in the background in a low priority and reload nginx when finished (grep removes the progress indicator).
 (
     (
-        nice -n +5 openssl dhparam -dsaparam -out $DHPARAM_FILE.tmp $DHPARAM_BITS 2>&1 \
+        nice -n +5 openssl dhparam -dsaparam -out $DHPARAM_FILE.tmp "$DHPARAM_BITS" 2>&1 \
         && mv $DHPARAM_FILE.tmp $DHPARAM_FILE \
         && echo "dhparam generation complete, reloading nginx" \
         && nginx -s reload
     ) | grep -vE '^[\.+]+'
     rm $GEN_LOCKFILE
-) &disown
+) & disown

+ 3 - 2
nginx.tmpl

@@ -172,7 +172,7 @@ server {
 
 {{ $host := trim $host }}
 {{ $is_regexp := hasPrefix "~" $host }}
-{{ $upstream_name := when $is_regexp (sha1 $host) $host }}
+{{ $upstream_name := (print (when $is_regexp (sha1 $host) $host) "-upstream") }}
 
 # {{ $host }}
 upstream {{ $upstream_name }} {
@@ -253,8 +253,9 @@ server {
 	{{ $access_log }}
 	
 	# Do not HTTPS redirect Let'sEncrypt ACME challenge
-	location /.well-known/acme-challenge/ {
+	location ^~ /.well-known/acme-challenge/ {
 		auth_basic off;
+		auth_request off;
 		allow all;
 		root /usr/share/nginx/html;
 		try_files $uri =404;

+ 7 - 13
test/README.md

@@ -4,25 +4,20 @@ Nginx proxy test suite
 Install requirements
 --------------------
 
-You need [python 2.7](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installing/) installed. Then run the commands:
+You need [python 3.9](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installing/) installed. Then run the commands:
 
-    requirements/build.sh
     pip install -r requirements/python-requirements.txt
 
-If you can't install those requirements on your computer, you can alternatively use the _pytest.sh_ script which will run the tests from a Docker container which has those requirements.
 
 
 Prepare the nginx-proxy test image
 ----------------------------------
 
-    docker build -t jwilder/nginx-proxy:test ..
+    make build-nginx-proxy-test-debian
 
 or if you want to test the alpine flavor:
 
-    docker build -t jwilder/nginx-proxy:test -f Dockerfile.alpine ..
-
-make sure to tag that test image exactly `jwilder/nginx-proxy:test` or the test suite won't work.
-
+    make build-nginx-proxy-test-alpine
 
 Run the test suite
 ------------------
@@ -61,11 +56,11 @@ The fixture will run the _docker-compose_ command with the `-f` option to load t
 
 In the case you are running pytest from within a docker container, the `docker_compose` fixture will make sure the container running pytest is attached to all docker networks. That way, your test will be able to reach any of them.
 
-In your tests, you can use the `docker_compose` variable to query and command the docker daemon as it provides you with a [client from the docker python module](https://docker-py.readthedocs.io/en/2.0.2/client.html#client-reference).
+In your tests, you can use the `docker_compose` variable to query and command the docker daemon as it provides you with a [client from the docker python module](https://docker-py.readthedocs.io/en/4.4.4/client.html#client-reference).
 
 Also this fixture alters the way the python interpreter resolves domain names to IP addresses in the following ways:
 
-Any domain name containing the substring `nginx-proxy` will resolve to the IP address of the container that was created from the `jwilder/nginx-proxy:test` image. So all the following domain names will resolve to the nginx-proxy container in tests:
+Any domain name containing the substring `nginx-proxy` will resolve to the IP address of the container that was created from the `nginxproxy/nginx-proxy:test` image. So all the following domain names will resolve to the nginx-proxy container in tests:
 - `nginx-proxy`
 - `nginx-proxy.com`
 - `www.nginx-proxy.com`
@@ -99,9 +94,8 @@ Furthermore, the nginxproxy methods accept an additional keyword parameter: `ipv
 
 ### The web docker image
 
-When you ran the `requirements/build.sh` script earlier, you built a [`web`](requirements/README.md) docker image which is convenient for running a small web server in a container. This image can produce containers that listens on multiple ports at the same time.
-
+When you run the `make build-webserver` command, you built a [`web`](requirements/README.md) docker image which is convenient for running a small web server in a container. This image can produce containers that listens on multiple ports at the same time.
 
 ### Testing TLS
 
-If you need to create server certificates, use the [`certs/create_server_certificate.sh`](certs/) script. Pytest will be able to validate any certificate issued from this script.
+If you need to create server certificates, use the [`certs/create_server_certificate.sh`](certs/) script. Pytest will be able to validate any certificate issued from this script.

+ 55 - 53
test/conftest.py

@@ -1,4 +1,3 @@
-from __future__ import print_function
 import contextlib
 import logging
 import os
@@ -68,11 +67,11 @@ class requests_for_docker(object):
         """
         Return the nginx config file
         """
-        nginx_proxy_containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"})
+        nginx_proxy_containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"})
         if len(nginx_proxy_containers) > 1:
-            pytest.fail("Too many running jwilder/nginx-proxy:test containers", pytrace=False)
+            pytest.fail("Too many running nginxproxy/nginx-proxy:test containers", pytrace=False)
         elif len(nginx_proxy_containers) == 0:
-            pytest.fail("No running jwilder/nginx-proxy:test container", pytrace=False)
+            pytest.fail("No running nginxproxy/nginx-proxy:test container", pytrace=False)
         return get_nginx_conf_from_container(nginx_proxy_containers[0])
 
     def get(self, *args, **kwargs):
@@ -133,7 +132,7 @@ def container_ip(container):
             pytest.skip("This system does not support IPv6")
         ip = container_ipv6(container)
         if ip == '':
-            pytest.skip("Container %s has no IPv6 address" % container.name)
+            pytest.skip(f"Container {container.name} has no IPv6 address")
         else:
             return ip
     else:
@@ -142,7 +141,7 @@ def container_ip(container):
             return net_info["bridge"]["IPAddress"]
 
         # not default bridge network, fallback on first network defined
-        network_name = net_info.keys()[0]
+        network_name = list(net_info.keys())[0]
         return net_info[network_name]["IPAddress"]
 
 
@@ -155,27 +154,27 @@ def container_ipv6(container):
         return net_info["bridge"]["GlobalIPv6Address"]
 
     # not default bridge network, fallback on first network defined
-    network_name = net_info.keys()[0]
+    network_name = list(net_info.keys())[0]
     return net_info[network_name]["GlobalIPv6Address"]
 
 
 def nginx_proxy_dns_resolver(domain_name):
     """
     if "nginx-proxy" if found in host, return the ip address of the docker container
-    issued from the docker image jwilder/nginx-proxy:test.
+    issued from the docker image nginxproxy/nginx-proxy:test.
 
     :return: IP or None
     """
     log = logging.getLogger('DNS')
-    log.debug("nginx_proxy_dns_resolver(%r)" % domain_name)
+    log.debug(f"nginx_proxy_dns_resolver({domain_name!r})")
     if 'nginx-proxy' in domain_name:
-        nginxproxy_containers = docker_client.containers.list(filters={"status": "running", "ancestor": "jwilder/nginx-proxy:test"})
+        nginxproxy_containers = docker_client.containers.list(filters={"status": "running", "ancestor": "nginxproxy/nginx-proxy:test"})
         if len(nginxproxy_containers) == 0:
-            log.warn("no container found from image jwilder/nginx-proxy:test while resolving %r", domain_name)
+            log.warn(f"no container found from image nginxproxy/nginx-proxy:test while resolving {domain_name!r}")
             return
         nginxproxy_container = nginxproxy_containers[0]
         ip = container_ip(nginxproxy_container)
-        log.info("resolving domain name %r as IP address %s of nginx-proxy container %s" % (domain_name, ip, nginxproxy_container.name))
+        log.info(f"resolving domain name {domain_name!r} as IP address {ip} of nginx-proxy container {nginxproxy_container.name}")
         return ip
 
 def docker_container_dns_resolver(domain_name):
@@ -186,24 +185,24 @@ def docker_container_dns_resolver(domain_name):
     :return: IP or None
     """
     log = logging.getLogger('DNS')
-    log.debug("docker_container_dns_resolver(%r)" % domain_name)
+    log.debug(f"docker_container_dns_resolver({domain_name!r})")
 
-    match = re.search('(^|.+\.)(?P<container>[^.]+)\.container\.docker$', domain_name)
+    match = re.search(r'(^|.+\.)(?P<container>[^.]+)\.container\.docker$', domain_name)
     if not match:
-        log.debug("%r does not match" % domain_name)
+        log.debug(f"{domain_name!r} does not match")
         return
 
     container_name = match.group('container')
-    log.debug("looking for container %r" % container_name)
+    log.debug(f"looking for container {container_name!r}")
     try:
         container = docker_client.containers.get(container_name)
     except docker.errors.NotFound:
-        log.warn("container named %r not found while resolving %r" % (container_name, domain_name))
+        log.warn(f"container named {container_name!r} not found while resolving {domain_name!r}")
         return
-    log.debug("container %r found (%s)" % (container.name, container.short_id))
+    log.debug(f"container {container.name!r} found ({container.short_id})")
 
     ip = container_ip(container)
-    log.info("resolving domain name %r as IP address %s of container %s" % (domain_name, ip, container.name))
+    log.info(f"resolving domain name {domain_name!r} as IP address {ip} of container {container.name}")
     return ip 
 
 
@@ -211,12 +210,12 @@ def monkey_patch_urllib_dns_resolver():
     """
     Alter the behavior of the urllib DNS resolver so that any domain name
     containing substring 'nginx-proxy' will resolve to the IP address
-    of the container created from image 'jwilder/nginx-proxy:test'.
+    of the container created from image 'nginxproxy/nginx-proxy:test'.
     """
     prv_getaddrinfo = socket.getaddrinfo
     dns_cache = {}
     def new_getaddrinfo(*args):
-        logging.getLogger('DNS').debug("resolving domain name %s" % repr(args))
+        logging.getLogger('DNS').debug(f"resolving domain name {repr(args)}")
         _args = list(args)
 
         # custom DNS resolvers
@@ -244,7 +243,7 @@ def remove_all_containers():
     for container in docker_client.containers.list(all=True):
         if I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER and container.id.startswith(socket.gethostname()):
             continue  # pytest is running within a Docker container, so we do not want to remove that particular container
-        logging.info("removing container %s" % container.name)
+        logging.info(f"removing container {container.name}")
         container.remove(v=True, force=True)
 
 
@@ -253,40 +252,43 @@ def get_nginx_conf_from_container(container):
     return the nginx /etc/nginx/conf.d/default.conf file content from a container
     """
     import tarfile
-    from cStringIO import StringIO
-    strm, stat = container.get_archive('/etc/nginx/conf.d/default.conf')
-    with tarfile.open(fileobj=StringIO(strm.read())) as tf:
+    from io import BytesIO
+
+    strm_generator, stat = container.get_archive('/etc/nginx/conf.d/default.conf')
+    strm_fileobj = BytesIO(b"".join(strm_generator))
+
+    with tarfile.open(fileobj=strm_fileobj) as tf:
         conffile = tf.extractfile('default.conf')
         return conffile.read()
 
 
 def docker_compose_up(compose_file='docker-compose.yml'):
-    logging.info('docker-compose -f %s up -d' % compose_file)
+    logging.info(f'docker-compose -f {compose_file} up -d')
     try:
-        subprocess.check_output(shlex.split('docker-compose -f %s up -d' % compose_file), stderr=subprocess.STDOUT)
-    except subprocess.CalledProcessError, e:
-        pytest.fail("Error while runninng 'docker-compose -f %s up -d':\n%s" % (compose_file, e.output), pytrace=False)
+        subprocess.check_output(shlex.split(f'docker-compose -f {compose_file} up -d'), stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+        pytest.fail(f"Error while runninng 'docker-compose -f {compose_file} up -d':\n{e.output}", pytrace=False)
 
 
 def docker_compose_down(compose_file='docker-compose.yml'):
-    logging.info('docker-compose -f %s down' % compose_file)
+    logging.info(f'docker-compose -f {compose_file} down')
     try:
-        subprocess.check_output(shlex.split('docker-compose -f %s down' % compose_file), stderr=subprocess.STDOUT)
-    except subprocess.CalledProcessError, e:
-        pytest.fail("Error while runninng 'docker-compose -f %s down':\n%s" % (compose_file, e.output), pytrace=False)
+        subprocess.check_output(shlex.split(f'docker-compose -f {compose_file} down'), stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+        pytest.fail(f"Error while runninng 'docker-compose -f {compose_file} down':\n{e.output}", pytrace=False)
 
 
 def wait_for_nginxproxy_to_be_ready():
     """
-    If one (and only one) container started from image jwilder/nginx-proxy:test is found, 
+    If one (and only one) container started from image nginxproxy/nginx-proxy:test is found, 
     wait for its log to contain substring "Watching docker events"
     """
-    containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"})
+    containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"})
     if len(containers) != 1:
         return
     container = containers[0]
     for line in container.logs(stream=True):
-        if "Watching docker events" in line:
+        if b"Watching docker events" in line:
             logging.debug("nginx-proxy ready")
             break
 
@@ -307,7 +309,7 @@ def find_docker_compose_file(request):
     if docker_compose_file_module_variable is not None:
         docker_compose_file = os.path.join( test_module_dir, docker_compose_file_module_variable)
         if not os.path.isfile(docker_compose_file):
-            raise ValueError("docker compose file %r could not be found. Check your test module `docker_compose_file` variable value." % docker_compose_file)
+            raise ValueError(f"docker compose file {docker_compose_file!r} could not be found. Check your test module `docker_compose_file` variable value.")
     else:
         if os.path.isfile(yml_file):
             docker_compose_file = yml_file
@@ -319,7 +321,7 @@ def find_docker_compose_file(request):
     if not os.path.isfile(docker_compose_file):
         logging.error("Could not find any docker-compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__))
 
-    logging.debug("using docker compose file %s" % docker_compose_file)
+    logging.debug(f"using docker compose file {docker_compose_file}")
     return docker_compose_file
 
 
@@ -333,15 +335,15 @@ def connect_to_network(network):
         try:
             my_container = docker_client.containers.get(socket.gethostname())
         except docker.errors.NotFound:
-            logging.warn("container %r not found" % socket.gethostname())
+            logging.warn(f"container {socket.gethostname()!r} not found")
             return
 
         # figure out our container networks
-        my_networks = my_container.attrs["NetworkSettings"]["Networks"].keys()
+        my_networks = list(my_container.attrs["NetworkSettings"]["Networks"].keys())
 
         # make sure our container is connected to the nginx-proxy's network
         if network not in my_networks:
-            logging.info("Connecting to docker network: %s" % network.name)
+            logging.info(f"Connecting to docker network: {network.name}")
             network.connect(my_container)
             return network
 
@@ -356,15 +358,15 @@ def disconnect_from_network(network=None):
         try:
             my_container = docker_client.containers.get(socket.gethostname())
         except docker.errors.NotFound:
-            logging.warn("container %r not found" % socket.gethostname())
+            logging.warn(f"container {socket.gethostname()!r} not found")
             return
 
         # figure out our container networks
-        my_networks_names = my_container.attrs["NetworkSettings"]["Networks"].keys()
+        my_networks_names = list(my_container.attrs["NetworkSettings"]["Networks"].keys())
 
         # disconnect our container from the given network
         if network.name in my_networks_names:
-            logging.info("Disconnecting from network %s" % network.name)
+            logging.info(f"Disconnecting from network {network.name}")
             network.disconnect(my_container)
 
 
@@ -378,7 +380,7 @@ def connect_to_all_networks():
         return []
     else:
         # find the list of docker networks
-        networks = filter(lambda network: len(network.containers) > 0 and network.name != 'bridge', docker_client.networks.list())
+        networks = [network for network in docker_client.networks.list() if len(network.containers) > 0 and network.name != 'bridge']
         return [connect_to_network(network) for network in networks]
 
 
@@ -388,7 +390,7 @@ def connect_to_all_networks():
 # 
 ###############################################################################
 
-@pytest.yield_fixture(scope="module")
+@pytest.fixture(scope="module")
 def docker_compose(request):
     """
     pytest fixture providing containers described in a docker compose file. After the tests, remove the created containers
@@ -412,7 +414,7 @@ def docker_compose(request):
     restore_urllib_dns_resolver(original_dns_resolver)
 
 
-@pytest.yield_fixture()
+@pytest.fixture()
 def nginxproxy():
     """
     Provides the `nginxproxy` object that can be used in the same way the requests module is:
@@ -439,7 +441,7 @@ def nginxproxy():
 def pytest_runtest_logreport(report):
     if report.failed:
         if isinstance(report.longrepr, ReprExceptionInfo):
-            test_containers = docker_client.containers.list(all=True, filters={"ancestor": "jwilder/nginx-proxy:test"})
+            test_containers = docker_client.containers.list(all=True, filters={"ancestor": "nginxproxy/nginx-proxy:test"})
             for container in test_containers:
                 report.longrepr.addsection('nginx-proxy logs', container.logs())
                 report.longrepr.addsection('nginx-proxy conf', get_nginx_conf_from_container(container))
@@ -456,7 +458,7 @@ def pytest_runtest_makereport(item, call):
 def pytest_runtest_setup(item):
     previousfailed = getattr(item.parent, "_previousfailed", None)
     if previousfailed is not None:
-        pytest.xfail("previous test failed (%s)" % previousfailed.name)
+        pytest.xfail(f"previous test failed ({previousfailed.name})")
 
 ###############################################################################
 # 
@@ -465,9 +467,9 @@ def pytest_runtest_setup(item):
 ###############################################################################
 
 try:
-    docker_client.images.get('jwilder/nginx-proxy:test')
+    docker_client.images.get('nginxproxy/nginx-proxy:test')
 except docker.errors.ImageNotFound:
-    pytest.exit("The docker image 'jwilder/nginx-proxy:test' is missing")
+    pytest.exit("The docker image 'nginxproxy/nginx-proxy:test' is missing")
 
-if docker.__version__ != "2.1.0":
-    pytest.exit("This test suite is meant to work with the python docker module v2.1.0")
+if docker.__version__ != "4.4.4":
+    pytest.exit("This test suite is meant to work with the python docker module v4.4.4")

+ 3 - 1
test/pytest.ini

@@ -1,3 +1,5 @@
 [pytest]
 # disable the creation of the `.cache` folders
-addopts = -p no:cacheprovider --ignore=requirements --ignore=certs -r s -v
+addopts = -p no:cacheprovider --ignore=requirements --ignore=certs -r s -v
+markers =
+    incremental: mark a test as incremental.

+ 1 - 4
test/requirements/Dockerfile-nginx-proxy-tester

@@ -1,7 +1,4 @@
-FROM python:2.7-alpine
-
-# Note: we're using alpine because it has openssl 1.0.2, which we need for testing
-RUN apk add --update bash openssl curl && rm -rf /var/cache/apk/*
+FROM python:3.9
 
 COPY python-requirements.txt /requirements.txt
 RUN pip install -r /requirements.txt

+ 1 - 1
test/requirements/README.md

@@ -2,7 +2,7 @@ This directory contains resources to build Docker images tests depend on
 
 # Build images
 
-    ./build.sh   
+    make build-webserver
 
 
 # python-requirements.txt

+ 0 - 6
test/requirements/build.sh

@@ -1,6 +0,0 @@
-#!/bin/bash
-set -e
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-docker build -t web $DIR/web

+ 5 - 5
test/requirements/python-requirements.txt

@@ -1,5 +1,5 @@
-backoff==1.3.2
-docker-compose==1.11.2
-docker==2.1.0
-pytest==3.0.5
-requests==2.11.1
+backoff==1.10.0
+docker-compose==1.28.5
+docker==4.4.4
+pytest==6.2.2
+requests==2.25.1

+ 3 - 3
test/requirements/web/webserver.py

@@ -13,13 +13,13 @@ class Handler(http.server.SimpleHTTPRequestHandler):
         if self.path == "/headers":
             response_body += self.headers.as_string()
         elif self.path == "/port":
-            response_body += "answer from port %s\n" % PORT
+            response_body += f"answer from port {PORT}\n"
         elif re.match("/status/(\d+)", self.path):
             result = re.match("/status/(\d+)", self.path)
             response_code = int(result.group(1))
-            response_body += "answer with response code %s\n" % response_code
+            response_body += f"answer with response code {response_code}\n"
         elif self.path == "/":
-            response_body += "I'm %s\n" % os.environ['HOSTNAME']
+            response_body += f"I'm {os.environ['HOSTNAME']}\n"
         else:
             response_body += "No route for this path!\n"
             response_code = 404

+ 1 - 1
test/stress_tests/test_deleted_cert/docker-compose.yml

@@ -8,7 +8,7 @@ web:
 
 
 reverseproxy:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   container_name: reverseproxy
   environment:
     DEBUG: "true"

+ 2 - 2
test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py

@@ -12,7 +12,7 @@ script_dir = os.path.dirname(__file__)
 pytestmark = pytest.mark.xfail()  # TODO delete this marker once those issues are fixed
 
 
-@pytest.yield_fixture(scope="module", autouse=True)
+@pytest.fixture(scope="module", autouse=True)
 def certs():
     """
     pytest fixture that provides cert and key files into the tmp_certs directory
@@ -43,7 +43,7 @@ def test_http_web_is_301(docker_compose, nginxproxy):
 def test_https_web_is_200(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy/port")
     assert r.status_code == 200
-    assert 'answer from port 81\n' in r.text
+    assert "answer from port 81\n" in r.text
 
 
 @pytest.mark.incremental

+ 1 - 1
test/stress_tests/test_unreachable_network/README.md

@@ -6,7 +6,7 @@ Furthermore, if the nginx-proxy in such state is restarted, the nginx process wi
 
 In the generated nginx config file, we can notice the presence of an empty `upstream {}` block.
 
-This can be fixed by merging [PR-585](https://github.com/jwilder/nginx-proxy/pull/585).
+This can be fixed by merging [PR-585](https://github.com/nginx-proxy/nginx-proxy/pull/585).
 
 ## How to reproduce
 

+ 1 - 1
test/stress_tests/test_unreachable_network/docker-compose.yml

@@ -9,7 +9,7 @@ services:
     container_name: reverseproxy
     networks:
       - netA
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
 

+ 1 - 1
test/test_DOCKER_HOST_unix_socket.yml

@@ -16,7 +16,7 @@ web2:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/f00.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_composev2.yml

@@ -1,7 +1,7 @@
 version: '2'
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_custom/test_defaults-location.yml

@@ -1,5 +1,5 @@
 nginx-proxy:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_custom/test_defaults.yml

@@ -1,7 +1,7 @@
 version: '2'
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_custom/test_location-per-vhost.py

@@ -19,4 +19,4 @@ def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
     assert "X-test" not in r.headers
 
 def test_custom_block_is_present_in_nginx_generated_conf(docker_compose, nginxproxy):
-    assert "include /etc/nginx/vhost.d/web1.nginx-proxy.local_location;" in nginxproxy.get_conf()
+    assert b"include /etc/nginx/vhost.d/web1.nginx-proxy.local_location;" in nginxproxy.get_conf()

+ 1 - 1
test/test_custom/test_location-per-vhost.yml

@@ -1,7 +1,7 @@
 version: '2'
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_custom/test_per-vhost.yml

@@ -1,7 +1,7 @@
 version: '2'
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_custom/test_proxy-wide.yml

@@ -1,7 +1,7 @@
 version: '2'
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_default-host.yml

@@ -10,7 +10,7 @@ web1:
 
 # WHEN nginx-proxy runs with DEFAULT_HOST set to web1.tld
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 16 - 12
test/test_dockergen/test_dockergen_v2.py

@@ -4,23 +4,27 @@ import logging
 import pytest
 
 
-@pytest.yield_fixture(scope="module")
+@pytest.fixture(scope="module")
 def nginx_tmpl():
     """
     pytest fixture which extracts the the nginx config template from
-    the jwilder/nginx-proxy:test image
+    the nginxproxy/nginx-proxy:test image
     """
     script_dir = os.path.dirname(__file__)
-    logging.info("extracting nginx.tmpl from jwilder/nginx-proxy:test")
+    logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test")
     docker_client = docker.from_env()
-    print(docker_client.containers.run(
-        image='jwilder/nginx-proxy:test',
-        remove=True,
-        volumes=['{current_dir}:{current_dir}'.format(current_dir=script_dir)],
-        entrypoint='sh',
-        command='-xc "cp /app/nginx.tmpl {current_dir} && chmod 777 {current_dir}/nginx.tmpl"'.format(
-            current_dir=script_dir),
-        stderr=True))
+    print(
+        docker_client.containers.run(
+            image="nginxproxy/nginx-proxy:test",
+            remove=True,
+            volumes=["{current_dir}:{current_dir}".format(current_dir=script_dir)],
+            entrypoint="sh",
+            command='-xc "cp /app/nginx.tmpl {current_dir} && chmod 777 {current_dir}/nginx.tmpl"'.format(
+                current_dir=script_dir
+            ),
+            stderr=True,
+        )
+    )
     yield
     logging.info("removing nginx.tmpl")
     os.remove(os.path.join(script_dir, "nginx.tmpl"))
@@ -35,4 +39,4 @@ def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy):
     r = nginxproxy.get("http://whoami.nginx.container.docker/")
     assert r.status_code == 200
     whoami_container = docker_compose.containers.get("whoami")
-    assert r.text == "I'm %s\n" % whoami_container.id[:12]
+    assert r.text == f"I'm {whoami_container.id[:12]}\n"

+ 22 - 32
test/test_dockergen/test_dockergen_v3.py

@@ -3,47 +3,37 @@ import docker
 import logging
 import pytest
 import re
-
-def versiontuple(v):
-    """
-    >>> versiontuple("1.12.3")
-    (1, 12, 3)
-
-    >>> versiontuple("1.13.0")
-    (1, 13, 0)
-
-    >>> versiontuple("17.03.0-ce")
-    (17, 3, 0)
-
-    >>> versiontuple("17.03.0-ce") < (1, 13)
-    False
-    """
-    return tuple(map(int, (v.split('-')[0].split("."))))
+from distutils.version import LooseVersion
 
 
-raw_version = docker.from_env().version()['Version']
+raw_version = docker.from_env().version()["Version"]
 pytestmark = pytest.mark.skipif(
-    versiontuple(raw_version) < (1, 13),
-    reason="Docker compose syntax v3 requires docker engine v1.13 or later (got %s)" % raw_version)
+    LooseVersion(raw_version) < LooseVersion("1.13"),
+    reason="Docker compose syntax v3 requires docker engine v1.13 or later (got {raw_version})"
+)
 
 
-@pytest.yield_fixture(scope="module")
+@pytest.fixture(scope="module")
 def nginx_tmpl():
     """
     pytest fixture which extracts the the nginx config template from
-    the jwilder/nginx-proxy:test image
+    the nginxproxy/nginx-proxy:test image
     """
     script_dir = os.path.dirname(__file__)
-    logging.info("extracting nginx.tmpl from jwilder/nginx-proxy:test")
+    logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test")
     docker_client = docker.from_env()
-    print(docker_client.containers.run(
-        image='jwilder/nginx-proxy:test',
-        remove=True,
-        volumes=['{current_dir}:{current_dir}'.format(current_dir=script_dir)],
-        entrypoint='sh',
-        command='-xc "cp /app/nginx.tmpl {current_dir} && chmod 777 {current_dir}/nginx.tmpl"'.format(
-            current_dir=script_dir),
-        stderr=True))
+    print(
+        docker_client.containers.run(
+            image="nginxproxy/nginx-proxy:test",
+            remove=True,
+            volumes=["{current_dir}:{current_dir}".format(current_dir=script_dir)],
+            entrypoint="sh",
+            command='-xc "cp /app/nginx.tmpl {current_dir} && chmod 777 {current_dir}/nginx.tmpl"'.format(
+                current_dir=script_dir
+            ),
+            stderr=True,
+        )
+    )
     yield
     logging.info("removing nginx.tmpl")
     os.remove(os.path.join(script_dir, "nginx.tmpl"))
@@ -58,9 +48,9 @@ def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy):
     r = nginxproxy.get("http://whoami.nginx.container.docker/")
     assert r.status_code == 200
     whoami_container = docker_compose.containers.get("whoami")
-    assert r.text == "I'm %s\n" % whoami_container.id[:12]
+    assert r.text == f"I'm {whoami_container.id[:12]}\n"
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     import doctest
     doctest.testmod()

+ 1 - 1
test/test_events.py

@@ -7,7 +7,7 @@ import pytest
 from docker.errors import NotFound
 
 
-@pytest.yield_fixture()
+@pytest.fixture()
 def web1(docker_compose):
     """
     pytest fixture creating a web container with `VIRTUAL_HOST=web1.nginx-proxy` listening on port 81.

+ 1 - 1
test/test_events.yml

@@ -1,5 +1,5 @@
 nginxproxy:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_headers/test_http.yml

@@ -8,7 +8,7 @@ web:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_headers/test_https.yml

@@ -8,7 +8,7 @@ web:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro

+ 1 - 1
test/test_ipv6.yml

@@ -16,7 +16,7 @@ web2:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_multiple-hosts.yml

@@ -8,7 +8,7 @@ web:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_multiple-networks.yml

@@ -6,7 +6,7 @@ networks:
 
 services:
   nginx-proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_multiple-ports/test_VIRTUAL_PORT.yml

@@ -9,7 +9,7 @@ web:
     VIRTUAL_PORT: 90
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_multiple-ports/test_default-80.yml

@@ -8,7 +8,7 @@ web:
     VIRTUAL_HOST: "web.nginx-proxy.tld"
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_multiple-ports/test_single-port-not-80.yml

@@ -8,7 +8,7 @@ web:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_nominal.yml

@@ -16,7 +16,7 @@ web2:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 9 - 9
test/test_ssl/test_dhparam.py

@@ -26,7 +26,7 @@ def assert_log_contains(expected_log_line):
     """
     sut_container = docker_client.containers.get("nginxproxy")
     docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
-    assert expected_log_line in docker_logs
+    assert bytes(expected_log_line, encoding="utf8") in docker_logs
 
 
 def require_openssl(required_version):
@@ -42,7 +42,7 @@ def require_openssl(required_version):
     """
 
     def versiontuple(v):
-        clean_v = re.sub("[^\d\.]", "", v)
+        clean_v = re.sub(r"[^\d\.]", "", v)
         return tuple(map(int, (clean_v.split("."))))
 
     try:
@@ -52,10 +52,10 @@ def require_openssl(required_version):
     else:
         if not command_output:
             raise Exception("Could not get openssl version")
-        openssl_version = command_output.split()[1]
+        openssl_version = str(command_output.split()[1])
         return pytest.mark.skipif(
             versiontuple(openssl_version) < versiontuple(required_version),
-            reason="openssl v%s is less than required version %s" % (openssl_version, required_version))
+            reason=f"openssl v{openssl_version} is less than required version {required_version}")
 
 
 ###############################################################################
@@ -71,8 +71,8 @@ def test_dhparam_is_not_generated_if_present(docker_compose):
     assert_log_contains("Custom dhparam.pem file found, generation skipped")
 
     # Make sure the dhparam in use is not the default, pre-generated one
-    default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split()
-    current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split()
+    default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").output.split()
+    current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split()
     assert default_checksum[0] != current_checksum[0]
 
 
@@ -87,7 +87,7 @@ def test_web5_dhparam_is_used(docker_compose):
     sut_container = docker_client.containers.get("nginxproxy")
     assert sut_container.status == "running"
 
-    host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"]
+    host = f"{sut_container.attrs['NetworkSettings']['IPAddress']}:443"
     r = subprocess.check_output(
-        "echo '' | openssl s_client -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True)
-    assert "Server Temp Key: X25519, 253 bits\n" == r
+        f"echo '' | openssl s_client -connect {host} -cipher 'EDH' | grep 'Server Temp Key'", shell=True)
+    assert b"Server Temp Key: X25519, 253 bits\n" == r

+ 1 - 1
test/test_ssl/test_dhparam.yml

@@ -8,7 +8,7 @@ web5:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   container_name: nginxproxy
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro

+ 4 - 4
test/test_ssl/test_dhparam_generation.py

@@ -22,7 +22,7 @@ def assert_log_contains(expected_log_line):
     """
     sut_container = docker_client.containers.get("nginxproxy")
     docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
-    assert expected_log_line in docker_logs
+    assert bytes(expected_log_line, encoding="utf8") in docker_logs
 
 
 ###############################################################################
@@ -35,10 +35,10 @@ def test_dhparam_is_generated_if_missing(docker_compose):
     sut_container = docker_client.containers.get("nginxproxy")
     assert sut_container.status == "running"
 
-    assert_log_contains("Generating DH parameters")
+    assert_log_contains("Generating DSA parameters")
     assert_log_contains("dhparam generation complete, reloading nginx")
 
     # Make sure the dhparam in use is not the default, pre-generated one
-    default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split()
-    generated_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split()
+    default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").output.split()
+    generated_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split()
     assert default_checksum[0] != generated_checksum[0]

+ 1 - 1
test/test_ssl/test_dhparam_generation.yml

@@ -1,5 +1,5 @@
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   container_name: nginxproxy
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro

+ 2 - 2
test/test_ssl/test_hsts.py

@@ -8,7 +8,7 @@ def test_web1_HSTS_default(docker_compose, nginxproxy):
     assert "max-age=31536000" == r.headers["Strict-Transport-Security"]
 
 # Regression test to ensure HSTS is enabled even when the upstream sends an error in response
-# Issue #1073 https://github.com/jwilder/nginx-proxy/pull/1073
+# Issue #1073 https://github.com/nginx-proxy/nginx-proxy/pull/1073
 def test_web1_HSTS_error(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web1.nginx-proxy.tld/status/500", allow_redirects=False)
     assert "Strict-Transport-Security" in r.headers
@@ -26,7 +26,7 @@ def test_web3_HSTS_custom(docker_compose, nginxproxy):
     assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"]
 
 # Regression test for issue 1080
-# https://github.com/jwilder/nginx-proxy/issues/1080
+# https://github.com/nginx-proxy/nginx-proxy/issues/1080
 def test_web4_HSTS_off_noredirect(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web4.nginx-proxy.tld/port", allow_redirects=False)
     assert "answer from port 81\n" in r.text

+ 1 - 1
test/test_ssl/test_hsts.yml

@@ -35,7 +35,7 @@ web4:
     HTTPS_METHOD: "noredirect"
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_ssl/test_nohttp.yml

@@ -9,7 +9,7 @@ web2:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_ssl/test_nohttps.yml

@@ -9,7 +9,7 @@ web:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_ssl/test_noredirect.yml

@@ -9,7 +9,7 @@ web3:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 4 - 4
test/test_ssl/test_wildcard.py

@@ -3,21 +3,21 @@ import pytest
 
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_http_redirects_to_https(docker_compose, nginxproxy, subdomain):
-    r = nginxproxy.get("http://%s.nginx-proxy.tld/" % subdomain, allow_redirects=False)
+    r = nginxproxy.get(f"http://{subdomain}.nginx-proxy.tld/", allow_redirects=False)
     assert r.status_code == 301
     assert "Location" in r.headers
-    assert "https://%s.nginx-proxy.tld/" % subdomain == r.headers['Location']
+    assert f"https://{subdomain}.nginx-proxy.tld/" == r.headers['Location']
 
 
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_https_is_forwarded(docker_compose, nginxproxy, subdomain):
-    r = nginxproxy.get("https://%s.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
+    r = nginxproxy.get(f"https://{subdomain}.nginx-proxy.tld/port", allow_redirects=False)
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
 
 
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_HSTS_policy_is_active(docker_compose, nginxproxy, subdomain):
-    r = nginxproxy.get("https://%s.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
+    r = nginxproxy.get(f"https://{subdomain}.nginx-proxy.tld/port", allow_redirects=False)
     assert "answer from port 81\n" in r.text
     assert "Strict-Transport-Security" in r.headers

+ 1 - 1
test/test_ssl/test_wildcard.yml

@@ -7,7 +7,7 @@ web1:
     VIRTUAL_HOST: "*.nginx-proxy.tld"
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

+ 1 - 1
test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml

@@ -3,7 +3,7 @@ version: "3"
 services:
 
   proxy:
-    image: jwilder/nginx-proxy:test
+    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
       - ./certs:/etc/nginx/certs:ro

+ 6 - 6
test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py

@@ -1,5 +1,5 @@
 import pytest
-from backports.ssl_match_hostname import CertificateError
+from ssl import CertificateError
 from requests.exceptions import SSLError
 
 
@@ -9,19 +9,19 @@ from requests.exceptions import SSLError
     (3, False),
 ])
 def test_http_redirects_to_https(docker_compose, nginxproxy, subdomain, should_redirect_to_https):
-    r = nginxproxy.get("http://%s.web.nginx-proxy.tld/port" % subdomain)
+    r = nginxproxy.get(f"http://{subdomain}.web.nginx-proxy.tld/port")
     if should_redirect_to_https:
         assert len(r.history) > 0
         assert r.history[0].is_redirect
-        assert r.history[0].headers.get("Location") == "https://%s.web.nginx-proxy.tld/port" % subdomain
-    assert "answer from port 8%s\n" % subdomain == r.text
+        assert r.history[0].headers.get("Location") == f"https://{subdomain}.web.nginx-proxy.tld/port"
+    assert f"answer from port 8{subdomain}\n" == r.text
 
 
 @pytest.mark.parametrize("subdomain", [1, 2])
 def test_https_get_served(docker_compose, nginxproxy, subdomain):
-    r = nginxproxy.get("https://%s.web.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
+    r = nginxproxy.get(f"https://{subdomain}.web.nginx-proxy.tld/port", allow_redirects=False)
     assert r.status_code == 200
-    assert "answer from port 8%s\n" % subdomain == r.text
+    assert f"answer from port 8{subdomain}\n" == r.text
 
 
 def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy):

+ 3 - 3
test/test_wildcard_host.py

@@ -18,9 +18,9 @@ import pytest
     ("web4.whatever.nginx-proxy.regexp", 84),
 ])
 def test_wildcard_prefix(docker_compose, nginxproxy, host, expected_port):
-    r = nginxproxy.get("http://%s/port" % host)
+    r = nginxproxy.get(f"http://{host}/port")
     assert r.status_code == 200
-    assert r.text == "answer from port %s\n" % expected_port
+    assert r.text == f"answer from port {expected_port}\n"
 
 
 @pytest.mark.parametrize("host", [
@@ -28,5 +28,5 @@ def test_wildcard_prefix(docker_compose, nginxproxy, host, expected_port):
     "web4.whatever.nginx-proxy.regexp-to-infinity-and-beyond"
 ])
 def test_non_matching_host_is_503(docker_compose, nginxproxy, host):
-    r = nginxproxy.get("http://%s/port" % host)
+    r = nginxproxy.get(f"http://{host}/port")
     assert r.status_code == 503, r.text

+ 1 - 1
test/test_wildcard_host.yml

@@ -32,7 +32,7 @@ web4:
 
 
 sut:
-  image: jwilder/nginx-proxy:test
+  image: nginxproxy/nginx-proxy:test
   volumes:
     - /var/run/docker.sock:/tmp/docker.sock:ro
     - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro