mirror of
https://github.com/thib8956/nginx-proxy
synced 2025-02-24 09:48:14 +00:00
Merge branch 'main' into remove_scoped
This commit is contained in:
commit
65a88a0291
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@ -1,9 +1,5 @@
|
||||
# !!!PLEASE READ!!!
|
||||
|
||||
## Questions
|
||||
|
||||
If you have a question, DO NOT SUBMIT a new issue. Please ask the question on the Q&A Group: https://groups.google.com/forum/#!forum/nginx-proxy
|
||||
|
||||
## Bugs or Features
|
||||
|
||||
If you are logging a bug or feature request, please search the current open issues to see if there is already a bug or feature opened.
|
||||
|
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
# Maintain dependencies for Docker
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- "area/chore"
|
||||
- "area/dockerfile"
|
114
.github/workflows/dockerhub.yml
vendored
Normal file
114
.github/workflows/dockerhub.yml
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
name: DockerHub
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 1'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- '*.*.*'
|
||||
paths-ignore:
|
||||
- 'test/*'
|
||||
- '.gitignore'
|
||||
- '.travis.yml'
|
||||
- 'docker-compose-separate-containers.yml'
|
||||
- 'docker-compose.yml'
|
||||
- 'LICENSE'
|
||||
- 'Makefile'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
multiarch-build-debian:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Docker tags for Debian based image
|
||||
id: docker_meta_debian
|
||||
uses: crazy-max/ghaction-docker-meta@v2
|
||||
with:
|
||||
images: |
|
||||
nginxproxy/nginx-proxy
|
||||
jwilder/nginx-proxy
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push the Debian based image
|
||||
id: docker_build_debian
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
file: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ steps.docker_meta_debian.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta_debian.outputs.labels }}
|
||||
|
||||
- name: Images digests
|
||||
run: echo ${{ steps.docker_build_debian.outputs.digest }}
|
||||
|
||||
multiarch-build-alpine:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Docker tags for Alpine based image
|
||||
id: docker_meta_alpine
|
||||
uses: crazy-max/ghaction-docker-meta@v2
|
||||
with:
|
||||
images: |
|
||||
nginxproxy/nginx-proxy
|
||||
jwilder/nginx-proxy
|
||||
tags: |
|
||||
type=semver,suffix=-alpine,pattern={{version}}
|
||||
type=semver,suffix=-alpine,pattern={{major}}.{{minor}}
|
||||
type=raw,value=alpine,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
|
||||
flavor: latest=false
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push the Alpine based image
|
||||
id: docker_build_alpine
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
file: Dockerfile.alpine
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ steps.docker_meta_alpine.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta_alpine.outputs.labels }}
|
||||
|
||||
- name: Images digests
|
||||
run: echo ${{ steps.docker_build_alpine.outputs.digest }}
|
37
.github/workflows/test.yml
vendored
Normal file
37
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
name: Unit Test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
base_docker_image: [alpine, debian]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r python-requirements.txt
|
||||
working-directory: test/requirements
|
||||
|
||||
- name: Build Docker web server image
|
||||
run: make build-webserver
|
||||
|
||||
- name: Build Docker nginx proxy test image
|
||||
run: make build-nginx-proxy-test-${{ matrix.base_docker_image }}
|
||||
|
||||
- name: Run tests
|
||||
run: pytest
|
||||
working-directory: test
|
22
.travis.yml
22
.travis.yml
@ -1,22 +0,0 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- TEST_TARGET: test-debian
|
||||
- TEST_TARGET: test-alpine
|
||||
|
||||
before_install:
|
||||
- sudo apt-get -y remove docker docker-engine docker-ce
|
||||
- sudo rm /etc/apt/sources.list.d/docker.list
|
||||
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install docker-ce
|
||||
- docker version
|
||||
- docker info
|
||||
# prepare docker test requirements
|
||||
- make update-dependencies
|
||||
|
||||
script:
|
||||
- make $TEST_TARGET
|
63
Dockerfile
63
Dockerfile
@ -1,5 +1,46 @@
|
||||
FROM nginx:1.19.3
|
||||
LABEL maintainer="Jason Wilder mail@jasonwilder.com"
|
||||
# setup build arguments for version of dependencies to use
|
||||
ARG DOCKER_GEN_VERSION=0.7.6
|
||||
ARG FOREGO_VERSION=0.16.1
|
||||
|
||||
# Use a specific version of golang to build both binaries
|
||||
FROM golang:1.15.10 as gobuilder
|
||||
|
||||
# Build docker-gen from scratch
|
||||
FROM gobuilder as dockergen
|
||||
|
||||
ARG DOCKER_GEN_VERSION
|
||||
|
||||
RUN git clone https://github.com/jwilder/docker-gen \
|
||||
&& cd /go/docker-gen \
|
||||
&& git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \
|
||||
&& go mod download \
|
||||
&& CGO_ENABLED=0 GOOS=linux go build -ldflags "-X main.buildVersion=${DOCKER_GEN_VERSION}" ./cmd/docker-gen \
|
||||
&& go clean -cache \
|
||||
&& mv docker-gen /usr/local/bin/ \
|
||||
&& cd - \
|
||||
&& rm -rf /go/docker-gen
|
||||
|
||||
# Build forego from scratch
|
||||
# Because this relies on golang workspaces, we need to use go < 1.8.
|
||||
FROM gobuilder as forego
|
||||
|
||||
# Download the sources for the given version
|
||||
ARG FOREGO_VERSION
|
||||
ADD https://github.com/jwilder/forego/archive/v${FOREGO_VERSION}.tar.gz sources.tar.gz
|
||||
|
||||
# Move the sources into the right directory
|
||||
RUN tar -xzf sources.tar.gz && \
|
||||
mkdir -p /go/src/github.com/ddollar/ && \
|
||||
mv forego-* /go/src/github.com/ddollar/forego
|
||||
|
||||
# Install the dependencies and make the forego executable
|
||||
WORKDIR /go/src/github.com/ddollar/forego/
|
||||
RUN go get -v ./... && \
|
||||
CGO_ENABLED=0 GOOS=linux go build -o forego .
|
||||
|
||||
# Build the final image
|
||||
FROM nginx:1.19.10
|
||||
LABEL maintainer="Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag)"
|
||||
|
||||
# Install wget and install/updates certificates
|
||||
RUN apt-get update \
|
||||
@ -12,17 +53,17 @@ RUN apt-get update \
|
||||
|
||||
# Configure Nginx and apply fix for very long server names
|
||||
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
|
||||
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
|
||||
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \
|
||||
&& sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf
|
||||
|
||||
# Install Forego
|
||||
ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego
|
||||
RUN chmod u+x /usr/local/bin/forego
|
||||
# Install Forego + docker-gen
|
||||
COPY --from=forego /go/src/github.com/ddollar/forego/forego /usr/local/bin/forego
|
||||
COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen
|
||||
|
||||
ENV DOCKER_GEN_VERSION 0.7.4
|
||||
|
||||
RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
|
||||
&& tar -C /usr/local/bin -xvzf docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
|
||||
&& rm /docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz
|
||||
# Add DOCKER_GEN_VERSION environment variable
|
||||
# Because some external projects rely on it
|
||||
ARG DOCKER_GEN_VERSION
|
||||
ENV DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION}
|
||||
|
||||
COPY network_internal.conf /etc/nginx/
|
||||
|
||||
|
@ -1,5 +1,46 @@
|
||||
FROM nginx:1.19.3-alpine
|
||||
LABEL maintainer="Jason Wilder mail@jasonwilder.com"
|
||||
# setup build arguments for version of dependencies to use
|
||||
ARG DOCKER_GEN_VERSION=0.7.6
|
||||
ARG FOREGO_VERSION=0.16.1
|
||||
|
||||
# Use a specific version of golang to build both binaries
|
||||
FROM golang:1.15.10-alpine as gobuilder
|
||||
RUN apk add --no-cache git
|
||||
|
||||
# Build docker-gen from scratch
|
||||
FROM gobuilder as dockergen
|
||||
|
||||
ARG DOCKER_GEN_VERSION
|
||||
|
||||
RUN git clone https://github.com/jwilder/docker-gen \
|
||||
&& cd /go/docker-gen \
|
||||
&& git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \
|
||||
&& go mod download \
|
||||
&& CGO_ENABLED=0 go build -ldflags "-X main.buildVersion=${DOCKER_GEN_VERSION}" ./cmd/docker-gen \
|
||||
&& go clean -cache \
|
||||
&& mv docker-gen /usr/local/bin/ \
|
||||
&& cd - \
|
||||
&& rm -rf /go/docker-gen
|
||||
|
||||
# Build forego from scratch
|
||||
FROM gobuilder as forego
|
||||
|
||||
# Download the sources for the given version
|
||||
ARG FOREGO_VERSION
|
||||
ADD https://github.com/jwilder/forego/archive/v${FOREGO_VERSION}.tar.gz sources.tar.gz
|
||||
|
||||
# Move the sources into the right directory
|
||||
RUN tar -xzf sources.tar.gz && \
|
||||
mkdir -p /go/src/github.com/ddollar/ && \
|
||||
mv forego-* /go/src/github.com/ddollar/forego
|
||||
|
||||
# Install the dependencies and make the forego executable
|
||||
WORKDIR /go/src/github.com/ddollar/forego/
|
||||
RUN go get -v ./... && \
|
||||
CGO_ENABLED=0 GOOS=linux go build -o forego .
|
||||
|
||||
# Build the final image
|
||||
FROM nginx:1.19.10-alpine
|
||||
LABEL maintainer="Nicolas Duchon <nicolas.duchon@gmail.com> (@buchdag)"
|
||||
|
||||
# Install wget and install/updates certificates
|
||||
RUN apk add --no-cache --virtual .run-deps \
|
||||
@ -9,17 +50,17 @@ RUN apk add --no-cache --virtual .run-deps \
|
||||
|
||||
# Configure Nginx and apply fix for very long server names
|
||||
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
|
||||
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
|
||||
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \
|
||||
&& sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf
|
||||
|
||||
# Install Forego
|
||||
ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego
|
||||
RUN chmod u+x /usr/local/bin/forego
|
||||
# Install Forego + docker-gen
|
||||
COPY --from=forego /go/src/github.com/ddollar/forego/forego /usr/local/bin/forego
|
||||
COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen
|
||||
|
||||
ENV DOCKER_GEN_VERSION 0.7.4
|
||||
|
||||
RUN wget --quiet https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
|
||||
&& tar -C /usr/local/bin -xvzf docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
|
||||
&& rm /docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz
|
||||
# Add DOCKER_GEN_VERSION environment variable
|
||||
# Because some external projects rely on it
|
||||
ARG DOCKER_GEN_VERSION
|
||||
ENV DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION}
|
||||
|
||||
COPY network_internal.conf /etc/nginx/
|
||||
|
||||
|
16
Makefile
16
Makefile
@ -2,15 +2,19 @@
|
||||
.PHONY : test-debian test-alpine test
|
||||
|
||||
|
||||
update-dependencies:
|
||||
test/requirements/build.sh
|
||||
build-webserver:
|
||||
docker build -t web test/requirements/web
|
||||
|
||||
test-debian: update-dependencies
|
||||
docker build -t jwilder/nginx-proxy:test .
|
||||
build-nginx-proxy-test-debian:
|
||||
docker build -t nginxproxy/nginx-proxy:test .
|
||||
|
||||
build-nginx-proxy-test-alpine:
|
||||
docker build -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test .
|
||||
|
||||
test-debian: build-webserver build-nginx-proxy-test-debian
|
||||
test/pytest.sh
|
||||
|
||||
test-alpine: update-dependencies
|
||||
docker build -f Dockerfile.alpine -t jwilder/nginx-proxy:test .
|
||||
test-alpine: build-webserver build-nginx-proxy-test-alpine
|
||||
test/pytest.sh
|
||||
|
||||
test: test-debian test-alpine
|
||||
|
87
README.md
87
README.md
@ -1,5 +1,9 @@
|
||||

