Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# mesudip/python-nginx:alpine is merge of official python and nginx images.
FROM mesudip/python-nginx:alpine
HEALTHCHECK --interval=10s --timeout=2s --start-period=10s --retries=3 CMD pgrep nginx >> /dev/null || exit 1
HEALTHCHECK --interval=10s --timeout=2s --start-period=10s --retries=3 CMD pgrep nginx && pgrep python3 >> /dev/null || exit 1
VOLUME ["/etc/nginx/dhparam", "/tmp/acme-challenges/","/etc/nginx/conf.d","/etc/nginx/ssl"]
CMD ["sh","-e" ,"/docker-entrypoint.sh"]
COPY ./requirements.txt /requirements.txt
Expand All @@ -14,6 +14,8 @@ RUN apk --no-cache add openssl && \
ARG LETSENCRYPT_API="https://acme-v02.api.letsencrypt.org/directory"
ENV LETSENCRYPT_API=${LETSENCRYPT_API} \
CHALLENGE_DIR=/tmp/acme-challenges/ \
DHPARAM_SIZE=2048
DHPARAM_SIZE=2048 \
CLIENT_MAX_BODY_SIZE=1m \
DEFAULT_HOST=true
WORKDIR /app
COPY . /app/
117 changes: 90 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,70 @@ Nginx-Proxy
===================================================
Docker container for automatically creating nginx configuration based on active containers in docker host.

## Basic setup of nginx-proxy
- Easy server configuration with environment variables
- Map multiple containers to different locations on same server
- Automatic Let's Encrypt ssl certificate registration
- Basic Authorization

## Quick Setup
### Setup nginx-proxy
```
docker pull mesudip/nginx-proxy
docker network create frontend; # create a network for nginx proxy
docker run --network frontend \
--name nginx \
--name nginx-proxy \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /etc/ssl:/etc/ssl \
-v /etc/ssl/dhparam:/etc/nginx/dhparam \
-p 80:80 \
-p 443:443 \
mesudip/nginx-proxy
-d --restart always mesudip/nginx-proxy
```
### Volumes
Following directries can be made into volumes to persist configurations
- `/etc/nginx/conf.d` nginx configuration directory. You can add your own server configurations here
- `/etc/nginx/dhparam` the directory for storing DH parameter for ssl connections
- `/etc/ssl` directory for storing ssl certificates, ssl private key and letsencrypt account key.

## Configuring the container in detail
### Setup your container
The only thing that matters is that the container shares at least one common network to the nginx container and `VIRTUAL_HOST`
environment variable is set. If you have multiple exposed ports in the container, don't forget to
mention the container port too.
environment variable is set.

Examples:
- **WordPress**
```
docker run --network frontend \
--name test-host \
-e VIRTUAL_HOST="example.com" \
nginx:alpine
--name wordpress-server \
-e VIRTUAL_HOST="wordpress.example.com" \
wordpress
```
- **Docker Registry**
```
docker run --network frontend \
--name docker-registry \
-e VIRTUAL_HOST='registry.example.com/v2 -> /v2; client_max_body_size 2g' \
-e PROXY_BASIC_AUTH="registry.example.com -> user1:password,user2:password2,user3:password3"
registry:2
```

