Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add htpasswd from reading containers VIRTUAL_HTPASSWD env var #1308

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/__pycache__/
**/.cache/
.idea/
conf.d
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ COPY network_internal.conf /etc/nginx/

COPY . /app/
WORKDIR /app/
RUN touch /app/htpasswd_generator.sh && chmod +x /app/htpasswd_generator.sh

ENV DOCKER_HOST unix:///tmp/docker.sock
ENV RESOLVERS="127.0.0.11 valid=5s"

VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]

Expand Down
1 change: 1 addition & 0 deletions Dockerfile.alpine
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ COPY network_internal.conf /etc/nginx/

COPY . /app/
WORKDIR /app/
RUN touch /app/htpasswd_generator.sh && chmod +x /app/htpasswd_generator.sh

ENV DOCKER_HOST unix:///tmp/docker.sock

Expand Down
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
htpasswdgen: docker-gen -watch -notify "/app/htpasswd_generator.sh" /app/htpasswd_generator.tmpl /app/htpasswd_generator.sh
dockergen: docker-gen -watch -notify "nginx -s reload" /app/nginx.tmpl /etc/nginx/conf.d/default.conf
nginx: nginx
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,17 @@ $ docker run -d -p 80:80 -p 443:443 \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
jwilder/nginx-proxy
```
Or have your container with `VHOST_HTPASSWD`

```
$ docker run -d -p 80:80 -p 443:443 \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
jwilder/nginx-proxy
$ docker run -d \
-e VIRTUAL_HOST=whoami.local \
-e VHOST_HTPASSWD='abc:900150983CD24FB0D6963F7D28E17F72' `# this is abc:abc using md5` \
jwilder/whoami
```
You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html)

### Custom Nginx Configuration
Expand Down Expand Up @@ -385,6 +395,8 @@ 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 configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default` file. This file
will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}` file associated with it.

You can also have `VHOST_CONF` environment variable in your container.

#### Per-VIRTUAL_HOST location configuration

To add settings to the "location" block on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d`
Expand All @@ -405,6 +417,8 @@ 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.

You can also have `VHOST_LOCATION_CONF` environment variable in your container.

### Contributing

Before submitting pull requests or issues, please check github to make sure an existing issue or pull request is not already open.
Expand Down
23 changes: 0 additions & 23 deletions docker-compose-separate-containers.yml

This file was deleted.

6 changes: 6 additions & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: '2'
services:
nginx:
build: .
volumes:
- ./conf.d:/etc/nginx/conf.d
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ version: '2'
services:
nginx-proxy:
image: jwilder/nginx-proxy
build: .
container_name: nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./conf.d:/etc/nginx/conf.d

whoami:
image: jwilder/whoami
environment:
- VIRTUAL_HOST=whoami.local
- VIRTUAL_PORT=8000
16 changes: 16 additions & 0 deletions htpasswd_generator.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

mkdir -p /etc/nginx/htpasswd
{{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }}

{{ $host := trim $host }}

{{ $htpasswd := or (first (groupByKeys $containers "Env.VHOST_HTPASSWD")) "" }}

if [ ! -z '{{$htpasswd}}' ]
then
echo '{{ $htpasswd }}' > /etc/nginx/htpasswd/{{ $host }}
fi

{{ end }}
nginx -s reload
99 changes: 39 additions & 60 deletions nginx.tmpl
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
{{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }}

{{ define "upstream" }}
{{ if .Address }}
{{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}}
{{ if and .Container.Node.ID .Address.HostPort }}
# {{ .Container.Node.Name }}/{{ .Container.Name }}
server {{ .Container.Node.Address.IP }}:{{ .Address.HostPort }};
{{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}}
{{ else if .Network }}
# {{ .Container.Name }}
server {{ .Network.IP }}:{{ .Address.Port }};
{{ end }}
{{ else if .Network }}
# {{ .Container.Name }}
{{ if .Network.IP }}
server {{ .Network.IP }} down;
{{ else }}
server 127.0.0.1 down;
{{ end }}
{{ end }}

