diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cf600cf..fbbbc5c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -64,11 +64,9 @@ jobs: push: true platforms: linux/amd64,linux/arm/v7,linux/arm64 tags: | - bfren/nginx-proxy:latest bfren/nginx-proxy:${{ steps.version_major.outputs.contents }} bfren/nginx-proxy:${{ steps.version_minor.outputs.contents }} bfren/nginx-proxy:${{ steps.version.outputs.contents }} - ghcr.io/bfren/nginx-proxy:latest ghcr.io/bfren/nginx-proxy:${{ steps.version_major.outputs.contents }} ghcr.io/bfren/nginx-proxy:${{ steps.version_minor.outputs.contents }} ghcr.io/bfren/nginx-proxy:${{ steps.version.outputs.contents }} diff --git a/README.md b/README.md index 5027359..96b0f53 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Nginx Proxy which uses [getssl](https://github.com/srvrco/getssl) to automate requesting and renewing SSL certificates via Let's Encrypt. Certificates are checked for renewal every day - the last check can be viewed in the `/ssl` volume. +As of v4, configuration is handled via a JSON file - see ssl-conf-sample.json for an example and ssl-conf-schema.json for the full file definition. + ## Contents * [Ports](#ports) @@ -25,11 +27,11 @@ For SSL certificate requests to work correctly, ports 80 and 443 need mapping fr ## Volumes -| Volume | Purpose | -| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `/www` | *From base image.* | -| `/sites` | Nginx site configuration, auto-generated on first run based on `conf.sh`. After they are generated, you can alter them to suit their needs. Running `nginx-regenerate` will wipe them all and start again. | -| `/ssl` | Contains auto-generated SSL configuration and certificates (for backup purposes). Your `conf.sh` file should be stored in here for auto-configuration (see `ssl-conf-sample.sh`). Certificate update log (`update.log`) will be created here weekly. | +| Volume | Purpose | +| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `/www` | *From base image.* | +| `/sites` | Nginx site configuration, auto-generated on first run based on `conf.json`. After they are generated, you can alter them to suit their needs. Running `nginx-regenerate` will wipe them all and start again. | +| `/ssl` | Contains auto-generated SSL configuration and certificates (for backup purposes). Your `conf.json` file should be stored in here for auto-configuration (see `ssl-conf-sample.json`). Certificate update log (`update.log`) will be created here daily. | ## Environment Variables @@ -40,20 +42,20 @@ For SSL certificate requests to work correctly, ports 80 and 443 need mapping fr | `PROXY_LETS_ENCRYPT_EMAIL` | A valid email address | Used by Lets Encrypt for notification emails. | *None* - **required** | | `PROXY_LETS_ENCRYPT_LIVE` | 0 or 1 | Only set to 1 (to request live certificates) when your config is correct - Lets Encrypt rate limit certificate requests. | 0 | | `PROXY_SSL_DHPARAM_BITS` | A valid integer | The size of your DHPARAM variables - adjust down only if you have limited processing resources. | 4096 | -| `PROXY_SSL_REDIRECT_TO_CANONICAL` | 0 or 1 | If 1, all requests will be redirected to the primary domain (defined in `conf.sh`). | 0 | +| `PROXY_SSL_REDIRECT_TO_CANONICAL` | 0 or 1 | If 1, all requests will be redirected to the primary domain (defined in `conf.json`). | 0 | | `PROXY_GETSSL_SKIP_HTTP_TOKEN_CHECK` | true or false | Set to true to enable `getssl`'s [skip HTTP token check](https://github.com/srvrco/getssl/wiki/Config-variables#skip_http_token_checkfalse). | false | ## Helper Functions -| Function | Arguments | Description | -| --------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- | -| `nginx-regenerate` | *None* | Removes Nginx configuration files (in `/sites`) and regenerates based on `conf.sh`. | -| `ssl-cleanup` | *None* | Removes SSL and Nginx configuration files and directories not defined in `conf.sh`. | -| `ssl-init` | *None* | Initialises SSL configuration based on `conf.sh`. | -| `ssl-regenerate` | *None* | Removes SSL configuration files (in `/ssl/certs`) and regenerates based on `conf.sh`. | -| `ssl-regenerate-full` | *None* | Removes SSL configuration files (in `/ssl/certs`), as well as DH parameters, and regenerates based on `conf.sh`. | -| `ssl-request` | *None* | Requests SSL certificates from Lets Encrypt. | -| `ssl-update` | *None* | Attempts to update SSL certificates manually. | +| Function | Arguments | Description | +| --------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `nginx-regenerate` | -f: force | Removes non-custom Nginx configuration files (in `/sites`) and regenerates based on `conf.json` (with force, removes all). | +| `ssl-cleanup` | -m: mode | Removes SSL and Nginx configuration files and directories not defined in `conf.json` (mode 0 = dry run, 1 = live). | +| `ssl-init` | *None* | Initialises SSL configuration based on `conf.json`. | +| `ssl-regenerate` | *None* | Removes SSL configuration files (in `/ssl/certs`) and regenerates based on `conf.json`. | +| `ssl-regenerate-full` | *None* | Removes SSL configuration files (in `/ssl/certs`), as well as DH parameters, and regenerates based on `conf.json`. | +| `ssl-request` | *None* | Requests SSL certificates from Lets Encrypt. | +| `ssl-update` | *None* | Attempts to update SSL certificates manually. | ## Nginx Configuration Helpers diff --git a/VERSION b/VERSION index 050ffa7..0c89fc9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.13 \ No newline at end of file +4.0.0 \ No newline at end of file diff --git a/VERSION_MAJOR b/VERSION_MAJOR index e440e5c..bf0d87a 100644 --- a/VERSION_MAJOR +++ b/VERSION_MAJOR @@ -1 +1 @@ -3 \ No newline at end of file +4 \ No newline at end of file diff --git a/VERSION_MINOR b/VERSION_MINOR index f30101c..389f774 100644 --- a/VERSION_MINOR +++ b/VERSION_MINOR @@ -1 +1 @@ -3.3 \ No newline at end of file +4.0 \ No newline at end of file diff --git a/overlay/etc/bf/templates/nginx-proxy.conf.esh b/overlay/etc/bf/templates/nginx-proxy.conf.esh index 9372824..52fd7d8 100644 --- a/overlay/etc/bf/templates/nginx-proxy.conf.esh +++ b/overlay/etc/bf/templates/nginx-proxy.conf.esh @@ -4,7 +4,7 @@ # # Use environment variable PROXY_URI to change this file. # -# Copyright (c) 2021 bfren +# Copyright (c) 2021-2022 bfren #====================================================================================================================== #====================================================================================================================== diff --git a/overlay/etc/bf/templates/nginx-site.conf.esh b/overlay/etc/bf/templates/nginx-site.conf.esh index a4cfef7..33438cc 100644 --- a/overlay/etc/bf/templates/nginx-site.conf.esh +++ b/overlay/etc/bf/templates/nginx-site.conf.esh @@ -1,17 +1,4 @@ -<% if [ -z "${DOMAIN_NGXCONF}" ] ; then -%> -#====================================================================================================================== -# WARNING: This file is generated. Do not make changes to this file. -# Changes will be overwritten the next time the container is started. -# -# To add server names or aliases please use /ssl/conf.sh (see ssl-conf-sample.sh). -# -# If you need a fully custom configuration then add the following to /ssl/conf.sh: -# NGXCONF["<%= "${DOMAIN_NAME}" %>"]="custom" -# This will stop this file being generated next time the container is started. -# -# Copyright (c) 2021 bfren -#====================================================================================================================== -<% else -%> +<% if [ "${DOMAIN_NGXCONF}" = "true" ] ; then -%> #====================================================================================================================== # You can make changes to this file. # @@ -23,11 +10,26 @@ # d) custom configuration can be added to the /sites/<%= "${DOMAIN_NAME}" %>.d directory - # these are loaded as part of the HTTPS server block below # -# If you would like to return to using generated configuration then remove the following from /ssl/conf.sh: -# NGXCONF["<%= "${DOMAIN_NAME}" %>"]="" +# If you would like to return to using generated configuration then remove the following from /ssl/conf.json in the +# object where the primary domain is "<%= "${DOMAIN_NAME}" %>": +# "custom": true # This will cause this file to be regenerated next time the container is started. # -# Copyright (c) 2021 bfren +# Copyright (c) 2021-2022 bfren +#====================================================================================================================== +<% else -%> +#====================================================================================================================== +# WARNING: This file is generated. Do not make changes to this file. +# Changes will be overwritten the next time the container is started. +# +# To add server names or aliases please use /ssl/conf.sh (see ssl-conf-sample.sh). +# +# If you need a fully custom configuration then add the following to /ssl/conf.json in the object where the primary +# domain is "<%= "${DOMAIN_NAME}" %>": +# "custom": true +# This will stop this file being generated next time the container is started. +# +# Copyright (c) 2021-2022 bfren #====================================================================================================================== <% fi %> #====================================================================================================================== diff --git a/overlay/tmp/install b/overlay/tmp/install index 61714b7..4a4aae3 100644 --- a/overlay/tmp/install +++ b/overlay/tmp/install @@ -12,6 +12,7 @@ bf-echo "Installing packages..." apk add --no-cache \ bash \ curl \ + jq \ openssl bf-done diff --git a/overlay/usr/bin/bf/nginx-regenerate b/overlay/usr/bin/bf/nginx-regenerate index ad9e487..faaa7c2 100644 --- a/overlay/usr/bin/bf/nginx-regenerate +++ b/overlay/usr/bin/bf/nginx-regenerate @@ -32,7 +32,7 @@ done bf-echo "Loading SSL configuration." source ${BF_INC}/proxy-load-conf.sh -bf-debug "Loaded: ${!DOMAINS[*]}." +bf-debug "Loaded: ${DOMAINS[*]}." #====================================================================================================================== @@ -54,7 +54,8 @@ for CFG in "${NGINX_CONFIGS[@]}" ; do bf-debug " .. ${STRIPPED}" # the domain has standard config - delete conf file - if [[ -z "${NGXCONF[${STRIPPED}]-}" ]] ; then + CUSTOM_CONF=`get-custom "${STRIPPED}"` + if [[ "${CUSTOM_CONF}" = "false" ]] ; then bf-debug " .. standard config: remove configuration file" rm -f ${PROXY_SITES}/${STRIPPED}.conf diff --git a/overlay/usr/bin/bf/ssl-cleanup b/overlay/usr/bin/bf/ssl-cleanup index a34d228..1732a3a 100644 --- a/overlay/usr/bin/bf/ssl-cleanup +++ b/overlay/usr/bin/bf/ssl-cleanup @@ -42,9 +42,9 @@ esac remove () { if [ "${MODE}" = "0" ] ; then - bf-echo " .. will remove ${1}/*" + bf-echo " .. will remove ${1}*" elif [ "${MODE}" = "1" ] ; then - bf-echo " .. removing ${1}/*" + bf-echo " .. removing ${1}*" bf-rmrf ${1}* > /dev/null 2>&1 fi @@ -57,7 +57,7 @@ remove () { bf-echo "Loading SSL configuration." source ${BF_INC}/proxy-load-conf.sh -bf-debug "Loaded: ${!DOMAINS[*]}." +bf-debug "Loaded: ${DOMAINS[*]}." #====================================================================================================================== @@ -79,7 +79,7 @@ for CFG in "${SSL_CONFIGS[@]}" ; do # if NAME is not the main PROXY_URI nor in the DOMAINS array, delete everything [[ "${PROXY_URI}" != "${NAME}" ]] \ - && [[ ! " ${!DOMAINS[*]} " =~ " ${NAME} " ]] \ + && [[ -z "`get-domain ${NAME}`" ]] \ && remove "${PROXY_SSL_CERTS}/${NAME}" done @@ -105,7 +105,7 @@ for CFG in "${NGINX_CONFIGS[@]}" ; do # if STRIPPED is not the main PROXY_URI nor in the DOMAINS array, delete everything [[ "${PROXY_URI}" != "${STRIPPED}" ]] \ - && [[ ! " ${!DOMAINS[*]} " =~ " ${STRIPPED} " ]] \ + && [[ -z "`get-domain ${STRIPPED}`" ]] \ && remove "${PROXY_SITES}/${STRIPPED}" done diff --git a/overlay/usr/lib/bf/inc/proxy-check.sh b/overlay/usr/lib/bf/inc/proxy-check.sh index c1425d8..b07b5ea 100644 --- a/overlay/usr/lib/bf/inc/proxy-check.sh +++ b/overlay/usr/lib/bf/inc/proxy-check.sh @@ -22,7 +22,7 @@ fi #====================================================================================================================== -# Create arrays and include configuration. +# Load configuration (creates DOMAINS array). #====================================================================================================================== source ${BF_INC}/proxy-load-conf.sh @@ -32,7 +32,7 @@ source ${BF_INC}/proxy-load-conf.sh # Check whether or not domains have been registered. #====================================================================================================================== -if [ "${#DOMAINS[@]}" = "0" ] ; then +if [ "${#DOMAINS[*]}" = "0" ] ; then bf-error "No domains have been registered for SSL - please add them to /ssl/conf.sh." "inc/proxy-check.sh" exit 1 fi diff --git a/overlay/usr/lib/bf/inc/proxy-load-conf.sh b/overlay/usr/lib/bf/inc/proxy-load-conf.sh index 05d45b9..7bc4f39 100644 --- a/overlay/usr/lib/bf/inc/proxy-load-conf.sh +++ b/overlay/usr/lib/bf/inc/proxy-load-conf.sh @@ -2,17 +2,34 @@ #====================================================================================================================== -# Create arrays and include configuration. +# Check JSON configuration file exists. #====================================================================================================================== -SSL_CONF=${PROXY_SSL}/conf.sh +SSL_CONF=${PROXY_SSL}/conf.json if [ ! -f ${SSL_CONF} ] ; then - bf-error "You must create ${SSL_CONF} - see ssl-conf-sample.sh." "inc/proxy-load-conf.sh" + bf-error "You must create ${SSL_CONF} - see ssl-conf-sample.json." "inc/proxy-load-conf.sh" exit 1 fi -declare -A DOMAINS -declare -A ALIASES -declare -A NGXCONF -source ${SSL_CONF} +#====================================================================================================================== +# Load JSON and create DOMAINS array by selecting primary keys. +#====================================================================================================================== + +JSON=`cat "${SSL_CONF}" | jq '.'` + +declare -a DOMAINS=(`jq -r '.domains[].primary' <<< "${JSON}"`) + + +#====================================================================================================================== +# Gets a domain object from the JSON configuration. +# +# Arguments +# 1 Primary domain name to select +#====================================================================================================================== + +function get-domain() { jq --arg PRIMARY "${1}" '.domains[] | select(.primary == $PRIMARY)' <<< "${JSON}" ; } + +function get-upstream() { get-domain "${1}" | jq -r '.upstream' ; } +function get-aliases() { get-domain "${1}" | jq -r '.aliases[]?' ; } +function get-custom() { get-domain "${1}" | jq -r '.custom == true' ; } diff --git a/overlay/usr/lib/bf/inc/proxy-setup-nginx.sh b/overlay/usr/lib/bf/inc/proxy-setup-nginx.sh index a2b4b23..f435c46 100644 --- a/overlay/usr/lib/bf/inc/proxy-setup-nginx.sh +++ b/overlay/usr/lib/bf/inc/proxy-setup-nginx.sh @@ -5,10 +5,11 @@ # Set up Nginx. # # Arguments -# 1 Domain name -# 2 Upstream URL -# 3 Name of Domain Aliases array -# 4 Blank (regenerate) or 'custom' (keep) Nginx configuration file +# 1 0 for proxied domain, 1 for domain of the proxy server itself +# 2 Domain name +# 3 Upstream URL +# 4 Name of Domain Aliases array +# 5 Blank (regenerate) or 'custom' (keep) Nginx configuration file #====================================================================================================================== setup-nginx () { @@ -31,20 +32,20 @@ setup-nginx () { # check for existing configuration file if [ -f ${CONF} ] ; then - # if empty, remove config so it can be regenerated - if [ -z "${DOMAIN_NGXCONF}" ] ; then - bf-debug " removing and regnerating Nginx configuration" "inc/proxy-setup-nginx.sh" - rm ${CONF} - - # otherwise, leave file (allows custom config) - else + # if true, leave file (allows custom config) + if [ "${DOMAIN_NGXCONF}" = "true" ] ; then bf-debug " keeping existing configuration." "inc/proxy-setup-nginx.sh" return 0 + + # otherwise, remove config so it can be regenerated + else + bf-debug " removing and regnerating Nginx configuration" "inc/proxy-setup-nginx.sh" + rm ${CONF} fi else - # no need to do anything, be a good log citizen + # no need to remove anything, be a good log citizen bf-debug " generating default Nginx configuration" "inc/proxy-setup-nginx.sh" fi diff --git a/overlay/usr/lib/bf/proxy/init b/overlay/usr/lib/bf/proxy/init index 48d1dcc..81e7198 100644 --- a/overlay/usr/lib/bf/proxy/init +++ b/overlay/usr/lib/bf/proxy/init @@ -47,16 +47,16 @@ bf-ok " . done." "proxy/init" #====================================================================================================================== bf-echo "Setting up domains..." "proxy/init" -for DN in "${!DOMAINS[@]}" ; do +for DN in "${DOMAINS[@]}" ; do - UP=${DOMAINS[${DN}]} # upstream server - AL=${ALIASES[${DN}]} # aliases - CF=${NGXCONF[${DN}]} # use default / custom Nginx config + UP=`get-upstream ${DN}` # upstream server + AL=`get-aliases ${DN}` # aliases + CF=`get-custom ${DN}` # whether or not to use custom Nginx config bf-echo " .. ${DN}" "proxy/init" bf-echo " . Nginx..." "proxy/init" - setup-nginx 0 ${DN} "${UP}" "${AL}" "${CF}" + setup-nginx 0 ${DN} ${UP} "${AL}" ${CF} bf-echo " . SSL..." "proxy/init" setup-ssl ${DN} "${AL}" diff --git a/overlay/usr/lib/bf/proxy/request b/overlay/usr/lib/bf/proxy/request index eef93ac..972bb14 100644 --- a/overlay/usr/lib/bf/proxy/request +++ b/overlay/usr/lib/bf/proxy/request @@ -39,7 +39,7 @@ bf-done "proxy/request" #====================================================================================================================== bf-echo "Requesting domain certificates..." "proxy/request" -for DN in "${!DOMAINS[@]}" ; do +for DN in "${DOMAINS[@]}" ; do bf-debug " .. ${DN}" "proxy/request" request "${DN}" done diff --git a/overlay/usr/lib/bf/proxy/update b/overlay/usr/lib/bf/proxy/update index a4d47d6..ccc95a6 100644 --- a/overlay/usr/lib/bf/proxy/update +++ b/overlay/usr/lib/bf/proxy/update @@ -30,5 +30,5 @@ bf-done "proxy/update" bf-echo "Updating pem files..." "proxy/update" create-pem ${PROXY_URI} -for DN in "${!DOMAINS[@]}" ; do create-pem "${DN}" ; done +for DN in "${DOMAINS[@]}" ; do create-pem "${DN}" ; done bf-done "proxy/update" diff --git a/ssl-conf-sample.json b/ssl-conf-sample.json new file mode 100644 index 0000000..2c345d2 --- /dev/null +++ b/ssl-conf-sample.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://raw.githubusercontent.com/bfren/docker-nginx-proxy/main/ssl-conf-schema.json", + "domains": [ + { + "primary": "example.com", + "upstream": "http://example:5000", + "aliases": [ "www.example.com", "ex.com", "www.ex.com" ], + "custom": true + }, + { + "primary": "test.com", + "upstream": "http://test", + "aliases": [ "www.test.com", "fred.co.uk" ], + "custom": false + } + ] +} diff --git a/ssl-conf-sample.sh b/ssl-conf-sample.sh deleted file mode 100644 index ad25f29..0000000 --- a/ssl-conf-sample.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -#====================================================================================================================== -# This file should be modified to define domain arrays and then stored in /ssl/conf.sh -# -# DOMAINS is an associative array -# key: (string) primary domain name -# value: (string) upstream server -# -# ALIASES is an associative array -# key: (string) primary domain name - if it doesn't match one of the keys in DOMAINS, it will be ignored -# value: (string) alias domain names to be included in the SSL certificate, separated by a space -# -# NGXCONF is an optional associative array -# key: (string) primary domain name - if it doesn't match one of the keys in DOMAINS, it will be ignored -# value: (string) "custom" by convention - but if you set this to *anything*, Nginx config for this site won't be -# automatically regenerated, so you won't get new features and be responsible for maintaining it yourself -# -# These arrays will generate configuration files that will be stored in /sites and /ssl/certs -# After generation they can be modified to suit your needs - after modification, the container should be restarted -#====================================================================================================================== - -DOMAINS["example.com"]="http://example" -ALIASES["example.com"]="www.example.com ex.com www.ex.com" -NGXCONF["example.com"]="custom" - -DOMAINS["test.com"]="http://test" -ALIASES["test.com"]="www.test.com" -# no NGXCONF means Nginx configuration will be regenerated each time the container starts -# the advantage of this is you automatically get new features / bug fixes diff --git a/ssl-conf-schema.json b/ssl-conf-schema.json index 607b40f..f740f46 100644 --- a/ssl-conf-schema.json +++ b/ssl-conf-schema.json @@ -1,6 +1,7 @@ { "$id": "https://raw.githubusercontent.com/bfren/docker-nginx-proxy/main/ssl-conf-schema.json", "$schema": "https://json-schema.org/draft-07/schema", + "description": "Docker Nginx Proxy Configuration Settings", "type": "object", "required": [ "domains" ], "additionalProperties": false, @@ -17,19 +18,23 @@ "additionalProperties": false, "properties" : { "primary": { - "type": "string" + "type": "string", + "description": "Primary domain name, e.g. 'www.example.com'." }, "upstream": { - "type": "string" + "type": "string", + "description": "Upstream server being proxied (include port), e.g. 'http://up:5000'." }, "aliases": { "type": "array", + "description": "Aliases of the primary domain, e.g. 'example.com'.", "items": { "type": "string" } }, "custom": { - "type": "boolean" + "type": "boolean", + "description": "Whether or not to use custom Nginx configuration - if true, once generated the file will be ignored so changes here will have no effect." } } }