Merge tag '1.3.1' into merge-upstream

This commit is contained in:
Robin Windey 2023-07-13 08:30:22 +00:00 committed by GitHub
commit 51191e168a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 2512 additions and 772 deletions

View file

@ -1,11 +1,12 @@
version: 2 version: 2
updates: updates:
# Maintain dependencies for Docker # Maintain dependencies for Docker
- package-ecosystem: "docker" - package-ecosystem: "docker"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
commit-message:
prefix: "build"
labels: labels:
- "type/build" - "type/build"
- "scope/dockerfile" - "scope/dockerfile"
@ -14,6 +15,18 @@ updates:
- package-ecosystem: "pip" - package-ecosystem: "pip"
directory: "/test/requirements" directory: "/test/requirements"
schedule: schedule:
interval: "daily" interval: "weekly"
commit-message:
prefix: "ci"
labels:
- "type/ci"
# Maintain GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "ci"
labels: labels:
- "type/ci" - "type/ci"

View file

@ -1,39 +1,40 @@
name: DockerHub name: Build and publish Docker images
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: '0 0 * * 1' - cron: "0 0 * * 1"
push: push:
branches: branches:
- main - main
tags: tags:
- '*.*.*' - "*.*.*"
paths-ignore: paths-ignore:
- 'test/*' - "test/*"
- '.gitignore' - ".gitignore"
- 'docker-compose-separate-containers.yml' - "docker-compose-separate-containers.yml"
- 'docker-compose.yml' - "docker-compose.yml"
- 'LICENSE' - "LICENSE"
- 'Makefile' - "Makefile"
- '*.md' - "*.md"
jobs: jobs:
multiarch-build-debian: multiarch-build-debian:
name: Build and publish Debian image
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Retrieve version - name: Retrieve nginx-proxy version
run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV id: nginx-proxy_version
run: echo "VERSION=$(git describe --tags)" >> "$GITHUB_OUTPUT"
- name: Get Docker tags for Debian based image - name: Get Docker tags for Debian based image
id: docker_meta_debian id: docker_meta_debian
uses: docker/metadata-action@v3 uses: docker/metadata-action@v4
with: with:
images: | images: |
ghcr.io/nginx-proxy/nginx-proxy ghcr.io/nginx-proxy/nginx-proxy
@ -42,37 +43,43 @@ jobs:
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} type=raw,value=latest,enable={{is_default_branch}}
labels: | labels: |
org.opencontainers.image.authors=Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag), Jason Wilder org.opencontainers.image.authors=Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag), Jason Wilder
org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v2
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GitHub Container Registry - name: Log in to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Retrieve docker-gen version
id: docker-gen_version
run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile >> "$GITHUB_OUTPUT"
- name: Build and push the Debian based image - name: Build and push the Debian based image
id: docker_build_debian id: docker_build_debian
uses: docker/build-push-action@v2 uses: docker/build-push-action@v4
with: with:
context: . context: .
file: Dockerfile file: Dockerfile
build-args: NGINX_PROXY_VERSION=${{ env.GIT_DESCRIBE }} build-args: |
NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }}
DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }}
platforms: linux/amd64,linux/arm64,linux/arm/v7 platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true push: true
tags: ${{ steps.docker_meta_debian.outputs.tags }} tags: ${{ steps.docker_meta_debian.outputs.tags }}
@ -82,20 +89,21 @@ jobs:
run: echo ${{ steps.docker_build_debian.outputs.digest }} run: echo ${{ steps.docker_build_debian.outputs.digest }}
multiarch-build-alpine: multiarch-build-alpine:
name: Build and publish Alpine image
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Retrieve version - name: Retrieve nginx-proxy version
run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV id: nginx-proxy_version
run: echo "VERSION=$(git describe --tags)" >> "$GITHUB_OUTPUT"
- name: Get Docker tags for Alpine based image - name: Get Docker tags for Alpine based image
id: docker_meta_alpine id: docker_meta_alpine
uses: docker/metadata-action@v3 uses: docker/metadata-action@v4
with: with:
images: | images: |
ghcr.io/nginx-proxy/nginx-proxy ghcr.io/nginx-proxy/nginx-proxy
@ -104,38 +112,44 @@ jobs:
tags: | tags: |
type=semver,suffix=-alpine,pattern={{version}} type=semver,suffix=-alpine,pattern={{version}}
type=semver,suffix=-alpine,pattern={{major}}.{{minor}} type=semver,suffix=-alpine,pattern={{major}}.{{minor}}
type=raw,value=alpine,enable=${{ github.ref == 'refs/heads/main' }} type=raw,value=alpine,enable={{is_default_branch}}
labels: | labels: |
org.opencontainers.image.authors=Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag), Jason Wilder org.opencontainers.image.authors=Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag), Jason Wilder
org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }}
flavor: latest=false flavor: latest=false
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v2
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GitHub Container Registry - name: Log in to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Retrieve docker-gen version
id: docker-gen_version
run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile >> "$GITHUB_OUTPUT"
- name: Build and push the Alpine based image - name: Build and push the Alpine based image
id: docker_build_alpine id: docker_build_alpine
uses: docker/build-push-action@v2 uses: docker/build-push-action@v4
with: with:
context: . context: .
file: Dockerfile.alpine file: Dockerfile.alpine
build-args: NGINX_PROXY_VERSION=${{ env.GIT_DESCRIBE }} build-args: |
NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }}
DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }}
platforms: linux/amd64,linux/arm64,linux/arm/v7 platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true push: true
tags: ${{ steps.docker_meta_alpine.outputs.tags }} tags: ${{ steps.docker_meta_alpine.outputs.tags }}

View file

@ -3,13 +3,15 @@ name: Tests
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches:
- main
paths-ignore: paths-ignore:
- 'LICENSE' - "LICENSE"
- '**.md' - "**.md"
pull_request: pull_request:
paths-ignore: paths-ignore:
- 'LICENSE' - "LICENSE"
- '**.md' - "**.md"
jobs: jobs:
unit: unit:
@ -22,10 +24,10 @@ jobs:
base_docker_image: [alpine, debian] base_docker_image: [alpine, debian]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Set up Python 3.9 - name: Set up Python 3.9
uses: actions/setup-python@v2 uses: actions/setup-python@v4
with: with:
python-version: 3.9 python-version: 3.9

View file

