From 8320b5ae578217c91cea6d80ca943bc6e269200a Mon Sep 17 00:00:00 2001 From: berckk Date: Mon, 18 Nov 2019 23:16:11 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=B0=D0=BF?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B2=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 68007e6..73136f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ tmp/ .vagrant/ .env +certs/ +html/ +htpasswd/ +vhost.d/ +conf.d/default.conf From f0dee67ec9751b5df7d7506052fea32e00e1234d Mon Sep 17 00:00:00 2001 From: berckk Date: Mon, 18 Nov 2019 23:17:32 +0300 Subject: [PATCH 2/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20docker-compose-letsencrypt-nginx-proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion.git --- conf.d/realip.conf | 57 ++++++ conf.d/servertokens.conf | 7 + conf.d/uploadsize.conf | 7 + docker-compose.yml | 54 +++++- docs/HOWTO-Synlogy.md | 27 +++ nginx.tmpl | 381 +++++++++++++++++++++++++++++++++++++++ scripts/base.sh | 18 ++ scripts/update.sh | 42 +++++ 8 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 conf.d/realip.conf create mode 100644 conf.d/servertokens.conf create mode 100644 conf.d/uploadsize.conf create mode 100755 docs/HOWTO-Synlogy.md create mode 100644 nginx.tmpl create mode 100644 scripts/base.sh create mode 100755 scripts/update.sh diff --git a/conf.d/realip.conf b/conf.d/realip.conf new file mode 100644 index 0000000..5dfb8a0 --- /dev/null +++ b/conf.d/realip.conf @@ -0,0 +1,57 @@ +# +# [WARNING] To enable this files you need to uncomment USE_NGINX_CONF_FILES=true in .env file +# +# [WARNING] Also, read all the comments in .env about NGINX use special conf files +# + +# +# Real IP Settings +# +# This option get user's real ip address +# to be fowared to your service container + +# +# Basic settings +# +# The option 'set_real_ip_from' +# must correspont to your docker network address +set_real_ip_from 172.16.0.0/12; +set_real_ip_from 10.0.0.0/8; +set_real_ip_from 192.168.0.0/16; + +# +# CloudFlare settings +# +# If you CloudFlare and want to forward the +# user's real IP to your app services you +# must uncomment all lines below and be sure +# to comment the lines of the "Basic settings" +set_real_ip_from 103.21.244.0/22; +set_real_ip_from 103.22.200.0/22; +set_real_ip_from 103.31.4.0/22; +set_real_ip_from 104.16.0.0/12; +set_real_ip_from 108.162.192.0/18; +set_real_ip_from 131.0.72.0/22; +set_real_ip_from 141.101.64.0/18; +set_real_ip_from 162.158.0.0/15; +set_real_ip_from 172.64.0.0/13; +set_real_ip_from 173.245.48.0/20; +set_real_ip_from 188.114.96.0/20; +set_real_ip_from 190.93.240.0/20; +set_real_ip_from 197.234.240.0/22; +set_real_ip_from 198.41.128.0/17; +set_real_ip_from 2400:cb00::/32; +set_real_ip_from 2606:4700::/32; +set_real_ip_from 2803:f800::/32; +set_real_ip_from 2405:b500::/32; +set_real_ip_from 2405:8100::/32; +set_real_ip_from 2c0f:f248::/32; +set_real_ip_from 2a06:98c0::/29; + +# +# Header for Real IP Address +# +real_ip_header X-Forwarded-For; +#real_ip_header X-Real-IP; +real_ip_recursive on; + diff --git a/conf.d/servertokens.conf b/conf.d/servertokens.conf new file mode 100644 index 0000000..242d50b --- /dev/null +++ b/conf.d/servertokens.conf @@ -0,0 +1,7 @@ +# +# [WARNING] To enable this files you need to uncomment USE_NGINX_CONF_FILES=true in .env file +# +# [WARNING] Also, read all the comments in .env about NGINX use special conf files +# + +server_tokens off; diff --git a/conf.d/uploadsize.conf b/conf.d/uploadsize.conf new file mode 100644 index 0000000..ed6efd1 --- /dev/null +++ b/conf.d/uploadsize.conf @@ -0,0 +1,7 @@ +# +# [WARNING] To enable this files you need to uncomment USE_NGINX_CONF_FILES=true in .env file +# +# [WARNING] Also, read all the comments in .env about NGINX use special conf files +# + +client_max_body_size 100m; diff --git a/docker-compose.yml b/docker-compose.yml index 701b468..360b194 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,13 +7,17 @@ services: - "jenkins" # - "opm_database" ports: - - "80:80" + - "80" volumes: - web_content:/var/www/ depends_on: - opm_hub - site - site-dev + - nginx-web + environment: + - VIRTUAL_HOST=oscript.io + - LETSENCRYPT_HOST=oscript.io site: build: web/site @@ -61,6 +65,54 @@ services: - /var/run/docker.sock:/var/run/docker.sock - jenkins_home:/var/jenkins_home - web_content:/var/www + + nginx-web: + image: nginx + labels: + com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true" + container_name: nginx-web + restart: always + ports: + - "80:80" + - "443:443" + depends_on: + - nginx-gen + - nginx-letsencrypt + volumes: + - ./conf.d:/etc/nginx/conf.d + - .//vhost.d:/etc/nginx/vhost.d + - ./html:/usr/share/nginx/html + - ./certs:/etc/nginx/certs:ro + - ./htpasswd:/etc/nginx/htpasswd:ro + + nginx-gen: + image: jwilder/docker-gen + command: -notify-sighup ${NGINX_WEB:-nginx-web} -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf + container_name: nginx-gen + restart: always + volumes: + - ./conf.d:/etc/nginx/conf.d + - ./vhost.d:/etc/nginx/vhost.d + - ./html:/usr/share/nginx/html + - ./certs:/etc/nginx/certs:ro + - ./htpasswd:/etc/nginx/htpasswd:ro + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro + + nginx-letsencrypt: + image: jrcs/letsencrypt-nginx-proxy-companion + container_name: nginx-letsencrypt + restart: always + volumes: + - ./conf.d:/etc/nginx/conf.d + - ./vhost.d:/etc/nginx/vhost.d + - ./html:/usr/share/nginx/html + - ./certs:/etc/nginx/certs:rw + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + NGINX_DOCKER_GEN_CONTAINER: nginx-gen + NGINX_PROXY_CONTAINER: nginx-web + volumes: web_content: jenkins_home: diff --git a/docs/HOWTO-Synlogy.md b/docs/HOWTO-Synlogy.md new file mode 100755 index 0000000..4c456f8 --- /dev/null +++ b/docs/HOWTO-Synlogy.md @@ -0,0 +1,27 @@ +## Port mapping +Synology default installs a web server on port 80 blocking certificate generation. + +To circumvent this - if you do not need external access to the default web server (and you should not expose it anyway) configure your .env to use alternative ports and your router to forward the external official port to the alternative internal ports: + +# +# Set the local exposed ports for http and https - this will allow you to run with a legacy web +# server already installed for local use +# +# NOTE: For this to function your internet router must forward the official ports to the mapped ports - +# in this example external port 80 to docker host 81 and external port 443 to docker host 444 +# +DOCKER_HTTP=81 +DOCKER_HTTPS=444 + +## File permissions +To setup the needed configuration directoties and proper permissions run the below commands (assuming default ./data is where you have your catalog for persistent files) + +mkdir -p data/certs +mkdir data/htpasswd +mkdir data/conf.d +mkdir data/vhost.d +mkdir data/html +chgrp -R 101 data +chmod -R g+rwx data + +Contributed by https://github.com/nicolailang/ diff --git a/nginx.tmpl b/nginx.tmpl new file mode 100644 index 0000000..c1383c6 --- /dev/null +++ b/nginx.tmpl @@ -0,0 +1,381 @@ +{{ $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 }} + +{{ 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 }} + +# 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 { + default $http_x_forwarded_proto; + '' $scheme; +} + +# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the +# server port the client connected to +map $http_x_forwarded_port $proxy_x_forwarded_port { + default $http_x_forwarded_port; + '' $server_port; +} + +# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any +# Connection header that may have been passed to this server +map $http_upgrade $proxy_connection { + default upgrade; + '' 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; + https on; +} + +gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; + +log_format vhost '$host $remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent"'; + +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 }} +# HTTP 1.1 support +proxy_http_version 1.1; +proxy_buffering off; +proxy_set_header Host $http_host; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $proxy_connection; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; +proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; +proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; + +# Mitigate httpoxy attack (see README for details) +proxy_set_header Proxy ""; +{{ end }} + +{{ $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; + {{ if $enable_ipv6 }} + listen [::]:80; + {{ end }} + access_log /var/log/nginx/access.log vhost; + 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; + {{ if $enable_ipv6 }} + listen [::]:443 ssl http2; + {{ end }} + access_log /var/log/nginx/access.log vhost; + 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; +} +{{ 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 (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") }} + +{{/* 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")) }} + +{{/* Get the best matching cert by name for the vhost. */}} +{{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} + +{{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} +{{ $vhostCert := trimSuffix ".crt" $vhostCert }} +{{ $vhostCert := trimSuffix ".key" $vhostCert }} + +{{/* Use the cert specified on the container or fallback to the best vhost match */}} +{{ $cert := (coalesce $certName $vhostCert) }} + +{{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} + +{{ if $is_https }} + +{{ if eq $https_method "redirect" }} +server { + server_name {{ $host }}; + listen 80 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:80 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + return 301 https://$host$request_uri; +} +{{ end }} + +server { + server_name {{ $host }}; + listen 443 ssl http2 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:443 ssl http2 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + + {{ 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_session_timeout 5m; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + + ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; + ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; + + {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} + ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; + {{ end }} + + {{ 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)) }} + include {{ printf "/etc/nginx/vhost.d/%s" $host }}; + {{ else if (exists "/etc/nginx/vhost.d/default") }} + include /etc/nginx/vhost.d/default; + {{ end }} + + 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 }} + 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 }} + } +} + +{{ end }} + +{{ if or (not $is_https) (eq $https_method "noredirect") }} + +server { + server_name {{ $host }}; + listen 80 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:80 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + + {{ 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 }}; + {{ else if (exists "/etc/nginx/vhost.d/default") }} + include /etc/nginx/vhost.d/default; + {{ end }} + + 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 }} + 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 (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 }}; + {{ if $enable_ipv6 }} + listen [::]:443 ssl http2 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + return 500; + + ssl_certificate /etc/nginx/certs/default.crt; + ssl_certificate_key /etc/nginx/certs/default.key; +} +{{ end }} + +{{ end }} +{{ end }} diff --git a/scripts/base.sh b/scripts/base.sh new file mode 100644 index 0000000..b2520ad --- /dev/null +++ b/scripts/base.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Basic scripts +# + +# 1. Check if .env file exists +check_env_file() { + if [ -e .env ]; then + source .env + else + echo + echo "Please set up your .env file before starting your enviornment." + echo + exit 1 + fi +} + + diff --git a/scripts/update.sh b/scripts/update.sh new file mode 100755 index 0000000..6f5c15f --- /dev/null +++ b/scripts/update.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# +# This scrip update the web proxy without downtime +# +# Source: https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion +# + +# 1. Check if .env file exists +if [ -e .env ]; then + source .env +else + echo + echo "Please set up your .env file before starting your enviornment." + echo + exit 1 +fi + +# 2. Update your repo +git pull +git checkout master + +# 3. Check if your env files has the same line numbers +if [ "$(wc -l .env | cut -f1 -d' ')" != "$(wc -l .env.sample | cut -f1 -d' ')" ]; then + echo + echo "The sample .env are different from the your current .env file." + echo "Please update your .env file to continue." + echo "It must has the same lines of the sample env file." + echo + echo "If you keep receiving this message please check the number of line of both files" + echo +fi + +# 3. Download the latest version of nginx.tmpl +curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > nginx.tmpl + +# 4. Update containers without downtime +docker-compose up -d --no-deps --build nginx-web +docker-compose up -d --no-deps --build nginx-gen +docker-compose up -d --no-deps --build nginx-letsencrypt + +exit 0 From 60d4aba904ad51f81fbfbc9549b5fe850f605c77 Mon Sep 17 00:00:00 2001 From: Pavel Khodakov Date: Tue, 19 Nov 2019 08:40:33 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BE=D0=BA=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20=D0=BA=D0=BE=D0=BD=D1=82?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=B5=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 98 +++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 360b194..04bb3d0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,51 @@ version: '3' services: + nginx-web: + image: nginx + labels: + com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true" + container_name: nginx-web + restart: always + ports: + - "80:80" + - "443:443" + depends_on: + - nginx-gen + - nginx-letsencrypt + volumes: + - ./conf.d:/etc/nginx/conf.d + - .//vhost.d:/etc/nginx/vhost.d + - ./html:/usr/share/nginx/html + - ./certs:/etc/nginx/certs:ro + - ./htpasswd:/etc/nginx/htpasswd:ro + + nginx-gen: + image: jwilder/docker-gen + command: -notify-sighup ${NGINX_WEB:-nginx-web} -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf + container_name: nginx-gen + restart: always + volumes: + - ./conf.d:/etc/nginx/conf.d + - ./vhost.d:/etc/nginx/vhost.d + - ./html:/usr/share/nginx/html + - ./certs:/etc/nginx/certs:ro + - ./htpasswd:/etc/nginx/htpasswd:ro + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro + + nginx-letsencrypt: + image: jrcs/letsencrypt-nginx-proxy-companion + container_name: nginx-letsencrypt + restart: always + volumes: + - ./conf.d:/etc/nginx/conf.d + - ./vhost.d:/etc/nginx/vhost.d + - ./html:/usr/share/nginx/html + - ./certs:/etc/nginx/certs:rw + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + NGINX_DOCKER_GEN_CONTAINER: nginx-gen + NGINX_PROXY_CONTAINER: nginx-web nginx: build: web/nginx image: nginx-simple @@ -15,10 +61,13 @@ services: - site - site-dev - nginx-web + - nginx-gen + - nginx-letsencrypt environment: - VIRTUAL_HOST=oscript.io - LETSENCRYPT_HOST=oscript.io - + - LETSENCRYPT_EMAIL=webmaster@oscript.io + site: build: web/site image: site_osweb @@ -66,53 +115,6 @@ services: - jenkins_home:/var/jenkins_home - web_content:/var/www - nginx-web: - image: nginx - labels: - com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true" - container_name: nginx-web - restart: always - ports: - - "80:80" - - "443:443" - depends_on: - - nginx-gen - - nginx-letsencrypt - volumes: - - ./conf.d:/etc/nginx/conf.d - - .//vhost.d:/etc/nginx/vhost.d - - ./html:/usr/share/nginx/html - - ./certs:/etc/nginx/certs:ro - - ./htpasswd:/etc/nginx/htpasswd:ro - - nginx-gen: - image: jwilder/docker-gen - command: -notify-sighup ${NGINX_WEB:-nginx-web} -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf - container_name: nginx-gen - restart: always - volumes: - - ./conf.d:/etc/nginx/conf.d - - ./vhost.d:/etc/nginx/vhost.d - - ./html:/usr/share/nginx/html - - ./certs:/etc/nginx/certs:ro - - ./htpasswd:/etc/nginx/htpasswd:ro - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro - - nginx-letsencrypt: - image: jrcs/letsencrypt-nginx-proxy-companion - container_name: nginx-letsencrypt - restart: always - volumes: - - ./conf.d:/etc/nginx/conf.d - - ./vhost.d:/etc/nginx/vhost.d - - ./html:/usr/share/nginx/html - - ./certs:/etc/nginx/certs:rw - - /var/run/docker.sock:/var/run/docker.sock:ro - environment: - NGINX_DOCKER_GEN_CONTAINER: nginx-gen - NGINX_PROXY_CONTAINER: nginx-web - volumes: web_content: jenkins_home: From a8131df2bcf081e7449e9ab3969c7679c28ad728 Mon Sep 17 00:00:00 2001 From: Pavel Khodakov Date: Tue, 19 Nov 2019 09:12:45 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/HOWTO-Synlogy.md | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100755 docs/HOWTO-Synlogy.md diff --git a/docs/HOWTO-Synlogy.md b/docs/HOWTO-Synlogy.md deleted file mode 100755 index 4c456f8..0000000 --- a/docs/HOWTO-Synlogy.md +++ /dev/null @@ -1,27 +0,0 @@ -## Port mapping -Synology default installs a web server on port 80 blocking certificate generation. - -To circumvent this - if you do not need external access to the default web server (and you should not expose it anyway) configure your .env to use alternative ports and your router to forward the external official port to the alternative internal ports: - -# -# Set the local exposed ports for http and https - this will allow you to run with a legacy web -# server already installed for local use -# -# NOTE: For this to function your internet router must forward the official ports to the mapped ports - -# in this example external port 80 to docker host 81 and external port 443 to docker host 444 -# -DOCKER_HTTP=81 -DOCKER_HTTPS=444 - -## File permissions -To setup the needed configuration directoties and proper permissions run the below commands (assuming default ./data is where you have your catalog for persistent files) - -mkdir -p data/certs -mkdir data/htpasswd -mkdir data/conf.d -mkdir data/vhost.d -mkdir data/html -chgrp -R 101 data -chmod -R g+rwx data - -Contributed by https://github.com/nicolailang/