|
||||
  [](https://travis-ci.org/jwilder/nginx-proxy) [](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub')
|
||||
[](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml)
|
||||
[](https://github.com/nginx-proxy/nginx-proxy/releases)
|
||||

|
||||
[](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub")
|
||||
[](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub')
|
||||
[](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub')
|
||||
|
||||
|
||||
nginx-proxy sets up a container running nginx and [docker-gen][1]. docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped.
|
||||
@ -10,7 +14,7 @@ See [Automated Nginx Reverse Proxy for Docker][2] for why you might want to use
|
||||
|
||||
To run it:
|
||||
|
||||
$ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
|
||||
Then start any containers you want proxied with an env var `VIRTUAL_HOST=subdomain.youdomain.com`
|
||||
|
||||
@ -24,17 +28,17 @@ Provided your DNS is setup to forward foo.bar.com to the host running nginx-prox
|
||||
|
||||
The nginx-proxy images are available in two flavors.
|
||||
|
||||
#### jwilder/nginx-proxy:latest
|
||||
#### nginxproxy/nginx-proxy:latest
|
||||
|
||||
This image uses the debian:jessie based nginx image.
|
||||
This image uses the debian:buster based nginx image.
|
||||
|
||||
$ docker pull jwilder/nginx-proxy:latest
|
||||
$ docker pull nginxproxy/nginx-proxy:latest
|
||||
|
||||
#### jwilder/nginx-proxy:alpine
|
||||
#### nginxproxy/nginx-proxy:alpine
|
||||
|
||||
This image is based on the nginx:alpine image. Use this image to fully support HTTP/2 (including ALPN required by recent Chrome versions). A valid certificate is required as well (see eg. below "SSL Support using letsencrypt" for more info).
|
||||
This image is based on the nginx:alpine image. Use this image to fully support HTTP/2 (including ALPN required by recent Chrome versions). A valid certificate is required as well (see eg. below "SSL Support using an ACME CA" for more info).
|
||||
|
||||
$ docker pull jwilder/nginx-proxy:alpine
|
||||
$ docker pull nginxproxy/nginx-proxy:alpine
|
||||
|
||||
### Docker Compose
|
||||
|
||||
@ -43,7 +47,7 @@ version: '2'
|
||||
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy
|
||||
image: nginxproxy/nginx-proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
@ -51,8 +55,11 @@ services:
|
||||
|
||||
whoami:
|
||||
image: jwilder/whoami
|
||||
expose:
|
||||
- "8000"
|
||||
environment:
|
||||
- VIRTUAL_HOST=whoami.local
|
||||
- VIRTUAL_PORT=8000
|
||||
```
|
||||
|
||||
```shell
|
||||
@ -65,7 +72,7 @@ I'm 5b129ab83266
|
||||
|
||||
You can activate the IPv6 support for the nginx-proxy container by passing the value `true` to the `ENABLE_IPV6` environment variable:
|
||||
|
||||
$ docker run -d -p 80:80 -e ENABLE_IPV6=true -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -e ENABLE_IPV6=true -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
|
||||
#### Scoped IPv6 Resolvers
|
||||
|
||||
@ -98,7 +105,7 @@ If you want your `nginx-proxy` container to be attached to a different network,
|
||||
|
||||
```console
|
||||
$ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro \
|
||||
--name my-nginx-proxy --net my-network jwilder/nginx-proxy
|
||||
--name my-nginx-proxy --net my-network nginxproxy/nginx-proxy
|
||||
$ docker network connect my-other-network my-nginx-proxy
|
||||
```
|
||||
|
||||
@ -119,7 +126,7 @@ allow 172.16.0.0/12;
|
||||
deny all;
|
||||
```
|
||||
|
||||
When internal-only access is enabled, external clients with be denied with an `HTTP 403 Forbidden`
|
||||
When internal-only access is enabled, external clients will be denied with an `HTTP 403 Forbidden`
|
||||
|
||||
> If there is a load-balancer / reverse proxy in front of `nginx-proxy` that hides the client IP (example: AWS Application/Elastic Load Balancer), you will need to use the nginx `realip` module (already installed) to extract the client's IP from the HTTP request headers. Please see the [nginx realip module configuration](http://nginx.org/en/docs/http/ngx_http_realip_module.html) for more details. This configuration can be added to a new config file and mounted in `/etc/nginx/conf.d/`.
|
||||
|
||||
@ -150,8 +157,11 @@ If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory
|
||||
|
||||
To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example
|
||||
|
||||
$ docker run -d -p 80:80 -e DEFAULT_HOST=foo.bar.com -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -e DEFAULT_HOST=foo.bar.com -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
|
||||
nginx-proxy will then redirect all requests to a container where `VIRTUAL_HOST` is set to `DEFAULT_HOST`, if they don't match any (other) `VIRTUAL_HOST`. Using the example above requests without matching `VIRTUAL_HOST` will be redirected to a plain nginx instance after running the following command:
|
||||
|
||||
$ docker run -d -e VIRTUAL_HOST=foo.bar.com nginx
|
||||
|
||||
### Separate Containers
|
||||
|
||||
@ -168,7 +178,7 @@ $ curl -H "Host: whoami.local" localhost
|
||||
I'm 5b129ab83266
|
||||
```
|
||||
|
||||
To run nginx proxy as a separate container you'll need to have [nginx.tmpl](https://github.com/jwilder/nginx-proxy/blob/master/nginx.tmpl) on your host system.
|
||||
To run nginx proxy as a separate container you'll need to have [nginx.tmpl](https://github.com/nginx-proxy/nginx-proxy/blob/main/nginx.tmpl) on your host system.
|
||||
|
||||
First start nginx with a volume:
|
||||
|
||||
@ -187,9 +197,9 @@ $ docker run --volumes-from nginx \
|
||||
Finally, start your containers with `VIRTUAL_HOST` environment variables.
|
||||
|
||||
$ docker run -e VIRTUAL_HOST=foo.bar.com ...
|
||||
### SSL Support using letsencrypt
|
||||
### SSL Support using an ACME CA
|
||||
|
||||
[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allows the creation/renewal of Let's Encrypt certificates automatically.
|
||||
[acme-companion](https://github.com/nginx-proxy/acme-companion) is a lightweight companion container for the nginx-proxy. It allows the automated creation/renewal of SSL certificates using the ACME protocol.
|
||||
|
||||
Set `DHPARAM_GENERATION` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`.
|
||||
The default value is `true`
|
||||
@ -202,7 +212,7 @@ certificates or optionally specifying a cert name (for SNI) as an environment va
|
||||
|
||||
To enable SSL:
|
||||
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
|
||||
The contents of `/path/to/certs` should contain the certificates and private keys for any virtual
|
||||
hosts in use. The certificate and keys should be named after the virtual host with a `.crt` and
|
||||
@ -226,7 +236,7 @@ at startup. Since it can take minutes to generate a new `dhparam.pem`, it is do
|
||||
background. Once generation is complete, the `dhparam.pem` is saved on a persistent volume and nginx
|
||||
is reloaded. This generation process only occurs the first time you start `nginx-proxy`.
|
||||
|
||||
> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 2048 bits for A+ security. Some
|
||||
> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 4096 bits for A+ security. Some
|
||||
> older clients (like Java 6 and 7) do not support DH keys with over 1024 bits. In order to support these
|
||||
> clients, you must either provide your own `dhparam.pem`, or tell `nginx-proxy` to generate a 1024-bit
|
||||
> key on startup by passing `-e DHPARAM_BITS=1024`.
|
||||
@ -234,7 +244,7 @@ is reloaded. This generation process only occurs the first time you start `ngin
|
||||
In the separate container setup, no pregenerated key will be available and neither the
|
||||
[jwilder/docker-gen](https://hub.docker.com/r/jwilder/docker-gen) image nor the offical
|
||||
[nginx](https://registry.hub.docker.com/_/nginx/) image will generate one. If you still want A+ security
|
||||
in a separate container setup, you'll have to generate a 2048 bits DH key file manually and mount it on the
|
||||
in a separate container setup, you'll have to generate a 2048 or 4096 bits DH key file manually and mount it on the
|
||||
nginx container, at `/etc/nginx/dhparam/dhparam.pem`.
|
||||
|
||||
#### Wildcard Certificates
|
||||
@ -276,7 +286,7 @@ and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalan
|
||||
`AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`.
|
||||
|
||||
Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container generates
|
||||
a 2048 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing
|
||||
a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing
|
||||
this, either globally or per virtual-host.
|
||||
|
||||
The default behavior for the proxy when port 80 and 443 are exposed is as follows:
|
||||
@ -317,7 +327,7 @@ $ docker run -d -p 80:80 -p 443:443 \
|
||||
-v /path/to/htpasswd:/etc/nginx/htpasswd \
|
||||
-v /path/to/certs:/etc/nginx/certs \
|
||||
-v /var/run/docker.sock:/tmp/docker.sock:ro \
|
||||
jwilder/nginx-proxy
|
||||
nginxproxy/nginx-proxy
|
||||
```
|
||||
|
||||
You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html)
|
||||
@ -359,7 +369,7 @@ To add settings on a proxy-wide basis, add your configuration file under `/etc/n
|
||||
This can be done in a derived image by creating the file in a `RUN` command or by `COPY`ing the file into `conf.d`:
|
||||
|
||||
```Dockerfile
|
||||
FROM jwilder/nginx-proxy
|
||||
FROM nginxproxy/nginx-proxy
|
||||
RUN { \
|
||||
echo 'server_tokens off;'; \
|
||||
echo 'client_max_body_size 100m;'; \
|
||||
@ -368,7 +378,7 @@ RUN { \
|
||||
|
||||
Or it can be done by mounting in your custom configuration in your `docker run` command:
|
||||
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
|
||||
#### Per-VIRTUAL_HOST
|
||||
|
||||
@ -378,7 +388,7 @@ In order to allow virtual hosts to be dynamically configured as backends are add
|
||||
|
||||
For example, if you have a virtual host named `app.example.com`, you could provide a custom configuration for that host as follows:
|
||||
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
$ { echo 'server_tokens off;'; echo 'client_max_body_size 100m;'; } > /path/to/vhost.d/app.example.com
|
||||
|
||||
If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink:
|
||||
@ -398,7 +408,7 @@ just like the previous section except with the suffix `_location`.
|
||||
|
||||
For example, if you have a virtual host named `app.example.com` and you have configured a proxy_cache `my-cache` in another custom file, you could tell it to use a proxy cache as follows:
|
||||
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
|
||||
$ docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy
|
||||
$ { echo 'proxy_cache my-cache;'; echo 'proxy_cache_valid 200 302 60m;'; echo 'proxy_cache_valid 404 1m;' } > /path/to/vhost.d/app.example.com_location
|
||||
|
||||
If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink:
|
||||
@ -417,26 +427,15 @@ Before submitting pull requests or issues, please check github to make sure an e
|
||||
|
||||
#### Running Tests Locally
|
||||
|
||||
To run tests, you need to prepare the docker image to test which must be tagged `jwilder/nginx-proxy:test`:
|
||||
|
||||
docker build -t jwilder/nginx-proxy:test . # build the Debian variant image
|
||||
|
||||
and call the [test/pytest.sh](test/pytest.sh) script.
|
||||
|
||||
Then build the Alpine variant of the image:
|
||||
|
||||
docker build -f Dockerfile.alpine -t jwilder/nginx-proxy:test . # build the Alpline variant image
|
||||
|
||||
and call the [test/pytest.sh](test/pytest.sh) script again.
|
||||
|
||||
|
||||
If your system has the `make` command, you can automate those tasks by calling:
|
||||
To run tests, you just need to run the command below:
|
||||
|
||||
make test
|
||||
|
||||
This commands run tests on two variants of the nginx-proxy docker image: Debian and Alpine.
|
||||
|
||||
You can run the tests for each of these images with their respective commands:
|
||||
|
||||
make test-debian
|
||||
make test-alpine
|
||||
|
||||
You can learn more about how the test suite works and how to write new tests in the [test/README.md](test/README.md) file.
|
||||
|
||||
### Need help?
|
||||
|
||||
If you have questions on how to use the image, please ask them on the [Q&A Group](https://groups.google.com/forum/#!forum/nginx-proxy)
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy
|
||||
image: nginxproxy/nginx-proxy
|
||||
container_name: nginx-proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
|
@ -4,10 +4,10 @@ set -e
|
||||
# Warn if the DOCKER_HOST socket does not exist
|
||||
if [[ $DOCKER_HOST = unix://* ]]; then
|
||||
socket_file=${DOCKER_HOST#unix://}
|
||||
if ! [ -S $socket_file ]; then
|
||||
if ! [ -S "$socket_file" ]; then
|
||||
cat >&2 <<-EOT
|
||||
ERROR: you need to share your Docker host socket with a volume at $socket_file
|
||||
Typically you should run your jwilder/nginx-proxy with: \`-v /var/run/docker.sock:$socket_file:ro\`
|
||||
Typically you should run your nginxproxy/nginx-proxy with: \`-v /var/run/docker.sock:$socket_file:ro\`
|
||||
See the documentation at http://git.io/vZaGJ
|
||||
EOT
|
||||
socketMissing=1
|
||||
@ -15,26 +15,24 @@ if [[ $DOCKER_HOST = unix://* ]]; then
|
||||
fi
|
||||
|
||||
# Generate dhparam file if required
|
||||
# Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default
|
||||
# Note2: if $DHPARAM_GENERATION is set to false in environment variable, dh param generator will skip completely
|
||||
/app/generate-dhparam.sh $DHPARAM_BITS $DHPARAM_GENERATION
|
||||
/app/generate-dhparam.sh
|
||||
|
||||
# Compute the DNS resolvers for use in the templates - if the IP contains ":", it's IPv6 and must be enclosed in []
|
||||
export RESOLVERS=$(awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g')
|
||||
RESOLVERS=$(awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g'); export RESOLVERS
|
||||
|
||||
SCOPED_IPV6_REGEX="\[fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}\]"
|
||||
|
||||
if [ "x$RESOLVERS" = "x" ]; then
|
||||
if [ "$RESOLVERS" = "" ]; then
|
||||
echo "Warning: unable to determine DNS resolvers for nginx" >&2
|
||||
unset RESOLVERS
|
||||
elif [[ $RESOLVERS =~ $SCOPED_IPV6_REGEX ]]; then
|
||||
echo -n "Warning: Scoped IPv6 addresses removed from resolvers: " >&2
|
||||
echo $RESOLVERS | grep -Eo $SCOPED_IPV6_REGEX | paste -s -d ' ' >&2
|
||||
export RESOLVERS=$(echo $RESOLVERS | sed -r "s/$SCOPED_IPV6_REGEX//g" | xargs echo -n)
|
||||
echo "$RESOLVERS" | grep -Eo "$SCOPED_IPV6_REGEX" | paste -s -d ' ' >&2
|
||||
RESOLVERS=$(echo "$RESOLVERS" | sed -r "s/$SCOPED_IPV6_REGEX//g" | xargs echo -n); export RESOLVERS
|
||||
fi
|
||||
|
||||
# If the user has run the default command and the socket doesn't exist, fail
|
||||
if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then
|
||||
if [ "$socketMissing" = 1 ] && [ "$1" = forego ] && [ "$2" = start ] && [ "$3" = '-r' ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# The first argument is the bit depth of the dhparam, or 4096 if unspecified
|
||||
DHPARAM_BITS=${1:-4096}
|
||||
GENERATE_DHPARAM=${2:-true}
|
||||
# DHPARAM_BITS is the bit depth of the dhparam, or 4096 if unspecified
|
||||
DHPARAM_BITS=${DHPARAM_BITS:-4096}
|
||||
# DHPARAM_GENERATION=false skips dhparam generation
|
||||
DHPARAM_GENERATION=${DHPARAM_GENERATION:-true}
|
||||
|
||||
# If a dhparam file is not available, use the pre-generated one and generate a new one in the background.
|
||||
# Note that /etc/nginx/dhparam is a volume, so this dhparam will persist restarts.
|
||||
@ -14,7 +15,7 @@ GEN_LOCKFILE="/tmp/dhparam_generating.lock"
|
||||
PREGEN_HASH=$(md5sum $PREGEN_DHPARAM_FILE | cut -d" " -f1)
|
||||
if [[ -f $DHPARAM_FILE ]]; then
|
||||
CURRENT_HASH=$(md5sum $DHPARAM_FILE | cut -d" " -f1)
|
||||
if [[ $PREGEN_HASH != $CURRENT_HASH ]]; then
|
||||
if [[ $PREGEN_HASH != "$CURRENT_HASH" ]]; then
|
||||
# There is already a dhparam, and it's not the default
|
||||
echo "Custom dhparam.pem file found, generation skipped"
|
||||
exit 0
|
||||
@ -26,7 +27,7 @@ if [[ -f $DHPARAM_FILE ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $GENERATE_DHPARAM =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then
|
||||
if [[ $DHPARAM_GENERATION =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then
|
||||
echo "Skipping Diffie-Hellman parameters generation and Ignoring pre-generated dhparam.pem"
|
||||
exit 0
|
||||
fi
|
||||
@ -43,10 +44,10 @@ touch $GEN_LOCKFILE
|
||||
# Generate a new dhparam in the background in a low priority and reload nginx when finished (grep removes the progress indicator).
|
||||
(
|
||||
(
|
||||
nice -n +5 openssl dhparam -dsaparam -out $DHPARAM_FILE.tmp $DHPARAM_BITS 2>&1 \
|
||||
nice -n +5 openssl dhparam -dsaparam -out $DHPARAM_FILE.tmp "$DHPARAM_BITS" 2>&1 \
|
||||
&& mv $DHPARAM_FILE.tmp $DHPARAM_FILE \
|
||||
&& echo "dhparam generation complete, reloading nginx" \
|
||||
&& nginx -s reload
|
||||
) | grep -vE '^[\.+]+'
|
||||
rm $GEN_LOCKFILE
|
||||
) &disown
|
||||
) & disown
|
||||
|
@ -172,7 +172,7 @@ server {
|
||||
|
||||
{{ $host := trim $host }}
|
||||
{{ $is_regexp := hasPrefix "~" $host }}
|
||||
{{ $upstream_name := when $is_regexp (sha1 $host) $host }}
|
||||
{{ $upstream_name := (print (when $is_regexp (sha1 $host) $host) "-upstream") }}
|
||||
|
||||
# {{ $host }}
|
||||
upstream {{ $upstream_name }} {
|
||||
@ -253,8 +253,9 @@ server {
|
||||
{{ $access_log }}
|
||||
|
||||
# Do not HTTPS redirect Let'sEncrypt ACME challenge
|
||||
location /.well-known/acme-challenge/ {
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
auth_basic off;
|
||||
auth_request off;
|
||||
allow all;
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri =404;
|
||||
|
@ -4,25 +4,20 @@ Nginx proxy test suite
|
||||
Install requirements
|
||||
--------------------
|
||||
|
||||
You need [python 2.7](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installing/) installed. Then run the commands:
|
||||
You need [python 3.9](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installing/) installed. Then run the commands:
|
||||
|
||||
requirements/build.sh
|
||||
pip install -r requirements/python-requirements.txt
|
||||
|
||||
If you can't install those requirements on your computer, you can alternatively use the _pytest.sh_ script which will run the tests from a Docker container which has those requirements.
|
||||
|
||||
|
||||
Prepare the nginx-proxy test image
|
||||
----------------------------------
|
||||
|
||||
docker build -t jwilder/nginx-proxy:test ..
|
||||
make build-nginx-proxy-test-debian
|
||||
|
||||
or if you want to test the alpine flavor:
|
||||
|
||||
docker build -t jwilder/nginx-proxy:test -f Dockerfile.alpine ..
|
||||
|
||||
make sure to tag that test image exactly `jwilder/nginx-proxy:test` or the test suite won't work.
|
||||
|
||||
make build-nginx-proxy-test-alpine
|
||||
|
||||
Run the test suite
|
||||
------------------
|
||||
@ -61,11 +56,11 @@ The fixture will run the _docker-compose_ command with the `-f` option to load t
|
||||
|
||||
In the case you are running pytest from within a docker container, the `docker_compose` fixture will make sure the container running pytest is attached to all docker networks. That way, your test will be able to reach any of them.
|
||||
|
||||
In your tests, you can use the `docker_compose` variable to query and command the docker daemon as it provides you with a [client from the docker python module](https://docker-py.readthedocs.io/en/2.0.2/client.html#client-reference).
|
||||
In your tests, you can use the `docker_compose` variable to query and command the docker daemon as it provides you with a [client from the docker python module](https://docker-py.readthedocs.io/en/4.4.4/client.html#client-reference).
|
||||
|
||||
Also this fixture alters the way the python interpreter resolves domain names to IP addresses in the following ways:
|
||||
|
||||
Any domain name containing the substring `nginx-proxy` will resolve to the IP address of the container that was created from the `jwilder/nginx-proxy:test` image. So all the following domain names will resolve to the nginx-proxy container in tests:
|
||||
Any domain name containing the substring `nginx-proxy` will resolve to the IP address of the container that was created from the `nginxproxy/nginx-proxy:test` image. So all the following domain names will resolve to the nginx-proxy container in tests:
|
||||
- `nginx-proxy`
|
||||
- `nginx-proxy.com`
|
||||
- `www.nginx-proxy.com`
|
||||
@ -99,8 +94,7 @@ Furthermore, the nginxproxy methods accept an additional keyword parameter: `ipv
|
||||
|
||||
### The web docker image
|
||||
|
||||
When you ran the `requirements/build.sh` script earlier, you built a [`web`](requirements/README.md) docker image which is convenient for running a small web server in a container. This image can produce containers that listens on multiple ports at the same time.
|
||||
|
||||
When you run the `make build-webserver` command, you built a [`web`](requirements/README.md) docker image which is convenient for running a small web server in a container. This image can produce containers that listens on multiple ports at the same time.
|
||||
|
||||
### Testing TLS
|
||||
|
||||
|
108
test/conftest.py
108
test/conftest.py
@ -1,4 +1,3 @@
|
||||
from __future__ import print_function
|
||||
import contextlib
|
||||
import logging
|
||||
import os
|
||||
@ -68,11 +67,11 @@ class requests_for_docker(object):
|
||||
"""
|
||||
Return the nginx config file
|
||||
"""
|
||||
nginx_proxy_containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"})
|
||||
nginx_proxy_containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"})
|
||||
if len(nginx_proxy_containers) > 1:
|
||||
pytest.fail("Too many running jwilder/nginx-proxy:test containers", pytrace=False)
|
||||
pytest.fail("Too many running nginxproxy/nginx-proxy:test containers", pytrace=False)
|
||||
elif len(nginx_proxy_containers) == 0:
|
||||
pytest.fail("No running jwilder/nginx-proxy:test container", pytrace=False)
|
||||
pytest.fail("No running nginxproxy/nginx-proxy:test container", pytrace=False)
|
||||
return get_nginx_conf_from_container(nginx_proxy_containers[0])
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
@ -133,7 +132,7 @@ def container_ip(container):
|
||||
pytest.skip("This system does not support IPv6")
|
||||
ip = container_ipv6(container)
|
||||
if ip == '':
|
||||
pytest.skip("Container %s has no IPv6 address" % container.name)
|
||||
pytest.skip(f"Container {container.name} has no IPv6 address")
|
||||
else:
|
||||
return ip
|
||||
else:
|
||||
@ -142,7 +141,7 @@ def container_ip(container):
|
||||
return net_info["bridge"]["IPAddress"]
|
||||
|
||||
# not default bridge network, fallback on first network defined
|
||||
network_name = net_info.keys()[0]
|
||||
network_name = list(net_info.keys())[0]
|
||||
return net_info[network_name]["IPAddress"]
|
||||
|
||||
|
||||
@ -155,27 +154,27 @@ def container_ipv6(container):
|
||||
return net_info["bridge"]["GlobalIPv6Address"]
|
||||
|
||||
# not default bridge network, fallback on first network defined
|
||||
network_name = net_info.keys()[0]
|
||||
network_name = list(net_info.keys())[0]
|
||||
return net_info[network_name]["GlobalIPv6Address"]
|
||||
|
||||
|
||||
def nginx_proxy_dns_resolver(domain_name):
|
||||
"""
|
||||
if "nginx-proxy" if found in host, return the ip address of the docker container
|
||||
issued from the docker image jwilder/nginx-proxy:test.
|
||||
issued from the docker image nginxproxy/nginx-proxy:test.
|
||||
|
||||
:return: IP or None
|
||||
"""
|
||||
log = logging.getLogger('DNS')
|
||||
log.debug("nginx_proxy_dns_resolver(%r)" % domain_name)
|
||||
log.debug(f"nginx_proxy_dns_resolver({domain_name!r})")
|
||||
if 'nginx-proxy' in domain_name:
|
||||
nginxproxy_containers = docker_client.containers.list(filters={"status": "running", "ancestor": "jwilder/nginx-proxy:test"})
|
||||
nginxproxy_containers = docker_client.containers.list(filters={"status": "running", "ancestor": "nginxproxy/nginx-proxy:test"})
|
||||
if len(nginxproxy_containers) == 0:
|
||||
log.warn("no container found from image jwilder/nginx-proxy:test while resolving %r", domain_name)
|
||||
log.warn(f"no container found from image nginxproxy/nginx-proxy:test while resolving {domain_name!r}")
|
||||
return
|
||||
nginxproxy_container = nginxproxy_containers[0]
|
||||
ip = container_ip(nginxproxy_container)
|
||||
log.info("resolving domain name %r as IP address %s of nginx-proxy container %s" % (domain_name, ip, nginxproxy_container.name))
|
||||
log.info(f"resolving domain name {domain_name!r} as IP address {ip} of nginx-proxy container {nginxproxy_container.name}")
|
||||
return ip
|
||||
|
||||
def docker_container_dns_resolver(domain_name):
|
||||
@ -186,24 +185,24 @@ def docker_container_dns_resolver(domain_name):
|
||||
:return: IP or None
|
||||
"""
|
||||
log = logging.getLogger('DNS')
|
||||
log.debug("docker_container_dns_resolver(%r)" % domain_name)
|
||||
log.debug(f"docker_container_dns_resolver({domain_name!r})")
|
||||
|
||||
match = re.search('(^|.+\.)(?P<container>[^.]+)\.container\.docker$', domain_name)
|
||||
match = re.search(r'(^|.+\.)(?P<container>[^.]+)\.container\.docker$', domain_name)
|
||||
if not match:
|
||||
log.debug("%r does not match" % domain_name)
|
||||
log.debug(f"{domain_name!r} does not match")
|
||||
return
|
||||
|
||||
container_name = match.group('container')
|
||||
log.debug("looking for container %r" % container_name)
|
||||
log.debug(f"looking for container {container_name!r}")
|
||||
try:
|
||||
container = docker_client.containers.get(container_name)
|
||||
except docker.errors.NotFound:
|
||||
log.warn("container named %r not found while resolving %r" % (container_name, domain_name))
|
||||
log.warn(f"container named {container_name!r} not found while resolving {domain_name!r}")
|
||||
return
|
||||
log.debug("container %r found (%s)" % (container.name, container.short_id))
|
||||
log.debug(f"container {container.name!r} found ({container.short_id})")
|
||||
|
||||
ip = container_ip(container)
|
||||
log.info("resolving domain name %r as IP address %s of container %s" % (domain_name, ip, container.name))
|
||||
log.info(f"resolving domain name {domain_name!r} as IP address {ip} of container {container.name}")
|
||||
return ip
|
||||
|
||||
|
||||
@ -211,12 +210,12 @@ def monkey_patch_urllib_dns_resolver():
|
||||
"""
|
||||
Alter the behavior of the urllib DNS resolver so that any domain name
|
||||
containing substring 'nginx-proxy' will resolve to the IP address
|
||||
of the container created from image 'jwilder/nginx-proxy:test'.
|
||||
of the container created from image 'nginxproxy/nginx-proxy:test'.
|
||||
"""
|
||||
prv_getaddrinfo = socket.getaddrinfo
|
||||
dns_cache = {}
|
||||
def new_getaddrinfo(*args):
|
||||
logging.getLogger('DNS').debug("resolving domain name %s" % repr(args))
|
||||
logging.getLogger('DNS').debug(f"resolving domain name {repr(args)}")
|
||||
_args = list(args)
|
||||
|
||||
# custom DNS resolvers
|
||||
@ -244,7 +243,7 @@ def remove_all_containers():
|
||||
for container in docker_client.containers.list(all=True):
|
||||
if I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER and container.id.startswith(socket.gethostname()):
|
||||
continue # pytest is running within a Docker container, so we do not want to remove that particular container
|
||||
logging.info("removing container %s" % container.name)
|
||||
logging.info(f"removing container {container.name}")
|
||||
container.remove(v=True, force=True)
|
||||
|
||||
|
||||
@ -253,40 +252,43 @@ def get_nginx_conf_from_container(container):
|
||||
return the nginx /etc/nginx/conf.d/default.conf file content from a container
|
||||
"""
|
||||
import tarfile
|
||||
from cStringIO import StringIO
|
||||
strm, stat = container.get_archive('/etc/nginx/conf.d/default.conf')
|
||||
with tarfile.open(fileobj=StringIO(strm.read())) as tf:
|
||||
from io import BytesIO
|
||||
|
||||
strm_generator, stat = container.get_archive('/etc/nginx/conf.d/default.conf')
|
||||
strm_fileobj = BytesIO(b"".join(strm_generator))
|
||||
|
||||
with tarfile.open(fileobj=strm_fileobj) as tf:
|
||||
conffile = tf.extractfile('default.conf')
|
||||
return conffile.read()
|
||||
|
||||
|
||||
def docker_compose_up(compose_file='docker-compose.yml'):
|
||||
logging.info('docker-compose -f %s up -d' % compose_file)
|
||||
logging.info(f'docker-compose -f {compose_file} up -d')
|
||||
try:
|
||||
subprocess.check_output(shlex.split('docker-compose -f %s up -d' % compose_file), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError, e:
|
||||
pytest.fail("Error while runninng 'docker-compose -f %s up -d':\n%s" % (compose_file, e.output), pytrace=False)
|
||||
subprocess.check_output(shlex.split(f'docker-compose -f {compose_file} up -d'), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
pytest.fail(f"Error while runninng 'docker-compose -f {compose_file} up -d':\n{e.output}", pytrace=False)
|
||||
|
||||
|
||||
def docker_compose_down(compose_file='docker-compose.yml'):
|
||||
logging.info('docker-compose -f %s down' % compose_file)
|
||||
logging.info(f'docker-compose -f {compose_file} down')
|
||||
try:
|
||||
subprocess.check_output(shlex.split('docker-compose -f %s down' % compose_file), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError, e:
|
||||
pytest.fail("Error while runninng 'docker-compose -f %s down':\n%s" % (compose_file, e.output), pytrace=False)
|
||||
subprocess.check_output(shlex.split(f'docker-compose -f {compose_file} down'), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
pytest.fail(f"Error while runninng 'docker-compose -f {compose_file} down':\n{e.output}", pytrace=False)
|
||||
|
||||
|
||||
def wait_for_nginxproxy_to_be_ready():
|
||||
"""
|
||||
If one (and only one) container started from image jwilder/nginx-proxy:test is found,
|
||||
If one (and only one) container started from image nginxproxy/nginx-proxy:test is found,
|
||||
wait for its log to contain substring "Watching docker events"
|
||||
"""
|
||||
containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"})
|
||||
containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"})
|
||||
if len(containers) != 1:
|
||||
return
|
||||
container = containers[0]
|
||||
for line in container.logs(stream=True):
|
||||
if "Watching docker events" in line:
|
||||
if b"Watching docker events" in line:
|
||||
logging.debug("nginx-proxy ready")
|
||||
break
|
||||
|
||||
@ -307,7 +309,7 @@ def find_docker_compose_file(request):
|
||||
if docker_compose_file_module_variable is not None:
|
||||
docker_compose_file = os.path.join( test_module_dir, docker_compose_file_module_variable)
|
||||
if not os.path.isfile(docker_compose_file):
|
||||
raise ValueError("docker compose file %r could not be found. Check your test module `docker_compose_file` variable value." % docker_compose_file)
|
||||
raise ValueError(f"docker compose file {docker_compose_file!r} could not be found. Check your test module `docker_compose_file` variable value.")
|
||||
else:
|
||||
if os.path.isfile(yml_file):
|
||||
docker_compose_file = yml_file
|
||||
@ -319,7 +321,7 @@ def find_docker_compose_file(request):
|
||||
if not os.path.isfile(docker_compose_file):
|
||||
logging.error("Could not find any docker-compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__))
|
||||
|
||||
logging.debug("using docker compose file %s" % docker_compose_file)
|
||||
logging.debug(f"using docker compose file {docker_compose_file}")
|
||||
return docker_compose_file
|
||||
|
||||
|
||||
@ -333,15 +335,15 @@ def connect_to_network(network):
|
||||
try:
|
||||
my_container = docker_client.containers.get(socket.gethostname())
|
||||
except docker.errors.NotFound:
|
||||
logging.warn("container %r not found" % socket.gethostname())
|
||||
logging.warn(f"container {socket.gethostname()!r} not found")
|
||||
return
|
||||
|
||||
# figure out our container networks
|
||||
my_networks = my_container.attrs["NetworkSettings"]["Networks"].keys()
|
||||
my_networks = list(my_container.attrs["NetworkSettings"]["Networks"].keys())
|
||||
|
||||
# make sure our container is connected to the nginx-proxy's network
|
||||
if network not in my_networks:
|
||||
logging.info("Connecting to docker network: %s" % network.name)
|
||||
logging.info(f"Connecting to docker network: {network.name}")
|
||||
network.connect(my_container)
|
||||
return network
|
||||
|
||||
@ -356,15 +358,15 @@ def disconnect_from_network(network=None):
|
||||
try:
|
||||
my_container = docker_client.containers.get(socket.gethostname())
|
||||
except docker.errors.NotFound:
|
||||
logging.warn("container %r not found" % socket.gethostname())
|
||||
logging.warn(f"container {socket.gethostname()!r} not found")
|
||||
return
|
||||
|
||||
# figure out our container networks
|
||||
my_networks_names = my_container.attrs["NetworkSettings"]["Networks"].keys()
|
||||
my_networks_names = list(my_container.attrs["NetworkSettings"]["Networks"].keys())
|
||||
|
||||
# disconnect our container from the given network
|
||||
if network.name in my_networks_names:
|
||||
logging.info("Disconnecting from network %s" % network.name)
|
||||
logging.info(f"Disconnecting from network {network.name}")
|
||||
network.disconnect(my_container)
|
||||
|
||||
|
||||
@ -378,7 +380,7 @@ def connect_to_all_networks():
|
||||
return []
|
||||
else:
|
||||
# find the list of docker networks
|
||||
networks = filter(lambda network: len(network.containers) > 0 and network.name != 'bridge', docker_client.networks.list())
|
||||
networks = [network for network in docker_client.networks.list() if len(network.containers) > 0 and network.name != 'bridge']
|
||||
return [connect_to_network(network) for network in networks]
|
||||
|
||||
|
||||
@ -388,7 +390,7 @@ def connect_to_all_networks():
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
@pytest.yield_fixture(scope="module")
|
||||
@pytest.fixture(scope="module")
|
||||
def docker_compose(request):
|
||||
"""
|
||||
pytest fixture providing containers described in a docker compose file. After the tests, remove the created containers
|
||||
@ -412,7 +414,7 @@ def docker_compose(request):
|
||||
restore_urllib_dns_resolver(original_dns_resolver)
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
@pytest.fixture()
|
||||
def nginxproxy():
|
||||
"""
|
||||
Provides the `nginxproxy` object that can be used in the same way the requests module is:
|
||||
@ -439,7 +441,7 @@ def nginxproxy():
|
||||
def pytest_runtest_logreport(report):
|
||||
if report.failed:
|
||||
if isinstance(report.longrepr, ReprExceptionInfo):
|
||||
test_containers = docker_client.containers.list(all=True, filters={"ancestor": "jwilder/nginx-proxy:test"})
|
||||
test_containers = docker_client.containers.list(all=True, filters={"ancestor": "nginxproxy/nginx-proxy:test"})
|
||||
for container in test_containers:
|
||||
report.longrepr.addsection('nginx-proxy logs', container.logs())
|
||||
report.longrepr.addsection('nginx-proxy conf', get_nginx_conf_from_container(container))
|
||||
@ -456,7 +458,7 @@ def pytest_runtest_makereport(item, call):
|
||||
def pytest_runtest_setup(item):
|
||||
previousfailed = getattr(item.parent, "_previousfailed", None)
|
||||
if previousfailed is not None:
|
||||
pytest.xfail("previous test failed (%s)" % previousfailed.name)
|
||||
pytest.xfail(f"previous test failed ({previousfailed.name})")
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -465,9 +467,9 @@ def pytest_runtest_setup(item):
|
||||
###############################################################################
|
||||
|
||||
try:
|
||||
docker_client.images.get('jwilder/nginx-proxy:test')
|
||||
docker_client.images.get('nginxproxy/nginx-proxy:test')
|
||||
except docker.errors.ImageNotFound:
|
||||
pytest.exit("The docker image 'jwilder/nginx-proxy:test' is missing")
|
||||
pytest.exit("The docker image 'nginxproxy/nginx-proxy:test' is missing")
|
||||
|
||||
if docker.__version__ != "2.1.0":
|
||||
pytest.exit("This test suite is meant to work with the python docker module v2.1.0")
|
||||
if docker.__version__ != "4.4.4":
|
||||
pytest.exit("This test suite is meant to work with the python docker module v4.4.4")
|
||||
|
@ -1,3 +1,5 @@
|
||||
[pytest]
|
||||
# disable the creation of the `.cache` folders
|
||||
addopts = -p no:cacheprovider --ignore=requirements --ignore=certs -r s -v
|
||||
markers =
|
||||
incremental: mark a test as incremental.
|
@ -1,7 +1,4 @@
|
||||
FROM python:2.7-alpine
|
||||
|
||||
# Note: we're using alpine because it has openssl 1.0.2, which we need for testing
|
||||
RUN apk add --update bash openssl curl && rm -rf /var/cache/apk/*
|
||||
FROM python:3.9
|
||||
|
||||
COPY python-requirements.txt /requirements.txt
|
||||
RUN pip install -r /requirements.txt
|
||||
|
@ -2,7 +2,7 @@ This directory contains resources to build Docker images tests depend on
|
||||
|
||||
# Build images
|
||||
|
||||
./build.sh
|
||||
make build-webserver
|
||||
|
||||
|
||||
# python-requirements.txt
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
docker build -t web $DIR/web
|
@ -1,5 +1,5 @@
|
||||
backoff==1.3.2
|
||||
docker-compose==1.11.2
|
||||
docker==2.1.0
|
||||
pytest==3.0.5
|
||||
requests==2.11.1
|
||||
backoff==1.10.0
|
||||
docker-compose==1.28.5
|
||||
docker==4.4.4
|
||||
pytest==6.2.2
|
||||
requests==2.25.1
|
||||
|
@ -13,13 +13,13 @@ class Handler(http.server.SimpleHTTPRequestHandler):
|
||||
if self.path == "/headers":
|
||||
response_body += self.headers.as_string()
|
||||
elif self.path == "/port":
|
||||
response_body += "answer from port %s\n" % PORT
|
||||
response_body += f"answer from port {PORT}\n"
|
||||
elif re.match("/status/(\d+)", self.path):
|
||||
result = re.match("/status/(\d+)", self.path)
|
||||
response_code = int(result.group(1))
|
||||
response_body += "answer with response code %s\n" % response_code
|
||||
response_body += f"answer with response code {response_code}\n"
|
||||
elif self.path == "/":
|
||||
response_body += "I'm %s\n" % os.environ['HOSTNAME']
|
||||
response_body += f"I'm {os.environ['HOSTNAME']}\n"
|
||||
else:
|
||||
response_body += "No route for this path!\n"
|
||||
response_code = 404
|
||||
|
@ -8,7 +8,7 @@ web:
|
||||
|
||||
|
||||
reverseproxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
container_name: reverseproxy
|
||||
environment:
|
||||
DEBUG: "true"
|
||||
|
@ -12,7 +12,7 @@ script_dir = os.path.dirname(__file__)
|
||||
pytestmark = pytest.mark.xfail() # TODO delete this marker once those issues are fixed
|
||||
|
||||
|
||||
@pytest.yield_fixture(scope="module", autouse=True)
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def certs():
|
||||
"""
|
||||
pytest fixture that provides cert and key files into the tmp_certs directory
|
||||
@ -43,7 +43,7 @@ def test_http_web_is_301(docker_compose, nginxproxy):
|
||||
def test_https_web_is_200(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy/port")
|
||||
assert r.status_code == 200
|
||||
assert 'answer from port 81\n' in r.text
|
||||
assert "answer from port 81\n" in r.text
|
||||
|
||||
|
||||
@pytest.mark.incremental
|
||||
|
@ -6,7 +6,7 @@ Furthermore, if the nginx-proxy in such state is restarted, the nginx process wi
|
||||
|
||||
In the generated nginx config file, we can notice the presence of an empty `upstream {}` block.
|
||||
|
||||
This can be fixed by merging [PR-585](https://github.com/jwilder/nginx-proxy/pull/585).
|
||||
This can be fixed by merging [PR-585](https://github.com/nginx-proxy/nginx-proxy/pull/585).
|
||||
|
||||
## How to reproduce
|
||||
|
||||
|
@ -9,7 +9,7 @@ services:
|
||||
container_name: reverseproxy
|
||||
networks:
|
||||
- netA
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
|
||||
|
@ -16,7 +16,7 @@ web2:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/f00.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,5 +1,5 @@
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -19,4 +19,4 @@ def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
|
||||
assert "X-test" not in r.headers
|
||||
|
||||
def test_custom_block_is_present_in_nginx_generated_conf(docker_compose, nginxproxy):
|
||||
assert "include /etc/nginx/vhost.d/web1.nginx-proxy.local_location;" in nginxproxy.get_conf()
|
||||
assert b"include /etc/nginx/vhost.d/web1.nginx-proxy.local_location;" in nginxproxy.get_conf()
|
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -10,7 +10,7 @@ web1:
|
||||
|
||||
# WHEN nginx-proxy runs with DEFAULT_HOST set to web1.tld
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -4,23 +4,27 @@ import logging
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.yield_fixture(scope="module")
|
||||
@pytest.fixture(scope="module")
|
||||
def nginx_tmpl():
|
||||
"""
|
||||
pytest fixture which extracts the the nginx config template from
|
||||
the jwilder/nginx-proxy:test image
|
||||
the nginxproxy/nginx-proxy:test image
|
||||
"""
|
||||
script_dir = os.path.dirname(__file__)
|
||||
logging.info("extracting nginx.tmpl from jwilder/nginx-proxy:test")
|
||||
logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test")
|
||||
docker_client = docker.from_env()
|
||||
print(docker_client.containers.run(
|
||||
image='jwilder/nginx-proxy:test',
|
||||
print(
|
||||
docker_client.containers.run(
|
||||
image="nginxproxy/nginx-proxy:test",
|
||||
remove=True,
|
||||
volumes=['{current_dir}:{current_dir}'.format(current_dir=script_dir)],
|
||||
entrypoint='sh',
|
||||
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))
|
||||
current_dir=script_dir
|
||||
),
|
||||
stderr=True,
|
||||
)
|
||||
)
|
||||
yield
|
||||
logging.info("removing nginx.tmpl")
|
||||
os.remove(os.path.join(script_dir, "nginx.tmpl"))
|
||||
@ -35,4 +39,4 @@ def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://whoami.nginx.container.docker/")
|
||||
assert r.status_code == 200
|
||||
whoami_container = docker_compose.containers.get("whoami")
|
||||
assert r.text == "I'm %s\n" % whoami_container.id[:12]
|
||||
assert r.text == f"I'm {whoami_container.id[:12]}\n"
|
||||
|
@ -3,47 +3,37 @@ import docker
|
||||
import logging
|
||||
import pytest
|
||||
import re
|
||||
|
||||
def versiontuple(v):
|
||||
"""
|
||||
>>> versiontuple("1.12.3")
|
||||
(1, 12, 3)
|
||||
|
||||
>>> versiontuple("1.13.0")
|
||||
(1, 13, 0)
|
||||
|
||||
>>> versiontuple("17.03.0-ce")
|
||||
(17, 3, 0)
|
||||
|
||||
>>> versiontuple("17.03.0-ce") < (1, 13)
|
||||
False
|
||||
"""
|
||||
return tuple(map(int, (v.split('-')[0].split("."))))
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
|
||||
raw_version = docker.from_env().version()['Version']
|
||||
raw_version = docker.from_env().version()["Version"]
|
||||
pytestmark = pytest.mark.skipif(
|
||||
versiontuple(raw_version) < (1, 13),
|
||||
reason="Docker compose syntax v3 requires docker engine v1.13 or later (got %s)" % raw_version)
|
||||
LooseVersion(raw_version) < LooseVersion("1.13"),
|
||||
reason="Docker compose syntax v3 requires docker engine v1.13 or later (got {raw_version})"
|
||||
)
|
||||
|
||||
|
||||
@pytest.yield_fixture(scope="module")
|
||||
@pytest.fixture(scope="module")
|
||||
def nginx_tmpl():
|
||||
"""
|
||||
pytest fixture which extracts the the nginx config template from
|
||||
the jwilder/nginx-proxy:test image
|
||||
the nginxproxy/nginx-proxy:test image
|
||||
"""
|
||||
script_dir = os.path.dirname(__file__)
|
||||
logging.info("extracting nginx.tmpl from jwilder/nginx-proxy:test")
|
||||
logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test")
|
||||
docker_client = docker.from_env()
|
||||
print(docker_client.containers.run(
|
||||
image='jwilder/nginx-proxy:test',
|
||||
print(
|
||||
docker_client.containers.run(
|
||||
image="nginxproxy/nginx-proxy:test",
|
||||
remove=True,
|
||||
volumes=['{current_dir}:{current_dir}'.format(current_dir=script_dir)],
|
||||
entrypoint='sh',
|
||||
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))
|
||||
current_dir=script_dir
|
||||
),
|
||||
stderr=True,
|
||||
)
|
||||
)
|
||||
yield
|
||||
logging.info("removing nginx.tmpl")
|
||||
os.remove(os.path.join(script_dir, "nginx.tmpl"))
|
||||
@ -58,9 +48,9 @@ def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://whoami.nginx.container.docker/")
|
||||
assert r.status_code == 200
|
||||
whoami_container = docker_compose.containers.get("whoami")
|
||||
assert r.text == "I'm %s\n" % whoami_container.id[:12]
|
||||
assert r.text == f"I'm {whoami_container.id[:12]}\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
@ -7,7 +7,7 @@ import pytest
|
||||
from docker.errors import NotFound
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
@pytest.fixture()
|
||||
def web1(docker_compose):
|
||||
"""
|
||||
pytest fixture creating a web container with `VIRTUAL_HOST=web1.nginx-proxy` listening on port 81.
|
||||
|
@ -1,5 +1,5 @@
|
||||
nginxproxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -8,7 +8,7 @@ web:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -8,7 +8,7 @@ web:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro
|
||||
|
@ -16,7 +16,7 @@ web2:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -8,7 +8,7 @@ web:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -6,7 +6,7 @@ networks:
|
||||
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -9,7 +9,7 @@ web:
|
||||
VIRTUAL_PORT: 90
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -8,7 +8,7 @@ web:
|
||||
VIRTUAL_HOST: "web.nginx-proxy.tld"
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -8,7 +8,7 @@ web:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -16,7 +16,7 @@ web2:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -26,7 +26,7 @@ def assert_log_contains(expected_log_line):
|
||||
"""
|
||||
sut_container = docker_client.containers.get("nginxproxy")
|
||||
docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
|
||||
assert expected_log_line in docker_logs
|
||||
assert bytes(expected_log_line, encoding="utf8") in docker_logs
|
||||
|
||||
|
||||
def require_openssl(required_version):
|
||||
@ -42,7 +42,7 @@ def require_openssl(required_version):
|
||||
"""
|
||||
|
||||
def versiontuple(v):
|
||||
clean_v = re.sub("[^\d\.]", "", v)
|
||||
clean_v = re.sub(r"[^\d\.]", "", v)
|
||||
return tuple(map(int, (clean_v.split("."))))
|
||||
|
||||
try:
|
||||
@ -52,10 +52,10 @@ def require_openssl(required_version):
|
||||
else:
|
||||
if not command_output:
|
||||
raise Exception("Could not get openssl version")
|
||||
openssl_version = command_output.split()[1]
|
||||
openssl_version = str(command_output.split()[1])
|
||||
return pytest.mark.skipif(
|
||||
versiontuple(openssl_version) < versiontuple(required_version),
|
||||
reason="openssl v%s is less than required version %s" % (openssl_version, required_version))
|
||||
reason=f"openssl v{openssl_version} is less than required version {required_version}")
|
||||
|
||||
|
||||
###############################################################################
|
||||
@ -71,8 +71,8 @@ def test_dhparam_is_not_generated_if_present(docker_compose):
|
||||
assert_log_contains("Custom dhparam.pem file found, generation skipped")
|
||||
|
||||
# Make sure the dhparam in use is not the default, pre-generated one
|
||||
default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split()
|
||||
current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split()
|
||||
default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").output.split()
|
||||
current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split()
|
||||
assert default_checksum[0] != current_checksum[0]
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ def test_web5_dhparam_is_used(docker_compose):
|
||||
sut_container = docker_client.containers.get("nginxproxy")
|
||||
assert sut_container.status == "running"
|
||||
|
||||
host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"]
|
||||
host = f"{sut_container.attrs['NetworkSettings']['IPAddress']}:443"
|
||||
r = subprocess.check_output(
|
||||
"echo '' | openssl s_client -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True)
|
||||
assert "Server Temp Key: X25519, 253 bits\n" == r
|
||||
f"echo '' | openssl s_client -connect {host} -cipher 'EDH' | grep 'Server Temp Key'", shell=True)
|
||||
assert b"Server Temp Key: X25519, 253 bits\n" == r
|
||||
|
@ -8,7 +8,7 @@ web5:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
container_name: nginxproxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
|
@ -22,7 +22,7 @@ def assert_log_contains(expected_log_line):
|
||||
"""
|
||||
sut_container = docker_client.containers.get("nginxproxy")
|
||||
docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
|
||||
assert expected_log_line in docker_logs
|
||||
assert bytes(expected_log_line, encoding="utf8") in docker_logs
|
||||
|
||||
|
||||
###############################################################################
|
||||
@ -35,10 +35,10 @@ def test_dhparam_is_generated_if_missing(docker_compose):
|
||||
sut_container = docker_client.containers.get("nginxproxy")
|
||||
assert sut_container.status == "running"
|
||||
|
||||
assert_log_contains("Generating DH parameters")
|
||||
assert_log_contains("Generating DSA parameters")
|
||||
assert_log_contains("dhparam generation complete, reloading nginx")
|
||||
|
||||
# Make sure the dhparam in use is not the default, pre-generated one
|
||||
default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split()
|
||||
generated_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split()
|
||||
default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").output.split()
|
||||
generated_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split()
|
||||
assert default_checksum[0] != generated_checksum[0]
|
||||
|
@ -1,5 +1,5 @@
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
container_name: nginxproxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
|
@ -8,7 +8,7 @@ def test_web1_HSTS_default(docker_compose, nginxproxy):
|
||||
assert "max-age=31536000" == r.headers["Strict-Transport-Security"]
|
||||
|
||||
# Regression test to ensure HSTS is enabled even when the upstream sends an error in response
|
||||
# Issue #1073 https://github.com/jwilder/nginx-proxy/pull/1073
|
||||
# Issue #1073 https://github.com/nginx-proxy/nginx-proxy/pull/1073
|
||||
def test_web1_HSTS_error(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web1.nginx-proxy.tld/status/500", allow_redirects=False)
|
||||
assert "Strict-Transport-Security" in r.headers
|
||||
@ -26,7 +26,7 @@ def test_web3_HSTS_custom(docker_compose, nginxproxy):
|
||||
assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"]
|
||||
|
||||
# Regression test for issue 1080
|
||||
# https://github.com/jwilder/nginx-proxy/issues/1080
|
||||
# https://github.com/nginx-proxy/nginx-proxy/issues/1080
|
||||
def test_web4_HSTS_off_noredirect(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web4.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 81\n" in r.text
|
||||
|
@ -35,7 +35,7 @@ web4:
|
||||
HTTPS_METHOD: "noredirect"
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -9,7 +9,7 @@ web2:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -9,7 +9,7 @@ web:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -9,7 +9,7 @@ web3:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -3,21 +3,21 @@ import pytest
|
||||
|
||||
@pytest.mark.parametrize("subdomain", ["foo", "bar"])
|
||||
def test_web1_http_redirects_to_https(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("http://%s.nginx-proxy.tld/" % subdomain, allow_redirects=False)
|
||||
r = nginxproxy.get(f"http://{subdomain}.nginx-proxy.tld/", allow_redirects=False)
|
||||
assert r.status_code == 301
|
||||
assert "Location" in r.headers
|
||||
assert "https://%s.nginx-proxy.tld/" % subdomain == r.headers['Location']
|
||||
assert f"https://{subdomain}.nginx-proxy.tld/" == r.headers['Location']
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain", ["foo", "bar"])
|
||||
def test_web1_https_is_forwarded(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("https://%s.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
|
||||
r = nginxproxy.get(f"https://{subdomain}.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 81\n" in r.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain", ["foo", "bar"])
|
||||
def test_web1_HSTS_policy_is_active(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("https://%s.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
|
||||
r = nginxproxy.get(f"https://{subdomain}.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 81\n" in r.text
|
||||
assert "Strict-Transport-Security" in r.headers
|
||||
|
@ -7,7 +7,7 @@ web1:
|
||||
VIRTUAL_HOST: "*.nginx-proxy.tld"
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -3,7 +3,7 @@ version: "3"
|
||||
services:
|
||||
|
||||
proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
|
@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from backports.ssl_match_hostname import CertificateError
|
||||
from ssl import CertificateError
|
||||
from requests.exceptions import SSLError
|
||||
|
||||
|
||||
@ -9,19 +9,19 @@ from requests.exceptions import SSLError
|
||||
(3, False),
|
||||
])
|
||||
def test_http_redirects_to_https(docker_compose, nginxproxy, subdomain, should_redirect_to_https):
|
||||
r = nginxproxy.get("http://%s.web.nginx-proxy.tld/port" % subdomain)
|
||||
r = nginxproxy.get(f"http://{subdomain}.web.nginx-proxy.tld/port")
|
||||
if should_redirect_to_https:
|
||||
assert len(r.history) > 0
|
||||
assert r.history[0].is_redirect
|
||||
assert r.history[0].headers.get("Location") == "https://%s.web.nginx-proxy.tld/port" % subdomain
|
||||
assert "answer from port 8%s\n" % subdomain == r.text
|
||||
assert r.history[0].headers.get("Location") == f"https://{subdomain}.web.nginx-proxy.tld/port"
|
||||
assert f"answer from port 8{subdomain}\n" == r.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain", [1, 2])
|
||||
def test_https_get_served(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("https://%s.web.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
|
||||
r = nginxproxy.get(f"https://{subdomain}.web.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 8%s\n" % subdomain == r.text
|
||||
assert f"answer from port 8{subdomain}\n" == r.text
|
||||
|
||||
|
||||
def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy):
|
||||
|
@ -18,9 +18,9 @@ import pytest
|
||||
("web4.whatever.nginx-proxy.regexp", 84),
|
||||
])
|
||||
def test_wildcard_prefix(docker_compose, nginxproxy, host, expected_port):
|
||||
r = nginxproxy.get("http://%s/port" % host)
|
||||
r = nginxproxy.get(f"http://{host}/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port %s\n" % expected_port
|
||||
assert r.text == f"answer from port {expected_port}\n"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("host", [
|
||||
@ -28,5 +28,5 @@ def test_wildcard_prefix(docker_compose, nginxproxy, host, expected_port):
|
||||
"web4.whatever.nginx-proxy.regexp-to-infinity-and-beyond"
|
||||
])
|
||||
def test_non_matching_host_is_503(docker_compose, nginxproxy, host):
|
||||
r = nginxproxy.get("http://%s/port" % host)
|
||||
r = nginxproxy.get(f"http://{host}/port")
|
||||
assert r.status_code == 503, r.text
|
||||
|
@ -32,7 +32,7 @@ web4:
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
image: nginxproxy/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
Loading…
x
Reference in New Issue
Block a user