@ -1,60 +1,24 @@
# setup build arguments for version of dependencies to use FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen
ARG DOCKER_GEN_VERSION=0.9.0
ARG FOREGO_VERSION=v0.17.0
# Use a specific version of golang to build both binaries FROM nginxproxy/forego:0.17.1-debian AS forego
FROM golang:1.20.6 as gobuilder
# Build docker-gen from scratch
FROM gobuilder as dockergen
ARG DOCKER_GEN_VERSION
RUN git clone https://github.com/nginx-proxy/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
FROM gobuilder as forego
ARG FOREGO_VERSION
RUN git clone https://github.com/nginx-proxy/forego/ \
&& cd /go/forego \
&& git -c advice.detachedHead=false checkout $FOREGO_VERSION \
&& go mod download \
&& CGO_ENABLED=0 GOOS=linux go build -o forego . \
&& go clean -cache \
&& mv forego /usr/local/bin/ \
&& cd - \
&& rm -rf /go/forego
# Build the final image # Build the final image
FROM nginx:1.25.1 FROM nginx:1.23.4
ARG NGINX_PROXY_VERSION ARG NGINX_PROXY_VERSION
# Add DOCKER_GEN_VERSION environment variable # Add DOCKER_GEN_VERSION environment variable because
# Because some external projects rely on it # acme-companion rely on it (but the actual value is not important)
ARG DOCKER_GEN_VERSION ARG DOCKER_GEN_VERSION="unknown"
ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \
DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \
DOCKER_HOST=unix:///tmp/docker.sock DOCKER_HOST=unix:///tmp/docker.sock
# Install wget and install/updates certificates # Install/update certificates
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y -q --no-install-recommends \ && apt-get install -y -q --no-install-recommends ca-certificates \
ca-certificates \
wget \
&& apt-get clean \ && apt-get clean \
&& rm -r /var/lib/apt/lists/* && rm -r /var/lib/apt/lists/*
# Configure Nginx # Configure Nginx
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \
@ -63,7 +27,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
# Install Forego + docker-gen # Install Forego + docker-gen
COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego
COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY --from=docker-gen /usr/local/bin/docker-gen /usr/local/bin/docker-gen
COPY network_internal.conf /etc/nginx/ COPY network_internal.conf /etc/nginx/

View file

@ -1,55 +1,23 @@
# setup build arguments for version of dependencies to use FROM nginxproxy/docker-gen:0.10.4 AS docker-gen
ARG DOCKER_GEN_VERSION=0.9.0
ARG FOREGO_VERSION=v0.17.0
# Use a specific version of golang to build both binaries FROM nginxproxy/forego:0.17.1 AS forego
FROM golang:1.20.6-alpine as gobuilder
RUN apk add --no-cache git musl-dev
# Build docker-gen from scratch
FROM gobuilder as dockergen
ARG DOCKER_GEN_VERSION
RUN git clone https://github.com/nginx-proxy/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
ARG FOREGO_VERSION
RUN git clone https://github.com/nginx-proxy/forego/ \
&& cd /go/forego \
&& git -c advice.detachedHead=false checkout $FOREGO_VERSION \
&& go mod download \
&& CGO_ENABLED=0 go build -o forego . \
&& go clean -cache \
&& mv forego /usr/local/bin/ \
&& cd - \
&& rm -rf /go/forego
# Build the final image # Build the final image
FROM nginx:1.25.1-alpine FROM nginx:1.23.4-alpine
ARG NGINX_PROXY_VERSION ARG NGINX_PROXY_VERSION
# Add DOCKER_GEN_VERSION environment variable # Add DOCKER_GEN_VERSION environment variable because
# Because some external projects rely on it # acme-companion rely on it (but the actual value is not important)
ARG DOCKER_GEN_VERSION ARG DOCKER_GEN_VERSION="unknown"
ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \
DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \
DOCKER_HOST=unix:///tmp/docker.sock DOCKER_HOST=unix:///tmp/docker.sock
# Install wget and install/updates certificates # Install dependencies
RUN apk add --no-cache --virtual .run-deps \ RUN apk add --no-cache --virtual .run-deps \
ca-certificates bash wget openssl \ bash \
ca-certificates \
openssl \
&& update-ca-certificates && update-ca-certificates
# Configure Nginx # Configure Nginx
@ -60,7 +28,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
# Install Forego + docker-gen # Install Forego + docker-gen
COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego
COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY --from=docker-gen /usr/local/bin/docker-gen /usr/local/bin/docker-gen
COPY network_internal.conf /etc/nginx/ COPY network_internal.conf /etc/nginx/

View file

@ -3,13 +3,13 @@
build-webserver: build-webserver:
docker build -t web test/requirements/web docker build --pull -t web test/requirements/web
build-nginx-proxy-test-debian: build-nginx-proxy-test-debian:
docker build --build-arg NGINX_PROXY_VERSION="test" -t nginxproxy/nginx-proxy:test . docker build --pull --build-arg NGINX_PROXY_VERSION="test" -t nginxproxy/nginx-proxy:test .
build-nginx-proxy-test-alpine: build-nginx-proxy-test-alpine:
docker build --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . docker build --pull --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test .
test-debian: build-webserver build-nginx-proxy-test-debian test-debian: build-webserver build-nginx-proxy-test-debian
test/pytest.sh test/pytest.sh

160
README.md
View file

@ -8,7 +8,7 @@ it to the docker hub automatically. See `.github/workflows/docker_push.yml` for
# Original Readme # Original Readme
[![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) [![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) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases)
![nginx 1.21.6](https://img.shields.io/badge/nginx-1.21.6-brightgreen.svg) ![nginx 1.23.4](https://img.shields.io/badge/nginx-1.23.4-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 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 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') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub')
@ -130,7 +130,7 @@ You can also use wildcards at the beginning and the end of host name, like `*.ba
You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`.
It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`. It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`.
The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. The full request URI will be forwarded to the serving container in the `X-Original-URI` header.
**NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request. **NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request.
@ -160,10 +160,17 @@ The filename of the previous example would be `example.tld_8610f6c344b4096614eab
This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx.
For example `DEFAUL_ROOT=418` will return a 418 error page instead of the normal 404 one. Exception: If this is set to the string `none`, no default `location /` directive will be generated. This makes it possible for you to provide your own `location /` directive in your [`/etc/nginx/vhost.d/VIRTUAL_HOST`](#per-virtual_host) or [`/etc/nginx/vhost.d/default`](#per-virtual_host-default-configuration) files.
Another example is `DEFAULT_ROOT="301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` which would redirect an invalid request to this documentation.
Nginx variables such as $scheme, $host, and $request_uri can be used. However, care must be taken to make sure the $ signs are escaped properly. If unspecified, `DEFAULT_ROOT` defaults to `404`.
If you want to use `301 $scheme://$host/myapp1$request_uri` you should use:
Examples (YAML syntax):
* `DEFAULT_ROOT: "none"` prevents `nginx-proxy` from generating a default `location /` directive.
* `DEFAULT_ROOT: "418"` returns a 418 error page instead of the normal 404 one.
* `DEFAULT_ROOT: "301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` redirects the client to this documentation.
Nginx variables such as `$scheme`, `$host`, and `$request_uri` can be used. However, care must be taken to make sure the `$` signs are escaped properly. For example, if you want to use `301 $scheme://$host/myapp1$request_uri` you should use:
* Bash: `DEFAULT_ROOT='301 $scheme://$host/myapp1$request_uri'` * Bash: `DEFAULT_ROOT='301 $scheme://$host/myapp1$request_uri'`
* Docker Compose yaml: `- DEFAULT_ROOT: 301 $$scheme://$$host/myapp1$$request_uri` * Docker Compose yaml: `- DEFAULT_ROOT: 301 $$scheme://$$host/myapp1$$request_uri`
@ -228,6 +235,11 @@ If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on
If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory
### Custom log format
If you want to use a custom log format, you can set `LOG_FORMAT=xxx` on the proxy container.
With docker compose take care to escape the `$` character with `$$` to avoid variable interpolation. Example: `$remote_addr` becomes `$$remote_addr`.
### Default Host ### Default Host
@ -343,10 +355,9 @@ Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibili
The default behavior for the proxy when port 80 and 443 are exposed is as follows: The default behavior for the proxy when port 80 and 443 are exposed is as follows:
* If a container has a usable cert, port 80 will redirect to 443 for that container so that HTTPS is always preferred when available. * If a virtual host has a usable cert, port 80 will redirect to 443 for that virtual host so that HTTPS is always preferred when available.
* If the container does not have a usable cert, a 503 will be returned. * If the virtual host does not have a usable cert, but `default.crt` and `default.key` exist, those will be used as the virtual host's certificate and the client browser will receive a 500 error.
* If the virtual host does not have a usable cert, and `default.crt` and `default.key` do not exist, TLS negotiation will fail (see [Missing Certificate](#missing-certificate) below).
Note that in the latter case, a browser may get an connection error as no certificate is available to establish a connection. A self-signed or generic cert named `default.crt` and `default.key` will allow a client browser to make a SSL connection (likely w/ a warning) and subsequently receive a 500.
To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`). You can also disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with `HTTPS_METHOD=nohttps`. `HTTPS_METHOD` can be specified on each container for which you want to override the default behavior or on the proxy container to set it globally. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP site after changing this setting, your browser has probably cached the HSTS policy and is automatically redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser. To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`). You can also disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with `HTTPS_METHOD=nohttps`. `HTTPS_METHOD` can be specified on each container for which you want to override the default behavior or on the proxy container to set it globally. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP site after changing this setting, your browser has probably cached the HSTS policy and is automatically redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser.
@ -354,6 +365,31 @@ By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.or
*WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - even if they type in `http://` manually. The only way to get to an HTTP site after receiving an HSTS response is to clear your browser's HSTS cache. *WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - even if they type in `http://` manually. The only way to get to an HTTP site after receiving an HSTS response is to clear your browser's HSTS cache.
#### Missing Certificate
If HTTPS is enabled for a virtual host but its certificate is missing, nginx-proxy will configure nginx to use the default certificate (`default.crt` with `default.key`) and return a 500 error.
If the default certificate is also missing, nginx-proxy will configure nginx to accept HTTPS connections but fail the TLS negotiation. Client browsers will render a TLS error page. As of March 2023, web browsers display the following error messages:
* Chrome:
> This site can't provide a secure connection
>
> example.test sent an invalid response.
>
> Try running Connectivity Diagnostics.
>
> `ERR_SSL_PROTOCOL_ERROR`
* Firefox:
> Secure Connection Failed
>
> An error occurred during a connection to example.test.
> Peer reports it experienced an internal error.
>
> Error code: `SSL_ERROR_INTERNAL_ERROR_ALERT` "TLS error".
### Basic Authentication Support ### Basic Authentication Support
In order to be able to secure your virtual host, you have to create a file named as its equivalent VIRTUAL_HOST variable on directory In order to be able to secure your virtual host, you have to create a file named as its equivalent VIRTUAL_HOST variable on directory
@ -369,6 +405,72 @@ docker run -d -p 80:80 -p 443:443 \
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) 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)
### Upstream (Backend) Server HTTP Load Balancing Support
> **Warning**
> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2195](https://github.com/nginx-proxy/nginx-proxy/discussions/2195). Once we have collected enough feedback we will promote this feature to officially supported.
If you have multiple containers with the same `VIRTUAL_HOST` and `VIRTUAL_PATH` settings, nginx will spread the load across all of them. To change the load balancing algorithm from nginx's default (round-robin), set the `com.github.nginx-proxy.nginx-proxy.loadbalance` label on one or more of your application containers to the desired load balancing directive. See the [`ngx_http_upstream_module` documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) for available directives.
> **Note**
> * Don't forget the terminating semicolon (`;`).
> * If you are using Docker Compose, remember to escape any dollar sign (`$`) characters (`$` becomes `$$`).
Docker Compose example:
```yaml
services:
nginx-proxy:
image: nginxproxy/nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
HTTPS_METHOD: nohttps
myapp:
image: jwilder/whoami
expose:
- "8000"
environment:
VIRTUAL_HOST: myapp.example
VIRTUAL_PORT: "8000"
labels:
com.github.nginx-proxy.nginx-proxy.loadbalance: "hash $$remote_addr;"
deploy:
replicas: 4
```
### Upstream (Backend) Server HTTP Keep-Alive Support
> **Warning**
> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2194](https://github.com/nginx-proxy/nginx-proxy/discussions/2194). Once we have collected enough feedback we will promote this feature to officially supported.
To enable HTTP keep-alive between `nginx-proxy` and a backend server, set the `com.github.nginx-proxy.nginx-proxy.keepalive` label on the server's container to the desired maximum number of idle connections. See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) and the [Docker label documentation](https://docs.docker.com/config/labels-custom-metadata/) for details.
### Headers
By default, `nginx-proxy` forwards all incoming request headers from the client to the backend server unmodified, with the following exceptions:
* `Connection`: Set to `upgrade` if the client sets the `Upgrade` header, otherwise set to `close`. (Keep-alive between `nginx-proxy` and the backend server is not supported.)
* `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`).
* `X-Real-IP`: Set to the client's IP address.
* `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.)
* `X-Forwarded-Host`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the value of the `Host` header provided by the client. Otherwise, the header is forwarded to the backend server unmodified.
* `X-Forwarded-Proto`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified.
* `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`.
* `X-Forwarded-Port`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified.
* `X-Original-URI`: Set to the original request URI.
#### Trusting Downstream Proxy Headers
For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`), `X-Forwarded-Host`, and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol, hostname, or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if:
* you do not operate a second reverse proxy downstream of `nginx-proxy`, or
* you do operate a second reverse proxy downstream of `nginx-proxy` but that proxy forwards those headers unchecked from untrusted clients.
The default for `TRUST_DOWNSTREAM_PROXY` may change to `false` in a future version of `nginx-proxy`. If you require it to be enabled, you are encouraged to explicitly set it to `true` to avoid compatibility problems when upgrading.
### Custom Nginx Configuration ### Custom Nginx Configuration
If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis.
@ -386,10 +488,11 @@ proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection; proxy_set_header Connection $proxy_connection;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
proxy_set_header X-Forwarded-Path $request_uri; proxy_set_header X-Original-URI $request_uri;
# Mitigate httpoxy attack (see README for details) # Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy ""; proxy_set_header Proxy "";
@ -397,8 +500,6 @@ proxy_set_header Proxy "";
***NOTE***: If you provide this file it will replace the defaults; you may want to check the .tmpl file to make sure you have all of the needed options. ***NOTE***: If you provide this file it will replace the defaults; you may want to check the .tmpl file to make sure you have all of the needed options.
***NOTE***: The default configuration blocks the `Proxy` HTTP request header from being sent to downstream servers. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`).
#### Proxy-wide #### Proxy-wide
To add settings on a proxy-wide basis, add your configuration file under `/etc/nginx/conf.d` using a name ending in `.conf`. To add settings on a proxy-wide basis, add your configuration file under `/etc/nginx/conf.d` using a name ending in `.conf`.
@ -465,6 +566,32 @@ ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com
If you want most of your virtual hosts to use a default single `location` block configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default_location` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}_location` file associated with it. If you want most of your virtual hosts to use a default single `location` block configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default_location` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}_location` file associated with it.
#### Overriding `location` blocks
The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `default_location` files documented above make it possible to *augment* the generated [`location` block(s)](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) in a virtual host. In some circumstances, you may need to *completely override* the `location` block for a particular combination of virtual host and path. To do this, create a file whose name follows this pattern:
```
/etc/nginx/vhost.d/${VIRTUAL_HOST}_${PATH_HASH}_location_override
```
where `${VIRTUAL_HOST}` is the name of the virtual host (the `VIRTUAL_HOST` environment variable) and `${PATH_HASH}` is the SHA-1 hash of the path, as [described above](#per-virtual_path-location-configuration).
For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`:
```
/etc/nginx/vhost.d/${VIRTUAL_HOST}_location_override
```
When an override file exists, the `location` block that is normally created by `nginx-proxy` is not generated. Instead, the override file is included via the [nginx `include` directive](https://nginx.org/en/docs/ngx_core_module.html#include).
You are responsible for providing a suitable `location` block in your override file as required for your service. By default, `nginx-proxy` uses the `VIRTUAL_HOST` name as the upstream name for your application's Docker container; see [here](#unhashed-vs-sha1-upstream-names) for details. As an example, if your container has a `VIRTUAL_HOST` value of `app.example.com`, then to override the location block for `/` you would create a file named `/etc/nginx/vhost.d/app.example.com_location_override` that contains something like this:
```
location / {
proxy_pass http://app.example.com;
}
```
#### Per-VIRTUAL_HOST `server_tokens` configuration #### Per-VIRTUAL_HOST `server_tokens` configuration
Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details. Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details.
@ -476,12 +603,13 @@ Please note that using regular expressions in `VIRTUAL_HOST` will always result
### Troubleshooting ### Troubleshooting
In case you can't access your VIRTUAL_HOST, set `DEBUG=true` in the client container's environment and have a look at the generated nginx configuration file `/etc/nginx/conf.d/default.conf`: If you can't access your `VIRTUAL_HOST`, inspect the generated nginx configuration:
```console ```console
docker exec <nginx-proxy-instance> cat /etc/nginx/conf.d/default.conf docker exec <nginx-proxy-instance> nginx -T
``` ```
Especially at `upstream` definition blocks which should look like:
Pay attention to the `upstream` definition blocks, which should look like this:
```Nginx ```Nginx
# foo.example.com # foo.example.com

View file

@ -109,6 +109,13 @@ if [[ $* == 'forego start -r' ]]; then
_resolvers _resolvers
_setup_dhparam _setup_dhparam
if [ -z "${TRUST_DOWNSTREAM_PROXY}" ]; then
cat >&2 <<-EOT
Warning: TRUST_DOWNSTREAM_PROXY is not set; defaulting to "true". For security, you should explicitly set TRUST_DOWNSTREAM_PROXY to "false" if there is not a trusted reverse proxy in front of this proxy.
Warning: The default value of TRUST_DOWNSTREAM_PROXY might change to "false" in a future version of nginx-proxy. If you require TRUST_DOWNSTREAM_PROXY to be enabled, explicitly set it to "true".
EOT
fi
fi fi
exec "$@" exec "$@"

File diff suppressed because it is too large Load diff

View file

@ -322,31 +322,28 @@ def wait_for_nginxproxy_to_be_ready():
logging.debug("nginx-proxy ready") logging.debug("nginx-proxy ready")
break break
def find_docker_compose_file(request):
"""
helper for fixture functions to figure out the name of the docker-compose file to consider.
- if the test module provides a `docker_compose_file` variable, take that @pytest.fixture
- else, if a yaml file exists with the same name as the test module (but for the `.yml` extension), use that def docker_compose_file(request):
- otherwise use `docker-compose.yml`. """Fixture naming the docker-compose file to consider.
If a YAML file exists with the same name as the test module (with the `.py` extension replaced
with `.yml` or `.yaml`), use that. Otherwise, use `docker-compose.yml` in the same directory
as the test module.
Tests can override this fixture to specify a custom location.
""" """
test_module_dir = os.path.dirname(request.module.__file__) test_module_dir = os.path.dirname(request.module.__file__)
yml_file = os.path.join(test_module_dir, request.module.__name__ + '.yml') yml_file = os.path.join(test_module_dir, request.module.__name__ + '.yml')
yaml_file = os.path.join(test_module_dir, request.module.__name__ + '.yaml') yaml_file = os.path.join(test_module_dir, request.module.__name__ + '.yaml')
default_file = os.path.join(test_module_dir, 'docker-compose.yml') default_file = os.path.join(test_module_dir, 'docker-compose.yml')
docker_compose_file_module_variable = getattr(request.module, "docker_compose_file", None) if os.path.isfile(yml_file):
if docker_compose_file_module_variable is not None: docker_compose_file = yml_file
docker_compose_file = os.path.join( test_module_dir, docker_compose_file_module_variable) elif os.path.isfile(yaml_file):
if not os.path.isfile(docker_compose_file): docker_compose_file = yaml_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: else:
if os.path.isfile(yml_file): docker_compose_file = default_file
docker_compose_file = yml_file
elif os.path.isfile(yaml_file):
docker_compose_file = yaml_file
else:
docker_compose_file = default_file
if not os.path.isfile(docker_compose_file): 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.error("Could not find any docker-compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__))
@ -419,34 +416,72 @@ def connect_to_all_networks():
return [connect_to_network(network) for network in networks] return [connect_to_network(network) for network in networks]
class DockerComposer(contextlib.AbstractContextManager):
def __init__(self):
self._docker_compose_file = None
def __exit__(self, *exc_info):
self._down()
def _down(self):
if self._docker_compose_file is None:
return
for network in self._networks:
disconnect_from_network(network)
docker_compose_down(self._docker_compose_file)
self._docker_compose_file = None
def compose(self, docker_compose_file):
if docker_compose_file == self._docker_compose_file:
return
self._down()
if docker_compose_file is None:
return
remove_all_containers()
docker_compose_up(docker_compose_file)
self._networks = connect_to_all_networks()
wait_for_nginxproxy_to_be_ready()
time.sleep(3) # give time to containers to be ready
self._docker_compose_file = docker_compose_file
############################################################################### ###############################################################################
# #
# Py.test fixtures # Py.test fixtures
# #
############################################################################### ###############################################################################
@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
A custom docker compose file name can be defined in a variable named `docker_compose_file`. @pytest.fixture(scope="module")
def docker_composer():
with DockerComposer() as d:
yield d
@pytest.fixture
def ca_root_certificate():
return CA_ROOT_CERTIFICATE
@pytest.fixture
def monkey_patched_dns():
original_dns_resolver = monkey_patch_urllib_dns_resolver()
yield
restore_urllib_dns_resolver(original_dns_resolver)
@pytest.fixture
def docker_compose(monkey_patched_dns, docker_composer, docker_compose_file):
"""Ensures containers described in a docker compose file are started.
A custom docker compose file name can be specified by overriding the `docker_compose_file`
fixture.
Also, in the case where pytest is running from a docker container, this fixture makes sure Also, in the case where pytest is running from a docker container, this fixture makes sure
our container will be attached to all the docker networks. our container will be attached to all the docker networks.
""" """
docker_compose_file = find_docker_compose_file(request) docker_composer.compose(docker_compose_file)
original_dns_resolver = monkey_patch_urllib_dns_resolver()
remove_all_containers()
docker_compose_up(docker_compose_file)
networks = connect_to_all_networks()
wait_for_nginxproxy_to_be_ready()
time.sleep(3) # give time to containers to be ready
yield docker_client yield docker_client
for network in networks:
disconnect_from_network(network)
docker_compose_down(docker_compose_file)
restore_urllib_dns_resolver(original_dns_resolver)
@pytest.fixture() @pytest.fixture()

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
############################################################################### ###############################################################################
# # # #
# This script is meant to run the test suite from a Docker container. # # This script is meant to run the test suite from a Docker container. #
@ -9,17 +9,20 @@
############################################################################### ###############################################################################
# Returns the absolute directory path to this script # Returns the absolute directory path to this script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" TESTDIR=$(cd "${0%/*}" && pwd) || exit 1
ARGS=("$@") DIR=$(cd "${TESTDIR}/.." && pwd) || exit 1
# check requirements # check requirements
echo "> Building nginx-proxy-tester image..." echo "> Building nginx-proxy-tester image..."
docker build -t nginx-proxy-tester -f "${DIR}/requirements/Dockerfile-nginx-proxy-tester" "${DIR}/requirements" docker build --pull -t nginx-proxy-tester \
-f "${TESTDIR}/requirements/Dockerfile-nginx-proxy-tester" \
"${TESTDIR}/requirements" \
|| exit 1
# run the nginx-proxy-tester container setting the correct value for the working dir in order for # run the nginx-proxy-tester container setting the correct value for the working dir in order for
# docker-compose to work properly when run from within that container. # docker-compose to work properly when run from within that container.
exec docker run --rm -it --name "nginx-proxy-pytest" \ exec docker run --rm -it --name "nginx-proxy-pytest" \
--volume "/var/run/docker.sock:/var/run/docker.sock" \ --volume "/var/run/docker.sock:/var/run/docker.sock" \
--volume "${DIR}:${DIR}" \ --volume "${DIR}:${DIR}" \
--workdir "${DIR}" \ --workdir "${TESTDIR}" \
nginx-proxy-tester "${ARGS[@]}" nginx-proxy-tester "$@"

View file

@ -2,4 +2,4 @@ backoff==2.2.1
docker-compose==1.29.2 docker-compose==1.29.2
docker==6.1.3 docker==6.1.3
pytest==7.4.0 pytest==7.4.0
requests==2.29.0 requests==2.30.0

View file

@ -10,8 +10,6 @@ web:
reverseproxy: reverseproxy:
image: nginxproxy/nginx-proxy:test image: nginxproxy/nginx-proxy:test
container_name: reverseproxy container_name: reverseproxy
environment:
DEBUG: "true"
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /var/run/docker.sock:/tmp/docker.sock:ro
- ./tmp_certs:/etc/nginx/certs:ro - ./tmp_certs:/etc/nginx/certs:ro

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,8 @@
import re
def test_default_root_none(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode()
assert re.search(r"(?m)^\s*location\s+/path\s+\{", conf)
assert not re.search(r"(?m)^\s*location\s+/\s+\{", conf)

View file

@ -0,0 +1,15 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
DEFAULT_ROOT: none
web:
image: web
expose:
- "80"
environment:
WEB_PORTS: "80"
VIRTUAL_HOST: web.nginx-proxy.test
VIRTUAL_PATH: /path

View file

@ -1,41 +1,9 @@
import os def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
import docker
import logging
import pytest
@pytest.fixture(scope="module")
def nginx_tmpl():
"""
pytest fixture which extracts the the nginx config template from
the nginxproxy/nginx-proxy:test image
"""
script_dir = os.path.dirname(__file__)
logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test")
docker_client = docker.from_env()
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"))
def test_unknown_virtual_host_is_503(nginx_tmpl, docker_compose, nginxproxy):
r = nginxproxy.get("http://unknown.nginx.container.docker/") r = nginxproxy.get("http://unknown.nginx.container.docker/")
assert r.status_code == 503 assert r.status_code == 503
def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy): def test_forwards_to_whoami(docker_compose, nginxproxy):
r = nginxproxy.get("http://whoami.nginx.container.docker/") r = nginxproxy.get("http://whoami.nginx.container.docker/")
assert r.status_code == 200 assert r.status_code == 200
whoami_container = docker_compose.containers.get("whoami") whoami_container = docker_compose.containers.get("whoami")

View file

@ -14,7 +14,7 @@ services:
- nginx - nginx
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /var/run/docker.sock:/tmp/docker.sock:ro
- ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl - ../../nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl
web: web:
image: web image: web

View file

@ -1,8 +1,5 @@
import os
import docker import docker
import logging
import pytest import pytest
import re
from distutils.version import LooseVersion from distutils.version import LooseVersion
@ -13,38 +10,12 @@ pytestmark = pytest.mark.skipif(
) )
@pytest.fixture(scope="module") def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
def nginx_tmpl():
"""
pytest fixture which extracts the the nginx config template from
the nginxproxy/nginx-proxy:test image
"""
script_dir = os.path.dirname(__file__)
logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test")
docker_client = docker.from_env()
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"))
def test_unknown_virtual_host_is_503(nginx_tmpl, docker_compose, nginxproxy):
r = nginxproxy.get("http://unknown.nginx.container.docker/") r = nginxproxy.get("http://unknown.nginx.container.docker/")
assert r.status_code == 503 assert r.status_code == 503
def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy): def test_forwards_to_whoami(docker_compose, nginxproxy):
r = nginxproxy.get("http://whoami.nginx.container.docker/") r = nginxproxy.get("http://whoami.nginx.container.docker/")
assert r.status_code == 200 assert r.status_code == 200
whoami_container = docker_compose.containers.get("whoami") whoami_container = docker_compose.containers.get("whoami")

View file

@ -11,7 +11,7 @@ services:
command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /var/run/docker.sock:/tmp/docker.sock:ro
- ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl - ../../nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl
- nginx_conf:/etc/nginx/conf.d - nginx_conf:/etc/nginx/conf.d
web: web:

View file

@ -0,0 +1,5 @@
server {
server_name __;
listen 80 default_server;
return 418;
}

View file

@ -0,0 +1,14 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro
http-only:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: http-only.nginx-proxy.test
HTTPS_METHOD: nohttps

View file

@ -0,0 +1,71 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 7 21:54:16 2023 GMT
Not After : Jun 25 21:54:16 2050 GMT
Subject: CN=http-only.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b4:62:61:07:54:2e:6d:55:83:2d:24:b7:e2:15:
34:13:bd:79:21:e9:10:75:3f:4c:f8:ba:60:29:87:
e5:8e:2a:1e:fd:33:51:5a:8a:3a:6f:60:ff:24:f1:
1b:27:30:8c:ac:43:04:b7:79:cb:7a:ec:c6:08:a4:
a0:15:b0:0f:ee:6b:15:84:24:11:bc:85:2b:48:06:
04:0a:58:bb:8c:e8:4d:48:f5:06:c5:91:fe:5d:99:
0a:29:31:8a:f1:9b:0c:e0:39:75:a1:06:9b:d4:f5:
06:74:8f:46:5e:64:ba:2f:d0:3d:7c:3d:30:03:e9:
7c:35:17:69:04:f6:2e:29:d4:93:d6:d6:d2:6c:04:
38:06:21:06:05:30:8a:b9:9d:05:8d:12:6e:48:39:
bb:f6:93:4f:ba:a5:84:c7:96:2f:be:92:25:e9:d0:
95:2a:d9:23:8a:b3:28:0b:b6:19:1c:3b:be:a2:91:
70:44:a8:77:18:94:4b:df:61:f4:5c:c9:78:76:34:
b5:87:0f:c0:92:04:26:b6:ca:62:cd:9b:5d:eb:bf:
10:ac:df:af:72:5f:af:09:38:b1:dc:e1:3d:13:db:
a0:ac:b7:2e:ca:39:5c:4c:f1:1e:81:a8:b4:44:a2:
72:d5:3b:c0:71:cc:dc:16:0d:fa:38:96:44:b3:00:
d6:65
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:http-only.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
3b:54:95:48:4d:f6:93:38:42:40:02:ab:b7:17:3b:50:3b:ca:
c7:12:69:b0:da:cb:d7:3e:0e:1f:bf:a2:59:c7:fe:c2:5c:43:
84:92:b9:3a:be:8f:7e:2e:81:3c:ed:f3:a9:77:21:c2:35:f1:
da:cf:3a:1e:e2:ee:a2:ce:72:55:97:87:0e:ad:59:61:f7:75:
46:c0:2b:d4:88:b7:36:97:11:fb:5e:28:89:e9:2a:92:f1:15:
f1:43:8e:c1:38:85:8d:3a:26:7d:25:72:93:17:96:8d:5a:ed:
e8:73:3a:d5:8d:80:f2:af:38:84:ff:85:2e:d1:36:7d:2e:e1:
f0:2c:d8:15:5f:fc:c5:70:5d:25:6a:22:f3:2a:cd:0f:25:ad:
d4:93:d3:9a:3e:50:bc:da:a5:6c:86:ea:1d:d9:b9:c5:90:db:
f5:02:c8:c9:77:5c:ef:77:fe:74:60:41:33:d9:3c:a2:e1:73:
aa:14:18:5d:36:58:c8:41:63:4c:59:0e:4b:3d:c5:65:5a:01:
b0:16:50:0f:d0:4f:0d:ca:97:f6:11:47:06:6b:b1:ae:bb:26:
30:34:8b:7a:91:5d:8a:22:c7:f9:05:0d:bb:a5:b7:60:c0:20:
ce:d0:0e:c0:66:b3:e7:c4:61:ec:c5:40:e6:52:11:41:c3:11:
18:04:c7:1e
-----BEGIN CERTIFICATE-----
MIIDCzCCAfOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDcyMTU0MTZaGA8yMDUwMDYyNTIxNTQxNlowJTEjMCEGA1UEAwwa
aHR0cC1vbmx5Lm5naW54LXByb3h5LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC0YmEHVC5tVYMtJLfiFTQTvXkh6RB1P0z4umAph+WOKh79M1Fa
ijpvYP8k8RsnMIysQwS3ect67MYIpKAVsA/uaxWEJBG8hStIBgQKWLuM6E1I9QbF
kf5dmQopMYrxmwzgOXWhBpvU9QZ0j0ZeZLov0D18PTAD6Xw1F2kE9i4p1JPW1tJs
BDgGIQYFMIq5nQWNEm5IObv2k0+6pYTHli++kiXp0JUq2SOKsygLthkcO76ikXBE
qHcYlEvfYfRcyXh2NLWHD8CSBCa2ymLNm13rvxCs369yX68JOLHc4T0T26Csty7K
OVxM8R6BqLREonLVO8BxzNwWDfo4lkSzANZlAgMBAAGjKTAnMCUGA1UdEQQeMByC
Gmh0dHAtb25seS5uZ2lueC1wcm94eS50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBAQA7
VJVITfaTOEJAAqu3FztQO8rHEmmw2svXPg4fv6JZx/7CXEOEkrk6vo9+LoE87fOp
dyHCNfHazzoe4u6iznJVl4cOrVlh93VGwCvUiLc2lxH7XiiJ6SqS8RXxQ47BOIWN
OiZ9JXKTF5aNWu3oczrVjYDyrziE/4Uu0TZ9LuHwLNgVX/zFcF0laiLzKs0PJa3U
k9OaPlC82qVshuod2bnFkNv1AsjJd1zvd/50YEEz2Tyi4XOqFBhdNljIQWNMWQ5L
PcVlWgGwFlAP0E8Nypf2EUcGa7GuuyYwNIt6kV2KIsf5BQ27pbdgwCDO0A7AZrPn
xGHsxUDmUhFBwxEYBMce
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtGJhB1QubVWDLSS34hU0E715IekQdT9M+LpgKYfljioe/TNR
Woo6b2D/JPEbJzCMrEMEt3nLeuzGCKSgFbAP7msVhCQRvIUrSAYECli7jOhNSPUG
xZH+XZkKKTGK8ZsM4Dl1oQab1PUGdI9GXmS6L9A9fD0wA+l8NRdpBPYuKdST1tbS
bAQ4BiEGBTCKuZ0FjRJuSDm79pNPuqWEx5YvvpIl6dCVKtkjirMoC7YZHDu+opFw
RKh3GJRL32H0XMl4djS1hw/AkgQmtspizZtd678QrN+vcl+vCTix3OE9E9ugrLcu
yjlcTPEegai0RKJy1TvAcczcFg36OJZEswDWZQIDAQABAoIBAAfDA/HQyX6i41YZ
8l+kEe2XhZLT+IVTB/jb7C9dTZ9kaJj0kFeZAxKv1cq9JTH2gNcYuyc58muDrLHK
g6jrPoQ/z1k0RB8ci9Q5jgrz7n4NsOWmxXfS5GMaprlHDHeA+HjdgBZBtorfUDvL
vndpVimgiETETUCd115hd39jKHFcRcdV6yCix7ObywK3dMgLVpagCcnlyCWffS/r
nhhMfJ+VstW0nUtfZ7JEYwT6Cg7lLAVtDkqPX8zGjJiRwUKH808bUyqEw1y5Cc8U
U5hbmMgPWfXsKxsEC6FSVHBG9ZX2jymOMQXijLFcBSuWvADHmyU+ZxXcbtd1rv4E
cGFj3wECgYEA5cNrr5WjrpEin6MYYVWxiQ+xEWPU2R17eApagrDRLM41JJpv7a5m
TYuZRfIxb59CBPi718Gi168P3T2KMvo2/BTh9Lq5ZBYHx3aDqW2QvMFn7/tgamj8
0DBxccd2QWfGIBrT1rAF7lD8TC86wtDDVKrvhucRSEXVKF/jWFFRGfUCgYEAyPt6
48khr7sfNMVdkDLjQjZVV6H7ZUMoSn0FGybgKWxW+b0XCBPObUQWIpyCNTRr1+4A
1TAUS+F/OVVfwnLNgemeE2wd6CaduxwiK1U4pHbyXCElH1ifonHWV3MoXOefYsiY
q5z2jfJzUi0JZVUKsveu9rQsFLsc//1s/I5T1LECgYEAldY6fNg2VVp63OZsuNU8
oSiljbSwEyMh6Oe/nOkYkIKtr4AzrCoGt11piG7ohGW0lS9suMijnMqiquI+JP5+
KyinLoUy761aR17nf+9e62mpkZw6hUqQTGi7Irs0SHUXhMpaCfDi/Ua9MiW+yVuB
ds6+xBgeciZwWxMlXOwy2p0CgYEAm+YWiSK3Mq0fo7uEvBn9Fps2z+ciLoZNdppL
n6gkMX2MaeQ3PVi/wxoRYX+tsL+c973yf2vwEnw0R7Dlutt6dc9VgxNWj4GE0GMe
Tiao7Uom7Tf4p7wC9+r9rI/zOz2f8OxRIK18wtbShWfR5fx1dCWUXmGb3+jUse1O
4Qk2FcECgYAvSvGFoJb8tuHFEYYHBbjficmvTUsrTE+EhxPqWKFhKfF19fFFIupy
XBCrN6nwrh+/YMxZXeIRbbTTf814cOO7PjLeNhnfhJZkaJq1HzbYe3bOurna3qrm
Ra3xiM8Ld2PyGnZPXf8+AWhMhuPkLX1KFVTCAxwCpmTZCHtiGCmXMA==
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,71 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 7 21:53:19 2023 GMT
Not After : Jun 25 21:53:19 2050 GMT
Subject: CN=https-and-http.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b7:97:85:d1:7f:6b:50:29:f3:87:b7:4e:f5:25:
40:6a:d8:fa:a1:63:3c:4a:2e:68:4a:c6:8b:38:df:
07:81:d0:08:9d:fc:17:f5:37:28:7f:31:e6:f3:81:
28:4e:22:b6:bd:a2:4e:f2:2f:e5:0f:dd:55:3c:e1:
04:84:4c:45:1b:1a:ae:b7:f0:2a:da:43:05:71:91:
92:b8:d1:49:fe:80:0a:53:b9:66:da:54:60:9a:fc:
e1:b2:e8:28:48:7f:96:94:3c:92:a3:b2:37:f6:7a:
c2:de:0b:12:f0:ae:4e:92:fe:2d:c1:b2:95:28:1f:
88:8d:79:99:81:19:ae:22:a4:95:f5:9f:db:25:8e:
1d:cf:43:cd:6f:85:93:5f:79:ee:f8:f3:d4:82:e1:
e9:4d:c9:ad:ae:5b:92:43:3a:3c:71:51:70:f7:3e:
bd:1b:24:52:6a:a3:cf:54:72:57:ed:fe:72:ea:96:
9b:5a:02:02:a7:df:85:b7:68:ae:1e:07:77:9f:59:
a5:a0:8b:28:c2:c8:b7:bb:8a:42:50:df:05:73:bf:
9c:55:13:b5:82:79:77:40:57:a4:8f:88:a5:71:50:
d7:70:b0:4d:0c:d9:86:b3:9b:db:8a:20:bd:19:68:
10:52:2d:53:ba:0e:2e:1c:ad:80:54:bb:b6:c9:ab:
11:39
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:https-and-http.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
2c:f3:e5:47:3f:8e:5a:28:b1:df:e5:95:50:85:6f:27:2f:a6:
8d:f1:5e:cf:df:e2:52:66:97:61:36:59:81:26:25:19:99:c9:
93:e5:85:cb:ca:69:af:4b:21:a3:d2:7a:bf:b5:5e:2d:42:fb:
99:f8:22:58:e5:bf:79:b8:8a:74:7e:c6:94:14:d9:f2:27:63:
b6:e5:74:21:5b:59:fb:f6:c8:a9:28:fb:60:f7:5e:bd:c2:e6:
74:24:14:96:61:95:6c:c2:66:b4:52:25:a1:85:5a:97:e5:68:
5c:62:cf:69:3b:b0:a9:56:d8:e3:5f:74:dc:84:18:d5:3e:4f:
c9:35:39:26:88:dc:9b:80:d9:40:e1:4f:09:27:8d:d2:89:55:
30:91:02:86:35:04:95:1e:1d:58:14:5b:c6:e0:2e:a7:bf:a8:
f6:2b:76:8a:4e:71:79:bc:c0:04:cd:db:81:73:46:ce:68:ed:
25:b0:0e:42:8d:96:64:77:3b:f4:9d:1a:c9:f6:78:4c:56:4f:
92:17:29:3d:80:50:71:77:4b:a8:29:c2:12:fc:ad:0a:37:81:
38:4c:fb:54:99:4d:12:5f:98:dc:d1:a9:7b:08:45:c4:6f:7e:
fe:00:e0:db:79:fe:d1:28:e3:8e:82:d1:fb:bc:0a:c4:42:93:
c9:5e:eb:ba
-----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDcyMTUzMTlaGA8yMDUwMDYyNTIxNTMxOVowKjEoMCYGA1UEAwwf
aHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBALeXhdF/a1Ap84e3TvUlQGrY+qFjPEouaErGizjfB4HQ
CJ38F/U3KH8x5vOBKE4itr2iTvIv5Q/dVTzhBIRMRRsarrfwKtpDBXGRkrjRSf6A
ClO5ZtpUYJr84bLoKEh/lpQ8kqOyN/Z6wt4LEvCuTpL+LcGylSgfiI15mYEZriKk
lfWf2yWOHc9DzW+Fk1957vjz1ILh6U3Jra5bkkM6PHFRcPc+vRskUmqjz1RyV+3+
cuqWm1oCAqffhbdorh4Hd59ZpaCLKMLIt7uKQlDfBXO/nFUTtYJ5d0BXpI+IpXFQ
13CwTQzZhrOb24ogvRloEFItU7oOLhytgFS7tsmrETkCAwEAAaMuMCwwKgYDVR0R
BCMwIYIfaHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDANBgkqhkiG9w0B
AQsFAAOCAQEALPPlRz+OWiix3+WVUIVvJy+mjfFez9/iUmaXYTZZgSYlGZnJk+WF
y8ppr0sho9J6v7VeLUL7mfgiWOW/ebiKdH7GlBTZ8idjtuV0IVtZ+/bIqSj7YPde
vcLmdCQUlmGVbMJmtFIloYVal+VoXGLPaTuwqVbY41903IQY1T5PyTU5Jojcm4DZ
QOFPCSeN0olVMJEChjUElR4dWBRbxuAup7+o9it2ik5xebzABM3bgXNGzmjtJbAO
Qo2WZHc79J0ayfZ4TFZPkhcpPYBQcXdLqCnCEvytCjeBOEz7VJlNEl+Y3NGpewhF
xG9+/gDg23n+0SjjjoLR+7wKxEKTyV7rug==
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAt5eF0X9rUCnzh7dO9SVAatj6oWM8Si5oSsaLON8HgdAInfwX
9TcofzHm84EoTiK2vaJO8i/lD91VPOEEhExFGxqut/Aq2kMFcZGSuNFJ/oAKU7lm
2lRgmvzhsugoSH+WlDySo7I39nrC3gsS8K5Okv4twbKVKB+IjXmZgRmuIqSV9Z/b
JY4dz0PNb4WTX3nu+PPUguHpTcmtrluSQzo8cVFw9z69GyRSaqPPVHJX7f5y6pab
WgICp9+Ft2iuHgd3n1mloIsowsi3u4pCUN8Fc7+cVRO1gnl3QFekj4ilcVDXcLBN
DNmGs5vbiiC9GWgQUi1Tug4uHK2AVLu2yasROQIDAQABAoIBACT4KSVHoEdzOyvw
GME6sB8T9Fw9TG2vrKaqFmzsVGmqh6Gwmu5xHgGG/fe44XHigaPsJDOWu2yXaEur
ECrH5P6RP++gODDdYCI/ayk2U80g4XN8mR6L8Swkkhphr4Lx1lOhYvH9uFE05Tqr
RjQbFY16C6K+oFSFDQ1YGDYsAqnM3RD7PH+lHpo8UN1TO/vogdSQEpMYZDwLAYnW
uD5G3c0u2PsGu9YLuz2p8hcs3chh+cqKJWXOeW0JLrNGx1bqeQWkn6nXRDdRYi9V
cJlTgDqGuF54bieSyq9ABDZQP4Ol+moYKDoIz5PwurNjcYSklrT1tw0gqHZoQK1L
fDjw3QECgYEA7QMRU1AFKTvO7/8WLHLN5BT63n31wm0e9PYpz/XVLWEfxBcp9Xmf
xAIhXZ/U9P4dfNqxTjN9mVGzCHh5KfDJnUFqOXFy/zvfMeRzJf6dJo6/4OX9Bijr
Tgd454vyGXYQP2t+F14UAwl6vlGOAjttiP5qY5Ef1gllBEeIPe9Ts9kCgYEAxkzZ
pq4HJ/5/iDquMEHXNXzpNPavSvgxQdl1ILvJ49LJImmQFBCP9PqiOTIfePz1OqUI
C4baFuc0FEDJ3x9CUNmMY1lEi2ZUq2agPSXaQNsMcKtEJH8SoJlJIRpkQA7unX09
zb4dam6g79OaGmb8scePuezXMLv1Ee6WWtXbzGECgYEA6PYn9Gzl9cacu9dOUzgw
2ewpPcIvawDY+cxwAsHO3MDneVWPX4JBoGa7pwvwRTL1hwBqYMRJwwbD5CKObcQI
V/KxV28Eqo2N77tt1z2x9/E99u/4yTI1P0gm9ejfeVlL1RpyIMPPBcEujZ0Z6WXC
X3I63k0KLtajHRa2erIf4tkCgYAfunAgwTuX5JqXO3xfcEl033WY6deGUUvgU2Dw
Sdu1viY8gVNyQmwmMGwAZsquWxsJtRoibgM7IucsTml+b8v2j7hstP3IqCjn+9Wr
swDG28WTyXNvu31JgP04dLaRoVIAlOdsofym6OiLNvozO0M3VsziXMjZnVlK8zfP
dORkQQKBgQDXAJEJPygxVA+bF104dzCMWGmU7K8ShEWC5eOdKK4KWf9bNDpY6M6c
i6zga/xBbj7e3Bxqprpp8Wy2gIsnYiVo4V9EQethbLdomPxOpBMNMARw81rL1CpO
jbHB7bIDcKs2tQoZEXUW86ZxC8sdaDaWTJTfUO0RpJow6ZO3yvxVIQ==
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,71 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 7 21:53:49 2023 GMT
Not After : Jun 25 21:53:49 2050 GMT
Subject: CN=https-only.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:d9:87:48:02:85:f4:5f:0d:90:7e:4c:4f:13:89:
41:ca:41:15:c2:6f:fd:a8:c7:17:83:c6:dd:8c:fe:
19:a4:b2:6b:0b:35:4f:b4:3d:7c:40:0a:04:33:2a:
fd:10:72:f7:63:63:99:5b:3d:ec:78:ee:c6:4d:c8:
0e:4c:be:f2:3f:e3:02:74:57:9a:c1:fe:15:95:63:
4e:e7:2c:eb:70:f2:6b:c8:ba:01:a2:ca:a1:c7:76:
ff:38:e4:c2:b0:66:fc:85:d2:af:0f:22:81:d4:82:
eb:d5:b0:e6:69:14:37:dd:8d:ad:29:ce:93:68:5a:
ce:f4:77:76:6f:78:13:b6:c8:2f:fe:e0:b6:7e:fb:
29:16:be:e2:f5:45:3b:39:5b:52:dc:26:b7:ca:0c:
b6:1c:fc:a8:38:0b:dd:c1:f4:04:9b:2d:38:c9:a5:
2d:3e:f1:42:88:53:a2:3b:17:cf:d5:3c:2b:d6:6a:
7f:6f:05:8d:c5:b7:5d:64:1e:83:1b:e7:ec:80:3d:
6d:34:c1:66:b2:e6:5d:d9:a7:6e:46:75:14:bf:10:
16:c5:fc:47:8e:63:fa:e5:b4:bd:f2:b9:e0:cb:ea:
75:f9:68:ee:7d:8f:ea:8f:1a:9f:34:27:7a:4a:9f:
85:fd:3e:17:a7:96:c3:d0:4e:50:a2:a2:e0:45:92:
d0:b5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:https-only.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
8a:52:46:42:a9:74:18:6a:52:90:ef:a4:e9:c5:54:d5:97:3a:
ff:8b:c2:76:4f:9e:47:aa:e1:ea:e5:b9:af:9d:33:e3:85:17:
54:7d:32:bd:ac:90:3f:5c:d2:a1:42:17:52:2b:b1:83:e5:c3:
bf:81:f0:e7:38:e2:88:67:7b:d8:59:fe:f9:94:99:ba:be:f4:
3c:24:b2:c7:9e:f0:98:21:c6:2d:c2:e8:f3:67:bd:62:00:aa:
ce:34:fa:b4:53:6d:c1:09:5e:55:bd:43:aa:86:c6:f8:c5:83:
46:3a:49:12:a2:ec:30:36:0c:99:44:74:09:9d:cc:4b:98:1f:
7e:c9:9b:68:a0:f8:1e:00:14:d0:da:2a:bf:c8:ca:a8:1c:10:
b5:68:a2:f1:41:93:0c:f3:3f:c0:c6:53:3c:8d:a7:dd:a5:7b:
35:cc:44:e0:5b:6d:c5:cb:33:6f:c1:43:7e:06:df:21:99:11:
b3:91:41:b4:5e:f0:37:1e:8e:e5:73:85:dc:4a:21:d5:41:f9:
4e:b8:f5:ed:21:93:09:91:c2:8c:6b:04:a4:84:ab:3a:fe:35:
64:fa:6b:a7:8d:40:a6:64:89:30:84:ac:28:99:5a:01:79:77:
c0:df:88:da:a9:75:5f:c4:51:ae:a8:45:7b:d2:e1:a2:81:29:
60:cd:7b:cd
-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDcyMTUzNDlaGA8yMDUwMDYyNTIxNTM0OVowJjEkMCIGA1UEAwwb
aHR0cHMtb25seS5uZ2lueC1wcm94eS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP
tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB
osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2
fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/
bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju
fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABoyowKDAmBgNVHREEHzAd
ghtodHRwcy1vbmx5Lm5naW54LXByb3h5LnRlc3QwDQYJKoZIhvcNAQELBQADggEB
AIpSRkKpdBhqUpDvpOnFVNWXOv+LwnZPnkeq4erlua+dM+OFF1R9Mr2skD9c0qFC
F1IrsYPlw7+B8Oc44ohne9hZ/vmUmbq+9Dwkssee8Jghxi3C6PNnvWIAqs40+rRT
bcEJXlW9Q6qGxvjFg0Y6SRKi7DA2DJlEdAmdzEuYH37Jm2ig+B4AFNDaKr/Iyqgc
ELVoovFBkwzzP8DGUzyNp92lezXMROBbbcXLM2/BQ34G3yGZEbORQbRe8DcejuVz
hdxKIdVB+U649e0hkwmRwoxrBKSEqzr+NWT6a6eNQKZkiTCErCiZWgF5d8DfiNqp
dV/EUa6oRXvS4aKBKWDNe80=
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP
tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB
osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2
fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/
bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju
fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABAoIBAAWs//YA5MVuJy0E
dLO/yxWp6RVvsqCqwTRRBgrdvnGLrjtWosPDLvDE0iM7peq99TKEsMWusfLd2BLD
e4wJF20PUUsT1hflt050juR9SY9i4+kS4WQMAXig5DvpzCKqLUCYpLSyY8zVta2X
tgtb2bFQNwp2N2ZrqCa8zzxNV8ZXGoW+ZlvBJEDtBwt1DCDhY39/pqHfIhFl4Vwk
YhhbVjID145D1j/fP6vLceM2YA4uRmF1itj1iQ6YNNpXRspUGE4DXdqR6HcbduiX
trZjmdtKXY8mJg6jyLZxYbjFlKV/LvqKRYF3Jb9K0vdd4juBdZoy7DQzoLhcnzui
pEnPLakCgYEA9tN6KdQGKGBXGuF+ZqhXfB/XSkKUf8o/5j62cbu11ZIJ+iEBx+d6
lQAxTz5hHUL6a3c5qiM+AWBxYuFD6oqptIlTlBfIXI978neDNvEWWffivPvQLbt9
o9ohOirfK1iGPvtrpAwjv5ylE5SiTmJ/6wDvQWjNGAnJ3aaxkesJUSMCgYEA4Z0K
UHZVtnKLtzzIY7KfLbuKF/fJEDfMNr4Wgl6ny21vqO9kJGmA7SaoNdhx8RDcKmeV
/Vey4ug6YlOG48eapKLTthdRz5mx+jIkUfdOhj81m28xm/OPTqCrviTHCNOHeYDy
NKAIlJMo2z0vTKJn5eP6CsYmDWLpHQNyXY5qcEcCgYAzDBWt5O3JF/Or2Yr8zEAb
qbIq544yx69jfQDakMnQe72Yf48Quuz9N+b6zpnjJWEJLMU+TL+cJUgN/SzAqyDh
96zTaf/ENOCbiuAWUtIelUfNcf7iFm6rnodUsl0pZ8uL5w+iA+i4zjrNy+WtdG2k
OrNAwd345L1dHAaJeSSaJQKBgQCUnF3r7Fa/TCpt87LHwSQK+sqWyRf+/9IbiRDI
pVL/s8FmVPHw7jIHhHwuo7lCImnz4LGy5C6oOnIizIRAy/04Ty0Hd8ri5YmPlbHI
8A8gbMiB7zeNU1zlXP5jzFPyo2tMhLyGH5gnTdwOtfnPD/dCPe45ZJYyISIOg3O0
3peMBwKBgH20cskAOCNclfoG+Nis52h8FqmDlflJ8waUarvk26JhO1e009kOytw8
x/qSuttpGtTG+4fdc2wJvFNczr4h9ZlftBdgZXj8PKgRpcIe8q97Xg8PUj+Xfu/t
vD/QV+tVcGoAMsQq4NeFxiTbPfwVyXdYFT1XVCu6JEdLL+gpWh5W
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,36 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./nodefault.certs:/etc/nginx/certs:ro
https-and-http:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
VIRTUAL_HOST: https-and-http.nginx-proxy.test
https-only:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: https-only.nginx-proxy.test
HTTPS_METHOD: nohttp
http-only:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: http-only.nginx-proxy.test
HTTPS_METHOD: nohttps
missing-cert:
image: web
expose:
- "84"
environment:
WEB_PORTS: "84"
VIRTUAL_HOST: missing-cert.nginx-proxy.test

View file

@ -0,0 +1,16 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./withdefault.certs:/etc/nginx/certs:ro
environment:
HTTPS_METHOD: redirect
https-only:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
HTTPS_METHOD: nohttp
VIRTUAL_HOST: https-only.nginx-proxy.test

View file

@ -0,0 +1,22 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./withdefault.certs:/etc/nginx/certs:ro
environment:
HTTPS_METHOD: nohttp
https-only:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: https-only.nginx-proxy.test
missing-cert:
image: web
expose:
- "84"
environment:
WEB_PORTS: "84"
VIRTUAL_HOST: missing-cert.nginx-proxy.test

View file

@ -0,0 +1,15 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./withdefault.certs:/etc/nginx/certs:ro
environment:
HTTPS_METHOD: nohttp
https-only:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: https-only.nginx-proxy.test

View file

@ -0,0 +1,15 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
HTTPS_METHOD: redirect
http-only:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
HTTPS_METHOD: nohttps
VIRTUAL_HOST: http-only.nginx-proxy.test

View file

@ -0,0 +1,14 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
HTTPS_METHOD: nohttps
http-only:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: http-only.nginx-proxy.test

View file

@ -0,0 +1,70 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 9 04:02:23 2023 GMT
Not After : Jun 27 04:02:23 2050 GMT
Subject: CN=*.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:db:bd:54:de:01:7e:82:4e:c0:f1:5d:12:fd:3a:
fb:21:19:4d:44:25:47:ea:ad:d8:11:5c:d1:65:88:
af:49:fc:8e:4b:c3:01:c1:0d:6d:22:67:bd:31:66:
9f:4a:50:17:9e:47:b3:3b:b3:21:73:1f:81:55:73:
52:47:9b:fb:85:6b:e8:d8:09:cc:e1:7d:1c:14:03:
1c:ae:84:b4:5b:e5:e5:c7:71:fc:1f:74:33:4f:ae:
f7:8d:21:1f:55:8d:93:c7:84:4d:93:01:a1:1c:37:
ae:85:5c:70:2c:21:ec:87:35:c3:86:d3:b3:0f:9a:
b0:9d:8a:cd:0e:49:e8:99:c5:4c:50:bd:a8:6e:a7:
01:3e:a7:dc:cf:c3:48:37:8e:c6:8a:89:b0:41:01:
58:ee:45:94:fa:90:eb:df:c8:0e:b7:dd:79:75:13:
1e:07:69:ee:54:47:92:18:9d:e0:a9:ee:4e:22:d1:
f4:a2:4d:a1:47:ed:9b:35:2a:70:cc:66:fb:3e:f0:
49:f7:ee:62:2a:27:a1:d3:52:7b:ff:e9:12:d9:5b:
6b:f6:18:bf:9c:9d:5f:00:29:d2:54:b5:f8:a4:a2:
9b:3f:fe:a6:ed:14:ae:a0:fe:13:33:18:33:17:a9:
8b:fe:fc:75:65:0c:fb:c2:d1:1e:81:ca:43:89:bd:
78:dd
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:*.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
43:a7:1f:4b:ec:ff:1d:70:c7:f8:6e:eb:fd:15:25:27:b2:54:
c7:92:cf:ed:51:31:28:56:76:5c:da:8b:17:31:55:8c:a1:c2:
37:95:27:7b:b6:58:e5:92:ef:1e:fe:35:f1:44:ca:c7:1b:7b:
75:bf:e1:91:61:6d:8a:6f:35:8b:73:f4:d9:08:60:25:07:7a:
3e:c2:79:e7:ae:b4:70:cc:8a:30:cb:80:aa:47:1a:40:82:00:
a0:5e:01:67:d1:95:21:3c:b1:52:7d:f5:87:b6:43:41:df:b2:
a7:ee:3b:73:17:c4:19:2c:6b:7b:3c:26:9e:4c:00:e3:e8:07:
f2:e1:a1:31:79:57:be:b6:b1:a7:93:70:4e:e1:7d:bf:08:c5:
e7:a0:de:7d:82:20:24:f7:b0:3f:c2:94:36:88:ef:7b:7d:c0:
7f:8a:78:a1:8e:56:42:82:ce:82:e6:8e:3d:1b:b7:ca:dd:a9:
a8:e6:f9:a3:f4:4a:a4:a0:9c:15:6f:44:8c:48:20:e5:85:ed:
6f:85:22:41:1d:1f:fe:58:e5:43:ad:f2:c4:10:5a:10:ed:36:
10:98:ad:73:97:6a:e0:19:18:d6:32:26:03:3d:dd:84:5c:2e:
97:ca:a2:f5:63:f2:7a:16:f1:55:ca:d2:a1:54:09:8a:bb:23:
f0:53:36:51
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDkwNDAyMjNaGA8yMDUwMDYyNzA0MDIyM1owHTEbMBkGA1UEAwwS
Ki5uZ2lueC1wcm94eS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEA271U3gF+gk7A8V0S/Tr7IRlNRCVH6q3YEVzRZYivSfyOS8MBwQ1tIme9MWaf
SlAXnkezO7Mhcx+BVXNSR5v7hWvo2AnM4X0cFAMcroS0W+Xlx3H8H3QzT673jSEf
VY2Tx4RNkwGhHDeuhVxwLCHshzXDhtOzD5qwnYrNDknomcVMUL2obqcBPqfcz8NI
N47GiomwQQFY7kWU+pDr38gOt915dRMeB2nuVEeSGJ3gqe5OItH0ok2hR+2bNSpw
zGb7PvBJ9+5iKieh01J7/+kS2Vtr9hi/nJ1fACnSVLX4pKKbP/6m7RSuoP4TMxgz
F6mL/vx1ZQz7wtEegcpDib143QIDAQABoyEwHzAdBgNVHREEFjAUghIqLm5naW54
LXByb3h5LnRlc3QwDQYJKoZIhvcNAQELBQADggEBAEOnH0vs/x1wx/hu6/0VJSey
VMeSz+1RMShWdlzaixcxVYyhwjeVJ3u2WOWS7x7+NfFEyscbe3W/4ZFhbYpvNYtz
9NkIYCUHej7CeeeutHDMijDLgKpHGkCCAKBeAWfRlSE8sVJ99Ye2Q0HfsqfuO3MX
xBksa3s8Jp5MAOPoB/LhoTF5V762saeTcE7hfb8Ixeeg3n2CICT3sD/ClDaI73t9
wH+KeKGOVkKCzoLmjj0bt8rdqajm+aP0SqSgnBVvRIxIIOWF7W+FIkEdH/5Y5UOt
8sQQWhDtNhCYrXOXauAZGNYyJgM93YRcLpfKovVj8noW8VXK0qFUCYq7I/BTNlE=
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA271U3gF+gk7A8V0S/Tr7IRlNRCVH6q3YEVzRZYivSfyOS8MB
wQ1tIme9MWafSlAXnkezO7Mhcx+BVXNSR5v7hWvo2AnM4X0cFAMcroS0W+Xlx3H8
H3QzT673jSEfVY2Tx4RNkwGhHDeuhVxwLCHshzXDhtOzD5qwnYrNDknomcVMUL2o
bqcBPqfcz8NIN47GiomwQQFY7kWU+pDr38gOt915dRMeB2nuVEeSGJ3gqe5OItH0
ok2hR+2bNSpwzGb7PvBJ9+5iKieh01J7/+kS2Vtr9hi/nJ1fACnSVLX4pKKbP/6m
7RSuoP4TMxgzF6mL/vx1ZQz7wtEegcpDib143QIDAQABAoIBAGUd9QXMTjkMoIDx
QaHCGHocuI+ZUETQBtPGkJ1WjsNPMvPuIsqBsSzZ7Bflj3uU66lseTAJuGTPpKZ7
0Ose/llhVN7Fc8B34AndfL9aVdzMKDblXw3iXRJYA5awHUkzQ0PWwBPb9hWUEf1Q
klXcrolx1i4fEREnMArvKnlezWikpXcqDYRcmUfEvVozaq75heavHpOcOq2dg7vo
N/gcJmfG4aDOhrZC1f22u5cNePvbVj+DdXOUHMEEfXOFbxk97VhmcIaH75ugvVh4
EMMg87mcGLZiqPO5k6SYcuGyquc32Tf5sK80mpt/+SAEHCvSmUt9c1ynQrS9IhNp
OGfZhQkCgYEA+LonwScVGVEgHg1A9E7BKhIrgUOlwWNM43s+o8Uuz1T72VUVZ6N/
aO0+2Panw1qjsb0CUC2zft3zZTiZd81gWRmBYQ0R9dHWyWHbJlOv8rAmJ+60Gr2a
UVTLHEdZKx6svSDNhL0HfxxfWwePgHB4NVa2RUA3KQ5y5C96EXb8WbsCgYEA4iow
nIIbRZ9ILDz1oThxE+dFifKWXWFOwa58EFBY+/y34itL7kXRu2+4ZIltwL0L8m5j
GUALUabuoOASKg4CFBhCvoAAlWZRr6L6EOecrElUnrefUrKuCWPCVo3MnCMuLXDp
p1mEGIwEZBCY+jrSBMrRCawsMRkcymLJhEBFYkcCgYB6xIey0vObF2ve6XPSIr09
YtKObzF1jun4rnBwrXc5Zx0YXOK/0PemdtO6i6SqzCZYKI7nvGcIi80DfThi5cBU
uj4eBTGEQBrgM6jT9iK2izOKKkxDlqqA0nWec6kTm4Rvpa1Lg3Ibz4lRiR3Pq7Pp
v+8fp16SqUsUTkrWLADK2QKBgCRIhHf3X4yx2xBNz1JIDcwVpFBXPMxKWio0Ze7w
FPaIOq/sJkhZpyYc7EYkzhjHu2zvTLK2VZqJ32qrx/47NRYoNjz9qBpPyfcVfGzN
25LASPUVnFfWFpmnCXx9T0AVXMkpfjK857ZQcDvldcVfPmZKa3LTzlsqHjZR1uaC
sR7tAoGBANBfInPZVZRJfqqkPN1K8j4P7uCGjTIBmys/vxoilh1d0scTgZrdqt92
EKi/3UsJW2ndqQNDLbvi5kcW8a6UU3UB1LLvpyQ5zuS81x3+kKfv+5cDM8rt/M4A
MXnJA5eDZZ4SlHFzdblUv/MZdT+1x0tivMn3zFKNNj2SmaSGkQ0m
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,71 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 7 21:54:16 2023 GMT
Not After : Jun 25 21:54:16 2050 GMT
Subject: CN=http-only.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b4:62:61:07:54:2e:6d:55:83:2d:24:b7:e2:15:
34:13:bd:79:21:e9:10:75:3f:4c:f8:ba:60:29:87:
e5:8e:2a:1e:fd:33:51:5a:8a:3a:6f:60:ff:24:f1:
1b:27:30:8c:ac:43:04:b7:79:cb:7a:ec:c6:08:a4:
a0:15:b0:0f:ee:6b:15:84:24:11:bc:85:2b:48:06:
04:0a:58:bb:8c:e8:4d:48:f5:06:c5:91:fe:5d:99:
0a:29:31:8a:f1:9b:0c:e0:39:75:a1:06:9b:d4:f5:
06:74:8f:46:5e:64:ba:2f:d0:3d:7c:3d:30:03:e9:
7c:35:17:69:04:f6:2e:29:d4:93:d6:d6:d2:6c:04:
38:06:21:06:05:30:8a:b9:9d:05:8d:12:6e:48:39:
bb:f6:93:4f:ba:a5:84:c7:96:2f:be:92:25:e9:d0:
95:2a:d9:23:8a:b3:28:0b:b6:19:1c:3b:be:a2:91:
70:44:a8:77:18:94:4b:df:61:f4:5c:c9:78:76:34:
b5:87:0f:c0:92:04:26:b6:ca:62:cd:9b:5d:eb:bf:
10:ac:df:af:72:5f:af:09:38:b1:dc:e1:3d:13:db:
a0:ac:b7:2e:ca:39:5c:4c:f1:1e:81:a8:b4:44:a2:
72:d5:3b:c0:71:cc:dc:16:0d:fa:38:96:44:b3:00:
d6:65
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:http-only.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
3b:54:95:48:4d:f6:93:38:42:40:02:ab:b7:17:3b:50:3b:ca:
c7:12:69:b0:da:cb:d7:3e:0e:1f:bf:a2:59:c7:fe:c2:5c:43:
84:92:b9:3a:be:8f:7e:2e:81:3c:ed:f3:a9:77:21:c2:35:f1:
da:cf:3a:1e:e2:ee:a2:ce:72:55:97:87:0e:ad:59:61:f7:75:
46:c0:2b:d4:88:b7:36:97:11:fb:5e:28:89:e9:2a:92:f1:15:
f1:43:8e:c1:38:85:8d:3a:26:7d:25:72:93:17:96:8d:5a:ed:
e8:73:3a:d5:8d:80:f2:af:38:84:ff:85:2e:d1:36:7d:2e:e1:
f0:2c:d8:15:5f:fc:c5:70:5d:25:6a:22:f3:2a:cd:0f:25:ad:
d4:93:d3:9a:3e:50:bc:da:a5:6c:86:ea:1d:d9:b9:c5:90:db:
f5:02:c8:c9:77:5c:ef:77:fe:74:60:41:33:d9:3c:a2:e1:73:
aa:14:18:5d:36:58:c8:41:63:4c:59:0e:4b:3d:c5:65:5a:01:
b0:16:50:0f:d0:4f:0d:ca:97:f6:11:47:06:6b:b1:ae:bb:26:
30:34:8b:7a:91:5d:8a:22:c7:f9:05:0d:bb:a5:b7:60:c0:20:
ce:d0:0e:c0:66:b3:e7:c4:61:ec:c5:40:e6:52:11:41:c3:11:
18:04:c7:1e
-----BEGIN CERTIFICATE-----
MIIDCzCCAfOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDcyMTU0MTZaGA8yMDUwMDYyNTIxNTQxNlowJTEjMCEGA1UEAwwa
aHR0cC1vbmx5Lm5naW54LXByb3h5LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC0YmEHVC5tVYMtJLfiFTQTvXkh6RB1P0z4umAph+WOKh79M1Fa
ijpvYP8k8RsnMIysQwS3ect67MYIpKAVsA/uaxWEJBG8hStIBgQKWLuM6E1I9QbF
kf5dmQopMYrxmwzgOXWhBpvU9QZ0j0ZeZLov0D18PTAD6Xw1F2kE9i4p1JPW1tJs
BDgGIQYFMIq5nQWNEm5IObv2k0+6pYTHli++kiXp0JUq2SOKsygLthkcO76ikXBE
qHcYlEvfYfRcyXh2NLWHD8CSBCa2ymLNm13rvxCs369yX68JOLHc4T0T26Csty7K
OVxM8R6BqLREonLVO8BxzNwWDfo4lkSzANZlAgMBAAGjKTAnMCUGA1UdEQQeMByC
Gmh0dHAtb25seS5uZ2lueC1wcm94eS50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBAQA7
VJVITfaTOEJAAqu3FztQO8rHEmmw2svXPg4fv6JZx/7CXEOEkrk6vo9+LoE87fOp
dyHCNfHazzoe4u6iznJVl4cOrVlh93VGwCvUiLc2lxH7XiiJ6SqS8RXxQ47BOIWN
OiZ9JXKTF5aNWu3oczrVjYDyrziE/4Uu0TZ9LuHwLNgVX/zFcF0laiLzKs0PJa3U
k9OaPlC82qVshuod2bnFkNv1AsjJd1zvd/50YEEz2Tyi4XOqFBhdNljIQWNMWQ5L
PcVlWgGwFlAP0E8Nypf2EUcGa7GuuyYwNIt6kV2KIsf5BQ27pbdgwCDO0A7AZrPn
xGHsxUDmUhFBwxEYBMce
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtGJhB1QubVWDLSS34hU0E715IekQdT9M+LpgKYfljioe/TNR
Woo6b2D/JPEbJzCMrEMEt3nLeuzGCKSgFbAP7msVhCQRvIUrSAYECli7jOhNSPUG
xZH+XZkKKTGK8ZsM4Dl1oQab1PUGdI9GXmS6L9A9fD0wA+l8NRdpBPYuKdST1tbS
bAQ4BiEGBTCKuZ0FjRJuSDm79pNPuqWEx5YvvpIl6dCVKtkjirMoC7YZHDu+opFw
RKh3GJRL32H0XMl4djS1hw/AkgQmtspizZtd678QrN+vcl+vCTix3OE9E9ugrLcu
yjlcTPEegai0RKJy1TvAcczcFg36OJZEswDWZQIDAQABAoIBAAfDA/HQyX6i41YZ
8l+kEe2XhZLT+IVTB/jb7C9dTZ9kaJj0kFeZAxKv1cq9JTH2gNcYuyc58muDrLHK
g6jrPoQ/z1k0RB8ci9Q5jgrz7n4NsOWmxXfS5GMaprlHDHeA+HjdgBZBtorfUDvL
vndpVimgiETETUCd115hd39jKHFcRcdV6yCix7ObywK3dMgLVpagCcnlyCWffS/r
nhhMfJ+VstW0nUtfZ7JEYwT6Cg7lLAVtDkqPX8zGjJiRwUKH808bUyqEw1y5Cc8U
U5hbmMgPWfXsKxsEC6FSVHBG9ZX2jymOMQXijLFcBSuWvADHmyU+ZxXcbtd1rv4E
cGFj3wECgYEA5cNrr5WjrpEin6MYYVWxiQ+xEWPU2R17eApagrDRLM41JJpv7a5m
TYuZRfIxb59CBPi718Gi168P3T2KMvo2/BTh9Lq5ZBYHx3aDqW2QvMFn7/tgamj8
0DBxccd2QWfGIBrT1rAF7lD8TC86wtDDVKrvhucRSEXVKF/jWFFRGfUCgYEAyPt6
48khr7sfNMVdkDLjQjZVV6H7ZUMoSn0FGybgKWxW+b0XCBPObUQWIpyCNTRr1+4A
1TAUS+F/OVVfwnLNgemeE2wd6CaduxwiK1U4pHbyXCElH1ifonHWV3MoXOefYsiY
q5z2jfJzUi0JZVUKsveu9rQsFLsc//1s/I5T1LECgYEAldY6fNg2VVp63OZsuNU8
oSiljbSwEyMh6Oe/nOkYkIKtr4AzrCoGt11piG7ohGW0lS9suMijnMqiquI+JP5+
KyinLoUy761aR17nf+9e62mpkZw6hUqQTGi7Irs0SHUXhMpaCfDi/Ua9MiW+yVuB
ds6+xBgeciZwWxMlXOwy2p0CgYEAm+YWiSK3Mq0fo7uEvBn9Fps2z+ciLoZNdppL
n6gkMX2MaeQ3PVi/wxoRYX+tsL+c973yf2vwEnw0R7Dlutt6dc9VgxNWj4GE0GMe
Tiao7Uom7Tf4p7wC9+r9rI/zOz2f8OxRIK18wtbShWfR5fx1dCWUXmGb3+jUse1O
4Qk2FcECgYAvSvGFoJb8tuHFEYYHBbjficmvTUsrTE+EhxPqWKFhKfF19fFFIupy
XBCrN6nwrh+/YMxZXeIRbbTTf814cOO7PjLeNhnfhJZkaJq1HzbYe3bOurna3qrm
Ra3xiM8Ld2PyGnZPXf8+AWhMhuPkLX1KFVTCAxwCpmTZCHtiGCmXMA==
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,71 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 7 21:53:19 2023 GMT
Not After : Jun 25 21:53:19 2050 GMT
Subject: CN=https-and-http.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b7:97:85:d1:7f:6b:50:29:f3:87:b7:4e:f5:25:
40:6a:d8:fa:a1:63:3c:4a:2e:68:4a:c6:8b:38:df:
07:81:d0:08:9d:fc:17:f5:37:28:7f:31:e6:f3:81:
28:4e:22:b6:bd:a2:4e:f2:2f:e5:0f:dd:55:3c:e1:
04:84:4c:45:1b:1a:ae:b7:f0:2a:da:43:05:71:91:
92:b8:d1:49:fe:80:0a:53:b9:66:da:54:60:9a:fc:
e1:b2:e8:28:48:7f:96:94:3c:92:a3:b2:37:f6:7a:
c2:de:0b:12:f0:ae:4e:92:fe:2d:c1:b2:95:28:1f:
88:8d:79:99:81:19:ae:22:a4:95:f5:9f:db:25:8e:
1d:cf:43:cd:6f:85:93:5f:79:ee:f8:f3:d4:82:e1:
e9:4d:c9:ad:ae:5b:92:43:3a:3c:71:51:70:f7:3e:
bd:1b:24:52:6a:a3:cf:54:72:57:ed:fe:72:ea:96:
9b:5a:02:02:a7:df:85:b7:68:ae:1e:07:77:9f:59:
a5:a0:8b:28:c2:c8:b7:bb:8a:42:50:df:05:73:bf:
9c:55:13:b5:82:79:77:40:57:a4:8f:88:a5:71:50:
d7:70:b0:4d:0c:d9:86:b3:9b:db:8a:20:bd:19:68:
10:52:2d:53:ba:0e:2e:1c:ad:80:54:bb:b6:c9:ab:
11:39
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:https-and-http.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
2c:f3:e5:47:3f:8e:5a:28:b1:df:e5:95:50:85:6f:27:2f:a6:
8d:f1:5e:cf:df:e2:52:66:97:61:36:59:81:26:25:19:99:c9:
93:e5:85:cb:ca:69:af:4b:21:a3:d2:7a:bf:b5:5e:2d:42:fb:
99:f8:22:58:e5:bf:79:b8:8a:74:7e:c6:94:14:d9:f2:27:63:
b6:e5:74:21:5b:59:fb:f6:c8:a9:28:fb:60:f7:5e:bd:c2:e6:
74:24:14:96:61:95:6c:c2:66:b4:52:25:a1:85:5a:97:e5:68:
5c:62:cf:69:3b:b0:a9:56:d8:e3:5f:74:dc:84:18:d5:3e:4f:
c9:35:39:26:88:dc:9b:80:d9:40:e1:4f:09:27:8d:d2:89:55:
30:91:02:86:35:04:95:1e:1d:58:14:5b:c6:e0:2e:a7:bf:a8:
f6:2b:76:8a:4e:71:79:bc:c0:04:cd:db:81:73:46:ce:68:ed:
25:b0:0e:42:8d:96:64:77:3b:f4:9d:1a:c9:f6:78:4c:56:4f:
92:17:29:3d:80:50:71:77:4b:a8:29:c2:12:fc:ad:0a:37:81:
38:4c:fb:54:99:4d:12:5f:98:dc:d1:a9:7b:08:45:c4:6f:7e:
fe:00:e0:db:79:fe:d1:28:e3:8e:82:d1:fb:bc:0a:c4:42:93:
c9:5e:eb:ba
-----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDcyMTUzMTlaGA8yMDUwMDYyNTIxNTMxOVowKjEoMCYGA1UEAwwf
aHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBALeXhdF/a1Ap84e3TvUlQGrY+qFjPEouaErGizjfB4HQ
CJ38F/U3KH8x5vOBKE4itr2iTvIv5Q/dVTzhBIRMRRsarrfwKtpDBXGRkrjRSf6A
ClO5ZtpUYJr84bLoKEh/lpQ8kqOyN/Z6wt4LEvCuTpL+LcGylSgfiI15mYEZriKk
lfWf2yWOHc9DzW+Fk1957vjz1ILh6U3Jra5bkkM6PHFRcPc+vRskUmqjz1RyV+3+
cuqWm1oCAqffhbdorh4Hd59ZpaCLKMLIt7uKQlDfBXO/nFUTtYJ5d0BXpI+IpXFQ
13CwTQzZhrOb24ogvRloEFItU7oOLhytgFS7tsmrETkCAwEAAaMuMCwwKgYDVR0R
BCMwIYIfaHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDANBgkqhkiG9w0B
AQsFAAOCAQEALPPlRz+OWiix3+WVUIVvJy+mjfFez9/iUmaXYTZZgSYlGZnJk+WF
y8ppr0sho9J6v7VeLUL7mfgiWOW/ebiKdH7GlBTZ8idjtuV0IVtZ+/bIqSj7YPde
vcLmdCQUlmGVbMJmtFIloYVal+VoXGLPaTuwqVbY41903IQY1T5PyTU5Jojcm4DZ
QOFPCSeN0olVMJEChjUElR4dWBRbxuAup7+o9it2ik5xebzABM3bgXNGzmjtJbAO
Qo2WZHc79J0ayfZ4TFZPkhcpPYBQcXdLqCnCEvytCjeBOEz7VJlNEl+Y3NGpewhF
xG9+/gDg23n+0SjjjoLR+7wKxEKTyV7rug==
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAt5eF0X9rUCnzh7dO9SVAatj6oWM8Si5oSsaLON8HgdAInfwX
9TcofzHm84EoTiK2vaJO8i/lD91VPOEEhExFGxqut/Aq2kMFcZGSuNFJ/oAKU7lm
2lRgmvzhsugoSH+WlDySo7I39nrC3gsS8K5Okv4twbKVKB+IjXmZgRmuIqSV9Z/b
JY4dz0PNb4WTX3nu+PPUguHpTcmtrluSQzo8cVFw9z69GyRSaqPPVHJX7f5y6pab
WgICp9+Ft2iuHgd3n1mloIsowsi3u4pCUN8Fc7+cVRO1gnl3QFekj4ilcVDXcLBN
DNmGs5vbiiC9GWgQUi1Tug4uHK2AVLu2yasROQIDAQABAoIBACT4KSVHoEdzOyvw
GME6sB8T9Fw9TG2vrKaqFmzsVGmqh6Gwmu5xHgGG/fe44XHigaPsJDOWu2yXaEur
ECrH5P6RP++gODDdYCI/ayk2U80g4XN8mR6L8Swkkhphr4Lx1lOhYvH9uFE05Tqr
RjQbFY16C6K+oFSFDQ1YGDYsAqnM3RD7PH+lHpo8UN1TO/vogdSQEpMYZDwLAYnW
uD5G3c0u2PsGu9YLuz2p8hcs3chh+cqKJWXOeW0JLrNGx1bqeQWkn6nXRDdRYi9V
cJlTgDqGuF54bieSyq9ABDZQP4Ol+moYKDoIz5PwurNjcYSklrT1tw0gqHZoQK1L
fDjw3QECgYEA7QMRU1AFKTvO7/8WLHLN5BT63n31wm0e9PYpz/XVLWEfxBcp9Xmf
xAIhXZ/U9P4dfNqxTjN9mVGzCHh5KfDJnUFqOXFy/zvfMeRzJf6dJo6/4OX9Bijr
Tgd454vyGXYQP2t+F14UAwl6vlGOAjttiP5qY5Ef1gllBEeIPe9Ts9kCgYEAxkzZ
pq4HJ/5/iDquMEHXNXzpNPavSvgxQdl1ILvJ49LJImmQFBCP9PqiOTIfePz1OqUI
C4baFuc0FEDJ3x9CUNmMY1lEi2ZUq2agPSXaQNsMcKtEJH8SoJlJIRpkQA7unX09
zb4dam6g79OaGmb8scePuezXMLv1Ee6WWtXbzGECgYEA6PYn9Gzl9cacu9dOUzgw
2ewpPcIvawDY+cxwAsHO3MDneVWPX4JBoGa7pwvwRTL1hwBqYMRJwwbD5CKObcQI
V/KxV28Eqo2N77tt1z2x9/E99u/4yTI1P0gm9ejfeVlL1RpyIMPPBcEujZ0Z6WXC
X3I63k0KLtajHRa2erIf4tkCgYAfunAgwTuX5JqXO3xfcEl033WY6deGUUvgU2Dw
Sdu1viY8gVNyQmwmMGwAZsquWxsJtRoibgM7IucsTml+b8v2j7hstP3IqCjn+9Wr
swDG28WTyXNvu31JgP04dLaRoVIAlOdsofym6OiLNvozO0M3VsziXMjZnVlK8zfP
dORkQQKBgQDXAJEJPygxVA+bF104dzCMWGmU7K8ShEWC5eOdKK4KWf9bNDpY6M6c
i6zga/xBbj7e3Bxqprpp8Wy2gIsnYiVo4V9EQethbLdomPxOpBMNMARw81rL1CpO
jbHB7bIDcKs2tQoZEXUW86ZxC8sdaDaWTJTfUO0RpJow6ZO3yvxVIQ==
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,71 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Feb 7 21:53:49 2023 GMT
Not After : Jun 25 21:53:49 2050 GMT
Subject: CN=https-only.nginx-proxy.test
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:d9:87:48:02:85:f4:5f:0d:90:7e:4c:4f:13:89:
41:ca:41:15:c2:6f:fd:a8:c7:17:83:c6:dd:8c:fe:
19:a4:b2:6b:0b:35:4f:b4:3d:7c:40:0a:04:33:2a:
fd:10:72:f7:63:63:99:5b:3d:ec:78:ee:c6:4d:c8:
0e:4c:be:f2:3f:e3:02:74:57:9a:c1:fe:15:95:63:
4e:e7:2c:eb:70:f2:6b:c8:ba:01:a2:ca:a1:c7:76:
ff:38:e4:c2:b0:66:fc:85:d2:af:0f:22:81:d4:82:
eb:d5:b0:e6:69:14:37:dd:8d:ad:29:ce:93:68:5a:
ce:f4:77:76:6f:78:13:b6:c8:2f:fe:e0:b6:7e:fb:
29:16:be:e2:f5:45:3b:39:5b:52:dc:26:b7:ca:0c:
b6:1c:fc:a8:38:0b:dd:c1:f4:04:9b:2d:38:c9:a5:
2d:3e:f1:42:88:53:a2:3b:17:cf:d5:3c:2b:d6:6a:
7f:6f:05:8d:c5:b7:5d:64:1e:83:1b:e7:ec:80:3d:
6d:34:c1:66:b2:e6:5d:d9:a7:6e:46:75:14:bf:10:
16:c5:fc:47:8e:63:fa:e5:b4:bd:f2:b9:e0:cb:ea:
75:f9:68:ee:7d:8f:ea:8f:1a:9f:34:27:7a:4a:9f:
85:fd:3e:17:a7:96:c3:d0:4e:50:a2:a2:e0:45:92:
d0:b5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:https-only.nginx-proxy.test
Signature Algorithm: sha256WithRSAEncryption
8a:52:46:42:a9:74:18:6a:52:90:ef:a4:e9:c5:54:d5:97:3a:
ff:8b:c2:76:4f:9e:47:aa:e1:ea:e5:b9:af:9d:33:e3:85:17:
54:7d:32:bd:ac:90:3f:5c:d2:a1:42:17:52:2b:b1:83:e5:c3:
bf:81:f0:e7:38:e2:88:67:7b:d8:59:fe:f9:94:99:ba:be:f4:
3c:24:b2:c7:9e:f0:98:21:c6:2d:c2:e8:f3:67:bd:62:00:aa:
ce:34:fa:b4:53:6d:c1:09:5e:55:bd:43:aa:86:c6:f8:c5:83:
46:3a:49:12:a2:ec:30:36:0c:99:44:74:09:9d:cc:4b:98:1f:
7e:c9:9b:68:a0:f8:1e:00:14:d0:da:2a:bf:c8:ca:a8:1c:10:
b5:68:a2:f1:41:93:0c:f3:3f:c0:c6:53:3c:8d:a7:dd:a5:7b:
35:cc:44:e0:5b:6d:c5:cb:33:6f:c1:43:7e:06:df:21:99:11:
b3:91:41:b4:5e:f0:37:1e:8e:e5:73:85:dc:4a:21:d5:41:f9:
4e:b8:f5:ed:21:93:09:91:c2:8c:6b:04:a4:84:ab:3a:fe:35:
64:fa:6b:a7:8d:40:a6:64:89:30:84:ac:28:99:5a:01:79:77:
c0:df:88:da:a9:75:5f:c4:51:ae:a8:45:7b:d2:e1:a2:81:29:
60:cd:7b:cd
-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAgFw0yMzAyMDcyMTUzNDlaGA8yMDUwMDYyNTIxNTM0OVowJjEkMCIGA1UEAwwb
aHR0cHMtb25seS5uZ2lueC1wcm94eS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP
tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB
osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2
fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/
bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju
fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABoyowKDAmBgNVHREEHzAd
ghtodHRwcy1vbmx5Lm5naW54LXByb3h5LnRlc3QwDQYJKoZIhvcNAQELBQADggEB
AIpSRkKpdBhqUpDvpOnFVNWXOv+LwnZPnkeq4erlua+dM+OFF1R9Mr2skD9c0qFC
F1IrsYPlw7+B8Oc44ohne9hZ/vmUmbq+9Dwkssee8Jghxi3C6PNnvWIAqs40+rRT
bcEJXlW9Q6qGxvjFg0Y6SRKi7DA2DJlEdAmdzEuYH37Jm2ig+B4AFNDaKr/Iyqgc
ELVoovFBkwzzP8DGUzyNp92lezXMROBbbcXLM2/BQ34G3yGZEbORQbRe8DcejuVz
hdxKIdVB+U649e0hkwmRwoxrBKSEqzr+NWT6a6eNQKZkiTCErCiZWgF5d8DfiNqp
dV/EUa6oRXvS4aKBKWDNe80=
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP
tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB
osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2
fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/
bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju
fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABAoIBAAWs//YA5MVuJy0E
dLO/yxWp6RVvsqCqwTRRBgrdvnGLrjtWosPDLvDE0iM7peq99TKEsMWusfLd2BLD
e4wJF20PUUsT1hflt050juR9SY9i4+kS4WQMAXig5DvpzCKqLUCYpLSyY8zVta2X
tgtb2bFQNwp2N2ZrqCa8zzxNV8ZXGoW+ZlvBJEDtBwt1DCDhY39/pqHfIhFl4Vwk
YhhbVjID145D1j/fP6vLceM2YA4uRmF1itj1iQ6YNNpXRspUGE4DXdqR6HcbduiX
trZjmdtKXY8mJg6jyLZxYbjFlKV/LvqKRYF3Jb9K0vdd4juBdZoy7DQzoLhcnzui
pEnPLakCgYEA9tN6KdQGKGBXGuF+ZqhXfB/XSkKUf8o/5j62cbu11ZIJ+iEBx+d6
lQAxTz5hHUL6a3c5qiM+AWBxYuFD6oqptIlTlBfIXI978neDNvEWWffivPvQLbt9
o9ohOirfK1iGPvtrpAwjv5ylE5SiTmJ/6wDvQWjNGAnJ3aaxkesJUSMCgYEA4Z0K
UHZVtnKLtzzIY7KfLbuKF/fJEDfMNr4Wgl6ny21vqO9kJGmA7SaoNdhx8RDcKmeV
/Vey4ug6YlOG48eapKLTthdRz5mx+jIkUfdOhj81m28xm/OPTqCrviTHCNOHeYDy
NKAIlJMo2z0vTKJn5eP6CsYmDWLpHQNyXY5qcEcCgYAzDBWt5O3JF/Or2Yr8zEAb
qbIq544yx69jfQDakMnQe72Yf48Quuz9N+b6zpnjJWEJLMU+TL+cJUgN/SzAqyDh
96zTaf/ENOCbiuAWUtIelUfNcf7iFm6rnodUsl0pZ8uL5w+iA+i4zjrNy+WtdG2k
OrNAwd345L1dHAaJeSSaJQKBgQCUnF3r7Fa/TCpt87LHwSQK+sqWyRf+/9IbiRDI
pVL/s8FmVPHw7jIHhHwuo7lCImnz4LGy5C6oOnIizIRAy/04Ty0Hd8ri5YmPlbHI
8A8gbMiB7zeNU1zlXP5jzFPyo2tMhLyGH5gnTdwOtfnPD/dCPe45ZJYyISIOg3O0
3peMBwKBgH20cskAOCNclfoG+Nis52h8FqmDlflJ8waUarvk26JhO1e009kOytw8
x/qSuttpGtTG+4fdc2wJvFNczr4h9ZlftBdgZXj8PKgRpcIe8q97Xg8PUj+Xfu/t
vD/QV+tVcGoAMsQq4NeFxiTbPfwVyXdYFT1XVCu6JEdLL+gpWh5W
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,36 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./withdefault.certs:/etc/nginx/certs:ro
https-and-http:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
VIRTUAL_HOST: https-and-http.nginx-proxy.test
https-only:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: https-only.nginx-proxy.test
HTTPS_METHOD: nohttp
http-only:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: http-only.nginx-proxy.test
HTTPS_METHOD: nohttps
missing-cert:
image: web
expose:
- "84"
environment:
WEB_PORTS: "84"
VIRTUAL_HOST: missing-cert.nginx-proxy.test

104
test/test_fallback.py Normal file
View file

@ -0,0 +1,104 @@
import os.path
import re
import backoff
import pytest
import requests
@pytest.fixture
def data_dir():
return f"{os.path.splitext(__file__)[0]}.data"
@pytest.fixture
def docker_compose_file(data_dir, compose_file):
return os.path.join(data_dir, compose_file)
@pytest.fixture
def get(docker_compose, nginxproxy, want_err_re):
@backoff.on_exception(
backoff.constant,
requests.exceptions.RequestException,
giveup=lambda e: want_err_re and want_err_re.search(str(e)),
interval=.3,
max_tries=30,
jitter=None)
def _get(url):
return nginxproxy.get(url, allow_redirects=False)
return _get
INTERNAL_ERR_RE = re.compile("TLSV1_ALERT_INTERNAL_ERROR")
CONNECTION_REFUSED_RE = re.compile("Connection refused")
@pytest.mark.parametrize("compose_file,url,want_code,want_err_re", [
# Has default.crt.
("withdefault.yml", "http://https-and-http.nginx-proxy.test/", 301, None),
("withdefault.yml", "https://https-and-http.nginx-proxy.test/", 200, None),
("withdefault.yml", "http://https-only.nginx-proxy.test/", 503, None),
("withdefault.yml", "https://https-only.nginx-proxy.test/", 200, None),
("withdefault.yml", "http://http-only.nginx-proxy.test/", 200, None),
("withdefault.yml", "https://http-only.nginx-proxy.test/", 503, None),
("withdefault.yml", "http://missing-cert.nginx-proxy.test/", 200, None),
("withdefault.yml", "https://missing-cert.nginx-proxy.test/", 500, None),
("withdefault.yml", "http://unknown.nginx-proxy.test/", 503, None),
("withdefault.yml", "https://unknown.nginx-proxy.test/", 503, None),
# Same as withdefault.yml, except there is no default.crt.
("nodefault.yml", "http://https-and-http.nginx-proxy.test/", 301, None),
("nodefault.yml", "https://https-and-http.nginx-proxy.test/", 200, None),
("nodefault.yml", "http://https-only.nginx-proxy.test/", 503, None),
("nodefault.yml", "https://https-only.nginx-proxy.test/", 200, None),
("nodefault.yml", "http://http-only.nginx-proxy.test/", 200, None),
("nodefault.yml", "https://http-only.nginx-proxy.test/", None, INTERNAL_ERR_RE),
("nodefault.yml", "http://missing-cert.nginx-proxy.test/", 200, None),
("nodefault.yml", "https://missing-cert.nginx-proxy.test/", None, INTERNAL_ERR_RE),
("nodefault.yml", "http://unknown.nginx-proxy.test/", 503, None),
("nodefault.yml", "https://unknown.nginx-proxy.test/", None, INTERNAL_ERR_RE),
# HTTPS_METHOD=nohttp on nginx-proxy, HTTPS_METHOD unset on the app container.
("nohttp.yml", "http://https-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
("nohttp.yml", "https://https-only.nginx-proxy.test/", 200, None),
("nohttp.yml", "http://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
("nohttp.yml", "https://unknown.nginx-proxy.test/", 503, None),
# HTTPS_METHOD=redirect on nginx-proxy, HTTPS_METHOD=nohttp on the app container.
("nohttp-on-app.yml", "http://https-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
("nohttp-on-app.yml", "https://https-only.nginx-proxy.test/", 200, None),
("nohttp-on-app.yml", "http://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
("nohttp-on-app.yml", "https://unknown.nginx-proxy.test/", 503, None),
# Same as nohttp.yml, except there is a vhost with a missing cert. This causes its
# HTTPS_METHOD=nohttp setting to effectively become HTTPS_METHOD=noredirect. This means that
# there will be a plain http server solely to support that vhost, so http requests to other
# vhosts get a 503, not a connection refused error.
("nohttp-with-missing-cert.yml", "http://https-only.nginx-proxy.test/", 503, None),
("nohttp-with-missing-cert.yml", "https://https-only.nginx-proxy.test/", 200, None),
("nohttp-with-missing-cert.yml", "http://missing-cert.nginx-proxy.test/", 200, None),
("nohttp-with-missing-cert.yml", "https://missing-cert.nginx-proxy.test/", 500, None),
("nohttp-with-missing-cert.yml", "http://unknown.nginx-proxy.test/", 503, None),
("nohttp-with-missing-cert.yml", "https://unknown.nginx-proxy.test/", 503, None),
# HTTPS_METHOD=nohttps on nginx-proxy, HTTPS_METHOD unset on the app container.
("nohttps.yml", "http://http-only.nginx-proxy.test/", 200, None),
("nohttps.yml", "https://http-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
("nohttps.yml", "http://unknown.nginx-proxy.test/", 503, None),
("nohttps.yml", "https://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
# HTTPS_METHOD=redirect on nginx-proxy, HTTPS_METHOD=nohttps on the app container.
("nohttps-on-app.yml", "http://http-only.nginx-proxy.test/", 200, None),
("nohttps-on-app.yml", "https://http-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
("nohttps-on-app.yml", "http://unknown.nginx-proxy.test/", 503, None),
("nohttps-on-app.yml", "https://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE),
# Custom nginx config that has a `server` directive that uses `default_server` and simply
# returns 418. Nginx should successfully start (in particular, the `default_server` in the
# custom config should not conflict with the fallback server generated by nginx-proxy) and nginx
# should prefer that server for handling requests for unknown vhosts.
("custom-fallback.yml", "http://unknown.nginx-proxy.test/", 418, None),
])
def test_fallback(get, url, want_code, want_err_re):
if want_err_re is None:
r = get(url)
assert r.status_code == want_code
else:
with pytest.raises(requests.exceptions.RequestException, match=want_err_re):
get(url)

View file

@ -30,6 +30,19 @@ def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy):
assert "X-Forwarded-Proto: f00\n" in r.text assert "X-Forwarded-Proto: f00\n" in r.text
##### Testing the handling of X-Forwarded-Host #####
def test_X_Forwarded_Host_is_generated(docker_compose, nginxproxy):
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
assert r.status_code == 200
assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text
def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy):
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'})
assert r.status_code == 200
assert "X-Forwarded-Host: example.com\n" in r.text
##### Testing the handling of X-Forwarded-Port ##### ##### Testing the handling of X-Forwarded-Port #####
def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy): def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy):

View file

@ -33,6 +33,19 @@ def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy):
assert "X-Forwarded-Proto: f00\n" in r.text assert "X-Forwarded-Proto: f00\n" in r.text
##### Testing the handling of X-Forwarded-Host #####
def test_X_Forwarded_Host_is_generated(docker_compose, nginxproxy):
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
assert r.status_code == 200
assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text
def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy):
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'})
assert r.status_code == 200
assert "X-Forwarded-Host: example.com\n" in r.text
##### Testing the handling of X-Forwarded-Port ##### ##### Testing the handling of X-Forwarded-Port #####
def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy): def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy):

31
test/test_keepalive.py Normal file
View file

@ -0,0 +1,31 @@
import re
def test_keepalive_disabled(docker_compose, nginxproxy):
r = nginxproxy.get("http://keepalive-disabled.nginx-proxy.test/headers")
assert r.status_code == 200
assert re.search(fr'(?m)^(?i:Connection): close$', r.text)
def test_keepalive_disabled_other_headers_ok(docker_compose, nginxproxy):
"""Make sure the other proxy_set_header headers are still set.
According to the nginx docs [1], any proxy_set_header directive in a block
disables inheritance of proxy_set_header directives in a parent block. Make
sure that doesn't happen.
[1] https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
"""
r = nginxproxy.get("http://keepalive-disabled.nginx-proxy.test/headers")
assert r.status_code == 200
assert re.search(fr'(?m)^(?i:X-Real-IP): ', r.text)
def test_keepalive_enabled(docker_compose, nginxproxy):
r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers")
assert r.status_code == 200
assert not re.search(fr'(?m)^(?i:Connection):', r.text)
def test_keepalive_enabled_other_headers_ok(docker_compose, nginxproxy):
"""See the docstring for the disabled case above."""
r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers")
assert r.status_code == 200
assert re.search(fr'(?m)^(?i:X-Real-IP): ', r.text)

25
test/test_keepalive.yml Normal file
View file

@ -0,0 +1,25 @@
keepalive-disabled:
image: web
expose:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: keepalive-disabled.nginx-proxy.test
keepalive-enabled:
image: web
expose:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: keepalive-enabled.nginx-proxy.test
labels:
com.github.nginx-proxy.nginx-proxy.keepalive: "64"
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
HTTPS_METHOD: nohttps

View file

@ -0,0 +1,16 @@
import pytest
import re
def test_loadbalance_hash(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII')
r1 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld")
r2 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld")
assert re.search(r"hash \$remote_addr\;", conf)
assert r1.status_code == 200
assert r2.text == r1.text
def test_loadbalance_roundrobin(docker_compose, nginxproxy):
r1 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld")
r2 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld")
assert r1.status_code == 200
assert r2.text != r1.text

View file

@ -0,0 +1,27 @@
services:
loadbalance-hash:
image: web
expose:
- "81"
environment:
WEB_PORTS: 81
VIRTUAL_HOST: loadbalance-enabled.nginx-proxy.tld
labels:
com.github.nginx-proxy.nginx-proxy.loadbalance: "hash $$remote_addr;"
deploy:
replicas: 2
loadbalance-roundrobin:
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: loadbalance-disabled.nginx-proxy.tld
deploy:
replicas: 2
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro

View file

@ -0,0 +1,39 @@
def test_explicit_root_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/port")
assert r.status_code == 418
r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/foo/port")
assert r.status_code == 200
assert r.text == "answer from port 82\n"
def test_explicit_root_hash(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/port")
assert r.status_code == 418
r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/foo/port")
assert r.status_code == 200
assert r.text == "answer from port 82\n"
def test_explicit_root_hash_and_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/port")
assert r.status_code == 418
r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/foo/port")
assert r.status_code == 200
assert r.text == "answer from port 82\n"
def test_explicit_nonroot(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/port")
assert r.status_code == 200
assert r.text == "answer from port 81\n"
r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/foo/port")
assert r.status_code == 418
def test_implicit_root_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://implicit-root-nohash.nginx-proxy.test/port")
assert r.status_code == 418
def test_implicit_root_hash(docker_compose, nginxproxy):
r = nginxproxy.get("http://implicit-root-hash.nginx-proxy.test/port")
assert r.status_code == 418
def test_implicit_root_hash_and_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://implicit-root-hash-and-nohash.nginx-proxy.test/port")
assert r.status_code == 418

View file

@ -0,0 +1,4 @@
# This file should trump the file without the hash.
location / {
return 418;
}

View file

@ -0,0 +1,4 @@
# The file with the hash should trump this file.
location / {
return 503;
}

View file

@ -0,0 +1,3 @@
location / {
return 418;
}

View file

@ -0,0 +1,4 @@
# This file should trump the file without the hash.
location / {
return 418;
}

View file

@ -0,0 +1,4 @@
# The file with the hash should trump this file.
location / {
return 503;
}

View file

@ -0,0 +1,3 @@
location / {
return 418;
}

View file

@ -0,0 +1,44 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./test_location-override.vhost.d:/etc/nginx/vhost.d:ro
explicit-root:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
VIRTUAL_HOST: >-
explicit-root-nohash.nginx-proxy.test,
explicit-root-hash.nginx-proxy.test,
explicit-root-hash-and-nohash.nginx-proxy.test,
explicit-nonroot.nginx-proxy.test
VIRTUAL_PATH: /
explicit-foo:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: >-
explicit-root-nohash.nginx-proxy.test,
explicit-root-hash.nginx-proxy.test,
explicit-root-hash-and-nohash.nginx-proxy.test,
explicit-nonroot.nginx-proxy.test
VIRTUAL_PATH: /foo/
VIRTUAL_DEST: /
# Same as explicit-root except VIRTUAL_PATH is left unset.
implicit-root:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: >-
implicit-root-nohash.nginx-proxy.test,
implicit-root-hash.nginx-proxy.test,
implicit-root-hash-and-nohash.nginx-proxy.test,

11
test/test_log_format.py Normal file
View file

@ -0,0 +1,11 @@
import pytest
def test_log_format(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy.test/port")
assert r.status_code == 200
assert r.text == "answer from port 81\n"
sut_container = docker_compose.containers.get("sut")
docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
docker_logs = docker_logs.decode("utf-8").splitlines()
docker_logs = [line for line in docker_logs if "GET /port" in line]
assert "request_time=" in docker_logs[0]

15
test/test_log_format.yml Normal file
View file

@ -0,0 +1,15 @@
web1:
image: web
expose:
- "81"
environment:
WEB_PORTS: 81
VIRTUAL_HOST: nginx-proxy.test
sut:
container_name: sut
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
LOG_FORMAT: "$$remote_addr - $$remote_user [$$time_local] \"$$request\" $$status $$body_bytes_sent \"$$http_referer\" \"$$http_user_agent\" request_time=$$request_time $$upstream_response_time"

View file

@ -1,5 +1,8 @@
import re
import pytest import pytest
def test_unknown_virtual_host(docker_compose, nginxproxy): def test_unknown_virtual_host(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy/") r = nginxproxy.get("http://nginx-proxy/")
assert r.status_code == 503 assert r.status_code == 503
@ -13,3 +16,13 @@ def test_forwards_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.local/port") r = nginxproxy.get("http://web2.nginx-proxy.local/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 82\n" assert r.text == "answer from port 82\n"
def test_multipath(docker_compose, nginxproxy):
r = nginxproxy.get("http://web3.nginx-proxy.test/port")
assert r.status_code == 200
assert r.text == "answer from port 83\n"
cfg = nginxproxy.get_conf().decode()
lines = cfg.splitlines()
web3_server_lines = [l for l in lines
if re.search(r'(?m)^\s*server\s+[^\s]*:83;\s*$', l)]
assert len(web3_server_lines) == 1

View file

@ -3,6 +3,8 @@ version: '2'
networks: networks:
net1: {} net1: {}
net2: {} net2: {}
net3a: {}
net3b: {}
services: services:
nginx-proxy: nginx-proxy:
@ -12,6 +14,8 @@ services:
networks: networks:
- net1 - net1
- net2 - net2
- net3a
- net3b
web1: web1:
image: web image: web
@ -32,3 +36,14 @@ services:
VIRTUAL_HOST: web2.nginx-proxy.local VIRTUAL_HOST: web2.nginx-proxy.local
networks: networks:
- net2 - net2
web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: web3.nginx-proxy.test
networks:
- net3a
- net3b

View file

@ -1,6 +1,5 @@
import re import re
import subprocess import subprocess
import os
import backoff import backoff
import docker import docker
@ -219,7 +218,7 @@ def test_custom_dhparam_is_supported(docker_compose):
# Only `web2` has a site-specific DH param file (which overrides all other DH config) # Only `web2` has a site-specific DH param file (which overrides all other DH config)
# Other tests here use `web5` explicitly, or implicitly (via ENV `DEFAULT_HOST`, otherwise first HTTPS server) # Other tests here use `web5` explicitly, or implicitly (via ENV `DEFAULT_HOST`, otherwise first HTTPS server)
def test_custom_dhparam_is_supported_per_site(docker_compose): def test_custom_dhparam_is_supported_per_site(docker_compose, ca_root_certificate):
container_name="dh-file" container_name="dh-file"
sut_container = docker_client.containers.get(container_name) sut_container = docker_client.containers.get(container_name)
assert sut_container.status == "running" assert sut_container.status == "running"
@ -242,7 +241,7 @@ def test_custom_dhparam_is_supported_per_site(docker_compose):
# - `web2` has it's own cert provisioned at `/etc/nginx/certs/web2.nginx-proxy.tld.crt`. # - `web2` has it's own cert provisioned at `/etc/nginx/certs/web2.nginx-proxy.tld.crt`.
can_verify_chain_of_trust( can_verify_chain_of_trust(
sut_container, sut_container,
ca_cert = f"{os.getcwd()}/certs/ca-root.crt", ca_cert = ca_root_certificate,
fqdn = 'web2.nginx-proxy.tld' fqdn = 'web2.nginx-proxy.tld'
) )

View file

@ -1,9 +1,10 @@
import pytest import pytest
import requests
def test_web2_http_is_not_forwarded(docker_compose, nginxproxy): def test_web2_http_is_connection_refused(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.tld/", allow_redirects=False) with pytest.raises(requests.exceptions.RequestException, match="Connection refused"):
assert r.status_code == 503 nginxproxy.get("http://web2.nginx-proxy.tld/")
def test_web2_https_is_forwarded(docker_compose, nginxproxy): def test_web2_https_is_forwarded(docker_compose, nginxproxy):

View file

@ -24,10 +24,10 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain):
assert f"answer from port 8{subdomain}\n" == r.text assert f"answer from port 8{subdomain}\n" == r.text
@pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning') @pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning')
def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy): def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose, nginxproxy):
with pytest.raises( (CertificateError, SSLError) ) as excinfo: with pytest.raises( (CertificateError, SSLError) ) as excinfo:
nginxproxy.get("https://3.web.nginx-proxy.tld/port") nginxproxy.get("https://3.web.nginx-proxy.tld/port")
assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) assert """certificate is not valid for '3.web.nginx-proxy.tld'""" in str(excinfo.value)
r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False)
assert r.status_code == 500 assert r.status_code == 503

View file

@ -0,0 +1,70 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
Validity
Not Before: Jan 13 03:06:39 2017 GMT
Not After : May 31 03:06:39 2044 GMT
Subject: CN=web.nginx-proxy.tld
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:95:56:c7:0d:48:a5:2b:3c:65:49:3f:26:e1:38:
2b:61:30:56:e4:92:d7:63:e0:eb:ad:ac:f9:33:9b:
b2:31:f1:39:13:0b:e5:43:7b:c5:bd:8a:85:c8:d9:
3d:d8:ac:71:ba:16:e7:81:96:b2:ab:ae:c6:c0:bd:
be:a7:d1:96:8f:b2:9b:df:ba:f9:4d:a1:3b:7e:21:
4a:cd:b6:45:f9:6d:79:50:bf:24:8f:c1:6b:c1:09:
19:5b:62:cb:96:e8:04:14:20:e8:d4:16:62:6a:f2:
37:c1:96:e2:9d:53:05:0b:52:1d:e7:68:92:db:8b:
36:68:cd:8d:5b:02:ff:12:f0:ac:5d:0c:c4:e0:7a:
55:a2:49:60:9f:ff:47:1f:52:73:55:4d:d4:f2:d1:
62:a2:f4:50:9d:c9:f6:f1:43:b3:dc:57:e1:31:76:
b4:e0:a4:69:7e:f2:6d:34:ae:b9:8d:74:26:7b:d9:
f6:07:00:ef:4b:36:61:b3:ef:7a:a1:36:3a:b6:d0:
9e:f8:b8:a9:0d:4c:30:a2:ed:eb:ab:6b:eb:2e:e2:
0b:28:be:f7:04:b1:e9:e0:84:d6:5d:31:77:7c:dc:
d2:1f:d4:1d:71:6f:6f:6c:6d:1b:bf:31:e2:5b:c3:
52:d0:14:fc:8b:fb:45:ea:41:ec:ca:c7:3b:67:12:
c4:df
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:web.nginx-proxy.tld
Signature Algorithm: sha256WithRSAEncryption
4e:48:7d:81:66:ba:2f:50:3d:24:42:61:3f:1f:de:cf:ec:1b:
1b:bd:0a:67:b6:62:c8:79:9d:31:a0:fd:a9:61:ce:ff:69:bf:
0e:f4:f7:e6:15:2b:b0:f0:e4:f2:f4:d2:8f:74:02:b1:1e:4a:
a8:6f:26:0a:77:32:29:cf:dc:b5:61:82:3e:58:47:61:92:f0:
0c:20:25:f8:41:4d:34:09:44:bc:39:9e:aa:82:06:83:13:8b:
1e:2c:3d:cf:cd:1a:f7:77:39:38:e0:a3:a7:f3:09:da:02:8d:
73:75:38:b4:dd:24:a7:f9:03:db:98:c6:88:54:87:dc:e0:65:
4c:95:c5:39:9c:00:30:dc:f0:d3:2c:19:ca:f1:f4:6c:c6:d9:
b5:c4:4a:c7:bc:a1:2e:88:7b:b5:33:d0:ff:fb:48:5e:3e:29:
fa:58:e5:03:de:d8:17:de:ed:96:fc:7e:1f:fe:98:f6:be:99:
38:87:51:c0:d3:b7:9a:0f:26:92:e5:53:1b:d6:25:4c:ac:48:
f3:29:fc:74:64:9d:07:6a:25:57:24:aa:a7:70:fa:8f:6c:a7:
2b:b7:9d:81:46:10:32:93:b9:45:6d:0f:16:18:b2:21:1f:f3:
30:24:62:3f:e1:6c:07:1d:71:28:cb:4c:bb:f5:39:05:f9:b2:
5b:a0:05:1b
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
ZDAeFw0xNzAxMTMwMzA2MzlaFw00NDA1MzEwMzA2MzlaMB4xHDAaBgNVBAMME3dl
Yi5uZ2lueC1wcm94eS50bGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQCVVscNSKUrPGVJPybhOCthMFbkktdj4OutrPkzm7Ix8TkTC+VDe8W9ioXI2T3Y
rHG6FueBlrKrrsbAvb6n0ZaPspvfuvlNoTt+IUrNtkX5bXlQvySPwWvBCRlbYsuW
6AQUIOjUFmJq8jfBluKdUwULUh3naJLbizZozY1bAv8S8KxdDMTgelWiSWCf/0cf
UnNVTdTy0WKi9FCdyfbxQ7PcV+ExdrTgpGl+8m00rrmNdCZ72fYHAO9LNmGz73qh
Njq20J74uKkNTDCi7eura+su4gsovvcEsenghNZdMXd83NIf1B1xb29sbRu/MeJb
w1LQFPyL+0XqQezKxztnEsTfAgMBAAGjIjAgMB4GA1UdEQQXMBWCE3dlYi5uZ2lu
eC1wcm94eS50bGQwDQYJKoZIhvcNAQELBQADggEBAE5IfYFmui9QPSRCYT8f3s/s
Gxu9Cme2Ysh5nTGg/alhzv9pvw709+YVK7Dw5PL00o90ArEeSqhvJgp3MinP3LVh
gj5YR2GS8AwgJfhBTTQJRLw5nqqCBoMTix4sPc/NGvd3OTjgo6fzCdoCjXN1OLTd
JKf5A9uYxohUh9zgZUyVxTmcADDc8NMsGcrx9GzG2bXESse8oS6Ie7Uz0P/7SF4+
KfpY5QPe2Bfe7Zb8fh/+mPa+mTiHUcDTt5oPJpLlUxvWJUysSPMp/HRknQdqJVck
qqdw+o9spyu3nYFGEDKTuUVtDxYYsiEf8zAkYj/hbAcdcSjLTLv1OQX5slugBRs=
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAlVbHDUilKzxlST8m4TgrYTBW5JLXY+Drraz5M5uyMfE5Ewvl
Q3vFvYqFyNk92KxxuhbngZayq67GwL2+p9GWj7Kb37r5TaE7fiFKzbZF+W15UL8k
j8FrwQkZW2LLlugEFCDo1BZiavI3wZbinVMFC1Id52iS24s2aM2NWwL/EvCsXQzE
4HpVoklgn/9HH1JzVU3U8tFiovRQncn28UOz3FfhMXa04KRpfvJtNK65jXQme9n2
BwDvSzZhs+96oTY6ttCe+LipDUwwou3rq2vrLuILKL73BLHp4ITWXTF3fNzSH9Qd
cW9vbG0bvzHiW8NS0BT8i/tF6kHsysc7ZxLE3wIDAQABAoIBAEmK7IecKMq7+V0y
3mC3GpXICmKR9cRX9XgX4LkLiZuSoXrBtuuevmhzGSMp6I0VjwQHV4a3wdFORs6Q
Ip3eVvj5Ck4Jc9BJAFVC6+WWR6tnwACFwOmSZRAw/O3GH2B3bdrDwiT/yQPFuLN7
LKoxQiCrFdLp6rh3PBosb9pMBXU7k/HUazIdgmSKg6/JIoo/4Gwyid04TF/4MI2l
RscxtP5/ANtS8VgwBEqhgdafRJ4KnLEpgvswgIQvUKmduVhZQlzd0LMY8FbhKVqz
Utg8gsXaTyH6df/nmgUIInxLMz/MKPnMkv99fS6Sp/hvYlGpLZFWBJ6unMq3lKEr
LMbHfIECgYEAxB+5QWdVqG2r9loJlf8eeuNeMPml4P8Jmi5RKyJC7Cww6DMlMxOS
78ZJfl4b3ZrWuyvhjOfX/aTq7kQaF1BI9o3KJBH8k6EtO4gI8KeNmDONyQk9zsrn
ru8Zwr7hVbAo8fCXxCnmPzhDLsYg6f3BVOsQWoX2SFYKZ1GvkPfIReECgYEAwu6G
qtgFb57Vim10ecfWGM6vrPxvyfqP+zlH/p4nR+aQ+2sFbt27D0B1byWBRZe4KQyw
Vq6XiQ09Fk6MJr8E8iAr9GXPPHcqlYI6bbNc6YOP3jVSKut0tQdTUOHll4kYIY+h
RS3VA3+BA//ADpWpywu+7RZRbaIECA+U2a224r8CgYB5PCMIixgoRaNHZeEHF+1/
iY1wOOKRcxY8eOU0BLnZxHd3EiasrCzoi2pi80nGczDKAxYqRCcAZDHVl8OJJdf0
kTGjmnrHx5pucmkUWn7s1vGOlGfgrQ0K1kLWX6hrj7m/1Tn7yOrLqbvd7hvqiTI5
jBVP3/+eN5G2zIf61TC4AQKBgCX2Q92jojNhsF58AHHy+/vqzIWYx8CC/mVDe4TX
kfjLqzJ7XhyAK/zFZdlWaX1/FYtRAEpxR+uV226rr1mgW7s3jrfS1/ADmRRyvyQ8
CP0k9PCmW7EmF51lptEanRbMyRlIGnUZfuFmhF6eAO4WMXHsgKs1bHg4VCapuihG
T1aLAoGACRGn1UxFuBGqtsh2zhhsBZE7GvXKJSk/eP7QJeEXUNpNjCpgm8kIZM5K
GorpL7PSB8mwVlDl18TpMm3P7nz6YkJYte+HdjO7pg59H39Uvtg3tZnIrFxNxVNb
YF62/yHfk2AyTgjQZQUSmDS84jq1zUK4oS90lxr+u8qwELTniMs=
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,25 @@
import pytest
import re
@pytest.mark.parametrize('url,header,input,want', [
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'),
])
def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want):
kwargs = {} if input is None else {'headers': {header: input}}
r = nginxproxy.get(url, **kwargs)
assert r.status_code == 200
assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text)

View file

@ -0,0 +1,16 @@
web:
image: web
expose:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: web.nginx-proxy.tld
HTTPS_METHOD: noredirect
sut:
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
- ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro

View file

@ -0,0 +1,25 @@
import pytest
import re
@pytest.mark.parametrize('url,header,input,want', [
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'http'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'https'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'web.nginx-proxy.tld'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'web.nginx-proxy.tld'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '80'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '443'),
])
def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want):
kwargs = {} if input is None else {'headers': {header: input}}
r = nginxproxy.get(url, **kwargs)
assert r.status_code == 200
assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text)

View file

@ -0,0 +1,18 @@
web:
image: web
expose:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: web.nginx-proxy.tld
HTTPS_METHOD: noredirect
sut:
image: nginxproxy/nginx-proxy:test
environment:
TRUST_DOWNSTREAM_PROXY: "false"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro
- ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro

View file

@ -0,0 +1,25 @@
import pytest
import re
@pytest.mark.parametrize('url,header,input,want', [
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'),
('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'),
('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'),
])
def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want):
kwargs = {} if input is None else {'headers': {header: input}}
r = nginxproxy.get(url, **kwargs)
assert r.status_code == 200
assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text)

View file

@ -0,0 +1,18 @@
web:
image: web
expose:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: web.nginx-proxy.tld
HTTPS_METHOD: noredirect
sut:
image: nginxproxy/nginx-proxy:test
environment:
TRUST_DOWNSTREAM_PROXY: "true"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro
- ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro

View file

@ -0,0 +1,10 @@
import re
def test_vhost_empty_string(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode()
assert re.search(r"(?m)^\s*server_name\s+web2\.nginx-proxy\.test\s*;", conf)
assert re.search(r"(?m)^\s*server_name\s+web3\.nginx-proxy\.test\s*;", conf)
assert re.search(r"(?m)^\s*server_name\s+web4a\.nginx-proxy\.test\s*;", conf)
assert re.search(r"(?m)^\s*server_name\s+web4b\.nginx-proxy\.test\s*;", conf)
assert not re.search(r"(?m)^\s*server_name\s*;", conf)

View file

@ -0,0 +1,37 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
web1:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
# The space is intentional (should be trimmed).
VIRTUAL_HOST: " "
web2:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
# The space is intentional (should be trimmed).
VIRTUAL_HOST: "web2.nginx-proxy.test ,"
web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
# The space is intentional (should be trimmed).
VIRTUAL_HOST: " ,web3.nginx-proxy.test"
web4:
image: web
expose:
- "84"
environment:
WEB_PORTS: "84"
# The spaces are intentional (should be trimmed).
VIRTUAL_HOST: "web4a.nginx-proxy.test, , web4b.nginx-proxy.test"

View file

@ -0,0 +1,29 @@
import pytest
import logging
import time
def test_forwards_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.local/port")
assert r.status_code == 200
assert r.text == "answer from port 81\n"
def test_nginx_config_remains_the_same_after_restart(docker_compose, nginxproxy):
"""
Restarts the Web container and returns nginx-proxy config after restart
"""
def get_conf_after_web_container_restart():
web_containers = docker_compose.containers.list(filters={"ancestor": "web:latest"})
assert len(web_containers) == 1
web_containers[0].restart()
time.sleep(3)
return nginxproxy.get_conf()
config_before_restart = nginxproxy.get_conf()
for i in range(1, 8):
logging.info(f"Checking for the {i}-st time that config is the same")
config_after_restart = get_conf_after_web_container_restart()
if config_before_restart != config_after_restart:
logging.debug(f"{config_before_restart!r} \n\n {config_after_restart!r}")
pytest.fail("nginx-proxy config before and after restart of a web container does not match", pytrace=False)

View file

@ -0,0 +1,26 @@
version: '2'
networks:
net1: {}
net2: {}
net3: {}
services:
nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
- net1
web:
image: web
expose:
- "81"
environment:
WEB_PORTS: 81
VIRTUAL_HOST: web1.nginx-proxy.local
networks:
- net1
- net2
- net3