### Using the environment `VIRTUAL_HOST`
Details of Using nginx-proxy
======================
- [Configure `nginx-proxy`](#configure-nginx-proxy)
- [Configure enrironment VIRTUAL_HOST in your containers](#configure-environment-virtual_host-in-your-containers)
- [WebSockets](#support-for-websocket)
- [Multiple hosts in same container](#multiple-virtual-hosts-on-same-container)
- [Redirection](#redirection)
- [Https and SSL](#ssl-support)
- [Basic Authorization](#basic-authorization)
- [Default Server](#default-server)

## Configure `nginx-proxy`
Following directries can be made into volumes to persist configurations
- `/etc/nginx/conf.d` nginx configuration directory. You can add your own server configurations here
- `/etc/nginx/dhparam` the directory for storing DH parameter for ssl connections
- `/etc/ssl` directory for storing ssl certificates, ssl private key and Let's Encrypt account key.
- `/var/log/nginx` directory nginx logs
- `/tmp/acme-challenges` directory for storing challenge content when registering Let's Encrypt certificate

Some of the default behaviour of `nginx-proxy` can be changed with environment variables.
- `DHPARAM_SIZE` Default - `2048` : Set size of dhparam usd for ssl certificates
- `CLIENT_MAX_BODY_SIZE` Default - `1m` : Set default max body size for all the servers.

## Configure environment `VIRTUAL_HOST` in your containers
When you want a container's to be hosted on a domain set `VIRTUAL_HOST` environment variable to desired `server_name` entry.
For virtual host to work it requires
- nginx-proxy container to be on the same network as that of the container.
Expand All @@ -49,7 +84,22 @@ example.com/<span></span>api | http://<span></span>example.com/api |/ | exposed
example.com/<span></span>api -> :8080/api | http://<span></span>example.com/api | /api | 8080
https://<span></span>example.com/<span></span>api/v1:5001 -> :8080/api | https://<span></span>example.com/<span></span>api/v1:5001 | /api | 8080
wss://example.com/websocket | wss://example.com/websocket | / | exposed port


With `VIRTUAL_HOST` you can inject nginx directives into location each configuration must be separed with a `;`
. You can see the possible directives in nginx documentation.

**Example :** `VIRTUAL_HOST=somesite.example.com -> :8080 ;proxy_read_timeout 900;client_max_body_size 2g;` will generate configuration as follows
```nginx.conf
server{
server_name somesite.example.com;
listen 80;
location /{
proxy_read_timeout 900;
client_max_body_size 2g;
proxy_pass http://127.2.3.4; // your container ip here
}
}
```
### Support for websocket
Exposing websocket requires the websocket endpoint to be explicitly configured via virtual host. The websocket endpoint can be `ws://` or `wss://`.
If you want to use both websocket and non-websocket endpoints you will have to use multiple hosts
Expand All @@ -67,10 +117,17 @@ To have multiple virtual hosts out of single container, you can use `VIRTUAL_HOS
ethereum/client-go \
--rpc --rpcaddr "0.0.0.0" --ws --wsaddr 0.0.0.0
```
## Redirection
Let's say you want to serve a website on `example.uk`. You might want users visiting `www.example.uk`,`example.com`,`www.example.com`
to redirect to `example.uk`. You can simply use `PROXY_FULL_REDIRECT` environment variable.
```
-e 'VIRTUAL_HOST=https://example.uk -> :7000' \
-e 'PROXY_FULL_REDIRECT=example.com,www.example.com,www.example.uk->example.uk'
```

## SSL Support
Issuing of SSL certificate is done using acme-nginx library for Let's Encrypt. If a precheck determines that
the domain we are trying to issue certificate is not owned by current machine, a self signed certificate is
the domain we are trying to issue certificate is not owned by current machine, a self-signed certificate is
generated instead.

### Using SSL for exposing endpoint
Expand All @@ -85,15 +142,14 @@ If you already have a ssl certificate that you want to use, copy it under the `/
Wildcard certificates can be used. For example to use `*.example.com` wildcard, you should create files
`/etc/ssl/certs/*.example.com.crt` and `/etc/ssl/private/*.example.com.key` in the container's filesystem.

**Note that `*.blah` or `*` is not a valid wildcard.**
**Note that `*.com` or `*` is not a valid wildcard.** Wild card must have at least 2 dots.

`/etc/ssl/certs/*.example.com.crt` certificate will :
- be used for `host1.example.com`
- be used for `www.example.com`
- not be used for `xyz.host1.example.com`
- not be used for `example.com`


***DHPARAM_SIZE :***
Default size of DH key used for https connection is `2048`bits. The key size can be changed by changing `DHPARAM_SIZE` environment variable

Expand All @@ -102,20 +158,27 @@ You can manually obtain Let's encrypt certificate using the nginx-proxy containe
Note that you must set ip in DNS entry to point the correct server.

To issue a certificate for a domain you can simply use this command.
- `docker exec nginx getssl www.example.com`
- `docker exec nginx-proxy getssl www.example.com`

Obtained certificate is saved on `/etc/ssl/certs/www.example.com` and private is saved on `/etc/ssl/private/www.example.com`

To issue certificates for multiple domain you can simply add more parameters to the above command

- `docker exec nginx getssl www.example.com example.com ww.example.com`
- `docker exec nginx-proxy getssl www.example.com example.com ww.example.com`

All the domains are registered on the same certificate and the filename is set from the first parameter
passed to the command. so `/etc/ssl/certs/www.example.com` and `/etc/ssl/private/www.example.com` are generated

Use `docker exec nginx getssl --help` for getting help with the command
Use `docker exec nginx-proxy getssl --help` for getting help with the command

## Basic Authorization
Basic Auth can be enabled on the container with environment variable `PROXY_BASIC_AUTH`.
- `PROXY_BASIC_AUTH=user1:password1,user2:password2,user3:password3` adds basic auth feature to your configured `VIRTUAL_HOST` server root.
- `PROXY_BASIC_AUTH=example.com/api/v1/admin -> admin1:password1,admin2:password2` adds basic auth only to the location starting from `api/v1/admin`

## Default Server
When request comes for a server name that is not registered in `nginx-proxy`, It responds with 503 by default.
If you want the requested to be passed to a container instead, when setting up the container you can add `PROXY_DEFAULT_SERVER=true` environment along with `VIRTUAL_HOST`.

## Compatibility with jwilder/nginx-proxy
This nginx-proxy supports `VIRTUAL_HOST` `LETSENCRYPT_HOST` AND `VIRTUAL_PORT` like in jwilder/nginx-proxy.
But comma separated `VIRTUAL_HOST` is not supported. It's still missing a lot of other feature of jwilder/nginx-proxy
hopefully they will be available in future versions.
This much is sufficient for http connections, but for https connections, you might want to setup
[wildcard certificates](#using-your-own-ssl-certificate) so that your users dont get invalid ssl certificate errors.
91 changes: 0 additions & 91 deletions acme_nginx/AWSRoute53.py

This file was deleted.

2 changes: 2 additions & 0 deletions acme_nginx/Acme.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ def _send_signed_request(self, url, payload=None, directory=None):
except UnicodeDecodeError:
pass
return resp.getcode(), resp_data, resp.headers
except (KeyboardInterrupt, SystemExit) as e:
raise e
except Exception as e:
return getattr(e, "code", None), \
getattr(e, "read", e.__str__)(), \
Expand Down
10 changes: 10 additions & 0 deletions acme_nginx/AcmeV1.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ def register_account(self):
try:
self.log.info('trying to create account key {0}'.format(self.account_key))
account_key = self.create_key(self.account_key)
except (KeyboardInterrupt, SystemExit) as e:
raise e
except Exception as e:
self.log.error('creating key {0} {1}'.format(type(e).__name__, e))
sys.exit(1)
Expand All @@ -44,6 +46,8 @@ def get_certificate(self):
self.register_account()
try:
self.create_key(self.domain_key)
except (KeyboardInterrupt, SystemExit) as e:
raise e
except Exception as e:
self.log.error('creating key {0} {1}'.format(type(e).__name__, e))
sys.exit(1)
Expand All @@ -66,6 +70,8 @@ def get_certificate(self):
self.log.info('adding nginx virtual host and completing challenge')
try:
self._write_challenge(token, thumbprint)
except (KeyboardInterrupt, SystemExit) as e:
raise e
except Exception as e:
self.log.error('error adding virtual host {0} {1}'.format(type(e).__name__, e))
sys.exit(1)
Expand Down Expand Up @@ -97,6 +103,8 @@ def get_certificate(self):
chain_str = urlopen(self.chain).read()
if chain_str:
chain_str = chain_str.decode('utf8')
except (KeyboardInterrupt, SystemExit) as e:
raise e
except Exception as e:
self.log.error('error getting chain: {0} {1}'.format(type(e).__name__, e))
sys.exit(1)
Expand All @@ -111,6 +119,8 @@ def get_certificate(self):
)))
)
fd.write(chain_str)
except (KeyboardInterrupt, SystemExit) as e:
raise e
except Exception as e:
self.log.error('error writing cert: {0} {1}'.format(type(e).__name__, e))
sys.exit(1)
Expand Down
Loading