mirror of
https://github.com/thib8956/nginx-proxy
synced 2025-04-11 16:21:01 +00:00
Compare commits
174 Commits
0.6.0
...
test-branc
Author | SHA1 | Date | |
---|---|---|---|
7470514e7b | |||
|
3cbc5417b7 | ||
|
8219788df6 | ||
|
941fd630a6 | ||
|
b4709639b3 | ||
|
b8141832a3 | ||
|
0223bae0af | ||
|
6798a6b800 | ||
|
4a2dc46002 | ||
|
718d45feaf | ||
|
0dfe09fb7c | ||
|
77227f8691 | ||
|
e762468759 | ||
|
cf911d950a | ||
|
a3e64a9433 | ||
|
11d644d645 | ||
|
4443ee8b5a | ||
|
08b953ba70 | ||
|
94f5763c04 | ||
|
8cf9ed7145 | ||
|
3ce7d99aea | ||
|
3a9de2d511 | ||
|
eba7d8af77 | ||
|
d8c04f666f | ||
|
ede9f9ec25 | ||
|
26e764950f | ||
|
b886c0bd14 | ||
|
a4cc268628 | ||
|
eb3613695c | ||
|
23823c4b21 | ||
|
16169a0f74 | ||
|
afa2dc53c7 | ||
|
8c590fc68f | ||
|
15d2817384 | ||
|
53a396f406 | ||
|
ad41178036 | ||
|
7dd97d4bc3 | ||
|
6a1a518fec | ||
|
62d51562b5 | ||
|
c33dedf10b | ||
|
58c1fe3606 | ||
|
593c3c29b0 | ||
|
c984ed2b18 | ||
|
e80fc0b304 | ||
|
936e57a6de | ||
|
a285717657 | ||
|
cb2b0e2bd3 | ||
|
4e6900e872 | ||
|
9521593cbc | ||
|
af266c0b83 | ||
|
9be2624d09 | ||
|
c417813df9 | ||
|
59aa78a4a6 | ||
|
ccbbbeb928 | ||
|
1c7ccc473f | ||
|
556b3364fb | ||
|
d7e939dc27 | ||
|
f68383add9 | ||
|
d8777c8689 | ||
|
3590c1bae0 | ||
|
c1ae91364c | ||
|
71225a28fa | ||
|
f8cd4483ac | ||
|
5266553e1b | ||
|
1f19ee3c56 | ||
|
6290f38069 | ||
|
1dce981707 | ||
|
b61c841929 | ||
|
000a44772d | ||
|
37714fa4f8 | ||
|
2f8ebe8d45 | ||
|
d6042d08f1 | ||
|
7a769a6a22 | ||
|
0f27ed800c | ||
|
226bfe158f | ||
|
32d42ffee7 | ||
|
3fab237f34 | ||
|
1eac894902 | ||
|
73f29846b3 | ||
|
6e9dc343cd | ||
|
35f092ca30 | ||
|
bf16afc665 | ||
|
ea80027525 | ||
|
a6e8fae7f5 | ||
|
9b8323d2e2 | ||
|
612bf72ceb | ||
|
ebd1485b09 | ||
|
58a02f107e | ||
|
a312472fb5 | ||
|
1374ee5b9e | ||
|
55610b8425 | ||
|
56fb58cc6f | ||
|
ea98780960 | ||
|
1b868259fe | ||
|
3ac478f284 | ||
|
2528a35656 | ||
|
3ef600a3b5 | ||
|
fc36514eb8 | ||
|
795e153c2e | ||
|
5d503b48cb | ||
|
93d90884e2 | ||
|
92379d8131 | ||
|
31d2ed172b | ||
|
3156b97f3a | ||
|
a3b1d5b7ab | ||
|
09271a333a | ||
|
4b22ccdc81 | ||
|
f05f7a0ff9 | ||
|
817db85aae | ||
|
df24d9dff5 | ||
|
343791b657 | ||
|
fff84de367 | ||
|
065dd7f1ea | ||
|
dfe7677eb5 | ||
|
0cc71fad49 | ||
|
6bdd184d6a | ||
|
febf85d7e2 | ||
|
2eb2ae9c93 | ||
|
29fffd6de8 | ||
|
8ac755e1d6 | ||
|
02121df3b9 | ||
|
14779ec4be | ||
|
a318b57408 | ||
|
57a33aaf8b | ||
|
026ba7cdac | ||
|
761bbf9dbc | ||
|
c41186a3a4 | ||
|
90b62e0abc | ||
|
a3cd96ead4 | ||
|
e3b6be79fc | ||
|
1867228cce | ||
|
a8ee64b059 | ||
|
4e4733f68e | ||
|
23a2c7d848 | ||
|
2c4102d396 | ||
|
fed6df3756 | ||
|
965c722344 | ||
|
f2487741dc | ||
|
b6a445b1a9 | ||
|
cf88817355 | ||
|
851b0e36cd | ||
|
172d79aff4 | ||
|
8414a94d59 | ||
|
de2f057c10 | ||
|
6dfc3f3f70 | ||
|
e25c78b00a | ||
|
a3fbaa5990 | ||
|
6912414750 | ||
|
e373a5199b | ||
|
c2544d4c78 | ||
|
abdd5883a1 | ||
|
98b5828f83 | ||
|
0244b4e71e | ||
|
ad9af2884d | ||
|
d320b43476 | ||
|
83a28f47d7 | ||
|
b0de1f19d3 | ||
|
7d253dd0f3 | ||
|
dffc0c47cf | ||
|
c219822cd8 | ||
|
f73a52afaf | ||
|
7c0f7b9449 | ||
|
6242403d33 | ||
|
ebfe5e9c17 | ||
|
dfdd67f5a4 | ||
|
f186815c2d | ||
|
b0de80d46b | ||
|
8534185b0c | ||
|
c091d08fee | ||
|
ebbf7a7b74 | ||
|
d3a0da451a | ||
|
c51c9980cf | ||
|
6f2b3f1c54 | ||
|
0b1e9e56e1 |
14
.github/ISSUE_TEMPLATE.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# !!!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.
|
||||
|
||||
For bugs, the easier you make it to reproduce the issue you see, the easier and faster it can get fixed. If you can provide a script or docker-compose file that reproduces the problems, that is very helpful.
|
||||
|
||||
Thanks,
|
||||
Jason
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
**/__pycache__/
|
||||
**/.cache/
|
||||
.idea/
|
||||
|
14
.travis.yml
14
.travis.yml
@ -1,20 +1,18 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- DOCKER_VERSION=1.13.1-0~ubuntu-trusty
|
||||
matrix:
|
||||
- TEST_TARGET: test-debian
|
||||
- TEST_TARGET: test-alpine
|
||||
|
||||
before_install:
|
||||
# list docker-engine versions
|
||||
- apt-cache madison docker-engine
|
||||
# upgrade docker-engine to specific version
|
||||
- sudo apt-get -o Dpkg::Options::="--force-confnew" install -y --force-yes docker-engine=${DOCKER_VERSION}
|
||||
- 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
|
||||
|
13
Dockerfile
13
Dockerfile
@ -1,5 +1,5 @@
|
||||
FROM nginx:1.11.10
|
||||
MAINTAINER Jason Wilder mail@jasonwilder.com
|
||||
FROM nginx:1.17.8
|
||||
LABEL maintainer="Jason Wilder mail@jasonwilder.com"
|
||||
|
||||
# Install wget and install/updates certificates
|
||||
RUN apt-get update \
|
||||
@ -9,26 +9,29 @@ RUN apt-get update \
|
||||
&& apt-get clean \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Configure Nginx and apply fix for very long server names
|
||||
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
|
||||
&& sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf
|
||||
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
|
||||
|
||||
# Install Forego
|
||||
ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego
|
||||
RUN chmod u+x /usr/local/bin/forego
|
||||
|
||||
ENV DOCKER_GEN_VERSION 0.7.3
|
||||
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
|
||||
|
||||
COPY network_internal.conf /etc/nginx/
|
||||
|
||||
COPY . /app/
|
||||
WORKDIR /app/
|
||||
|
||||
ENV DOCKER_HOST unix:///tmp/docker.sock
|
||||
|
||||
VOLUME ["/etc/nginx/certs"]
|
||||
VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]
|
||||
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
CMD ["forego", "start", "-r"]
|
||||
|
@ -1,31 +1,34 @@
|
||||
FROM nginx:1.11.10-alpine
|
||||
MAINTAINER Jason Wilder mail@jasonwilder.com
|
||||
FROM nginx:1.17.8-alpine
|
||||
LABEL maintainer="Jason Wilder mail@jasonwilder.com"
|
||||
|
||||
# Install wget and install/updates certificates
|
||||
RUN apk add --no-cache --virtual .run-deps \
|
||||
ca-certificates bash wget \
|
||||
ca-certificates bash wget openssl \
|
||||
&& update-ca-certificates
|
||||
|
||||
|
||||
# Configure Nginx and apply fix for very long server names
|
||||
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
|
||||
&& sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf
|
||||
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
|
||||
|
||||
# Install Forego
|
||||
ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego
|
||||
RUN chmod u+x /usr/local/bin/forego
|
||||
|
||||
ENV DOCKER_GEN_VERSION 0.7.3
|
||||
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
|
||||
|
||||
COPY network_internal.conf /etc/nginx/
|
||||
|
||||
COPY . /app/
|
||||
WORKDIR /app/
|
||||
|
||||
ENV DOCKER_HOST unix:///tmp/docker.sock
|
||||
|
||||
VOLUME ["/etc/nginx/certs"]
|
||||
VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]
|
||||
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
CMD ["forego", "start", "-r"]
|
||||
|
149
README.md
149
README.md
@ -1,4 +1,5 @@
|
||||
  [](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://travis-ci.org/jwilder/nginx-proxy) [](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [](https://hub.docker.com/r/jwilder/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.
|
||||
@ -15,9 +16,9 @@ Then start any containers you want proxied with an env var `VIRTUAL_HOST=subdoma
|
||||
|
||||
$ docker run -e VIRTUAL_HOST=foo.bar.com ...
|
||||
|
||||
The containers being proxied must [expose](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create`.
|
||||
The containers being proxied must [expose](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create` and be in the same network. By default, if you don't pass the --net flag when your nginx-proxy container is created, it will only be attached to the default bridge network. This means that it will not be able to connect to containers on networks other than bridge.
|
||||
|
||||
Provided your DNS is setup to forward foo.bar.com to the a host running nginx-proxy, the request will be routed to a container with the VIRTUAL_HOST env var set.
|
||||
Provided your DNS is setup to forward foo.bar.com to the host running nginx-proxy, the request will be routed to a container with the VIRTUAL_HOST env var set.
|
||||
|
||||
### Image variants
|
||||
|
||||
@ -39,10 +40,10 @@ This image is based on the nginx:alpine image. Use this image to fully support H
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy
|
||||
container_name: nginx-proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
@ -50,7 +51,6 @@ services:
|
||||
|
||||
whoami:
|
||||
image: jwilder/whoami
|
||||
container_name: whoami
|
||||
environment:
|
||||
- VIRTUAL_HOST=whoami.local
|
||||
```
|
||||
@ -96,16 +96,48 @@ $ docker network connect my-other-network my-nginx-proxy
|
||||
|
||||
In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks.
|
||||
|
||||
### Internet vs. Local Network Access
|
||||
|
||||
If you allow traffic from the public internet to access your `nginx-proxy` container, you may want to restrict some containers to the internal network only, so they cannot be accessed from the public internet. On containers that should be restricted to the internal network, you should set the environment variable `NETWORK_ACCESS=internal`. By default, the *internal* network is defined as `127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16`. To change the list of networks considered internal, mount a file on the `nginx-proxy` at `/etc/nginx/network_internal.conf` with these contents, edited to suit your needs:
|
||||
|
||||
```
|
||||
# These networks are considered "internal"
|
||||
allow 127.0.0.0/8;
|
||||
allow 10.0.0.0/8;
|
||||
allow 192.168.0.0/16;
|
||||
allow 172.16.0.0/12;
|
||||
|
||||
# Traffic from all other networks will be rejected
|
||||
deny all;
|
||||
```
|
||||
|
||||
When internal-only access is enabled, external clients with 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/`.
|
||||
|
||||
### SSL Backends
|
||||
|
||||
If you would like the reverse proxy to connect to your backend using HTTPS instead of HTTP, set `VIRTUAL_PROTO=https` on the backend container.
|
||||
|
||||
> Note: If you use `VIRTUAL_PROTO=https` and your backend container exposes port 80 and 443, `nginx-proxy` will use HTTPS on port 80. This is almost certainly not what you want, so you should also include `VIRTUAL_PORT=443`.
|
||||
|
||||
### uWSGI Backends
|
||||
|
||||
If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the
|
||||
backend container. Your backend container should than listen on a port rather
|
||||
backend container. Your backend container should then listen on a port rather
|
||||
than a socket and expose that port.
|
||||
|
||||
### FastCGI Backends
|
||||
|
||||
If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on the
|
||||
backend container. Your backend container should then listen on a port rather
|
||||
than a socket and expose that port.
|
||||
|
||||
### FastCGI File Root Directory
|
||||
|
||||
If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory
|
||||
|
||||
|
||||
### Default Host
|
||||
|
||||
To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example
|
||||
@ -149,8 +181,12 @@ Finally, start your containers with `VIRTUAL_HOST` environment variables.
|
||||
$ docker run -e VIRTUAL_HOST=foo.bar.com ...
|
||||
### SSL Support using letsencrypt
|
||||
|
||||
[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically.
|
||||
[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.
|
||||
|
||||
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`
|
||||
|
||||
$ docker run -e DHPARAM_GENERATION=false ....
|
||||
### SSL Support
|
||||
|
||||
SSL is supported using single host, wildcard and SNI certificates using naming conventions for
|
||||
@ -171,9 +207,27 @@ By default, Docker is not able to mount directories on the host machine to conta
|
||||
|
||||
#### Diffie-Hellman Groups
|
||||
|
||||
If you have Diffie-Hellman groups enabled, the files should be named after the virtual host with a
|
||||
Diffie-Hellman groups are enabled by default, with a pregenerated key in `/etc/nginx/dhparam/dhparam.pem`.
|
||||
You can mount a different `dhparam.pem` file at that location to override the default cert.
|
||||
To use custom `dhparam.pem` files per-virtual-host, the files should be named after the virtual host with a
|
||||
`dhparam` suffix and `.pem` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com`
|
||||
should have a `foo.bar.com.dhparam.pem` file in the certs directory.
|
||||
should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory.
|
||||
|
||||
> NOTE: If you don't mount a `dhparam.pem` file at `/etc/nginx/dhparam/dhparam.pem`, one will be generated
|
||||
at startup. Since it can take minutes to generate a new `dhparam.pem`, it is done at low priority in the
|
||||
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
|
||||
> 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`.
|
||||
|
||||
In the separate container setup, no pregenerated key will be available and neither the
|
||||
[jwilder/docker-gen](https://index.docker.io/u/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
|
||||
nginx container, at `/etc/nginx/dhparam/dhparam.pem`.
|
||||
|
||||
#### Wildcard Certificates
|
||||
|
||||
@ -187,12 +241,35 @@ to identify the certificate to be used. For example, a certificate for `*.foo.c
|
||||
could be named `shared.crt` and `shared.key`. A container running with `VIRTUAL_HOST=foo.bar.com`
|
||||
and `CERT_NAME=shared` will then use this shared cert.
|
||||
|
||||
#### OCSP Stapling
|
||||
To enable OCSP Stapling for a domain, `nginx-proxy` looks for a PEM certificate containing the trusted
|
||||
CA certificate chain at `/etc/nginx/certs/<domain>.chain.pem`, where `<domain>` is the domain name in
|
||||
the `VIRTUAL_HOST` directive. The format of this file is a concatenation of the public PEM CA
|
||||
certificates starting with the intermediate CA most near the SSL certificate, down to the root CA. This is
|
||||
often referred to as the "SSL Certificate Chain". If found, this filename is passed to the NGINX
|
||||
[`ssl_trusted_certificate` directive](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_trusted_certificate)
|
||||
and OCSP Stapling is enabled.
|
||||
|
||||
#### How SSL Support Works
|
||||
|
||||
The SSL cipher configuration is based on [mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) which
|
||||
should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1,
|
||||
Windows XP IE8, Android 2.3, Java 7. The configuration also enables HSTS, and SSL
|
||||
session caches.
|
||||
The default SSL cipher configuration is based on the [Mozilla intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) version 5.0 which
|
||||
should provide compatibility with clients back to Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7,
|
||||
Java 8u31, OpenSSL 1.0.1, Opera 20, and Safari 9. Note that the DES-based TLS ciphers were removed for security.
|
||||
The configuration also enables HSTS, PFS, OCSP stapling and SSL session caches. Currently TLS 1.2 and 1.3
|
||||
are supported.
|
||||
|
||||
If you don't require backward compatibility, you can use the [Mozilla modern profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility)
|
||||
profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to the nginx-proxy container or to your container.
|
||||
This profile is compatible with clients back to Firefox 63, Android 10.0, Chrome 70, Edge 75, Java 11,
|
||||
OpenSSL 1.1.1, Opera 57, and Safari 12.1. Note that this profile is **not** compatible with any version of Internet Explorer.
|
||||
|
||||
Other policies available through the `SSL_POLICY` environment variable are [`Mozilla-Old`](https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility)
|
||||
and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)
|
||||
`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
|
||||
this, either globally or per virtual-host.
|
||||
|
||||
The default behavior for the proxy when port 80 and 443 are exposed is as follows:
|
||||
|
||||
@ -207,14 +284,21 @@ 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` must be specified on each container for which you want to
|
||||
override the default behavior. 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
|
||||
disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with
|
||||
`HTTPS_METHOD=nohttps`. `HTTPS_METHOD` must be specified on each container for which you want to
|
||||
override the default behavior. 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.
|
||||
|
||||
By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
|
||||
is enabled with `max-age=31536000` for HTTPS sites. You can disable HSTS with the environment variable
|
||||
`HSTS=off` or use a custom HSTS configuration like `HSTS=max-age=31536000; includeSubDomains; preload`.
|
||||
*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.
|
||||
|
||||
### 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
|
||||
@ -319,6 +403,25 @@ If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=e
|
||||
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.
|
||||
|
||||
#### Pre-VIRTUAL_HOST custom location blocks
|
||||
|
||||
In some circumstances you may want to override nginx's default `/` location block behavior. Typically, this block acts as a catch-all in order to forward requests not already matched by a specific `location` block directly onto your container as-is.
|
||||
|
||||
To provide your own location blocks and bypass the automatic generation of them, simply add your location blocks to a configuration file file under `/etc/nginx/vhost.d` like in the other Per-VIRTUAL_HOST sections except with the suffix `_locations`. Notice the 's' to make the filename plural.
|
||||
The contents of this file will replace all auto-generated location blocks. Additionally, this file will take priority over the previously described location configuration.
|
||||
|
||||
When using location overrides, you are responsible for handling any requests that should be forwarded to your container. Passing a request to your container is done using the `proxy_pass` instruction within your defined location blocks. `proxy_pass` expects a qualified hostname in order
|
||||
to forward a request. By default, nginx-proxy aliases containers to the defined `VIRTUAL_HOST` name. So if you launch your container with a `VIRTUAL_HOST` value of `app.example.com`, then forwarding a request to your container would look something like this:
|
||||
|
||||
```
|
||||
location / {
|
||||
proxy_pass http://app.example.com;
|
||||
}
|
||||
```
|
||||
|
||||
If you are using an SSL-enabled container, you would use `https://` in place of `http://`. You could include any number of other location blocks for nginx to consider and even forward requests to external hosts when they match certain conditions. You can also use any other rules and instructions
|
||||
available to nginx location blocks.
|
||||
|
||||
### Contributing
|
||||
|
||||
Before submitting pull requests or issues, please check github to make sure an existing issue or pull request is not already open.
|
||||
@ -328,7 +431,7 @@ Before submitting pull requests or issues, please check github to make sure an e
|
||||
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:
|
||||
@ -341,6 +444,10 @@ 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:
|
||||
|
||||
make test
|
||||
|
||||
|
||||
|
||||
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)
|
||||
|
8
dhparam.pem.default
Normal file
8
dhparam.pem.default
Normal file
@ -0,0 +1,8 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEAzB2nIGzpVq7afJnKBm1X0d64avwOlP2oneiKwxRHdDI/5+6TpH1P
|
||||
F8ipodGuZBUMmupoB3D34pu2Qq5boNW983sm18ww9LMz2i/pxhSdB+mYAew+A6h6
|
||||
ltQ5pNtyn4NaKw1SDFkqvde3GNPhaWoPDbZDJhpHGblR3w1b/ag+lTLZUvVwcD8L
|
||||
jYS9f9YWAC6T7WxAxh4zvu1Z0I1EKde8KYBxrreZNheXpXHqMNyJYZCaY2Hb/4oI
|
||||
EL65qZq1GCWezpWMjhk6pOnV5gbvqfhoazCv/4OdRv6RoWOIYBNs9BmGho4AtXqV
|
||||
FYLdYDhOvN4aVs9Ir+G8ouwiRnix24+UewIBAg==
|
||||
-----END DH PARAMETERS-----
|
@ -2,7 +2,7 @@
|
||||
set -e
|
||||
|
||||
# Warn if the DOCKER_HOST socket does not exist
|
||||
if [[ $DOCKER_HOST == unix://* ]]; then
|
||||
if [[ $DOCKER_HOST = unix://* ]]; then
|
||||
socket_file=${DOCKER_HOST#unix://}
|
||||
if ! [ -S $socket_file ]; then
|
||||
cat >&2 <<-EOT
|
||||
@ -14,6 +14,18 @@ if [[ $DOCKER_HOST == unix://* ]]; then
|
||||
fi
|
||||
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
|
||||
|
||||
# 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')
|
||||
if [ "x$RESOLVERS" = "x" ]; then
|
||||
echo "Warning: unable to determine DNS resolvers for nginx" >&2
|
||||
unset 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
|
||||
exit 1
|
||||
|
52
generate-dhparam.sh
Executable file
52
generate-dhparam.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# The first argument is the bit depth of the dhparam, or 2048 if unspecified
|
||||
DHPARAM_BITS=${1:-2048}
|
||||
GENERATE_DHPARAM=${2:-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.
|
||||
PREGEN_DHPARAM_FILE="/app/dhparam.pem.default"
|
||||
DHPARAM_FILE="/etc/nginx/dhparam/dhparam.pem"
|
||||
GEN_LOCKFILE="/tmp/dhparam_generating.lock"
|
||||
|
||||
# The hash of the pregenerated dhparam file is used to check if the pregen dhparam is already in use
|
||||
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
|
||||
# There is already a dhparam, and it's not the default
|
||||
echo "Custom dhparam.pem file found, generation skipped"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -f $GEN_LOCKFILE ]]; then
|
||||
# Generation is already in progress
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $GENERATE_DHPARAM =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then
|
||||
echo "Skipping Diffie-Hellman parameters generation and Ignoring pre-generated dhparam.pem"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat >&2 <<-EOT
|
||||
WARNING: $DHPARAM_FILE was not found. A pre-generated dhparam.pem will be used for now while a new one
|
||||
is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded.
|
||||
EOT
|
||||
|
||||
# Put the default dhparam file in place so we can start immediately
|
||||
cp $PREGEN_DHPARAM_FILE $DHPARAM_FILE
|
||||
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 -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
|
6
network_internal.conf
Normal file
6
network_internal.conf
Normal file
@ -0,0 +1,6 @@
|
||||
# Only allow traffic from internal clients
|
||||
allow 127.0.0.0/8;
|
||||
allow 10.0.0.0/8;
|
||||
allow 192.168.0.0/16;
|
||||
allow 172.16.0.0/12;
|
||||
deny all;
|
211
nginx.tmpl
211
nginx.tmpl
@ -1,5 +1,8 @@
|
||||
{{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }}
|
||||
|
||||
{{ $external_http_port := coalesce $.Env.HTTP_PORT "80" }}
|
||||
{{ $external_https_port := coalesce $.Env.HTTPS_PORT "443" }}
|
||||
|
||||
{{ define "upstream" }}
|
||||
{{ if .Address }}
|
||||
{{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}}
|
||||
@ -13,7 +16,55 @@
|
||||
{{ end }}
|
||||
{{ else if .Network }}
|
||||
# {{ .Container.Name }}
|
||||
server {{ .Network.IP }} down;
|
||||
{{ if .Network.IP }}
|
||||
server {{ .Network.IP }} down;
|
||||
{{ else }}
|
||||
server 127.0.0.1 down;
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{ define "ssl_policy" }}
|
||||
{{ if eq .ssl_policy "Mozilla-Modern" }}
|
||||
ssl_protocols TLSv1.3;
|
||||
{{/* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 /*}}
|
||||
{{/* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) /*}}
|
||||
{{/* explicitly set ngnix default value in order to allow single servers to override the global http value */}}
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers off;
|
||||
{{ else if eq .ssl_policy "Mozilla-Intermediate" }}
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_prefer_server_ciphers off;
|
||||
{{ else if eq .ssl_policy "Mozilla-Old" }}
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }}
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }}
|
||||
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ else if eq .ssl_policy "AWS-2016-08" }}
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ else if eq .ssl_policy "AWS-2015-05" }}
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ else if eq .ssl_policy "AWS-2015-03" }}
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ else if eq .ssl_policy "AWS-2015-02" }}
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@ -38,6 +89,14 @@ map $http_upgrade $proxy_connection {
|
||||
'' close;
|
||||
}
|
||||
|
||||
# Apply fix for very long server names
|
||||
server_names_hash_bucket_size 128;
|
||||
|
||||
# Default dhparam
|
||||
{{ if (exists "/etc/nginx/dhparam/dhparam.pem") }}
|
||||
ssl_dhparam /etc/nginx/dhparam/dhparam.pem;
|
||||
{{ end }}
|
||||
|
||||
# Set appropriate X-Forwarded-Ssl header
|
||||
map $scheme $proxy_x_forwarded_ssl {
|
||||
default off;
|
||||
@ -52,6 +111,14 @@ log_format vhost '$host $remote_addr - $remote_user [$time_local] '
|
||||
|
||||
access_log off;
|
||||
|
||||
{{/* Get the SSL_POLICY defined by this container, falling back to "Mozilla-Intermediate" */}}
|
||||
{{ $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }}
|
||||
{{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }}
|
||||
|
||||
{{ if $.Env.RESOLVERS }}
|
||||
resolver {{ $.Env.RESOLVERS }};
|
||||
{{ end }}
|
||||
|
||||
{{ if (exists "/etc/nginx/proxy.conf") }}
|
||||
include /etc/nginx/proxy.conf;
|
||||
{{ else }}
|
||||
@ -71,27 +138,30 @@ proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header Proxy "";
|
||||
{{ end }}
|
||||
|
||||
{{ $access_log := (or (and (not $.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }}
|
||||
|
||||
{{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) "") "true" }}
|
||||
server {
|
||||
server_name _; # This is just an invalid value which will never trigger on a real hostname.
|
||||
listen 80;
|
||||
listen {{ $external_http_port }};
|
||||
{{ if $enable_ipv6 }}
|
||||
listen [::]:80;
|
||||
listen [::]:{{ $external_http_port }};
|
||||
{{ end }}
|
||||
access_log /var/log/nginx/access.log vhost;
|
||||
{{ $access_log }}
|
||||
return 503;
|
||||
}
|
||||
|
||||
{{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
|
||||
server {
|
||||
server_name _; # This is just an invalid value which will never trigger on a real hostname.
|
||||
listen 443 ssl http2;
|
||||
listen {{ $external_https_port }} ssl http2;
|
||||
{{ if $enable_ipv6 }}
|
||||
listen [::]:443 ssl http2;
|
||||
listen [::]:{{ $external_https_port }} ssl http2;
|
||||
{{ end }}
|
||||
access_log /var/log/nginx/access.log vhost;
|
||||
{{ $access_log }}
|
||||
return 503;
|
||||
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_tickets off;
|
||||
ssl_certificate /etc/nginx/certs/default.crt;
|
||||
ssl_certificate_key /etc/nginx/certs/default.key;
|
||||
@ -99,17 +169,21 @@ server {
|
||||
{{ end }}
|
||||
|
||||
{{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }}
|
||||
|
||||
{{ $host := trim $host }}
|
||||
{{ $is_regexp := hasPrefix "~" $host }}
|
||||
{{ $upstream_name := when $is_regexp (sha1 $host) $host }}
|
||||
|
||||
# {{ $host }}
|
||||
upstream {{ $upstream_name }} {
|
||||
|
||||
{{ range $container := $containers }}
|
||||
{{ $addrLen := len $container.Addresses }}
|
||||
|
||||
{{ range $knownNetwork := $CurrentContainer.Networks }}
|
||||
{{ range $containerNetwork := $container.Networks }}
|
||||
{{ if eq $knownNetwork.Name $containerNetwork.Name }}
|
||||
## Can be connect with "{{ $containerNetwork.Name }}" network
|
||||
{{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }}
|
||||
## Can be connected with "{{ $containerNetwork.Name }}" network
|
||||
|
||||
{{/* If only 1 port exposed, use that */}}
|
||||
{{ if eq $addrLen 1 }}
|
||||
@ -121,6 +195,9 @@ upstream {{ $upstream_name }} {
|
||||
{{ $address := where $container.Addresses "Port" $port | first }}
|
||||
{{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
# Cannot connect to network of this container
|
||||
server 127.0.0.1 down;
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@ -131,11 +208,24 @@ upstream {{ $upstream_name }} {
|
||||
{{ $default_server := index (dict $host "" $default_host "default_server") $host }}
|
||||
|
||||
{{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}}
|
||||
{{ $proto := or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http" }}
|
||||
{{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }}
|
||||
|
||||
{{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}}
|
||||
{{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }}
|
||||
|
||||
{{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}}
|
||||
{{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }}
|
||||
|
||||
{{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}}
|
||||
{{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }}
|
||||
|
||||
{{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}}
|
||||
{{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }}
|
||||
|
||||
{{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}}
|
||||
{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }}
|
||||
|
||||
|
||||
{{/* Get the first cert name defined by containers w/ the same vhost */}}
|
||||
{{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }}
|
||||
|
||||
@ -156,27 +246,42 @@ upstream {{ $upstream_name }} {
|
||||
{{ if eq $https_method "redirect" }}
|
||||
server {
|
||||
server_name {{ $host }};
|
||||
listen 80 {{ $default_server }};
|
||||
listen {{ $external_http_port }} {{ $default_server }};
|
||||
{{ if $enable_ipv6 }}
|
||||
listen [::]:80 {{ $default_server }};
|
||||
listen [::]:{{ $external_http_port }} {{ $default_server }};
|
||||
{{ end }}
|
||||
access_log /var/log/nginx/access.log vhost;
|
||||
return 301 https://$host$request_uri;
|
||||
{{ $access_log }}
|
||||
|
||||
# Do not HTTPS redirect Let'sEncrypt ACME challenge
|
||||
location /.well-known/acme-challenge/ {
|
||||
auth_basic off;
|
||||
allow all;
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri =404;
|
||||
break;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
server {
|
||||
server_name {{ $host }};
|
||||
listen 443 ssl http2 {{ $default_server }};
|
||||
listen {{ $external_https_port }} ssl http2 {{ $default_server }};
|
||||
{{ if $enable_ipv6 }}
|
||||
listen [::]:443 ssl http2 {{ $default_server }};
|
||||
listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }};
|
||||
{{ end }}
|
||||
access_log /var/log/nginx/access.log vhost;
|
||||
{{ $access_log }}
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
|
||||
{{ if eq $network_tag "internal" }}
|
||||
# Only allow traffic from internal clients
|
||||
include /etc/nginx/network_internal.conf;
|
||||
{{ end }}
|
||||
|
||||
{{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }}
|
||||
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_tickets off;
|
||||
@ -188,8 +293,14 @@ server {
|
||||
ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }};
|
||||
{{ end }}
|
||||
|
||||
{{ if (ne $https_method "noredirect") }}
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
{{ if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }}
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }};
|
||||
{{ end }}
|
||||
|
||||
{{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }}
|
||||
add_header Strict-Transport-Security "{{ trim $hsts }}" always;
|
||||
{{ end }}
|
||||
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}
|
||||
@ -198,23 +309,34 @@ server {
|
||||
include /etc/nginx/vhost.d/default;
|
||||
{{ end }}
|
||||
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s_locations" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s_locations" $host}};
|
||||
{{ else }}
|
||||
location / {
|
||||
{{ if eq $proto "uwsgi" }}
|
||||
include uwsgi_params;
|
||||
uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }};
|
||||
{{ else if eq $proto "fastcgi" }}
|
||||
root {{ trim $vhost_root }};
|
||||
include fastcgi_params;
|
||||
fastcgi_pass {{ trim $upstream_name }};
|
||||
{{ else if eq $proto "grpc" }}
|
||||
grpc_pass {{ trim $proto }}://{{ trim $upstream_name }};
|
||||
{{ else }}
|
||||
proxy_pass {{ trim $proto }}://{{ trim $upstream_name }};
|
||||
{{ end }}
|
||||
|
||||
{{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }}
|
||||
auth_basic "Restricted {{ $host }}";
|
||||
auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }};
|
||||
{{ end }}
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s_location" $host}};
|
||||
{{ else if (exists "/etc/nginx/vhost.d/default_location") }}
|
||||
include /etc/nginx/vhost.d/default_location;
|
||||
{{ end }}
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s_location" $host}};
|
||||
{{ else if (exists "/etc/nginx/vhost.d/default_location") }}
|
||||
include /etc/nginx/vhost.d/default_location;
|
||||
{{ end }}
|
||||
}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
{{ end }}
|
||||
@ -223,11 +345,16 @@ server {
|
||||
|
||||
server {
|
||||
server_name {{ $host }};
|
||||
listen 80 {{ $default_server }};
|
||||
listen {{ $external_http_port }} {{ $default_server }};
|
||||
{{ if $enable_ipv6 }}
|
||||
listen [::]:80 {{ $default_server }};
|
||||
{{ end }}
|
||||
access_log /var/log/nginx/access.log vhost;
|
||||
{{ $access_log }}
|
||||
|
||||
{{ if eq $network_tag "internal" }}
|
||||
# Only allow traffic from internal clients
|
||||
include /etc/nginx/network_internal.conf;
|
||||
{{ end }}
|
||||
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s" $host }};
|
||||
@ -235,10 +362,19 @@ server {
|
||||
include /etc/nginx/vhost.d/default;
|
||||
{{ end }}
|
||||
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s_locations" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s_locations" $host}};
|
||||
{{ else }}
|
||||
location / {
|
||||
{{ if eq $proto "uwsgi" }}
|
||||
include uwsgi_params;
|
||||
uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }};
|
||||
{{ else if eq $proto "fastcgi" }}
|
||||
root {{ trim $vhost_root }};
|
||||
include fastcgi_params;
|
||||
fastcgi_pass {{ trim $upstream_name }};
|
||||
{{ else if eq $proto "grpc" }}
|
||||
grpc_pass {{ trim $proto }}://{{ trim $upstream_name }};
|
||||
{{ else }}
|
||||
proxy_pass {{ trim $proto }}://{{ trim $upstream_name }};
|
||||
{{ end }}
|
||||
@ -246,22 +382,23 @@ server {
|
||||
auth_basic "Restricted {{ $host }}";
|
||||
auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }};
|
||||
{{ end }}
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s_location" $host}};
|
||||
{{ else if (exists "/etc/nginx/vhost.d/default_location") }}
|
||||
include /etc/nginx/vhost.d/default_location;
|
||||
{{ end }}
|
||||
{{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }}
|
||||
include {{ printf "/etc/nginx/vhost.d/%s_location" $host}};
|
||||
{{ else if (exists "/etc/nginx/vhost.d/default_location") }}
|
||||
include /etc/nginx/vhost.d/default_location;
|
||||
{{ end }}
|
||||
}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
|
||||
server {
|
||||
server_name {{ $host }};
|
||||
listen 443 ssl http2 {{ $default_server }};
|
||||
listen {{ $external_https_port }} ssl http2 {{ $default_server }};
|
||||
{{ if $enable_ipv6 }}
|
||||
listen [::]:443 ssl http2 {{ $default_server }};
|
||||
listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }};
|
||||
{{ end }}
|
||||
access_log /var/log/nginx/access.log vhost;
|
||||
{{ $access_log }}
|
||||
return 500;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/default.crt;
|
||||
|
@ -11,7 +11,7 @@ if [[ "$#" -eq 0 ]]; then
|
||||
|
||||
You can also create certificates for wildcard domains:
|
||||
$(basename $0) '*.my-domain.tdl'
|
||||
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
else
|
||||
@ -24,8 +24,8 @@ fi
|
||||
# Create a nginx container (which conveniently provides the `openssl` command)
|
||||
###############################################################################
|
||||
|
||||
CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.11.8)
|
||||
# Configure openssl
|
||||
CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.14.1)
|
||||
# Configure openssl
|
||||
docker exec $CONTAINER bash -c '
|
||||
mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null
|
||||
echo 1000 > /ca/serial
|
||||
@ -117,7 +117,7 @@ function openssl {
|
||||
}
|
||||
|
||||
function exitfail {
|
||||
echo
|
||||
echo
|
||||
echo ERROR: "$@"
|
||||
docker rm -f $CONTAINER
|
||||
exit 1
|
||||
@ -129,15 +129,15 @@ function exitfail {
|
||||
###############################################################################
|
||||
|
||||
if ! [[ -f "$DIR/ca-root.key" ]]; then
|
||||
echo
|
||||
echo
|
||||
echo "> Create a Certificate Authority root key: $DIR/ca-root.key"
|
||||
openssl genrsa -out ca-root.key 2048
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate CA root key
|
||||
fi
|
||||
|
||||
# Create a CA root certificate
|
||||
# Create a CA root certificate
|
||||
if ! [[ -f "$DIR/ca-root.crt" ]]; then
|
||||
echo
|
||||
echo
|
||||
echo "> Create a CA root certificate: $DIR/ca-root.crt"
|
||||
openssl req -config /ca/openssl.cnf \
|
||||
-key ca-root.key \
|
||||
@ -154,30 +154,30 @@ fi
|
||||
# create server key and certificate signed by the certificate authority
|
||||
###############################################################################
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "> Create a host key: $DIR/$DOMAIN.key"
|
||||
openssl genrsa -out "$DOMAIN.key" 2048
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "> Create a host certificate signing request"
|
||||
|
||||
SAN="$ALTERNATE_DOMAINS" openssl req -config /ca/openssl.cnf \
|
||||
-key "$DOMAIN.key" \
|
||||
-new -out "/ca/$DOMAIN.csr" -days 1000 -extensions san_env -subj "/CN=$DOMAIN"
|
||||
-new -out "/ca/$DOMAIN.csr" -days 1000 -extensions san_env -subj "/CN=$DOMAIN"
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate server certificate signing request
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "> Create server certificate: $DIR/$DOMAIN.crt"
|
||||
SAN="$ALTERNATE_DOMAINS" openssl ca -config /ca/openssl.cnf -batch \
|
||||
-extensions server_cert \
|
||||
-extensions san_env \
|
||||
-in "/ca/$DOMAIN.csr" \
|
||||
-out "$DOMAIN.crt"
|
||||
-out "$DOMAIN.crt"
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate server certificate
|
||||
|
||||
|
||||
# Verify host certificate
|
||||
#openssl x509 -noout -text -in "$DOMAIN.crt"
|
||||
#openssl x509 -noout -text -in "$DOMAIN.crt"
|
||||
|
||||
|
||||
docker rm -f $CONTAINER >/dev/null
|
||||
|
@ -257,7 +257,7 @@ def get_nginx_conf_from_container(container):
|
||||
strm, stat = container.get_archive('/etc/nginx/conf.d/default.conf')
|
||||
with tarfile.open(fileobj=StringIO(strm.read())) as tf:
|
||||
conffile = tf.extractfile('default.conf')
|
||||
return conffile.read()
|
||||
return conffile.read()
|
||||
|
||||
|
||||
def docker_compose_up(compose_file='docker-compose.yml'):
|
||||
@ -445,6 +445,18 @@ def pytest_runtest_logreport(report):
|
||||
report.longrepr.addsection('nginx-proxy conf', get_nginx_conf_from_container(container))
|
||||
|
||||
|
||||
# Py.test `incremental` marker, see http://stackoverflow.com/a/12579625/107049
|
||||
def pytest_runtest_makereport(item, call):
|
||||
if "incremental" in item.keywords:
|
||||
if call.excinfo is not None:
|
||||
parent = item.parent
|
||||
parent._previousfailed = item
|
||||
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
previousfailed = getattr(item.parent, "_previousfailed", None)
|
||||
if previousfailed is not None:
|
||||
pytest.xfail("previous test failed (%s)" % previousfailed.name)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -457,5 +469,5 @@ try:
|
||||
except docker.errors.ImageNotFound:
|
||||
pytest.exit("The docker image 'jwilder/nginx-proxy:test' is missing")
|
||||
|
||||
if docker.__version__ != "2.0.2":
|
||||
pytest.exit("This test suite is meant to work with the python docker module v2.0.2")
|
||||
if docker.__version__ != "2.1.0":
|
||||
pytest.exit("This test suite is meant to work with the python docker module v2.1.0")
|
||||
|
8
test/lib/ssl/dhparam.pem
Normal file
8
test/lib/ssl/dhparam.pem
Normal file
@ -0,0 +1,8 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEA1cae6HqPSgicEuAuSCf6Ii3d6qMX9Ta8lnwoX0JQ0CWK7mzaiiIi
|
||||
dY7oHmc4cq0S3SH+g0tdLP9yqygFS9hdUGINwS2VV6poj2/vdL/dUshegyxpEH58
|
||||
nofCPnFDeKkcPDMYAlGS8zjp60TsBkRJKcrxxwnjod1Q5mWuMN5KH3sxs842udKH
|
||||
0nHFE9kKW/NfXb+EGsjpocGpf786cGuCO2d00THsoItOEcM9/aI8DX1QcyxAHR6D
|
||||
HaYTFJnyyx8Q44u27M15idI4pbNoKORlotiuOwCTGYCfbN14aOV+Ict7aSF8FWpP
|
||||
48j9SMNuIu2DlF9pNLo6fsrOjYY3c9X12wIBAg==
|
||||
-----END DH PARAMETERS-----
|
@ -1,5 +1,10 @@
|
||||
FROM python:2.7
|
||||
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/*
|
||||
|
||||
COPY python-requirements.txt /requirements.txt
|
||||
RUN pip install -r /requirements.txt
|
||||
|
||||
WORKDIR /test
|
||||
ENTRYPOINT ["pytest"]
|
||||
|
@ -1,5 +1,5 @@
|
||||
backoff==1.3.2
|
||||
docker-compose==1.11.1
|
||||
docker==2.0.2
|
||||
docker-compose==1.11.2
|
||||
docker==2.1.0
|
||||
pytest==3.0.5
|
||||
requests==2.11.1
|
||||
requests==2.11.1
|
||||
|
@ -1,28 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, sys
|
||||
import os, sys, re
|
||||
import http.server
|
||||
import socketserver
|
||||
|
||||
|
||||
class Handler(http.server.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
|
||||
self.send_response(200)
|
||||
|
||||
response_body = ""
|
||||
response_code = 200
|
||||
|
||||
if self.path == "/headers":
|
||||
response_body += self.headers.as_string()
|
||||
elif self.path == "/port":
|
||||
response_body += "answer from port %s\n" % PORT
|
||||
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
|
||||
elif self.path == "/":
|
||||
response_body += "I'm %s\n" % os.environ['HOSTNAME']
|
||||
else:
|
||||
response_body += "No route for this path!\n"
|
||||
response_code = 404
|
||||
|
||||
self.send_response(response_code)
|
||||
self.send_header("Content-Type", "text/plain")
|
||||
self.end_headers()
|
||||
|
||||
if self.path == "/headers":
|
||||
self.wfile.write(self.headers.as_string().encode())
|
||||
elif self.path == "/port":
|
||||
response = "answer from port %s\n" % PORT
|
||||
self.wfile.write(response.encode())
|
||||
elif self.path == "/":
|
||||
response = "I'm %s\n" % os.environ['HOSTNAME']
|
||||
self.wfile.write(response.encode())
|
||||
else:
|
||||
self.wfile.write("No route for this path!\n".encode())
|
||||
|
||||
if (len(response_body)):
|
||||
self.wfile.write(response_body.encode())
|
||||
|
||||
if __name__ == '__main__':
|
||||
PORT = int(sys.argv[1])
|
||||
|
1
test/stress_tests/README.md
Normal file
1
test/stress_tests/README.md
Normal file
@ -0,0 +1 @@
|
||||
This directory contains tests that showcase scenarios known to break the expected behavior of nginx-proxy.
|
5
test/stress_tests/test_deleted_cert/README.md
Normal file
5
test/stress_tests/test_deleted_cert/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
Test the behavior of nginx-proxy when restarted after deleting a certificate file is was using.
|
||||
|
||||
1. nginx-proxy is created with a virtual host having a certificate
|
||||
1. while nginx-proxy is running, the certificate file is deleted
|
||||
1. nginx-proxy is then restarted (without removing the container)
|
@ -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 17 23:20:54 2017 GMT
|
||||
Not After : Jul 5 23:20:54 2044 GMT
|
||||
Subject: CN=web.nginx-proxy
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:b6:27:63:a5:c6:e8:f4:7a:94:0e:cc:a2:62:76:
|
||||
6d:5d:33:6f:cf:19:fc:e7:e5:bb:0e:0e:d0:7c:4f:
|
||||
73:4c:48:2b:17:d1:4d:d5:9f:42:08:73:84:54:8c:
|
||||
86:d2:c5:da:59:01:3f:42:22:e0:36:f0:dc:ab:de:
|
||||
0a:bd:26:2b:22:13:87:a6:1f:23:ef:0e:99:27:8b:
|
||||
15:4a:1b:ef:93:c9:6b:91:de:a0:02:0c:62:bb:cc:
|
||||
56:37:e8:25:92:c3:1f:f1:69:d8:7c:a8:33:e0:89:
|
||||
ce:14:67:a0:39:77:88:91:e6:a3:07:97:90:22:88:
|
||||
d0:79:18:63:fb:6f:7e:ee:2b:42:7e:23:f5:e7:da:
|
||||
e9:ee:6a:fa:96:65:9f:e1:2b:15:49:c8:cd:2d:ce:
|
||||
86:4f:2c:2a:67:79:bf:41:30:14:cc:f6:0f:14:74:
|
||||
9e:b6:d3:d0:3b:f0:1b:b8:e8:19:2a:fd:d6:fd:dc:
|
||||
4b:4e:65:7d:9b:bf:37:7e:2d:35:22:2e:74:90:ce:
|
||||
41:35:3d:41:a0:99:db:97:1f:bf:3e:18:3c:48:fb:
|
||||
da:df:c6:4e:4e:b9:67:b8:10:d5:a5:13:03:c4:b7:
|
||||
65:e7:aa:f0:14:4b:d3:4d:ea:fe:8f:69:cf:50:21:
|
||||
63:27:cf:9e:4c:67:15:7b:3f:3b:da:cb:17:80:61:
|
||||
1e:25
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:web.nginx-proxy
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
09:31:be:db:4e:b0:b6:68:da:ae:5b:16:51:29:fc:9f:61:b6:
|
||||
5a:2f:3c:35:ef:67:76:97:b0:34:4e:3b:b4:d6:88:19:4f:84:
|
||||
2e:73:d3:c0:3a:4c:41:54:6c:bb:67:89:67:ad:25:55:d7:d4:
|
||||
80:fe:a7:3f:3d:9e:f1:34:96:d8:da:5a:78:51:c0:63:f1:52:
|
||||
29:35:55:f4:7d:70:1c:d3:96:62:7f:64:86:81:52:27:c4:c6:
|
||||
10:13:c6:73:56:4d:32:d0:b3:c3:c8:2c:25:83:e4:2b:1d:d4:
|
||||
74:30:e5:85:af:2d:b6:a5:6b:fe:5d:d3:3c:00:58:94:f4:6a:
|
||||
f5:a6:1d:cf:f9:ed:d5:27:ed:13:24:b2:4f:2b:f3:b8:e4:af:
|
||||
0c:1d:fe:e0:6a:01:5e:a2:44:ff:3e:96:fa:6c:39:a3:51:37:
|
||||
f3:72:55:d8:2d:29:6e:de:95:b9:d8:e3:1e:65:a5:9c:0d:79:
|
||||
2d:39:ab:c7:ac:16:b6:a5:71:4b:35:a4:6c:72:47:1b:72:9c:
|
||||
67:58:c1:fc:f6:7f:a7:73:50:7b:d6:27:57:74:a1:31:38:a7:
|
||||
31:e3:b9:d4:c9:45:33:ec:ed:16:cf:c5:bd:d0:03:b1:45:3f:
|
||||
68:0d:91:5c:26:4e:37:05:74:ed:3e:75:5e:ca:5e:ee:e2:51:
|
||||
4b:da:08:99
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC8zCCAdugAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAyMTcyMzIwNTRaFw00NDA3MDUyMzIwNTRaMBoxGDAWBgNVBAMMD3dl
|
||||
Yi5uZ2lueC1wcm94eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALYn
|
||||
Y6XG6PR6lA7MomJ2bV0zb88Z/Ofluw4O0HxPc0xIKxfRTdWfQghzhFSMhtLF2lkB
|
||||
P0Ii4Dbw3KveCr0mKyITh6YfI+8OmSeLFUob75PJa5HeoAIMYrvMVjfoJZLDH/Fp
|
||||
2HyoM+CJzhRnoDl3iJHmoweXkCKI0HkYY/tvfu4rQn4j9efa6e5q+pZln+ErFUnI
|
||||
zS3Ohk8sKmd5v0EwFMz2DxR0nrbT0DvwG7joGSr91v3cS05lfZu/N34tNSIudJDO
|
||||
QTU9QaCZ25cfvz4YPEj72t/GTk65Z7gQ1aUTA8S3Zeeq8BRL003q/o9pz1AhYyfP
|
||||
nkxnFXs/O9rLF4BhHiUCAwEAAaMeMBwwGgYDVR0RBBMwEYIPd2ViLm5naW54LXBy
|
||||
b3h5MA0GCSqGSIb3DQEBCwUAA4IBAQAJMb7bTrC2aNquWxZRKfyfYbZaLzw172d2
|
||||
l7A0Tju01ogZT4Quc9PAOkxBVGy7Z4lnrSVV19SA/qc/PZ7xNJbY2lp4UcBj8VIp
|
||||
NVX0fXAc05Zif2SGgVInxMYQE8ZzVk0y0LPDyCwlg+QrHdR0MOWFry22pWv+XdM8
|
||||
AFiU9Gr1ph3P+e3VJ+0TJLJPK/O45K8MHf7gagFeokT/Ppb6bDmjUTfzclXYLSlu
|
||||
3pW52OMeZaWcDXktOavHrBa2pXFLNaRsckcbcpxnWMH89n+nc1B71idXdKExOKcx
|
||||
47nUyUUz7O0Wz8W90AOxRT9oDZFcJk43BXTtPnVeyl7u4lFL2giZ
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAtidjpcbo9HqUDsyiYnZtXTNvzxn85+W7Dg7QfE9zTEgrF9FN
|
||||
1Z9CCHOEVIyG0sXaWQE/QiLgNvDcq94KvSYrIhOHph8j7w6ZJ4sVShvvk8lrkd6g
|
||||
Agxiu8xWN+glksMf8WnYfKgz4InOFGegOXeIkeajB5eQIojQeRhj+29+7itCfiP1
|
||||
59rp7mr6lmWf4SsVScjNLc6GTywqZ3m/QTAUzPYPFHSettPQO/AbuOgZKv3W/dxL
|
||||
TmV9m783fi01Ii50kM5BNT1BoJnblx+/Phg8SPva38ZOTrlnuBDVpRMDxLdl56rw
|
||||
FEvTTer+j2nPUCFjJ8+eTGcVez872ssXgGEeJQIDAQABAoIBAGQCMFW+ZfyEqHGP
|
||||
rMA+oUEAkqy0agSwPwky3QjDXlxNa0uCYSeebtTRB6CcHxHuCzm+04puN4gyqhW6
|
||||
rU64fAoTivCMPGBuNWxekmvD9r+/YM4P2u4E+th9EgFT9f0kII+dO30FpKXtQzY0
|
||||
xuWGWXcxl+T9M+eiEkPKPmq4BoqgTDo5ty7qDv0ZqksGotKFmdYbtSvgBAueJdwu
|
||||
VWJvenI9F42ExBRKOW1aldiRiaYBCLiCVPKJtOg9iuOP9RHUL1SE8xy5I5mm78g3
|
||||
a13ji3BNq3yS+VhGjQ7zDy1V1jGupLoJw4I7OThu8hy+B8Vt8EN/iqakufOkjlTN
|
||||
xTJ33CkCgYEA5Iymg0NTjWk6aEkFa9pERjfUWqdVp9sWSpFFZZgi55n7LOx6ohi3
|
||||
vuLim3is/gYfK2kU/kHGZZLPnT0Rdx0MbOB4XK0CAUlqtUd0IyO4jMZ06g4/kn3N
|
||||
e2jLdCCIBoEQuLk4ELxj2mHsLQhEvDrg7nzU2WpTHHhvJbIbDWOAxhsCgYEAzAgv
|
||||
rKpanF+QDf4yeKHxAj2rrwRksTw4Pe7ZK/bog/i+HIVDA70vMapqftHbual/IRrB
|
||||
JL7hxskoJ/h9c1w4xkWDjqkSKz8/Ihr4dyPfWyGINWbx/rarT/m5MU5SarScoK7o
|
||||
Xgb25x+W+61rtI+2JhVRGO86+JiAeT4LkAX88L8CgYAwHHug/jdEeXZWJakCfzwI
|
||||
HBCT1M3vO+uBXvtg25ndb0i0uENIhDOJ93EEkW65Osis9r34mBgPocwaqZRXosHO
|
||||
2aH8wF6/rpjL+HK2QvrCh7Rs4Pr494qeA/1wQLjhxaGjgToQK9hJTHvPLwJpLWvU
|
||||
SGr2Ka+9Oo0LPmb7dorRKQKBgQCLsNcjOodLJMp2KiHYIdfmlt6itzlRd09yZ8Nc
|
||||
rHHJWVagJEUbnD1hnbHIHlp3pSqbObwfMmlWNoc9xo3tm6hrZ1CJLgx4e5b3/Ms8
|
||||
ltznge/F0DPDFsH3wZwfu+YFlJ7gDKCfL9l/qEsxCS0CtJobPOEHV1NivNbJK8ey
|
||||
1ca19QKBgDTdMOUsobAmDEkPQIpxfK1iqYAB7hpRLi79OOhLp23NKeyRNu8FH9fo
|
||||
G3DZ4xUi6hP2bwiYugMXDyLKfvxbsXwQC84kGF8j+bGazKNhHqEC1OpYwmaTB3kg
|
||||
qL9cHbjWySeRdIsRY/eWmiKjUwmiO54eAe1HWUdcsuz8yM3xf636
|
||||
-----END RSA PRIVATE KEY-----
|
17
test/stress_tests/test_deleted_cert/docker-compose.yml
Normal file
17
test/stress_tests/test_deleted_cert/docker-compose.yml
Normal file
@ -0,0 +1,17 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: web.nginx-proxy
|
||||
|
||||
|
||||
reverseproxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
container_name: reverseproxy
|
||||
environment:
|
||||
DEBUG: "true"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./tmp_certs:/etc/nginx/certs:ro
|
@ -0,0 +1,73 @@
|
||||
import logging
|
||||
import os
|
||||
from os.path import join, isfile
|
||||
from shutil import copy
|
||||
from time import sleep
|
||||
|
||||
import pytest
|
||||
from requests import ConnectionError
|
||||
|
||||
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)
|
||||
def certs():
|
||||
"""
|
||||
pytest fixture that provides cert and key files into the tmp_certs directory
|
||||
"""
|
||||
file_names = ("web.nginx-proxy.crt", "web.nginx-proxy.key")
|
||||
logging.info("copying server cert and key files into tmp_certs")
|
||||
for f_name in file_names:
|
||||
copy(join(script_dir, "certs", f_name), join(script_dir, "tmp_certs"))
|
||||
yield
|
||||
logging.info("cleaning up the tmp_cert directory")
|
||||
for f_name in file_names:
|
||||
if isfile(join(script_dir, "tmp_certs", f_name)):
|
||||
os.remove(join(script_dir, "tmp_certs", f_name))
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://foo.nginx-proxy/")
|
||||
assert r.status_code == 503
|
||||
|
||||
|
||||
def test_http_web_is_301(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy/port", allow_redirects=False)
|
||||
assert r.status_code == 301
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.incremental
|
||||
def test_delete_cert_and_restart_reverseproxy(docker_compose):
|
||||
os.remove(join(script_dir, "tmp_certs", "web.nginx-proxy.crt"))
|
||||
docker_compose.containers.get("reverseproxy").restart()
|
||||
sleep(3) # give time for the container to initialize
|
||||
assert "running" == docker_compose.containers.get("reverseproxy").status
|
||||
|
||||
|
||||
@pytest.mark.incremental
|
||||
def test_unknown_virtual_host_is_still_503(nginxproxy):
|
||||
r = nginxproxy.get("http://foo.nginx-proxy/")
|
||||
assert r.status_code == 503
|
||||
|
||||
|
||||
@pytest.mark.incremental
|
||||
def test_http_web_is_now_200(nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 81\n" == r.text
|
||||
|
||||
|
||||
@pytest.mark.incremental
|
||||
def test_https_web_is_now_broken_since_there_is_no_cert(nginxproxy):
|
||||
with pytest.raises(ConnectionError):
|
||||
nginxproxy.get("https://web.nginx-proxy/port")
|
2
test/stress_tests/test_deleted_cert/tmp_certs/.gitignore
vendored
Normal file
2
test/stress_tests/test_deleted_cert/tmp_certs/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
59
test/stress_tests/test_unreachable_network/README.md
Normal file
59
test/stress_tests/test_unreachable_network/README.md
Normal file
@ -0,0 +1,59 @@
|
||||
# nginx-proxy template is not considered when a container is not reachable
|
||||
|
||||
Having a container with the `VIRTUAL_HOST` environment variable set but on a network not reachable from the nginx-proxy container will result in nginx-proxy serving the default nginx welcome page for all requests.
|
||||
|
||||
Furthermore, if the nginx-proxy in such state is restarted, the nginx process will crash and the container stops.
|
||||
|
||||
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).
|
||||
|
||||
## How to reproduce
|
||||
|
||||
1. a first web container is created on network `netA`
|
||||
1. a second web container is created on network `netB`
|
||||
1. nginx-proxy is created with access to `netA` only
|
||||
|
||||
|
||||
## Erratic behavior
|
||||
|
||||
- nginx serves the default welcome page for all requests to `/` and error 404 for any other path
|
||||
- nginx-container crash on restart
|
||||
|
||||
Log shows:
|
||||
|
||||
```
|
||||
webB_1 | starting a web server listening on port 82
|
||||
webA_1 | starting a web server listening on port 81
|
||||
reverseproxy | forego | starting dockergen.1 on port 5000
|
||||
reverseproxy | forego | starting nginx.1 on port 5100
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Generated '/etc/nginx/conf.d/default.conf' from 3 containers
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Running 'nginx -s reload'
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Error running notify command: nginx -s reload, exit status 1
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Watching docker events
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload'
|
||||
reverseproxy | reverseproxy | forego | starting dockergen.1 on port 5000 <---- nginx-proxy container restarted
|
||||
reverseproxy | forego | starting nginx.1 on port 5100
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Generated '/etc/nginx/conf.d/default.conf' from 3 containers
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Running 'nginx -s reload'
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Error running notify command: nginx -s reload, exit status 1
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Watching docker events
|
||||
reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload'
|
||||
reverseproxy | forego | starting dockergen.1 on port 5000
|
||||
reverseproxy | forego | starting nginx.1 on port 5100
|
||||
reverseproxy | nginx.1 | 2017/02/20 01:11:02 [emerg] 17#17: no servers are inside upstream in /etc/nginx/conf.d/default.conf:64
|
||||
reverseproxy | forego | starting nginx.1 on port 5200
|
||||
reverseproxy | forego | sending SIGTERM to nginx.1
|
||||
reverseproxy | forego | sending SIGTERM to dockergen.1
|
||||
reverseproxy exited with code 0
|
||||
reverseproxy exited with code 0
|
||||
|
||||
```
|
||||
|
||||
## Expected behavior
|
||||
|
||||
- no default nginx welcome page should be served
|
||||
- nginx is able to forward requests to containers of `netA`
|
||||
- nginx respond with error 503 for unknown virtual hosts
|
||||
- nginx is not able to forward requests to containers of `netB` and responds with an error
|
||||
- nginx should survive restarts
|
@ -0,0 +1,35 @@
|
||||
version: "2"
|
||||
|
||||
networks:
|
||||
netA:
|
||||
netB:
|
||||
|
||||
services:
|
||||
reverseproxy:
|
||||
container_name: reverseproxy
|
||||
networks:
|
||||
- netA
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
|
||||
webA:
|
||||
networks:
|
||||
- netA
|
||||
image: web
|
||||
expose:
|
||||
- 81
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: webA.nginx-proxy
|
||||
|
||||
webB:
|
||||
networks:
|
||||
- netB
|
||||
image: web
|
||||
expose:
|
||||
- 82
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: webB.nginx-proxy
|
||||
|
@ -0,0 +1,35 @@
|
||||
from time import sleep
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
pytestmark = pytest.mark.xfail() # TODO delete this marker once #585 is merged
|
||||
|
||||
|
||||
def test_default_nginx_welcome_page_should_not_be_served(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://whatever.nginx-proxy/", allow_redirects=False)
|
||||
assert "<title>Welcome to nginx!</title>" not in r.text
|
||||
|
||||
|
||||
def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://unknown.nginx-proxy/", allow_redirects=False)
|
||||
assert r.status_code == 503
|
||||
|
||||
|
||||
def test_http_web_a_is_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://webA.nginx-proxy/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 81\n" == r.text
|
||||
|
||||
|
||||
def test_http_web_b_gets_an_error(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://webB.nginx-proxy/", allow_redirects=False)
|
||||
assert "<title>Welcome to nginx!</title>" not in r.text
|
||||
with pytest.raises(requests.exceptions.HTTPError):
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
def test_reverseproxy_survive_restart(docker_compose):
|
||||
docker_compose.containers.get("reverseproxy").restart()
|
||||
sleep(2) # give time for the container to initialize
|
||||
assert docker_compose.containers.get("reverseproxy").status == "running"
|
@ -1,5 +1,5 @@
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -8,7 +8,7 @@ web1:
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
@ -19,6 +19,6 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/f00.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
environment:
|
||||
DOCKER_HOST: unix:///f00.sock
|
||||
|
||||
|
@ -4,11 +4,12 @@ services:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
||||
web:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: web.nginx-proxy.local
|
||||
VIRTUAL_HOST: web.nginx-proxy.local
|
||||
|
@ -2,11 +2,12 @@ nginx-proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location:ro
|
||||
- ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.local_location:ro
|
||||
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -14,7 +15,7 @@ web1:
|
||||
VIRTUAL_HOST: web1.nginx-proxy.local
|
||||
|
||||
web2:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
@ -22,9 +23,9 @@ web2:
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
|
||||
web3:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "83"
|
||||
environment:
|
||||
WEB_PORTS: 83
|
||||
VIRTUAL_HOST: web3.nginx-proxy.local
|
||||
VIRTUAL_HOST: web3.nginx-proxy.local
|
||||
|
@ -4,10 +4,11 @@ services:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro
|
||||
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -15,9 +16,9 @@ services:
|
||||
VIRTUAL_HOST: web1.nginx-proxy.local
|
||||
|
||||
web2:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
|
@ -4,10 +4,11 @@ services:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local_location:ro
|
||||
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -15,9 +16,9 @@ services:
|
||||
VIRTUAL_HOST: web1.nginx-proxy.local
|
||||
|
||||
web2:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
|
@ -4,10 +4,11 @@ services:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local:ro
|
||||
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -15,9 +16,9 @@ services:
|
||||
VIRTUAL_HOST: web1.nginx-proxy.local
|
||||
|
||||
web2:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
|
@ -4,10 +4,11 @@ services:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro
|
||||
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -15,9 +16,9 @@ services:
|
||||
VIRTUAL_HOST: web1.nginx-proxy.local
|
||||
|
||||
web2:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
|
@ -13,5 +13,6 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
environment:
|
||||
DEFAULT_HOST: web1.tld
|
||||
|
@ -6,6 +6,7 @@ services:
|
||||
container_name: nginx
|
||||
volumes:
|
||||
- /etc/nginx/conf.d
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
||||
dockergen:
|
||||
image: jwilder/docker-gen
|
||||
@ -23,4 +24,4 @@ services:
|
||||
- "80"
|
||||
environment:
|
||||
WEB_PORTS: 80
|
||||
VIRTUAL_HOST: whoami.nginx.container.docker
|
||||
VIRTUAL_HOST: whoami.nginx.container.docker
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
import docker
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
import re
|
||||
|
||||
def versiontuple(v):
|
||||
"""
|
||||
|
@ -5,6 +5,7 @@ services:
|
||||
container_name: nginx
|
||||
volumes:
|
||||
- nginx_conf:/etc/nginx/conf.d
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
||||
dockergen:
|
||||
image: jwilder/docker-gen
|
||||
@ -24,4 +25,4 @@ services:
|
||||
VIRTUAL_HOST: whoami.nginx.container.docker
|
||||
|
||||
volumes:
|
||||
nginx_conf: {}
|
||||
nginx_conf: {}
|
||||
|
@ -2,3 +2,4 @@ nginxproxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -10,4 +10,5 @@ web:
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -13,3 +13,4 @@ sut:
|
||||
- /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
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,5 +1,5 @@
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -8,7 +8,7 @@ web1:
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
@ -19,5 +19,6 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
environment:
|
||||
ENABLE_IPV6: "true"
|
||||
|
@ -11,3 +11,4 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -9,12 +9,13 @@ services:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
networks:
|
||||
- net1
|
||||
- net2
|
||||
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -24,11 +25,11 @@ services:
|
||||
- net1
|
||||
|
||||
web2:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.local
|
||||
networks:
|
||||
- net2
|
||||
- net2
|
||||
|
@ -12,3 +12,4 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -11,3 +11,4 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -10,4 +10,5 @@ web:
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -1,5 +1,5 @@
|
||||
web1:
|
||||
image: web
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
@ -8,7 +8,7 @@ web1:
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
@ -19,3 +19,4 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
93
test/test_ssl/test_dhparam.py
Normal file
93
test/test_ssl/test_dhparam.py
Normal file
@ -0,0 +1,93 @@
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import backoff
|
||||
import docker
|
||||
import pytest
|
||||
|
||||
docker_client = docker.from_env()
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Tests helpers
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None)
|
||||
def assert_log_contains(expected_log_line):
|
||||
"""
|
||||
Check that the nginx-proxy container log contains a given string.
|
||||
The backoff decorator will retry the check 15 times with a 2 seconds delay.
|
||||
|
||||
:param expected_log_line: string to search for
|
||||
:return: None
|
||||
:raises: AssertError if the expected string is not found in the log
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
def require_openssl(required_version):
|
||||
"""
|
||||
This function checks that the required version of OpenSSL is present, and skips the test if not.
|
||||
Use it as a test function decorator:
|
||||
|
||||
@require_openssl("2.3.4")
|
||||
def test_something():
|
||||
...
|
||||
|
||||
:param required_version: minimal required version as a string: "1.2.3"
|
||||
"""
|
||||
|
||||
def versiontuple(v):
|
||||
clean_v = re.sub("[^\d\.]", "", v)
|
||||
return tuple(map(int, (clean_v.split("."))))
|
||||
|
||||
try:
|
||||
command_output = subprocess.check_output(["openssl", "version"])
|
||||
except OSError:
|
||||
return pytest.mark.skip("openssl command is not available in test environment")
|
||||
else:
|
||||
if not command_output:
|
||||
raise Exception("Could not get openssl version")
|
||||
openssl_version = 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))
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
def test_dhparam_is_not_generated_if_present(docker_compose):
|
||||
sut_container = docker_client.containers.get("nginxproxy")
|
||||
assert sut_container.status == "running"
|
||||
|
||||
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()
|
||||
assert default_checksum[0] != current_checksum[0]
|
||||
|
||||
|
||||
def test_web5_https_works(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web5.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 85\n" in r.text
|
||||
|
||||
|
||||
@require_openssl("1.0.2")
|
||||
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"]
|
||||
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
|
16
test/test_ssl/test_dhparam.yml
Normal file
16
test/test_ssl/test_dhparam.yml
Normal file
@ -0,0 +1,16 @@
|
||||
web5:
|
||||
image: web
|
||||
expose:
|
||||
- "85"
|
||||
environment:
|
||||
WEB_PORTS: "85"
|
||||
VIRTUAL_HOST: "web5.nginx-proxy.tld"
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
container_name: nginxproxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
44
test/test_ssl/test_dhparam_generation.py
Normal file
44
test/test_ssl/test_dhparam_generation.py
Normal file
@ -0,0 +1,44 @@
|
||||
import backoff
|
||||
import docker
|
||||
|
||||
docker_client = docker.from_env()
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Tests helpers
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None)
|
||||
def assert_log_contains(expected_log_line):
|
||||
"""
|
||||
Check that the nginx-proxy container log contains a given string.
|
||||
The backoff decorator will retry the check 15 times with a 2 seconds delay.
|
||||
|
||||
:param expected_log_line: string to search for
|
||||
:return: None
|
||||
:raises: AssertError if the expected string is not found in the log
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
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("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()
|
||||
assert default_checksum[0] != generated_checksum[0]
|
8
test/test_ssl/test_dhparam_generation.yml
Normal file
8
test/test_ssl/test_dhparam_generation.yml
Normal file
@ -0,0 +1,8 @@
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
container_name: nginxproxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
environment:
|
||||
- DHPARAM_BITS=256
|
33
test/test_ssl/test_hsts.py
Normal file
33
test/test_ssl/test_hsts.py
Normal file
@ -0,0 +1,33 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_web1_HSTS_default(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web1.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 81\n" in r.text
|
||||
assert "Strict-Transport-Security" in r.headers
|
||||
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
|
||||
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
|
||||
assert "max-age=31536000" == r.headers["Strict-Transport-Security"]
|
||||
|
||||
def test_web2_HSTS_off(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 81\n" in r.text
|
||||
assert "Strict-Transport-Security" not in r.headers
|
||||
|
||||
def test_web3_HSTS_custom(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 81\n" in r.text
|
||||
assert "Strict-Transport-Security" in r.headers
|
||||
assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"]
|
||||
|
||||
# Regression test for issue 1080
|
||||
# https://github.com/jwilder/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
|
||||
assert "Strict-Transport-Security" not in r.headers
|
42
test/test_ssl/test_hsts.yml
Normal file
42
test/test_ssl/test_hsts.yml
Normal file
@ -0,0 +1,42 @@
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "web1.nginx-proxy.tld"
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "web2.nginx-proxy.tld"
|
||||
HSTS: "off"
|
||||
|
||||
web3:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "web3.nginx-proxy.tld"
|
||||
HSTS: "max-age=86400; includeSubDomains; preload"
|
||||
|
||||
web4:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "web4.nginx-proxy.tld"
|
||||
HSTS: "off"
|
||||
HTTPS_METHOD: "noredirect"
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
@ -12,4 +12,5 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
|
@ -11,4 +11,5 @@ web:
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
@ -12,4 +12,5 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
|
@ -10,4 +10,5 @@ sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
|
6
test/test_ssl/wildcard_cert_and_nohttps/README.md
Normal file
6
test/test_ssl/wildcard_cert_and_nohttps/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
In this scenario, we have a wildcard certificate for `*.web.nginx-proxy.tld` and 3 web containers:
|
||||
- 1.web.nginx-proxy.tld
|
||||
- 2.web.nginx-proxy.tld
|
||||
- 3.web.nginx-proxy.tld
|
||||
|
||||
We want web containers 1 and 2 to support SSL, but 3 should not (using `HTTPS_METHOD=nohttps`)
|
70
test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt
Normal file
70
test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt
Normal 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: Mar 15 00:17:52 2017 GMT
|
||||
Not After : Jul 31 00:17:52 2044 GMT
|
||||
Subject: CN=nginx-proxy.tld
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:f2:fd:79:70:99:0c:da:63:5c:81:28:72:31:01:
|
||||
62:e9:68:d7:cb:8d:c6:95:f9:ec:26:34:1c:08:c6:
|
||||
6d:de:ad:d8:b0:c0:ae:48:03:73:76:6b:3f:c5:35:
|
||||
86:c6:42:91:53:3c:aa:85:89:84:92:67:92:ef:a9:
|
||||
5b:f2:d4:04:73:34:02:35:d4:6a:fa:c2:da:91:4a:
|
||||
a9:70:87:25:38:84:1d:93:99:3c:d7:03:61:a6:6d:
|
||||
33:6f:83:45:04:af:4f:96:62:1e:c1:79:87:c9:d5:
|
||||
4c:e9:8f:85:e2:c8:1b:5b:fc:b8:02:ff:7b:6d:34:
|
||||
4c:5d:40:73:44:9e:c5:1f:5f:e0:0f:89:88:c4:35:
|
||||
2b:04:53:8c:8e:a0:7c:7c:97:16:20:c2:4f:a1:c0:
|
||||
dd:bf:d5:13:2d:64:25:03:f2:d8:d5:27:01:70:c9:
|
||||
f4:37:33:36:7e:7b:48:54:ec:37:2b:81:3d:50:3c:
|
||||
d4:5f:05:19:e2:0b:ba:76:f6:2c:3b:23:4b:82:78:
|
||||
5f:e9:e3:57:fc:39:4a:5c:42:82:72:c8:a3:af:b7:
|
||||
b3:91:e4:01:9c:2c:47:5e:ff:aa:ad:63:1c:e7:9c:
|
||||
2e:a2:ac:5d:51:30:83:67:6e:f8:5a:ed:0b:70:e4:
|
||||
68:d4:e9:5e:a7:f5:5e:87:3b:e8:31:ad:00:04:f8:
|
||||
7b:d9
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:nginx-proxy.tld
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
39:d4:cc:78:a3:5e:64:e9:ab:9d:a9:89:3b:9e:18:01:98:cb:
|
||||
e2:0c:ef:e9:2b:50:34:ed:63:ed:e6:0e:53:59:30:80:e0:3b:
|
||||
5e:08:ca:09:55:da:e3:3e:c2:01:d8:d6:ca:92:2a:0b:ee:2c:
|
||||
a1:93:18:7b:15:28:8d:2a:17:25:76:eb:ef:70:e0:d7:02:d3:
|
||||
ad:81:33:47:9b:fb:d8:52:87:69:a4:3a:20:a4:9a:2d:3f:40:
|
||||
5f:52:bf:0b:96:e3:52:c3:59:55:dc:5a:37:f3:e6:d6:16:46:
|
||||
64:e4:20:32:5d:cd:4b:da:2b:ef:e9:85:af:00:a1:ca:a1:08:
|
||||
ed:0f:f4:65:dc:2a:c9:b3:4e:cc:f3:82:d7:69:3a:4d:fc:8e:
|
||||
db:10:95:28:20:07:55:f0:d1:11:1f:c5:00:74:88:c6:c9:94:
|
||||
15:90:93:3a:de:90:85:fb:72:9c:d8:57:58:05:7d:bb:6a:36:
|
||||
eb:d8:12:22:41:0e:fc:c9:24:79:c0:28:4f:4f:1b:4b:59:f9:
|
||||
e4:c6:97:be:b1:94:74:de:a7:65:d3:cb:0a:56:3b:d3:63:fc:
|
||||
b2:05:fc:e7:ec:bb:45:04:91:9f:21:f9:05:3b:5d:4c:af:8e:
|
||||
84:04:f5:25:fb:4d:ab:db:23:56:74:7e:4f:b3:da:bb:27:e7:
|
||||
ea:fb:bd:00
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC8zCCAdugAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAzMTUwMDE3NTJaFw00NDA3MzEwMDE3NTJaMBoxGDAWBgNVBAMMD25n
|
||||
aW54LXByb3h5LnRsZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPL9
|
||||
eXCZDNpjXIEocjEBYulo18uNxpX57CY0HAjGbd6t2LDArkgDc3ZrP8U1hsZCkVM8
|
||||
qoWJhJJnku+pW/LUBHM0AjXUavrC2pFKqXCHJTiEHZOZPNcDYaZtM2+DRQSvT5Zi
|
||||
HsF5h8nVTOmPheLIG1v8uAL/e200TF1Ac0SexR9f4A+JiMQ1KwRTjI6gfHyXFiDC
|
||||
T6HA3b/VEy1kJQPy2NUnAXDJ9DczNn57SFTsNyuBPVA81F8FGeILunb2LDsjS4J4
|
||||
X+njV/w5SlxCgnLIo6+3s5HkAZwsR17/qq1jHOecLqKsXVEwg2du+FrtC3DkaNTp
|
||||
Xqf1Xoc76DGtAAT4e9kCAwEAAaMeMBwwGgYDVR0RBBMwEYIPbmdpbngtcHJveHku
|
||||
dGxkMA0GCSqGSIb3DQEBCwUAA4IBAQA51Mx4o15k6audqYk7nhgBmMviDO/pK1A0
|
||||
7WPt5g5TWTCA4DteCMoJVdrjPsIB2NbKkioL7iyhkxh7FSiNKhclduvvcODXAtOt
|
||||
gTNHm/vYUodppDogpJotP0BfUr8LluNSw1lV3Fo38+bWFkZk5CAyXc1L2ivv6YWv
|
||||
AKHKoQjtD/Rl3CrJs07M84LXaTpN/I7bEJUoIAdV8NERH8UAdIjGyZQVkJM63pCF
|
||||
+3Kc2FdYBX27ajbr2BIiQQ78ySR5wChPTxtLWfnkxpe+sZR03qdl08sKVjvTY/yy
|
||||
Bfzn7LtFBJGfIfkFO11Mr46EBPUl+02r2yNWdH5Ps9q7J+fq+70A
|
||||
-----END CERTIFICATE-----
|
27
test/test_ssl/wildcard_cert_and_nohttps/certs/default.key
Normal file
27
test/test_ssl/wildcard_cert_and_nohttps/certs/default.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA8v15cJkM2mNcgShyMQFi6WjXy43GlfnsJjQcCMZt3q3YsMCu
|
||||
SANzdms/xTWGxkKRUzyqhYmEkmeS76lb8tQEczQCNdRq+sLakUqpcIclOIQdk5k8
|
||||
1wNhpm0zb4NFBK9PlmIewXmHydVM6Y+F4sgbW/y4Av97bTRMXUBzRJ7FH1/gD4mI
|
||||
xDUrBFOMjqB8fJcWIMJPocDdv9UTLWQlA/LY1ScBcMn0NzM2fntIVOw3K4E9UDzU
|
||||
XwUZ4gu6dvYsOyNLgnhf6eNX/DlKXEKCcsijr7ezkeQBnCxHXv+qrWMc55wuoqxd
|
||||
UTCDZ274Wu0LcORo1Olep/VehzvoMa0ABPh72QIDAQABAoIBAQDqcaW5/fFoxHV8
|
||||
KIoEvlGw4ndS7nesPHacZaqmzM01DIcGAuIkmS/OEax1mi9vGsschGwCa6x9lXEv
|
||||
yzfsEqQ4gvWe+lQ9ncNEa8UPzVUcMlxXDIKm8ZxF9xapgP4Whw9DCWijQ57AHg0X
|
||||
TGLhbDD5j9v7CIUN2GfVkVml24pVuUoeXqv7ZLzTJKZ+Q/eqxyeIikjFheXzaQxb
|
||||
bUHbEHIXJtHMYULXmfc5WCxuobHqal3z0ymCijoZVXV8hp8dtDP34tRV9MID9wck
|
||||
lRUVqboFCIXxmLLRTZgyCbiFLkCIu2nmgNobWCNfkHN7QQhToPEecSFMZzYtmo6/
|
||||
T1fHE3ABAoGBAP1J1Izfc4CF9t2iPGzXyn8oNkXHLMPKtFQ2Rb8XwBryUOOrAHqT
|
||||
FIZ2FsDJr0VvS1ihFs1kbO+WAY5W5GytwiiVXvztHz3/f5JnGgvMCeUcEmaj90vq
|
||||
sTyfHc2OKFjumIjGe87uav3bgac7nOWLO+RIJ/ua6UO7/8psqwryxY4FAoGBAPWX
|
||||
a502kT56VwI3Gf8hb37PZ/PD+gOzgzVcMn13yLZ4gC9xoP4TKUBHSz4wO8asjKk5
|
||||
1RD/DITXYKelyRXynOtMW+2j2s5bVBpOshN/n9jRC1haoGJZYb2JVP6+8WoZKQOF
|
||||
NwgNlI4he32kSFw59fjkdG64iw7KY8ZYUatkrgrFAoGBAPozTjUCHfRdYOi6c/oI
|
||||
h81oCYSQJVYbDFsLaYZEjc2Qg/sBVm2+kE3qpLs3/10VfVZFemLVyw44Hb1fdDEu
|
||||
y1aPhs9N5Mi3dGtIUWBJ45RgUIT3fzeM1BtQCn6c6JpAxoiFmJNmzGWLyd1Kc8gD
|
||||
69uqs2RFOBtiwGBTS/p6qk+JAoGBAM1QkpnzFYf69SSX9jbRuAl20Xv8GdbgS0/f
|
||||
zSIRcw4BPYDsaOAgGrtvHttVrZORi2KqQ5Ma9ldUS6y8L5kWo9MemjfYZUNhHLWF
|
||||
luAwMO0tDmQGF9FA0jKHTjROYzsE38Heq7wixk/wc/H81rWrixRRwXkS9MYfszwN
|
||||
d/FmkQ3VAoGAXHZrDEygUmf4q0LwjLVF0TPzElh530qVmyhPa0OBs/hVh9Mwv/i6
|
||||
fj3+k7uYWgKDzcaVXSMOFGt515F8qy0AUEY9r+IjAn01KTLKO4ZuPiSpxliqDbCs
|
||||
gzsX9CWVSVgTN+TY15QCoJNpzLiyrXe3uldAP5JEBQSnjt9OfSJQ5IU=
|
||||
-----END RSA PRIVATE KEY-----
|
@ -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: Mar 14 23:19:36 2017 GMT
|
||||
Not After : Jul 30 23:19:36 2044 GMT
|
||||
Subject: CN=*.web.nginx-proxy.tld
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:ce:2b:74:13:b2:1a:d5:72:5c:3e:10:f7:63:01:
|
||||
22:df:e8:d9:cf:0b:8a:3f:40:75:62:58:78:27:9e:
|
||||
af:33:d2:a1:19:6a:e1:b7:57:db:d9:8f:05:70:c2:
|
||||
35:5d:f1:44:0d:51:62:74:73:e5:77:d9:bb:c6:d0:
|
||||
33:7a:43:88:e9:e6:3c:2d:d4:39:9d:61:34:5a:19:
|
||||
f3:c1:96:e0:bd:26:5b:69:18:a6:4c:8c:21:04:d8:
|
||||
fa:56:22:ec:55:0d:ba:49:4d:8e:27:69:7f:82:e9:
|
||||
e7:e9:c4:b7:87:70:d7:d7:4b:49:d1:c1:8c:b0:5a:
|
||||
13:62:db:de:c1:94:31:d1:c9:74:c4:63:01:50:10:
|
||||
70:42:73:67:c4:76:32:fb:d2:b7:91:2f:e8:cf:3a:
|
||||
96:4a:ee:8e:0d:13:74:73:1b:e4:74:83:e7:66:d6:
|
||||
8d:81:19:54:5b:d8:47:3e:3b:b5:fd:35:a2:df:f3:
|
||||
7d:1c:9e:67:ee:50:da:28:9c:02:0a:ad:75:8d:04:
|
||||
f7:28:1f:04:89:13:ac:ed:a9:34:26:dc:f7:f9:1f:
|
||||
72:21:d5:72:fb:09:d9:cb:40:c0:0d:36:3c:c0:77:
|
||||
0e:9a:f7:41:f1:3b:dd:b6:05:ab:13:60:c5:fd:c6:
|
||||
5f:f5:05:c4:42:00:ba:b5:ef:fb:dc:64:98:d9:4d:
|
||||
2b:07
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:*.web.nginx-proxy.tld
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
9b:78:39:b3:90:8f:31:8c:7d:02:aa:6f:46:3d:8c:f5:93:86:
|
||||
03:e2:d8:9b:73:d1:e7:70:f1:d6:e6:3c:41:41:8c:76:c9:29:
|
||||
a4:83:47:c7:10:fd:d0:8b:fa:60:26:a8:36:41:a4:69:89:81:
|
||||
ec:bf:fd:33:72:bb:83:ea:42:e4:59:3f:10:df:d1:de:e2:bb:
|
||||
eb:fa:97:44:fe:f4:55:29:69:ca:a5:88:b2:94:60:58:5a:1a:
|
||||
19:16:fb:9f:42:4c:7c:d3:6b:21:45:22:56:5c:76:07:97:35:
|
||||
27:8f:46:d2:77:5b:65:1b:94:99:cb:73:37:ae:cf:61:6c:7a:
|
||||
5c:b3:3b:19:f2:9f:99:8f:89:eb:98:0b:74:0d:30:f5:49:19:
|
||||
d6:41:32:4e:c9:fc:59:2a:4a:53:2c:83:89:3d:e8:89:ed:37:
|
||||
d0:b4:f1:09:49:b5:0b:76:fd:a5:75:23:fb:01:c8:bb:59:02:
|
||||
5c:e4:8e:9c:f9:5b:85:5f:67:fb:04:40:de:bc:e8:c3:15:2f:
|
||||
ba:00:5c:36:57:47:e3:1a:95:44:5f:f4:10:55:b0:c4:af:12:
|
||||
dc:0e:6c:18:4a:70:9e:73:90:8d:55:37:73:a5:1a:41:7f:00:
|
||||
79:96:34:01:6b:10:2d:e9:61:3d:8f:8a:9a:c8:b6:bc:0f:57:
|
||||
91:84:7c:26
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/zCCAeegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAzMTQyMzE5MzZaFw00NDA3MzAyMzE5MzZaMCAxHjAcBgNVBAMMFSou
|
||||
d2ViLm5naW54LXByb3h5LnRsZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAM4rdBOyGtVyXD4Q92MBIt/o2c8Lij9AdWJYeCeerzPSoRlq4bdX29mPBXDC
|
||||
NV3xRA1RYnRz5XfZu8bQM3pDiOnmPC3UOZ1hNFoZ88GW4L0mW2kYpkyMIQTY+lYi
|
||||
7FUNuklNjidpf4Lp5+nEt4dw19dLSdHBjLBaE2Lb3sGUMdHJdMRjAVAQcEJzZ8R2
|
||||
MvvSt5Ev6M86lkrujg0TdHMb5HSD52bWjYEZVFvYRz47tf01ot/zfRyeZ+5Q2iic
|
||||
AgqtdY0E9ygfBIkTrO2pNCbc9/kfciHVcvsJ2ctAwA02PMB3Dpr3QfE73bYFqxNg
|
||||
xf3GX/UFxEIAurXv+9xkmNlNKwcCAwEAAaMkMCIwIAYDVR0RBBkwF4IVKi53ZWIu
|
||||
bmdpbngtcHJveHkudGxkMA0GCSqGSIb3DQEBCwUAA4IBAQCbeDmzkI8xjH0Cqm9G
|
||||
PYz1k4YD4tibc9HncPHW5jxBQYx2ySmkg0fHEP3Qi/pgJqg2QaRpiYHsv/0zcruD
|
||||
6kLkWT8Q39He4rvr+pdE/vRVKWnKpYiylGBYWhoZFvufQkx802shRSJWXHYHlzUn
|
||||
j0bSd1tlG5SZy3M3rs9hbHpcszsZ8p+Zj4nrmAt0DTD1SRnWQTJOyfxZKkpTLIOJ
|
||||
PeiJ7TfQtPEJSbULdv2ldSP7Aci7WQJc5I6c+VuFX2f7BEDevOjDFS+6AFw2V0fj
|
||||
GpVEX/QQVbDErxLcDmwYSnCec5CNVTdzpRpBfwB5ljQBaxAt6WE9j4qayLa8D1eR
|
||||
hHwm
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAzit0E7Ia1XJcPhD3YwEi3+jZzwuKP0B1Ylh4J56vM9KhGWrh
|
||||
t1fb2Y8FcMI1XfFEDVFidHPld9m7xtAzekOI6eY8LdQ5nWE0WhnzwZbgvSZbaRim
|
||||
TIwhBNj6ViLsVQ26SU2OJ2l/gunn6cS3h3DX10tJ0cGMsFoTYtvewZQx0cl0xGMB
|
||||
UBBwQnNnxHYy+9K3kS/ozzqWSu6ODRN0cxvkdIPnZtaNgRlUW9hHPju1/TWi3/N9
|
||||
HJ5n7lDaKJwCCq11jQT3KB8EiROs7ak0Jtz3+R9yIdVy+wnZy0DADTY8wHcOmvdB
|
||||
8TvdtgWrE2DF/cZf9QXEQgC6te/73GSY2U0rBwIDAQABAoIBAGVkDVPaVUP/V8nW
|
||||
QjNYTbRcKTGfdT+iDZht9blWWsdboIqFe7fU53PY2E4Z1HD8xADgs1Cd5o3IcIZX
|
||||
wdkw+VY+Of43zpXNRhfBh5T/BEtBX9cRnkcq6todcw+FYUB63dBK6cwMH/9b1Qes
|
||||
DK35GszwY79aNjxMMBiAFM6SeOW4EElPsV8wd9ldX/ndiZuwkZ6k9PfyWrfeeaF+
|
||||
EwVf/HaT0bV7cHQ73tYqzKjMpdbzIyaMzuAMGZDwPfLK+O1rEsWvLvK0ypl2Omzw
|
||||
ndon8U3z0JPNmBGoq+SFS2qtCeOezNX3lPz+TWxG05R5iiFtuK83zJ5qGqCgCNZ6
|
||||
qzpZsOECgYEA/NvWqT5MdZS1fdL2wROzFMTH4OBdUGr1Gh/DsNZj4qFVSFl969mA
|
||||
7Vntm+koNLFsJt2EB67kC3ZWjozLXomHJ55/uKNnJ5LrLxczQ9x4l52CsTzrlvFq
|
||||
crYjQZDmeN3B4Z+8RSi2icq6j1PeaCZRTvcz6eBjNYj/v/O0SmiXIp8CgYEA0Lsh
|
||||
fZWuw23a8UXS2YUrXXqfIEdisVMnLRu3Zi0Y1R4lIpuwn5+2n+TxnuWcY1q+ZTMw
|
||||
dcmGPi6aRj81kEN/Kw5raKoVb6YywTNB4/Dwz7PRQH386FrjfivGXGEEINgbPQ09
|
||||
2u0QV2Cr9yMGZ5qNXut70RYewkxjF7+s6L8+RpkCgYB9ikBHgtC/R/fb4pP0RG2T
|
||||
ECgUtBBgTtomAENOVwL8kBEhfJ0SLcjfDtjzoYz+rF//49cbYW+DaVuMJscJxso9
|
||||
l2neJ/KdKUpu9NvVA280B1XN3WsyY+Xv0hIrCWAD/kW2WXJF+/K08twxMPipSOzx
|
||||
gbZalbdr6vrfOIX4s3jmDQKBgDiXA3Vw53jEh99x9sBSgndNj2bI89DvomdwZECn
|
||||
aVweWCMR4sjkHDctcvSJe+TT7VqyjijhAixJpjn1WShLpGaf+i7eLgGfJZOLugl6
|
||||
gU9OiSTbA35bZeIHLDhPdTcSYBAlTufT7eJCq1zNeicMl9dsMJ13Sc+TtinyJYbU
|
||||
kqXBAoGBAL9gRa1PkNkpCJ5F9aYSohCAXB7DaAgYvVyvOTQ8Bw2uACPgdnpHmxQd
|
||||
/sT7qJ1h8ZCtn89Ug/4yx79eUcOImugoCRIUVtq1xhyXUdVl55Tuy5bKBSSAe/Vh
|
||||
T7sAmryCkzn9ihRziY2j84vK0mdMkCU5AoatPg5l0g1adn5zcY6q
|
||||
-----END RSA PRIVATE KEY-----
|
34
test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml
Normal file
34
test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml
Normal file
@ -0,0 +1,34 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
|
||||
proxy:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
- ../../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "1.web.nginx-proxy.tld"
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: "82"
|
||||
VIRTUAL_HOST: "2.web.nginx-proxy.tld"
|
||||
|
||||
web3_nohttps:
|
||||
image: web
|
||||
expose:
|
||||
- "83"
|
||||
environment:
|
||||
WEB_PORTS: "83"
|
||||
VIRTUAL_HOST: "3.web.nginx-proxy.tld"
|
||||
HTTPS_METHOD: nohttps
|
@ -0,0 +1,33 @@
|
||||
import pytest
|
||||
from backports.ssl_match_hostname import CertificateError
|
||||
from requests.exceptions import SSLError
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain,should_redirect_to_https", [
|
||||
(1, True),
|
||||
(2, True),
|
||||
(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)
|
||||
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
|
||||
|
||||
|
||||
@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)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 8%s\n" % subdomain == r.text
|
||||
|
||||
|
||||
def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy):
|
||||
with pytest.raises( (CertificateError, SSLError) ) as excinfo:
|
||||
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)
|
||||
|
||||
r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False)
|
||||
assert r.status_code == 500
|
@ -34,4 +34,5 @@ web4:
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- /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