{{ end }}

# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
# scheme used to connect to this server
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
Expand Down Expand Up @@ -119,44 +97,20 @@ server {

{{ $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 (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 }}
{{ $address := index $container.Addresses 0 }}
{{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }}
{{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}}
{{ else }}
{{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }}
{{ $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 }}
{{ end }}
}


{{ $default_host := or ($.Env.DEFAULT_HOST) "" }}
{{ $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 := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }}

{{ $vhost_conf := trim (or (first (groupByKeys $containers "Env.VHOST_CONF")) "") }}

{{ $vhost_location_conf := trim (or (first (groupByKeys $containers "Env.VHOST_LOCATION_CONF")) "") }}

{{ $container_pass := (printf "%v:%v" (first (groupByKeys $containers "Name")) (trim (or (first (groupByKeys $containers "Env.VIRTUAL_PORT")) "80"))) }}

{{/* 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" }}

Expand All @@ -172,6 +126,9 @@ upstream {{ $upstream_name }} {
{{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}}
{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }}

{{/* Get the SERVER_PASS By containers e.g. proxy_pass..., grpc_pass..., fastcgi_pass... */}}
{{ $server_pass := or ($container.Env.SERVER_PASS) "" }}


{{/* Get the first cert name defined by containers w/ the same vhost */}}
{{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }}
Expand Down Expand Up @@ -272,16 +229,23 @@ server {
include /etc/nginx/vhost.d/default;
{{ end }}

{{ if not (eq $vhost_conf "") }}
{{ $vhost_conf }}
{{ end }}

location / {
{{ if eq $proto "uwsgi" }}
set $target {{ trim $container_pass }};
{{ if ne $server_pass "" }}
{{ $server_pass }};
{{ else if eq $proto "uwsgi" }}
include uwsgi_params;
uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }};
uwsgi_pass {{ trim $proto }}://$target;
{{ else if eq $proto "fastcgi" }}
root {{ trim $vhost_root }};
include fastcgi.conf;
fastcgi_pass {{ trim $upstream_name }};
fastcgi_pass $target;
{{ else }}
proxy_pass {{ trim $proto }}://{{ trim $upstream_name }};
proxy_pass {{ trim $proto }}://$target;
{{ end }}

{{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }}
Expand All @@ -293,6 +257,9 @@ server {
{{ else if (exists "/etc/nginx/vhost.d/default_location") }}
include /etc/nginx/vhost.d/default_location;
{{ end }}
{{ if not (eq $vhost_location_conf "") }}
{{ $vhost_location_conf }}
{{ end }}
}
}

Expand All @@ -319,16 +286,24 @@ server {
include /etc/nginx/vhost.d/default;
{{ end }}

{{ if not (eq $vhost_conf "") }}
{{ $vhost_conf }}
{{ end }}

location / {
set $target {{ trim $container_pass }};
{{ if eq $proto "uwsgi" }}
{{ if ne $server_pass "" }}
{{ $server_pass }};
{{ else if eq $proto "uwsgi" }}
include uwsgi_params;
uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }};
uwsgi_pass {{ trim $proto }}://$target;
{{ else if eq $proto "fastcgi" }}
root {{ trim $vhost_root }};
include fastcgi.conf;
fastcgi_pass {{ trim $upstream_name }};
fastcgi_pass $target;
{{ else }}
proxy_pass {{ trim $proto }}://{{ trim $upstream_name }};
proxy_pass {{ trim $proto }}://$target;
{{ end }}
{{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }}
auth_basic "Restricted {{ $host }}";
Expand All @@ -339,6 +314,9 @@ server {
{{ else if (exists "/etc/nginx/vhost.d/default_location") }}
include /etc/nginx/vhost.d/default_location;
{{ end }}
{{ if not (eq $vhost_location_conf "") }}
{{ $vhost_location_conf }}
{{ end }}
}
}

Expand All @@ -359,3 +337,4 @@ server {

{{ end }}
{{ end }}