├── .env.sample ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── README.md └── workflows │ └── testing.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── bin ├── .env ├── fix-git-submodule.sh ├── fresh-start.sh ├── install.sh ├── localscript │ ├── bootstrap.sh │ ├── check-docker-nginx-proxy-automation-env-file.sh │ ├── check-local-env-file.sh │ ├── update-docker-compose-file.sh │ ├── update-env-new-site-variables.sh │ └── usage-fresh-start.sh ├── revert.sh ├── ssl_test.sh ├── stop.sh ├── test.sh ├── update-branch-name.sh ├── update-checksum.sh └── update-nginx-template.sh ├── conf.d ├── realip.conf ├── servertokens.conf └── uploadsize.conf ├── docker-compose.yml ├── docs ├── HOWTO-Synology.md ├── HOWTO-server-at-home.md ├── README.md ├── cloudflare.md ├── requirements.md └── upgrade-guide.md └── nginx.tmpl /.env.sample: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # https://github.com/evertramos/nginx-proxy-automation 4 | # 5 | # NGINX Proxy automation 6 | # 7 | # This is the .env file to set up nginx-proxy in your environment 8 | # 9 | #----------------------------------------------------------------------- 10 | 11 | #----------------------------------------------------------------------- 12 | # 13 | # Script requirements 14 | # 15 | 16 | # PID file the running script 17 | PID_FILE=.fresh_start.pid 18 | 19 | # Allow run commands with sudo if needed 20 | ALLOW_RUN_WITH_SUDO=false 21 | 22 | #----------------------------------------------------------------------- 23 | # 24 | # NGINX-Proxy containers/service 25 | # 26 | # The variables below is used to set the containers name for the nginx-proxy 27 | # and the image version for each service, please note that if you use our script 28 | # we will replace the service name in docker-compose file with the container name 29 | # 30 | NGINX_WEB_SEVICE_NAME=proxy-web 31 | NGINX_IMAGE_VERSION=stable-alpine 32 | 33 | DOCKER_GEN_SEVICE_NAME=docker-gen 34 | DOCKER_GEN_IMAGE_VERSION=latest 35 | 36 | LETS_ENCRYPT_SEVICE_NAME=acme-companion 37 | NGINX_PROXY_COMPANION_IMAGE_VERSION=latest 38 | 39 | #----------------------------------------------------------------------- 40 | # 41 | # IP address of the external interface 42 | # 43 | # The IP address below is used to bind your local services to the internet 44 | # please make sure you use the correct address otherwise your proxy will not 45 | # work properly, '0.0.0.0' will work, but we recommend to update this variable 46 | # 47 | IPv4=0.0.0.0 48 | IPv6=::0 49 | 50 | #----------------------------------------------------------------------- 51 | # 52 | # Default network name 53 | # 54 | # The network name set below is used by the proxy to forward internet requests 55 | # to the correct containers in your environment, so please make sure to add this 56 | # network in all docker containers, otherwise it will break the proxy redirection 57 | # 58 | NETWORK=proxy 59 | 60 | #----------------------------------------------------------------------- 61 | # 62 | # Data path for the nginx-proxy files 63 | # 64 | # The variable below will be used to place all files used by the nginx-proxy 65 | # please consider including this folder to your backup services, once all config 66 | # files, settings and certificates will be placed here in case you need to recover 67 | # 68 | NGINX_FILES_PATH=./data 69 | 70 | #----------------------------------------------------------------------- 71 | # 72 | # Docker logging settings 73 | # 74 | # Logs! Very important, right? But if you do not clean it up, it might causes you 75 | # issues on disk space over time, so keep in mind to set this log options making sure 76 | # you will have the least to audit, any further information on that please check the docs 77 | # 78 | # https://docs.docker.com/config/containers/logging/configure/ 79 | # 80 | NGINX_WEB_LOG_DRIVER=json-file 81 | NGINX_WEB_LOG_MAX_SIZE=4m 82 | NGINX_WEB_LOG_MAX_FILE=10 83 | 84 | NGINX_GEN_LOG_DRIVER=json-file 85 | NGINX_GEN_LOG_MAX_SIZE=2m 86 | NGINX_GEN_LOG_MAX_FILE=10 87 | 88 | NGINX_LETSENCRYPT_LOG_DRIVER=json-file 89 | NGINX_LETSENCRYPT_LOG_MAX_SIZE=2m 90 | NGINX_LETSENCRYPT_LOG_MAX_FILE=10 91 | 92 | #----------------------------------------------------------------------- 93 | # 94 | # Docker ports that should be binded by the proxy 95 | # 96 | # This option were added by a contributor long ago, so might be a very specific case 97 | # where you might need to change http and https port number, keep in mind that changes 98 | # on that setting might will break the auto renewing Let's Encrypt certificate services 99 | # 100 | DOCKER_HTTP_=80 101 | DOCKER_HTTPS=443 102 | 103 | #----------------------------------------------------------------------- 104 | # 105 | # SSL policy (defaults to Mozilla-Intermediate) 106 | # 107 | # This also was added by a contributor which sets the default cipher configuration 108 | # to the nginx-proxy container, which has the 'Mozilla-Intermediate' as default value 109 | # plase make sure you take a good look at options in the url below before messing around 110 | # 111 | # https://github.com/nginx-proxy/nginx-proxy#how-ssl-support-works 112 | # 113 | #SSL_POLICY=Mozilla-Modern 114 | 115 | #----------------------------------------------------------------------- 116 | # 117 | # Let's Encrypt default email 118 | # 119 | # You might want to inform a default email to Let's Encrypt certificate once it is 120 | # a required parameter in order to issue the new certificate. This information will be 121 | # replaced by the LETSENCRYPT_EMAIL environment varibale present in your docker container 122 | # 123 | DEFAULT_EMAIL=mail@yourdomain.tld 124 | 125 | #----------------------------------------------------------------------- 126 | # 127 | # Default host 128 | # 129 | # Nginx-proxy will then redirect all requests to a container where you have set 130 | # "VIRTUAL HOST" set to "DEFAULT HOST", if they don't match any (other) container 131 | # You might want to check the link below for more information: 132 | # https://github.com/nginx-proxy/nginx-proxy#default-host 133 | # 134 | DEFAULT_HOST= 135 | 136 | #----------------------------------------------------------------------- 137 | # 138 | # Docker Rootless 139 | # 140 | # In case you want to use this proxy on Docker Rootless (DR) and you also have followed 141 | # the DR installation from the official documentation (https://docs.docker.com/engine/security/rootless/) 142 | # Set the following value of the DOCKER_HOST variable that you got in the final info messages after executing 143 | # the "$ dockerd-rootless-setuptool.sh install" command. 144 | # For example DOCKER_HOST_PATH=$XDG_RUNTIME_DIR/docker.sock 145 | # If you are not using Docker Rootless, leave this variable blank 146 | DOCKER_HOST_ROOTLESS_PATH= 147 | 148 | #----------------------------------------------------------------------- 149 | # 150 | # Cloudflare API Token 151 | # 152 | # Despite nginx-proxy suggest the usage of global API keys, 153 | # I rather use a more restrict API token which you can follow 154 | # the steps to create it with Zone DNS restriction as documented. 155 | # 156 | # https://github.com/evertramos/nginx-proxy-automation/blob/main/docs/cloudflare.md 157 | # 158 | CLOUDFLARE_DNS_TOKEN= 159 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at evert.ramos@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributions 2 | 3 | ### NGINX template file (nginx.tmpl) 4 | 5 | All contributions regarding the `nginx.tmpl` should be suggested or implemented in the [nginx-proxy repository](https://github.com/nginx-proxy/nginx-proxy). 6 | 7 | We always use the latest version of this file: 8 | 9 | [https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl](https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl) 10 | 11 | ### Pull requests 12 | 13 | Sometimes it's better to start a discussion or an issue to find out the best solution of suggestion before sending a pull request... and if you do so, please test it with the automation script before sending new code. 14 | 15 | 16 | Thanks! 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: evertramos 5 | open_collective: # nginx-proxy-automation 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: '' 6 | assignees: evertramos 7 | 8 | --- 9 | 10 | **Check [Discussions](https://github.com/evertramos/nginx-proxy-automation/discussions) to see if there is an answer might help you before opening an issue** 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Run the script.... 18 | 2. ... 19 | 20 | **Server info (please complete the following information):** 21 | - Linux release: 22 | - Server type: 23 | - Docker version: 24 | - docker-compose version: 25 | 26 | **Logs:** 27 | - basescript.log (send only last execution log with an error) - This log is in ./bin folder 28 | - nginx container logs 29 | - letsencrypt/acme container (if related to ssl) 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: evertramos 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | 2 | # NGINX Proxy Automation 🔥 3 | 4 |

5 | 6 | 7 | 8 |

9 |

10 | 11 |

12 | 13 |

14 | 15 |

16 | 17 | ## How to start 🔰 18 | [![shell script](https://img.shields.io/badge/Shell_Script-121011?style=for-the-badge&logo=gnu-bash&logoColor=white)](https://github.com/evertramos) 19 | 20 | 21 | 1. Clone this repository using the option **_--recurse-submodules_** ⚠️ 22 | 23 | ```bash 24 | git clone --recurse-submodules https://github.com/evertramos/nginx-proxy-automation.git proxy 25 | ``` 26 | 27 | We use submodule for [basescript](https://github.com/evertramos/basescript) 28 | 29 | 2. 🚀 Run the script 'fresh_start.sh' from the _./proxy/bin_ folder 30 | 31 | ```bash 32 | cd proxy/bin && ./fresh-start.sh --yes --skip-docker-image-check -e your_email@domain 33 | ``` 34 | 35 | Update the email above with your real e-mail address 36 | 37 | 3. 🧪 Test the proxy 38 | 39 | ```bash 40 | docker run -dit -e VIRTUAL_HOST=your.domain.com --network=proxy --name test-web httpd:alpine 41 | ``` 42 | or simply run: 43 | ```bash 44 | ./test.sh your.domain.com 45 | ``` 46 | 47 | Use your own domain name when testing this proxy and make sure your DNS is correctly configured. 48 | 49 | ## Video Tutorial 🎥 50 | 51 | I made a tutorial video to walk you through this project: 52 | 53 | [![youtube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UCN5wb0eA3ZLlvJNYo23qBRQ) 54 | 55 | ### AWS EC2 56 |

57 | 58 |

59 | 60 | ### Digital Ocean Droplet 61 |

62 | 63 |

64 | 65 | ### OVH 66 |

67 | 68 |

69 | 70 | ## Server Automation 🚀 71 | 72 | Make user you try our [Server Automation](https://github.com/evertramos/server-automation) 73 | 74 | [https://github.com/evertramos/server-automation](https://github.com/evertramos/server-automation) 75 | 76 | ## Further information 📓 77 | 78 | For more installation details please [click here](/docs/). 79 | 80 | ## Supporting ♥️ 81 | [![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)](https://www.patreon.com/evertramos) 82 | [![image](https://img.shields.io/badge/picpay-21C25E?style=for-the-badge&logo=picpay&logoColor=white)](https://picpay.me/evert.ramos) 83 | 84 | [List of all supporters](https://github.com/evertramos/evertramos/blob/main/pages/supporters.md). 85 | 86 | ## Code Contributors 87 | 88 | [](https://opencollective.com/nginx-proxy-automation) 89 | -------------------------------------------------------------------------------- /.github/workflows/testing.yml: -------------------------------------------------------------------------------- 1 | name: Testing Proxy Automation 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: true 19 | 20 | #- name: Testing if has docker 21 | # run: docker ps -q -a 22 | 23 | # Runs a set of commands using the runners shell 24 | - name: Run a multi-line script 25 | run: | 26 | cd ./bin 27 | ./fresh-start.sh --yes -e evert.ramos@gmail.com --skip-docker-image-check 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data 2 | .env* 3 | !.env.sample 4 | .DS_Store 5 | .idea/ 6 | /bin/basescript.log 7 | /docker-compose.yml.* 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "basescript"] 2 | path = basescript 3 | url = https://github.com/evertramos/basescript.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Evert Ramos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/.env: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # https://github.com/evertramos/nginx-proxy-automation 4 | # 5 | # NGINX Proxy automation 6 | # 7 | # This is the .env file with default values for the nginx-proxy-automation script 8 | # 9 | #----------------------------------------------------------------------- 10 | 11 | #----------------------------------------------------------------------- 12 | # 13 | # NGINX-Proxy default image, version and service name 14 | # 15 | DEFAULT_NGINX_PROXY_SERVICE_NAME=proxy-web 16 | DEFAULT_NGINX_PROXY_IMAGE_NAME="nginx" 17 | DEFAULT_NGINX_PROXY_IMAGE_VERSION="stable-alpine" 18 | 19 | #----------------------------------------------------------------------- 20 | # 21 | # Docker-gen default image, version and service name 22 | # 23 | DEFAULT_DOCKER_GEN_SERVICE_NAME=docker-gen 24 | DEFAULT_DOCKER_GEN_IMAGE_NAME="nginxproxy/docker-gen" 25 | DEFAULT_DOCKER_GEN_IMAGE_VERSION="0.14" 26 | 27 | #----------------------------------------------------------------------- 28 | # 29 | # Letsencrypt acme-compantion default image, version and service name 30 | # 31 | DEFAULT_LETSENCRYPT_SERVICE_NAME=acme-companion 32 | DEFAULT_LETSENCRYPT_IMAGE_NAME="nginxproxy/acme-companion" 33 | DEFAULT_LETSENCRYPT_IMAGE_VERSION="2.5" 34 | 35 | #----------------------------------------------------------------------- 36 | # 37 | # Network default name for the nginx-proxy 38 | # 39 | DEFAULT_DOCKER_NETWORK_NAME=proxy 40 | 41 | #----------------------------------------------------------------------- 42 | # 43 | # Data path for the nginx-proxy files 44 | # 45 | #DEFAULT_DATA_LOCATION="./data" 46 | 47 | #----------------------------------------------------------------------- 48 | # 49 | # Default servies name in docker-compose.yml 50 | # 51 | REPLACE_NGINX_PROXY_SERVICE_NAME="nginx-proxy-automation-web" 52 | REPLACE_DOCKER_GEN_SERVICE_NAME="nginx-proxy-automation-gen" 53 | REPLACE_LETSENCRYPT_SERVICE_NAME="nginx-proxy-automation-letsencrypt" 54 | 55 | #----------------------------------------------------------------------- 56 | # 57 | # md5 checksum for .env and docker-compose.yml files 58 | # 59 | MD5_SUM_DOCKER_COMPOSE=54590c26c4f3d0ce52ef9ea4268d1408 60 | MD5_SUM_ENV_SAMPLE=eb0ca95b7f2d14d11e337863d8e47566 61 | -------------------------------------------------------------------------------- /bin/fix-git-submodule.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This script updates the branch name to 'main' 5 | # 6 | # Source: https://github.com/evertramos/nginx-proxy-automation 7 | # 8 | 9 | # Get the script name and its real file path 10 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 11 | SCRIPT_NAME="${0##*/}" 12 | CURRENT_PATH=$(pwd) 13 | 14 | cd "${SCRIPT_PATH}/../basescript" 15 | 16 | # Set submodules 17 | git submodule init 18 | git submodule update 19 | 20 | echo "Submodule is set" 21 | 22 | exit 0 23 | 24 | -------------------------------------------------------------------------------- /bin/fresh-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #----------------------------------------------------------------------- 4 | # 5 | # Fresh Start script - set up nginx-proxy in a fresh installed server 6 | # 7 | # https://github.com/evertramos/nginx-proxy-automation 8 | # 9 | # Script developed by 10 | # Evert Ramos 11 | # 12 | # Copyright Evert Ramos 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # Bash settings (do not mess with it) 17 | shopt -s nullglob globstar 18 | 19 | # Get the script name and its file real path 20 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 21 | SCRIPT_NAME="${0##*/}" 22 | 23 | # Source basescript functions 24 | source $SCRIPT_PATH"/../basescript/bootstrap.sh" 25 | 26 | # Source localscripts 27 | source $SCRIPT_PATH"/localscript/bootstrap.sh" 28 | 29 | # Log 30 | printf "${energy} Start execution '${SCRIPT_PATH}/${SCRIPT_NAME} " 31 | log "Start execution" 32 | log "$@" 33 | 34 | #----------------------------------------------------------------------- 35 | # Process arguments 36 | #----------------------------------------------------------------------- 37 | while [[ $# -gt 0 ]]; do 38 | case "$1" in 39 | -d) 40 | ARG_DATA_LOCATION="${2}" 41 | if [[ $ARG_DATA_LOCATION == "" ]]; then 42 | echoerror "Invalid option for -d" 43 | break 44 | fi 45 | shift 2 46 | ;; 47 | --data-files-location=*) 48 | ARG_DATA_LOCATION="${1#*=}" 49 | if [[ $ARG_DATA_LOCATION == "" ]]; then 50 | echoerror "Invalid option for --data-files-location=''" 51 | break 52 | fi 53 | shift 1 54 | ;; 55 | -e) 56 | ARG_DEFAULT_EMAIL="${2}" 57 | if [[ $ARG_DEFAULT_EMAIL == "" ]]; then 58 | echoerror "Invalid option for -e" 59 | break 60 | fi 61 | shift 2 62 | ;; 63 | --default-email=*) 64 | ARG_DEFAULT_EMAIL="${1#*=}" 65 | if [[ $ARG_DEFAULT_EMAIL == "" ]]; then 66 | echoerror "Invalid option for --default-email=''" 67 | break 68 | fi 69 | shift 1 70 | ;; 71 | -pn) 72 | ARG_NGINX_PROXY_SERVICE_NAME="${2}" 73 | if [[ $ARG_NGINX_PROXY_SERVICE_NAME == "" ]]; then 74 | echoerror "Invalid option for -pn" 75 | break 76 | fi 77 | shift 2 78 | ;; 79 | --proxy-name=*) 80 | ARG_NGINX_PROXY_SERVICE_NAME="${1#*=}" 81 | if [[ $ARG_NGINX_PROXY_SERVICE_NAME == "" ]]; then 82 | echoerror "Invalid option for --proxy-name=''" 83 | break 84 | fi 85 | shift 1 86 | ;; 87 | -ln) 88 | ARG_LETSENCRYPT_SERVICE_NAME="${2}" 89 | if [[ $ARG_LETSENCRYPT_SERVICE_NAME == "" ]]; then 90 | echoerror "Invalid option for -ln" 91 | break 92 | fi 93 | shift 2 94 | ;; 95 | --letsencrypt-name=*) 96 | ARG_LETSENCRYPT_SERVICE_NAME="${1#*=}" 97 | if [[ $ARG_LETSENCRYPT_SERVICE_NAME == "" ]]; then 98 | echoerror "Invalid option for --letsencrypt-name=''" 99 | break 100 | fi 101 | shift 1 102 | ;; 103 | -gn) 104 | ARG_DOCKER_GEN_SERVICE_NAME="${2}" 105 | if [[ $ARG_DOCKER_GEN_SERVICE_NAME == "" ]]; then 106 | echoerror "Invalid option for -gn" 107 | break 108 | fi 109 | shift 2 110 | ;; 111 | --docker-gen-name=*) 112 | ARG_DOCKER_GEN_SERVICE_NAME="${1#*=}" 113 | if [[ $ARG_DOCKER_GEN_SERVICE_NAME == "" ]]; then 114 | echoerror "Invalid option for --docker-gen-name=''" 115 | break 116 | fi 117 | shift 1 118 | ;; 119 | -piv) 120 | ARG_NGINX_PROXY_IMAGE_VERSION="${2}" 121 | if [[ $ARG_NGINX_PROXY_IMAGE_VERSION == "" ]]; then 122 | echoerror "Invalid option for -pversion" 123 | break 124 | fi 125 | shift 2 126 | ;; 127 | --proxy-image-version=*) 128 | ARG_NGINX_PROXY_IMAGE_VERSION="${1#*=}" 129 | if [[ $ARG_NGINX_PROXY_IMAGE_VERSION == "" ]]; then 130 | echoerror "Invalid option for --proxy-image-version=''" 131 | break 132 | fi 133 | shift 1 134 | ;; 135 | -liv) 136 | ARG_LETSENCRYPT_IMAGE_VERSION="${2}" 137 | if [[ $ARG_LETSENCRYPT_IMAGE_VERSION == "" ]]; then 138 | echoerror "Invalid option for -liv" 139 | break 140 | fi 141 | shift 2 142 | ;; 143 | --letsencrypt-image-version=*) 144 | ARG_LETSENCRYPT_IMAGE_VERSION="${1#*=}" 145 | if [[ $ARG_LETSENCRYPT_IMAGE_VERSION == "" ]]; then 146 | echoerror "Invalid option for --letsencrypt-image-version=''" 147 | break 148 | fi 149 | shift 1 150 | ;; 151 | -giv) 152 | ARG_DOCKER_GEN_IMAGE_VERSION="${2}" 153 | if [[ $ARG_DOCKER_GEN_IMAGE_VERSION == "" ]]; then 154 | echoerror "Invalid option for -giv" 155 | break 156 | fi 157 | shift 2 158 | ;; 159 | --docker-gen-image-version=*) 160 | ARG_DOCKER_GEN_IMAGE_VERSION="${1#*=}" 161 | if [[ $ARG_DOCKER_GEN_IMAGE_VERSION == "" ]]; then 162 | echoerror "Invalid option for --docker-gen-image-version=''" 163 | break 164 | fi 165 | shift 1 166 | ;; 167 | 168 | # Network options 169 | -ip) 170 | ARG_IP_ADDRESS="${2}" 171 | if [[ $ARG_IP_ADDRESS == "" ]]; then 172 | echoerror "Invalid option for -ip" 173 | break 174 | fi 175 | shift 2 176 | ;; 177 | --ip-address=*) 178 | ARG_IP_ADDRESS="${1#*=}" 179 | if [[ $ARG_IP_ADDRESS == "" ]]; then 180 | echoerror "Invalid option for --ip-address" 181 | break 182 | fi 183 | shift 1 184 | ;; 185 | -ipv6) 186 | ARG_IPv6_ADDRESS="${2}" 187 | if [[ $ARG_IPv6_ADDRESS == "" ]]; then 188 | echoerror "Invalid option for -ipv6" 189 | break 190 | fi 191 | shift 2 192 | ;; 193 | --ipv6-address=*) 194 | ARG_IPv6_ADDRESS="${1#*=}" 195 | if [[ $ARG_IPv6_ADDRESS == "" ]]; then 196 | echoerror "Invalid option for --ipv6-address" 197 | break 198 | fi 199 | shift 1 200 | ;; 201 | -net) 202 | ARG_NETWORK_NAME="${2}" 203 | if [[ $ARG_NETWORK_NAME == "" ]]; then 204 | echoerror "Invalid option for -net" 205 | break 206 | fi 207 | shift 2 208 | ;; 209 | --network-name=*) 210 | ARG_NETWORK_NAME="${1#*=}" 211 | if [[ $ARG_NETWORK_NAME == "" ]]; then 212 | echoerror "Invalid option for --network-name" 213 | break 214 | fi 215 | shift 1 216 | ;; 217 | -netopt) 218 | NETWORK_OPTION="${2}" 219 | if [[ $NETWORK_OPTION == "" ]]; then 220 | echoerror "Invalid option for -netopt" 221 | break 222 | fi 223 | shift 2 224 | ;; 225 | --network-option=*) 226 | NETWORK_OPTION="${1#*=}" 227 | if [[ $NETWORK_OPTION == "" ]]; then 228 | echoerror "Invalid option for --network-option" 229 | break 230 | fi 231 | shift 1 232 | ;; 233 | 234 | # Log settings 235 | -lpd) 236 | ARG_NGINX_PROXY_LOG_DRIVER="${2}" 237 | if [[ $ARG_NGINX_PROXY_LOG_DRIVER == "" ]]; then 238 | echoerror "Invalid option for -lpd" 239 | break 240 | fi 241 | shift 2 242 | ;; 243 | --log-nginx-proxy-driver=*) 244 | ARG_NGINX_PROXY_LOG_DRIVER="${1#*=}" 245 | if [[ $ARG_NGINX_PROXY_LOG_DRIVER == "" ]]; then 246 | echoerror "Invalid option for --log-nginx-proxy-driver" 247 | break 248 | fi 249 | shift 1 250 | ;; 251 | -lpms) 252 | ARG_NGINX_PROXY_LOG_MAX_SIZE="${2}" 253 | if [[ $ARG_NGINX_PROXY_LOG_MAX_SIZE == "" ]]; then 254 | echoerror "Invalid option for -lpms" 255 | break 256 | fi 257 | shift 2 258 | ;; 259 | --log-nginx-proxy-max_size=*) 260 | ARG_NGINX_PROXY_LOG_MAX_SIZE="${1#*=}" 261 | if [[ $ARG_NGINX_PROXY_LOG_MAX_SIZE == "" ]]; then 262 | echoerror "Invalid option for --log-nginx-proxy-max_size" 263 | break 264 | fi 265 | shift 1 266 | ;; 267 | -lpmf) 268 | ARG_NGINX_PROXY_LOG_MAX_FILE="${2}" 269 | if [[ $ARG_NGINX_PROXY_LOG_MAX_FILE == "" ]]; then 270 | echoerror "Invalid option for -lpmf" 271 | break 272 | fi 273 | shift 2 274 | ;; 275 | --log-nginx-proxy-max_file=*) 276 | ARG_NGINX_PROXY_LOG_MAX_FILE="${1#*=}" 277 | if [[ $ARG_NGINX_PROXY_LOG_MAX_FILE == "" ]]; then 278 | echoerror "Invalid option for --log-nginx-proxy-max_file" 279 | break 280 | fi 281 | shift 1 282 | ;; 283 | -lgd) 284 | ARG_DOCKER_GEN_LOG_DRIVER="${2}" 285 | if [[ $ARG_DOCKER_GEN_LOG_DRIVER == "" ]]; then 286 | echoerror "Invalid option for -lgd" 287 | break 288 | fi 289 | shift 2 290 | ;; 291 | --log-docker-gen-driver=*) 292 | ARG_DOCKER_GEN_LOG_DRIVER="${1#*=}" 293 | if [[ $ARG_DOCKER_GEN_LOG_DRIVER == "" ]]; then 294 | echoerror "Invalid option for --log-docker-gen-driver" 295 | break 296 | fi 297 | shift 1 298 | ;; 299 | -lgms) 300 | ARG_DOCKER_GEN_LOG_MAX_SIZE="${2}" 301 | if [[ $ARG_DOCKER_GEN_LOG_MAX_SIZE == "" ]]; then 302 | echoerror "Invalid option for -lgms" 303 | break 304 | fi 305 | shift 2 306 | ;; 307 | --log-docker-gen-max_size=*) 308 | ARG_DOCKER_GEN_LOG_MAX_SIZE="${1#*=}" 309 | if [[ $ARG_DOCKER_GEN_LOG_MAX_SIZE == "" ]]; then 310 | echoerror "Invalid option for --log-docker-gen-max_size" 311 | break 312 | fi 313 | shift 1 314 | ;; 315 | -lgmf) 316 | ARG_DOCKER_GEN_LOG_MAX_FILE="${2}" 317 | if [[ $ARG_DOCKER_GEN_LOG_MAX_FILE == "" ]]; then 318 | echoerror "Invalid option for -lgmf" 319 | break 320 | fi 321 | shift 2 322 | ;; 323 | --log-docker-gen-max_file=*) 324 | ARG_DOCKER_GEN_LOG_MAX_FILE="${1#*=}" 325 | if [[ $ARG_DOCKER_GEN_LOG_MAX_FILE == "" ]]; then 326 | echoerror "Invalid option for --log-docker-gen-max_file" 327 | break 328 | fi 329 | shift 1 330 | ;; 331 | -lld) 332 | ARG_LETSENCRYPT_LOG_DRIVER="${2}" 333 | if [[ $ARG_LETSENCRYPT_LOG_DRIVER == "" ]]; then 334 | echoerror "Invalid option for -lld" 335 | break 336 | fi 337 | shift 2 338 | ;; 339 | --log-letsencrypt-driver=*) 340 | ARG_LETSENCRYPT_LOG_DRIVER="${1#*=}" 341 | if [[ $ARG_LETSENCRYPT_LOG_DRIVER == "" ]]; then 342 | echoerror "Invalid option for --log-letsencrypt-driver" 343 | break 344 | fi 345 | shift 1 346 | ;; 347 | -llms) 348 | ARG_LETSENCRYPT_LOG_MAX_SIZE="${2}" 349 | if [[ $ARG_LETSENCRYPT_LOG_MAX_SIZE == "" ]]; then 350 | echoerror "Invalid option for -llms" 351 | break 352 | fi 353 | shift 2 354 | ;; 355 | --log-letsencrypt-max_size=*) 356 | ARG_LETSENCRYPT_LOG_MAX_SIZE="${1#*=}" 357 | if [[ $ARG_LETSENCRYPT_LOG_MAX_SIZE == "" ]]; then 358 | echoerror "Invalid option for --log-letsencrypt-max_size" 359 | break 360 | fi 361 | shift 1 362 | ;; 363 | -llmf) 364 | ARG_LETSENCRYPT_LOG_MAX_FILE="${2}" 365 | if [[ $ARG_LETSENCRYPT_LOG_MAX_FILE == "" ]]; then 366 | echoerror "Invalid option for -llmf" 367 | break 368 | fi 369 | shift 2 370 | ;; 371 | --log-letsencrypt-max_file=*) 372 | ARG_LETSENCRYPT_LOG_MAX_FILE="${1#*=}" 373 | if [[ $ARG_LETSENCRYPT_LOG_MAX_FILE == "" ]]; then 374 | echoerror "Invalid option for --log-letsencrypt-max_file" 375 | break 376 | fi 377 | shift 1 378 | ;; 379 | 380 | # Port binginds 381 | -phttp) 382 | ARG_DOCKER_HTTP="${2}" 383 | if [[ $ARG_DOCKER_HTTP == "" ]]; then 384 | echoerror "Invalid option for -phttp" 385 | break 386 | fi 387 | shift 2 388 | ;; 389 | --port-http=*) 390 | ARG_DOCKER_HTTP="${1#*=}" 391 | if [[ $ARG_DOCKER_HTTP == "" ]]; then 392 | echoerror "Invalid option for --port-http" 393 | break 394 | fi 395 | shift 1 396 | ;; 397 | -phttps) 398 | ARG_DOCKER_HTTPS="${2}" 399 | if [[ $ARG_DOCKER_HTTPS == "" ]]; then 400 | echoerror "Invalid option for -phttps" 401 | break 402 | fi 403 | shift 2 404 | ;; 405 | --port-https=*) 406 | ARG_DOCKER_HTTPS="${1#*=}" 407 | if [[ $ARG_DOCKER_HTTPS == "" ]]; then 408 | echoerror "Invalid option for --port-https" 409 | break 410 | fi 411 | shift 1 412 | ;; 413 | 414 | # SSL Policy 415 | -sp) 416 | ARG_SSL_POLICY="${2}" 417 | if [[ $ARG_SSL_POLICY == "" ]]; then 418 | echoerror "Invalid option for -sp" 419 | break 420 | fi 421 | shift 2 422 | ;; 423 | --ssl-policy=*) 424 | ARG_SSL_POLICY="${1#*=}" 425 | if [[ $ARG_SSL_POLICY == "" ]]; then 426 | echoerror "Invalid option for --ssl-policy" 427 | break 428 | fi 429 | shift 1 430 | ;; 431 | 432 | # Docker rootless support 433 | -dr) 434 | USE_DOCKER_ROOTLESS=true 435 | shift 1 436 | ;; 437 | --docker-rootless) 438 | USE_DOCKER_ROOTLESS=true 439 | shift 1 440 | ;; 441 | 442 | # IPv4 options 443 | --ipv4-subnet=*) 444 | ARG_IPv4_SUBNET="${1#*=}" 445 | if [[ $ARG_IPv4_SUBNET == "" ]]; then 446 | echoerror "Invalid option for --ipv4-subnet" 447 | break 448 | fi 449 | shift 1 450 | ;; 451 | # IPv6 options 452 | --ipv6-subnet=*) 453 | ARG_IPv6_SUBNET="${1#*=}" 454 | if [[ $ARG_IPv6_SUBNET == "" ]]; then 455 | echoerror "Invalid option for --ipv6-subnet" 456 | break 457 | fi 458 | shift 1 459 | ;; 460 | --activate-ipv6) 461 | ACTIVATE_IPV6=true 462 | shift 1 463 | ;; 464 | 465 | # Default host 466 | -dh) 467 | ARG_DEFAULT_HOST="${2}" 468 | if [[ $ARG_DEFAULT_HOST == "" ]]; then 469 | echoerror "Invalid option for -dh" 470 | break 471 | fi 472 | shift 2 473 | ;; 474 | --default-host=*) 475 | ARG_DEFAULT_HOST="${1#*=}" 476 | if [[ $ARG_DEFAULT_HOST == "" ]]; then 477 | echoerror "Invalid option for --default-host" 478 | break 479 | fi 480 | shift 1 481 | ;; 482 | 483 | # Other options 484 | --update-nginx-template) 485 | UPDATE_NGINX_TEMPLATE=true 486 | shift 1 487 | ;; 488 | --skip-docker-image-check) 489 | SKIP_DOCKER_IMAGE_CHECK=true 490 | shift 1 491 | ;; 492 | --use-nginx-conf-files) 493 | USE_NGINX_CONF_FILES=true 494 | shift 1 495 | ;; 496 | --yes) 497 | REPLY_YES=true 498 | shift 1 499 | ;; 500 | --debug) 501 | DEBUG=true 502 | shift 1 503 | ;; 504 | --silent) 505 | SILENT=true 506 | shift 1 507 | ;; 508 | -h | --help) 509 | usage 510 | exit 0 511 | ;; 512 | *) 513 | echoerror "Unknown argument: $1" false 514 | usage 515 | exit 0 516 | ;; 517 | esac 518 | done 519 | 520 | #----------------------------------------------------------------------- 521 | # Initial check - DO NOT CHANGE SETTINGS BELOW 522 | #----------------------------------------------------------------------- 523 | 524 | # Check if there is an .env file in local folder 525 | run_function check_local_env_file 526 | 527 | # Specific PID File if needs to run multiple scripts 528 | NEW_PID_FILE=${PID_FILE_FRESH_INSTALL:-".fresh_start.pid"} 529 | 530 | # Run initial check function 531 | run_function starts_initial_check $NEW_PID_FILE 532 | 533 | # Save PID 534 | system_save_pid $NEW_PID_FILE 535 | 536 | # DO NOT CHANGE ANY OPTIONS ABOVE THIS LINE! 537 | 538 | #----------------------------------------------------------------------- 539 | # [function] Undo script actions 540 | #----------------------------------------------------------------------- 541 | local_undo_restore() { 542 | local LOCAL_KEEP_RESTORE_FILES 543 | 544 | LOCAL_KEEP_RESTORE_FILES=${1:-$KEEP_RESTORE_FILES} 545 | 546 | echoerror \ 547 | "It seems something went wrong! \ 548 | \nRunning '${FUNCNAME[0]} to try to UNDO all actions done by this script. \ 549 | \nPlease make sure everything was put it back in place." false 550 | 551 | # If docker network was created 552 | if [[ "$ACTION_DOCKER_NETWORK_CREATED" == true ]]; then 553 | [[ "$SILENT" != true ]] && echowarning "[undo] Deleting created docker network '$DOCKER_NETWORK_NAME'." 554 | run_function docker_network_remove $DOCKER_NETWORK_NAME 555 | ACTION_DOCKER_NETWORK_CREATED=false 556 | fi 557 | 558 | # If docker-compose file was renamed (backup) 559 | if [[ "$ACTION_DOCKER_COMPOSE_FILE_RENAMED" == true ]]; then 560 | [[ "$SILENT" != true ]] && echowarning "[undo] Renaming docker-compose.yml file '$LOCAL_BACKUP_DOCKER_COMPOSE_FILE'." 561 | mv $LOCAL_BACKUP_DOCKER_COMPOSE_FILE "$SCRIPT_PATH/../docker-compose.yml" 562 | ACTION_DOCKER_COMPOSE_FILE_RENAMED=false 563 | fi 564 | 565 | # If .env file was renamed (backup) 566 | if [[ "$ACTION_ENV_FILE_RENAMED" == true ]]; then 567 | [[ "$SILENT" != true ]] && echowarning "[undo] Renaming .env file '$LOCAL_BACKUP_ENV_FILE'." 568 | mv $LOCAL_BACKUP_ENV_FILE "$SCRIPT_PATH/../.env" 569 | ACTION_ENV_FILE_RENAMED=false 570 | fi 571 | 572 | # If docker-compose file was renamed (backup) 573 | if [[ "$ACTION_DOCKER_COMPOSE_FILE_RENAMED" == true ]]; then 574 | [[ "$SILENT" != true ]] && echowarning "[undo] Renaming docker-compose file '$LOCAL_BACKUP_DOCKER_COMPOSE_FILE'." 575 | mv $LOCAL_BACKUP_DOCKER_COMPOSE_FILE "$SCRIPT_PATH/../docker-compose.yml" 576 | ACTION_DOCKER_COMPOSE_FILE_RENAMED=false 577 | fi 578 | 579 | # If the service was stopped try to restart it 580 | if [[ "$ACTION_DOCKER_COMPOSE_STOPPED" == true ]]; then 581 | [[ "$SILENT" != true ]] && echowarning "[undo] Stopping docker-compose service '$SCRIPT_PATH/../'." 582 | run_function docker_compose_start "$SCRIPT_PATH/../" 583 | ACTION_DOCKER_COMPOSE_STOPPED=false 584 | fi 585 | 586 | exit 0 587 | } 588 | 589 | #----------------------------------------------------------------------- 590 | # [function] Docker images and version check 591 | #----------------------------------------------------------------------- 592 | local_check_docker_hub_image_version() { 593 | local LOCAL_DOCKER_IMAGE_NAME LOCAL_DOCKER_IMAGE_VERSION 594 | 595 | LOCAL_DOCKER_IMAGE_NAME=${1:-null} 596 | LOCAL_DOCKER_IMAGE_VERSION=${2:-null} 597 | 598 | # Check image exists 599 | run_function dockerhub_check_image_exists $LOCAL_DOCKER_IMAGE_NAME 600 | 601 | if [[ "$DOCKERHUB_IMAGE_EXISTS" != true ]]; then 602 | echoerror "It seems the image '$LOCAL_DOCKER_IMAGE_NAME' does not exist in docker hub (https://hub.docker.com) or the site is down. Wait a few minutes and try again." false 603 | local_undo_restore 604 | fi 605 | 606 | # Check if image and version exists in docker hub 607 | run_function dockerhub_check_image_exists $LOCAL_DOCKER_IMAGE_NAME $LOCAL_DOCKER_IMAGE_VERSION 608 | 609 | if [[ "$DOCKERHUB_IMAGE_EXISTS" != true ]]; then 610 | echoerror "It seems the image '$LOCAL_DOCKER_IMAGE_NAME:$LOCAL_DOCKER_IMAGE_VERSION' does not exist in docker hub (https://hub.docker.com) or the site is down. Wait a few minutes and try again." false 611 | local_undo_restore 612 | fi 613 | } 614 | 615 | #----------------------------------------------------------------------- 616 | # Check if the docker compose is already running 617 | #----------------------------------------------------------------------- 618 | LOCAL_DOCKER_COMPOSE_FILE_FULL_PATH="$SCRIPT_PATH/../ " 619 | run_function docker_compose_check_service_exists $LOCAL_DOCKER_COMPOSE_FILE_FULL_PATH 620 | 621 | if [[ "$DOCKER_COMPOSE_SERVICE_EXISTS" == true ]]; then 622 | [[ "$SILENT" != true ]] && echowarning \ 623 | "The services in the docker compose file below is already running: \ 624 | \n'$LOCAL_DOCKER_COMPOSE_FILE_FULL_PATH' \ 625 | \nIf you continue, the services will be stopped and all settings replaced \ 626 | \nif you are uncertain, check your current files settings before continue." 627 | 628 | if [[ "$REPLY_YES" == true ]]; then 629 | LOCAL_STOP_CURRENT_NGINX_PROXY_SERVICES=true 630 | LOCAL_BACKUP_OLD_DOCKER_COMPOSE_FILE=true 631 | else 632 | run_function confirm_user_action "Your services for this project are already running, \ 633 | \nare you sure you want to continue?" 634 | 635 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_CURRENT_NGINX_PROXY_SERVICES=true && LOCAL_BACKUP_OLD_DOCKER_COMPOSE_FILE=true 636 | fi 637 | fi 638 | 639 | #----------------------------------------------------------------------- 640 | # Check if the .env file was already configured 641 | #----------------------------------------------------------------------- 642 | run_function check_docker_nginx_proxy_automation_env_file_exits 643 | 644 | # Result from function above 645 | if [[ "$DOCKER_NGINX_PROXY_AUTOMATION_ENV_FILE_EXISTS" == true ]]; then 646 | [[ "$SILENT" != true ]] && echowarning \ 647 | "There is an '.env' file already set to your project, if you continue \ 648 | \nall settings will be replaced, there is no turn back on that, ok?." 649 | 650 | if [[ "$REPLY_YES" == true ]]; then 651 | LOCAL_BACKUP_OLD_ENV_FILE=true 652 | LOCAL_BACKUP_OLD_DOCKER_COMPOSE_FILE=true 653 | else 654 | run_function confirm_user_action "There is an .env file at your proxy folder, \ 655 | \nall settings at will be replaced with new values, \ 656 | \nare you sure you want to continue?" 657 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_BACKUP_OLD_ENV_FILE=true && LOCAL_BACKUP_OLD_DOCKER_COMPOSE_FILE=true 658 | fi 659 | fi 660 | 661 | #----------------------------------------------------------------------- 662 | # Arguments validation and variables fulfillment 663 | #----------------------------------------------------------------------- 664 | 665 | #----------------------------------------------------------------------- 666 | # NGINX-proxy service/container name 667 | # 668 | # Parameters: -pn | --proxy-name 669 | # 670 | # Final result: 671 | # - NGINX_PROXY_SERVICE_NAME 672 | # 673 | # Further action: 674 | # - LOCAL_STOP_AND_REMOVE_NGINX_PROXY_SERVICE_CONTAINER 675 | #----------------------------------------------------------------------- 676 | LOCAL_DEFAULT_NGINX_PROXY_SERVICE_NAME="proxy-web-auto" 677 | if [[ $ARG_NGINX_PROXY_SERVICE_NAME == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 678 | 679 | # Get user's response 680 | run_function common_read_user_input "Please enter the nginx-proxy service name (default: $LOCAL_DEFAULT_NGINX_PROXY_SERVICE_NAME):" 681 | 682 | LOCAL_NGINX_PROXY_SERVICE_NAME=${USER_INPUT_RESPONSE:-$LOCAL_DEFAULT_NGINX_PROXY_SERVICE_NAME} 683 | else 684 | LOCAL_NGINX_PROXY_SERVICE_NAME=${ARG_NGINX_PROXY_SERVICE_NAME:-$LOCAL_DEFAULT_NGINX_PROXY_SERVICE_NAME} 685 | fi 686 | 687 | # Validate the name 688 | run_function string_remove_all_special_char_string $LOCAL_NGINX_PROXY_SERVICE_NAME "-_" 689 | NGINX_PROXY_SERVICE_NAME=${STRING_REMOVE_ALL_SPECIAL_CHAR_STRING_RESPONSE:-null} 690 | [[ $NGINX_PROXY_SERVICE_NAME == null ]] && echoerror "The service name can not contain special chars, neither be empty" 691 | 692 | # Check exists a container with this name 693 | run_function docker_check_container_exists $NGINX_PROXY_SERVICE_NAME 694 | 695 | if [[ "$DOCKER_CONTAINER_EXISTS" == true ]]; then 696 | # Check if there is a container running with this name 697 | run_function docker_check_container_is_running $NGINX_PROXY_SERVICE_NAME 698 | 699 | if [[ "$DOCKER_CONTAINER_IS_RUNNING" == true ]]; then 700 | [[ "$SILENT" != true ]] && echowarning \ 701 | "The container '$NGINX_PROXY_SERVICE_NAME' is running in this server \ 702 | \nmake sure you have unique names for each container. This script \ 703 | \nmight stop and remove the container if you set '--yes' or reply \ 704 | \n'yes' on the line below, but, there is no turn back on this action!" 705 | 706 | if [[ "$REPLY_YES" == true ]]; then 707 | LOCAL_STOP_AND_REMOVE_NGINX_PROXY_SERVICE_CONTAINER=true 708 | else 709 | run_function confirm_user_action \ 710 | "The container '$NGINX_PROXY_SERVICE_NAME' is running in this server. We will \ 711 | \nstop and REMOVE it, do you want to continue?" 712 | 713 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_AND_REMOVE_NGINX_PROXY_SERVICE_CONTAINER=true 714 | fi 715 | else 716 | [[ "$SILENT" != true ]] && echowarning \ 717 | "The container '$NGINX_PROXY_SERVICE_NAME' is exist in this server, but it is not running \ 718 | \nmake sure you have unique names for each container. This script \ 719 | \nmight stop and remove the container if you set '--yes' or reply \ 720 | \n'yes' on the line below, but, there is no turn back on this action!" 721 | 722 | if [[ "$REPLY_YES" == true ]]; then 723 | LOCAL_STOP_AND_REMOVE_NGINX_PROXY_SERVICE_CONTAINER=true 724 | else 725 | run_function confirm_user_action \ 726 | "The container '$NGINX_PROXY_SERVICE_NAME' exist in this server. We will \ 727 | \nREMOVE it, do you want to continue?" 728 | 729 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_AND_REMOVE_NGINX_PROXY_SERVICE_CONTAINER=true 730 | fi 731 | # We kept STOP and REMOVE because the stop function will not break the script even if the container isn't running 732 | fi 733 | fi 734 | 735 | #----------------------------------------------------------------------- 736 | # Let's Encrypt service/container name 737 | # 738 | # Parameters: -ln | --letsencrypt-name 739 | # 740 | # Final result: 741 | # - LETSENCRYPT_SERVICE_NAME 742 | # 743 | # Further action: 744 | # - LOCAL_STOP_AND_REMOVE_LETSENCRYPT_SERVICE_CONTAINER 745 | #----------------------------------------------------------------------- 746 | LOCAL_DEFAULT_LETSENCRYPT_SERVICE_NAME="letsencrypt-auto" 747 | if [[ $ARG_LETSENCRYPT_SERVICE_NAME == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 748 | 749 | # Get user's response 750 | run_function common_read_user_input "Please enter the letsencrypt service name (default: $LOCAL_DEFAULT_LETSENCRYPT_SERVICE_NAME):" 751 | 752 | LOCAL_LETSENCRYPT_SERVICE_NAME=${USER_INPUT_RESPONSE:-$LOCAL_DEFAULT_LETSENCRYPT_SERVICE_NAME} 753 | else 754 | LOCAL_LETSENCRYPT_SERVICE_NAME=${ARG_LETSENCRYPT_SERVICE_NAME:-$LOCAL_DEFAULT_LETSENCRYPT_SERVICE_NAME} 755 | fi 756 | 757 | # Validate the name 758 | run_function string_remove_all_special_char_string $LOCAL_LETSENCRYPT_SERVICE_NAME "-_" 759 | LETSENCRYPT_SERVICE_NAME=${STRING_REMOVE_ALL_SPECIAL_CHAR_STRING_RESPONSE:-null} 760 | [[ $LETSENCRYPT_SERVICE_NAME == null ]] && echoerror "The service name can not contain special chars, neither be empty" 761 | 762 | # Check exists a container with this name 763 | run_function docker_check_container_exists $LETSENCRYPT_SERVICE_NAME 764 | 765 | if [[ "$DOCKER_CONTAINER_EXISTS" == true ]]; then 766 | # Check if there is a container running with this name 767 | run_function docker_check_container_is_running $LETSENCRYPT_SERVICE_NAME 768 | 769 | if [[ "$DOCKER_CONTAINER_IS_RUNNING" == true ]]; then 770 | [[ "$SILENT" != true ]] && echowarning \ 771 | "The container '$LETSENCRYPT_SERVICE_NAME' is running in this server \ 772 | \nmake sure you have unique names for each container. This script \ 773 | \nmight stop and remove the container if you set '--yes' or reply \ 774 | \n'yes' on the line below, but, there is no turn back on this action!" 775 | 776 | if [[ "$REPLY_YES" == true ]]; then 777 | LOCAL_STOP_AND_REMOVE_LETSENCRYPT_SERVICE_CONTAINER=true 778 | else 779 | run_function confirm_user_action \ 780 | "The container '$LETSENCRYPT_SERVICE_NAME' is running in this server. We will \ 781 | \nstop and REMOVE it, do you want to continue?" 782 | 783 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_AND_REMOVE_LETSENCRYPT_SERVICE_CONTAINER=true 784 | fi 785 | else 786 | [[ "$SILENT" != true ]] && echowarning \ 787 | "The container '$LETSENCRYPT_SERVICE_NAME' is exist in this server, but it is not running \ 788 | \nmake sure you have unique names for each container. This script \ 789 | \nmight stop and remove the container if you set '--yes' or reply \ 790 | \n'yes' on the line below, but, there is no turn back on this action!" 791 | 792 | if [[ "$REPLY_YES" == true ]]; then 793 | LOCAL_STOP_AND_REMOVE_LETSENCRYPT_SERVICE_CONTAINER=true 794 | else 795 | run_function confirm_user_action \ 796 | "The container '$LETSENCRYPT_SERVICE_NAME' exist in this server. We will \ 797 | \nREMOVE it, do you want to continue?" 798 | 799 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_AND_REMOVE_LETSENCRYPT_SERVICE_CONTAINER=true 800 | fi 801 | # We kept STOP and REMOVE because the stop function will not break the script even if the container isn't running 802 | fi 803 | fi 804 | 805 | #----------------------------------------------------------------------- 806 | # Docker-gen service/container name 807 | # 808 | # Parameters: -gn | --docker-gen-name 809 | # 810 | # Final result: 811 | # - DOCKER_GEN_SERVICE_NAME 812 | # 813 | # Further action: 814 | # - LOCAL_STOP_AND_REMOVE_DOCKER_GEN_SERVICE_CONTAINER 815 | #----------------------------------------------------------------------- 816 | LOCAL_DEFAULT_DOCKER_GEN_SERVICE_NAME="docker-gen-auto" 817 | if [[ $ARG_DOCKER_GEN_SERVICE_NAME == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 818 | 819 | # Get user's response 820 | run_function common_read_user_input "Please enter the docker-gen service name (default: $LOCAL_DEFAULT_DOCKER_GEN_SERVICE_NAME):" 821 | 822 | LOCAL_DOCKER_GEN_SERVICE_NAME=${USER_INPUT_RESPONSE:-$LOCAL_DEFAULT_DOCKER_GEN_SERVICE_NAME} 823 | else 824 | LOCAL_DOCKER_GEN_SERVICE_NAME=${ARG_DOCKER_GEN_SERVICE_NAME:-$LOCAL_DEFAULT_DOCKER_GEN_SERVICE_NAME} 825 | fi 826 | 827 | # Validate the name 828 | run_function string_remove_all_special_char_string $LOCAL_DOCKER_GEN_SERVICE_NAME "-_" 829 | DOCKER_GEN_SERVICE_NAME=${STRING_REMOVE_ALL_SPECIAL_CHAR_STRING_RESPONSE:-null} 830 | [[ $DOCKER_GEN_SERVICE_NAME == null ]] && echoerror "The service name can not contain special chars, neither be empty" 831 | 832 | # Check exists a container with this name 833 | run_function docker_check_container_exists $DOCKER_GEN_SERVICE_NAME 834 | 835 | if [[ "$DOCKER_CONTAINER_EXISTS" == true ]]; then 836 | # Check if there is a container running with this name 837 | run_function docker_check_container_is_running $DOCKER_GEN_SERVICE_NAME 838 | 839 | if [[ "$DOCKER_CONTAINER_IS_RUNNING" == true ]]; then 840 | [[ "$SILENT" != true ]] && echowarning \ 841 | "The container '$DOCKER_GEN_SERVICE_NAME' is running in this server \ 842 | \nmake sure you have unique names for each container. This script \ 843 | \nmight stop and remove the container if you set '--yes' or reply \ 844 | \n'yes' on the line below, but, there is no turn back on this action!" 845 | 846 | if [[ "$REPLY_YES" == true ]]; then 847 | LOCAL_STOP_AND_REMOVE_DOCKER_GEN_SERVICE_CONTAINER=true 848 | else 849 | run_function confirm_user_action \ 850 | "The container '$DOCKER_GEN_SERVICE_NAME' is running in this server. We will \ 851 | \nstop and REMOVE it, do you want to continue?" 852 | 853 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_AND_REMOVE_DOCKER_GEN_SERVICE_CONTAINER=true 854 | fi 855 | else 856 | [[ "$SILENT" != true ]] && echowarning \ 857 | "The container '$DOCKER_GEN_SERVICE_NAME' is exist in this server, but it is not running \ 858 | \nmake sure you have unique names for each container. This script \ 859 | \nmight stop and remove the container if you set '--yes' or reply \ 860 | \n'yes' on the line below, but, there is no turn back on this action!" 861 | 862 | if [[ "$REPLY_YES" == true ]]; then 863 | LOCAL_STOP_AND_REMOVE_DOCKER_GEN_SERVICE_CONTAINER=true 864 | else 865 | run_function confirm_user_action \ 866 | "The container '$DOCKER_GEN_SERVICE_NAME' exist in this server. We will \ 867 | \nREMOVE it, do you want to continue?" 868 | 869 | [[ "$USER_ACTION_RESPONSE" == true ]] && LOCAL_STOP_AND_REMOVE_DOCKER_GEN_SERVICE_CONTAINER=true 870 | fi 871 | # We kept STOP and REMOVE because the stop function will not break the script even if the container isn't running 872 | fi 873 | fi 874 | 875 | #----------------------------------------------------------------------- 876 | # nginx-proxy image version 877 | # 878 | # Parameters: -piv | --proxy-image-version 879 | # 880 | # Final result: 881 | # - NGINX_PROXY_IMAGE_VERSION 882 | #----------------------------------------------------------------------- 883 | LOCAL_DEFAULT_NGINX_PROXY_IMAGE_NAME=${DEFAULT_NGINX_PROXY_IMAGE_NAME:-nginx} 884 | LOCAL_DEFAULT_NGINX_PROXY_IMAGE_VERSION=${DEFAULT_NGINX_PROXY_IMAGE_VERSION:-latest} 885 | # We have commented the lines below once the proxy will use a regular nginx container and it's not optional today 886 | #if [[ $ARG_NGINX_PROXY_IMAGE_VERSION == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 887 | # # Get user's response 888 | # run_function dockerhub_list_tags $LOCAL_DEFAULT_NGINX_PROXY_IMAGE_NAME 889 | # run_function select_one_option "${DOCKERHUB_LIST_TAGS[*]}" "Please select a tag for the image '$LOCAL_DEFAULT_NGINX_PROXY_IMAGE_NAME' (the list below comes from https://hub.docker.com):" 890 | # 891 | # [[ $SELECT_ONE_OPTION_NAME == "" ]] && echowarning "Once you did not select any option, '$LOCAL_DEFAULT_NGINX_PROXY_IMAGE_VERSION' will be used." 892 | # NGINX_PROXY_IMAGE_VERSION=${SELECT_ONE_OPTION_NAME:-$LOCAL_DEFAULT_NGINX_PROXY_IMAGE_VERSION} 893 | #else 894 | NGINX_PROXY_IMAGE_VERSION=${ARG_NGINX_PROXY_IMAGE_VERSION:-$LOCAL_DEFAULT_NGINX_PROXY_IMAGE_VERSION} 895 | #fi 896 | # 897 | #if [[ "$NGINX_PROXY_IMAGE_VERSION" == null ]] || [[ "$LOCAL_DEFAULT_NGINX_PROXY_IMAGE_NAME" == null ]]; then 898 | # echoerror "It seems there is no default image or version, please check the .env file at '$SCRIPT_PATH'" 899 | #fi 900 | 901 | # Final check image a version with dockerhub 902 | #[[ "$SKIP_DOCKER_IMAGE_CHECK" != true ]] && [[ ! "$REPLY_YES" == true ]] && local_check_docker_hub_image_version $LOCAL_DEFAULT_NGINX_PROXY_IMAGE_NAME $NGINX_PROXY_IMAGE_VERSION 903 | 904 | #----------------------------------------------------------------------- 905 | # Let's Encrypt image version 906 | # 907 | # Parameters: -liv | --letsencrypt-image-version 908 | # 909 | # Final result: 910 | # - LETSENCRYPT_IMAGE_VERSION 911 | #----------------------------------------------------------------------- 912 | LOCAL_DEFAULT_LETSENCRYPT_IMAGE_NAME=${DEFAULT_LETSENCRYPT_IMAGE_NAME:-null} 913 | LOCAL_DEFAULT_LETSENCRYPT_IMAGE_VERSION=${DEFAULT_LETSENCRYPT_IMAGE_VERSION:-null} 914 | if [[ $ARG_LETSENCRYPT_IMAGE_VERSION == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 915 | 916 | # ------- 917 | # docker hub api v2 does not allow to get tags from personal repos without login 918 | # @todo - fix this with user login 919 | # ------- 920 | 921 | LETSENCRYPT_IMAGE_VERSION=${LOCAL_DEFAULT_LETSENCRYPT_IMAGE_VERSION} 922 | 923 | 924 | # Get user's response (COMMENTED - TO BE FIXED) 925 | # run_function dockerhub_list_tags $LOCAL_DEFAULT_LETSENCRYPT_IMAGE_NAME 926 | # run_function select_one_option "${DOCKERHUB_LIST_TAGS[*]}" "Please select a tag for the image '$LOCAL_DEFAULT_LETSENCRYPT_IMAGE_NAME' (the list below comes from https://hub.docker.com):" 927 | # 928 | # [[ $SELECT_ONE_OPTION_NAME == "" ]] && echowarning "Once you did not select any option, '$LOCAL_DEFAULT_LETSENCRYPT_IMAGE_VERSION' will be used." 929 | # LETSENCRYPT_IMAGE_VERSION=${SELECT_ONE_OPTION_NAME:-$LOCAL_DEFAULT_LETSENCRYPT_IMAGE_VERSION} 930 | else 931 | LETSENCRYPT_IMAGE_VERSION=${ARG_LETSENCRYPT_IMAGE_VERSION:-$LOCAL_DEFAULT_LETSENCRYPT_IMAGE_VERSION} 932 | fi 933 | 934 | if [[ "$LETSENCRYPT_IMAGE_VERSION" == null ]] || [[ "$LOCAL_DEFAULT_LETSENCRYPT_IMAGE_VERSION" == null ]]; then 935 | echoerror "It seems there is no default image or version, please check the .env file at '$SCRIPT_PATH'" 936 | fi 937 | 938 | # ------- 939 | # docker hub api v2 does not allow to get tags from personal repos without login 940 | # @todo - fix this with user login 941 | # ------- 942 | 943 | # Final check image a version with dockerhub (COMMENTED - TO BE FIXED) 944 | #[[ "$SKIP_DOCKER_IMAGE_CHECK" != true ]] && [[ ! "$REPLY_YES" == true ]] && local_check_docker_hub_image_version $LOCAL_DEFAULT_LETSENCRYPT_IMAGE_NAME $LETSENCRYPT_IMAGE_VERSION 945 | 946 | #----------------------------------------------------------------------- 947 | # docker-gen image version 948 | # 949 | # Parameters: -giv | --docker-gen-image-versio 950 | # 951 | # Final result: 952 | # - DOCKER_GEN_IMAGE_VERSION 953 | #----------------------------------------------------------------------- 954 | LOCAL_DEFAULT_DOCKER_GEN_IMAGE_NAME=${DEFAULT_DOCKER_GEN_IMAGE_NAME:-null} 955 | LOCAL_DEFAULT_DOCKER_GEN_IMAGE_VERSION=${DEFAULT_DOCKER_GEN_IMAGE_VERSION:-null} 956 | if [[ $ARG_DOCKER_GEN_IMAGE_VERSION == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 957 | # ------- 958 | # docker hub api v2 does not allow to get tags from personal repos without login 959 | # @todo - fix this with user login 960 | # ------- 961 | 962 | # # Get user's response (COMMENTED - TO BE FIXED) 963 | # run_function dockerhub_list_tags $LOCAL_DEFAULT_DOCKER_GEN_IMAGE_NAME false 964 | # run_function select_one_option "${DOCKERHUB_LIST_TAGS[*]}" "Please select a tag for the image '$LOCAL_DEFAULT_DOCKER_GEN_IMAGE_NAME' (the list below comes from https://hub.docker.com):" 965 | # 966 | # [[ $SELECT_ONE_OPTION_NAME == "" ]] && echowarning "Once you did not select any option, '$LOCAL_DEFAULT_DOCKER_GEN_IMAGE_VERSION' will be used." 967 | # DOCKER_GEN_IMAGE_VERSION=${SELECT_ONE_OPTION_NAME:-$LOCAL_DEFAULT_DOCKER_GEN_IMAGE_VERSION} 968 | DOCKER_GEN_IMAGE_VERSION=${ARG_DOCKER_GEN_IMAGE_VERSION:-$LOCAL_DEFAULT_DOCKER_GEN_IMAGE_VERSION} 969 | else 970 | DOCKER_GEN_IMAGE_VERSION=${ARG_DOCKER_GEN_IMAGE_VERSION:-$LOCAL_DEFAULT_DOCKER_GEN_IMAGE_VERSION} 971 | fi 972 | 973 | if [[ "$DOCKER_GEN_IMAGE_VERSION" == null ]] || [[ "$LOCAL_DEFAULT_DOCKER_GEN_IMAGE_VERSION" == null ]]; then 974 | echoerror "It seems there is no default image or version, please check the .env file at '$SCRIPT_PATH'" 975 | fi 976 | 977 | # ------- 978 | # docker hub api v2 does not allow to get tags from personal repos without login 979 | # @todo - fix this with user login 980 | # ------- 981 | 982 | # Final check image a version with dockerhub (COMMENTED - TO BE FIXED) 983 | #[[ "$SKIP_DOCKER_IMAGE_CHECK" != true ]] && [[ ! "$REPLY_YES" == true ]] && local_check_docker_hub_image_version $LOCAL_DEFAULT_DOCKER_GEN_IMAGE_NAME $DOCKER_GEN_IMAGE_VERSION 984 | 985 | #----------------------------------------------------------------------- 986 | # IP address (IPv4) 987 | # 988 | # Parameters: -ip | --ip-address 989 | # 990 | # Final result: 991 | # - IP_ADDRESS 992 | #----------------------------------------------------------------------- 993 | if [[ $ARG_IP_ADDRESS == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 994 | 995 | run_function ip_get_external_ipv4 996 | 997 | # Get user's response 998 | run_function common_read_user_input \ 999 | "Please enter the IP address (ipv4) that your server uses to connect to the internet. \ 1000 | \nYou might try the following '$IP_EXTERNAL_IPV4' (default: 0.0.0.0):" 1001 | 1002 | LOCAL_IP_ADDRESS=${USER_INPUT_RESPONSE:-"0.0.0.0"} 1003 | else 1004 | LOCAL_IP_ADDRESS=${ARG_IP_ADDRESS:-"0.0.0.0"} 1005 | fi 1006 | 1007 | # Check the IP address 1008 | run_function ip_check_ipv4 $LOCAL_IP_ADDRESS 1009 | 1010 | if [[ ! "$IP_IPV4" == true ]]; then 1011 | echoerror "The IP address '$LOCAL_IP_ADDRESS' seems to be in wrong format. Please try again or keep the default value." 1012 | local_undo_restore 1013 | else 1014 | IP_ADDRESS=${LOCAL_IP_ADDRESS:-"0.0.0.0"} 1015 | fi 1016 | 1017 | #----------------------------------------------------------------------- 1018 | # IP address (IPv6) 1019 | # 1020 | # Parameters: -ipv6 | --ipv6-address 1021 | # 1022 | # Final result: 1023 | # - IPv6_ADDRESS 1024 | #----------------------------------------------------------------------- 1025 | if [[ "$ACTIVATE_IPV6" == true ]]; then 1026 | 1027 | # Check the ipv6 1028 | if [[ $ARG_IPv6_ADDRESS == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 1029 | 1030 | run_function ip_get_external_ipv6 1031 | 1032 | # Get user's response 1033 | run_function common_read_user_input \ 1034 | "Please enter the IP address (ipv6) that your server uses to connect to the internet. \ 1035 | \nYou might try the following '$IP_EXTERNAL_IPV6' (default: ::0):" 1036 | 1037 | LOCAL_IPv6_ADDRESS=${USER_INPUT_RESPONSE:-"::0"} 1038 | else 1039 | LOCAL_IPv6_ADDRESS=${ARG_IPv6_ADDRESS:-"::0"} 1040 | fi 1041 | 1042 | # Check the IP address 1043 | run_function ip_check_ipv6 $LOCAL_IPv6_ADDRESS 1044 | 1045 | if [[ ! "$IP_IPV6" == true ]]; then 1046 | echoerror "The IP address '$LOCAL_IPv6_ADDRESS' seems to be in wrong format. Please try again or keep the default value." 1047 | local_undo_restore 1048 | else 1049 | IPv6_ADDRESS=${LOCAL_IPv6_ADDRESS:-"::0"} 1050 | fi 1051 | fi 1052 | 1053 | #----------------------------------------------------------------------- 1054 | # Docker network for the nginx-proxy 1055 | # 1056 | # Parameters: -net | --network-name 1057 | # 1058 | # Final result: 1059 | # - DOCKER_NETWORK_NAME 1060 | #----------------------------------------------------------------------- 1061 | LOCAL_DEFAULT_DOCKER_NETWORK_NAME=${DEFAULT_DOCKER_NETWORK_NAME:-"proxy"} 1062 | if [[ $ARG_NETWORK_NAME == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 1063 | 1064 | # Get user's response 1065 | run_function common_read_user_input "Please enter the network name for your nginx-proxy (default: $LOCAL_DEFAULT_DOCKER_NETWORK_NAME):" 1066 | 1067 | LOCAL_DOCKER_NETWORK_NAME=${USER_INPUT_RESPONSE:-$LOCAL_DEFAULT_DOCKER_NETWORK_NAME} 1068 | else 1069 | LOCAL_DOCKER_NETWORK_NAME=${ARG_NETWORK_NAME:-$LOCAL_DEFAULT_DOCKER_NETWORK_NAME} 1070 | fi 1071 | 1072 | # Validate the name 1073 | run_function string_remove_all_special_char_string $LOCAL_DOCKER_NETWORK_NAME "-_" 1074 | DOCKER_NETWORK_NAME=${STRING_REMOVE_ALL_SPECIAL_CHAR_STRING_RESPONSE:-null} 1075 | [[ $DOCKER_NETWORK_NAME == null ]] && echoerror "The network name can not contain special chars, neither be empty" 1076 | 1077 | #----------------------------------------------------------------------- 1078 | # Data location for nginx-proxy files 1079 | # 1080 | # Parameters: -d | --data-files-location 1081 | # 1082 | # Final result: 1083 | # - DATA_LOCATION 1084 | #----------------------------------------------------------------------- 1085 | LOCAL_DEFAULT_DATA_LOCATION=${DEFAULT_DATA_LOCATION:-"$SCRIPT_PATH/../data"} 1086 | if [[ $ARG_DATA_LOCATION == "" ]] && [[ ! "$REPLY_YES" == true ]]; then 1087 | 1088 | # Get user's response 1089 | run_function common_read_user_input "Please enter the path location where you wish to place your nginx-proxy files (default: $LOCAL_DEFAULT_DATA_LOCATION):" 1090 | 1091 | DATA_LOCATION=${USER_INPUT_RESPONSE:-$LOCAL_DEFAULT_DATA_LOCATION} 1092 | else 1093 | DATA_LOCATION=${ARG_DATA_LOCATION:-$LOCAL_DEFAULT_DATA_LOCATION} 1094 | fi 1095 | 1096 | # Create folder if it does not exist 1097 | run_function common_create_folder $DATA_LOCATION 1098 | 1099 | #----------------------------------------------------------------------- 1100 | # Default email address for the Lets Encrypt certificates 1101 | # 1102 | # Parameters: -e | --default-email 1103 | # 1104 | # Final result: 1105 | # - DEFAULT_EMAIL 1106 | #----------------------------------------------------------------------- 1107 | if [[ $ARG_DEFAULT_EMAIL == "" ]]; then 1108 | 1109 | # Get user's response 1110 | run_function common_read_user_input "You must inform a valid email address in order to continue. Please check the docs:" 1111 | 1112 | DEFAULT_EMAIL=${USER_INPUT_RESPONSE} 1113 | else 1114 | DEFAULT_EMAIL=${ARG_DEFAULT_EMAIL} 1115 | fi 1116 | 1117 | # Check if email is valid 1118 | run_function email_check_is_valid $DEFAULT_EMAIL 1119 | 1120 | [[ ! "$EMAIL_IS_VALID" == true ]] && echoerror "You must inform a valid email address in order to continue. Please try again." 1121 | 1122 | #----------------------------------------------------------------------- 1123 | # Log settings for nginx-proxy 1124 | # 1125 | # We would like to comment that this is a very specific configuration 1126 | # that, once we will not offer the available options we decided to 1127 | # simplify these options once was not a common issue setting up 1128 | #----------------------------------------------------------------------- 1129 | NGINX_PROXY_LOG_DRIVER=${ARG_NGINX_PROXY_LOG_DRIVER:-"json-file"} 1130 | NGINX_PROXY_LOG_MAX_SIZE=${ARG_NGINX_PROXY_LOG_MAX_SIZE:-"4m"} 1131 | NGINX_PROXY_LOG_MAX_FILE=${ARG_NGINX_PROXY_LOG_MAX_FILE:-"10"} 1132 | 1133 | DOCKER_GEN_LOG_DRIVER=${ARG_DOCKER_GEN_LOG_DRIVER:-"json-file"} 1134 | DOCKER_GEN_LOG_MAX_SIZE=${ARG_DOCKER_GEN_LOG_MAX_SIZE:-"2m"} 1135 | DOCKER_GEN_LOG_MAX_FILE=${ARG_DOCKER_GEN_LOG_MAX_FILE:-"10"} 1136 | 1137 | LETSENCRYPT_LOG_DRIVER=${ARG_LETSENCRYPT_LOG_DRIVER:-"json-file"} 1138 | LETSENCRYPT_LOG_MAX_SIZE=${ARG_LETSENCRYPT_LOG_MAX_SIZE:-"2m"} 1139 | LETSENCRYPT_LOG_MAX_FILE=${ARG_LETSENCRYPT_LOG_MAX_FILE:-"10"} 1140 | 1141 | #----------------------------------------------------------------------- 1142 | # Port binding 1143 | # 1144 | # We would like to comment out that the settings below seems to be 1145 | # rearly changes by the users, so we kept that pretty simple in 1146 | # this script, if that is all right with you! Thank you! 1147 | #----------------------------------------------------------------------- 1148 | DOCKER_HTTP=${ARG_DOCKER_HTTP:-"80"} 1149 | DOCKER_HTTPS=${ARG_DOCKER_HTTPS:-"443"} 1150 | 1151 | #----------------------------------------------------------------------- 1152 | # SSL policy (set to Mozilla-Intermediate) 1153 | # 1154 | # Please read the options at the url below: 1155 | # https://github.com/nginx-proxy/nginx-proxy#how-ssl-support-works 1156 | #----------------------------------------------------------------------- 1157 | SSL_POLICY=${ARG_SSL_POLICY:-"Mozilla-Intermediate"} 1158 | 1159 | #----------------------------------------------------------------------- 1160 | # Docker rootless support. Add the current user's docker.sock path (default: blank) 1161 | # Please read the official documentation of installing Docker Rootless: 1162 | # https://docs.docker.com/engine/security/rootless/ 1163 | #----------------------------------------------------------------------- 1164 | if [[ "$USE_DOCKER_ROOTLESS" == true ]]; then 1165 | # Get the current user's $XDG_RUNTIME_DIR and concat with the '/docker.sock' 1166 | DOCKER_HOST_ROOTLESS_PATH=`echo ${XDG_RUNTIME_DIR}/docker.sock` 1167 | fi 1168 | 1169 | #----------------------------------------------------------------------- 1170 | # Start actions! 1171 | #----------------------------------------------------------------------- 1172 | 1173 | #----------------------------------------------------------------------- 1174 | # Verify checksum of docker-compose.yml and .env.sample files 1175 | #----------------------------------------------------------------------- 1176 | run_function md5_check_checksum "$SCRIPT_PATH/../" "docker-compose.yml" $MD5_SUM_DOCKER_COMPOSE 1177 | if [[ ! "$MD5_CHECKSUM" == true ]] && [[ ! "$REPLY_YES" == true ]]; then 1178 | 1179 | run_function confirm_user_action \ 1180 | "We could not verify the checksum (md5) for the docker-compose.yml \ 1181 | \n are you sure you want to continue?" 1182 | fi 1183 | 1184 | run_function md5_check_checksum "$SCRIPT_PATH/../" ".env.sample" $MD5_SUM_ENV_SAMPLE 1185 | if [[ ! "$MD5_CHECKSUM" == true ]] && [[ ! "$REPLY_YES" == true ]]; then 1186 | 1187 | run_function confirm_user_action \ 1188 | "We could not verify the checksum (md5) for the .env \ 1189 | \n are you sure you want to continue?" 1190 | fi 1191 | 1192 | #----------------------------------------------------------------------- 1193 | # Stop services (docker-compose) if they are running 1194 | #----------------------------------------------------------------------- 1195 | if [[ "$LOCAL_STOP_CURRENT_NGINX_PROXY_SERVICES" == true ]]; then 1196 | run_function docker_compose_stop "$SCRIPT_PATH/../" 1197 | 1198 | ACTION_DOCKER_COMPOSE_STOPPED=true 1199 | 1200 | [[ "$ERROR_DOCKER_COMPOSE_START" == true ]] && local_undo_restore 1201 | 1202 | # If there is no error when stopping container backup docker-compose file 1203 | run_function backup_file "$SCRIPT_PATH/../docker-compose.yml" 1204 | ACTION_DOCKER_COMPOSE_FILE_RENAMED=true 1205 | LOCAL_BACKUP_DOCKER_COMPOSE_FILE=$BACKUP_FILE 1206 | fi 1207 | 1208 | #----------------------------------------------------------------------- 1209 | # Add nginx config folder (conf.d) 1210 | #----------------------------------------------------------------------- 1211 | if [[ "$USE_NGINX_CONF_FILES" == true ]]; then 1212 | # Create the conf folder if it does not exists 1213 | run_function common_create_folder "$DATA_LOCATION/conf.d" 1214 | 1215 | # Copy the special configurations to the nginx conf folder 1216 | cp -R $SCRIPT_PATH/../conf.d/* $DATA_LOCATION/conf.d/ 1217 | 1218 | # Check if there was an error and try with sudo 1219 | if [ $? -ne 0 ]; then 1220 | echo "sudo cp -R $SCRIPT_PATH/../conf.d/* $DATA_LOCATION/conf.d/" 1221 | exit 0 1222 | sudo cp -R $SCRIPT_PATH/../conf.d/* $DATA_LOCATION/conf.d/ 1223 | fi 1224 | 1225 | # If there was any errors inform the user 1226 | if [ $? -ne 0 ]; then 1227 | echoerror "There was an error trying to copy the nginx conf files. \ 1228 | \nThe proxy will still work with default options, but \ 1229 | \nthe custom settings might not be loaded." 1230 | fi 1231 | fi 1232 | 1233 | #----------------------------------------------------------------------- 1234 | # Update the nginx.template with the latest version 1235 | #----------------------------------------------------------------------- 1236 | DEFAULT_NGINX_TEMPLATE_URL="https://raw.githubusercontent.com/nginx-proxy/nginx-proxy/master/nginx.tmpl" 1237 | if [[ "$UPDATE_NGINX_TEMPLATE" == true ]]; then 1238 | cd "$SCRIPT_PATH/../" 1239 | curl -L $DEFAULT_NGINX_TEMPLATE_URL -o nginx.tmpl 1240 | cd - > /dev/null 2>&1 1241 | fi 1242 | 1243 | #----------------------------------------------------------------------- 1244 | # Backup .env file if exists 1245 | #----------------------------------------------------------------------- 1246 | if [[ "$LOCAL_BACKUP_OLD_ENV_FILE" == true ]]; then 1247 | run_function backup_file "$SCRIPT_PATH/../.env" 1248 | ACTION_ENV_FILE_RENAMED=true 1249 | LOCAL_BACKUP_ENV_FILE=$BACKUP_FILE 1250 | fi 1251 | 1252 | #----------------------------------------------------------------------- 1253 | # Backup docker-compose.yml file if exists 1254 | #----------------------------------------------------------------------- 1255 | if [[ "$LOCAL_BACKUP_OLD_DOCKER_COMPOSE_FILE" == true ]]; then 1256 | run_function backup_file "$SCRIPT_PATH/../docker-compose.yml" 1257 | ACTION_DOCKER_COMPOSE_FILE_RENAMED=true 1258 | LOCAL_BACKUP_DOCKER_COMPOSE_FILE=$BACKUP_FILE 1259 | fi 1260 | 1261 | #----------------------------------------------------------------------- 1262 | # Create and update .env file for nginx-proxy 1263 | #----------------------------------------------------------------------- 1264 | cp "$SCRIPT_PATH/../.env.sample" "$SCRIPT_PATH/../.env" 1265 | 1266 | run_function local_update_env_new_site_variables "$SCRIPT_PATH/../" 1267 | 1268 | #----------------------------------------------------------------------- 1269 | # Create docker network if it does not exist 1270 | #----------------------------------------------------------------------- 1271 | run_function docker_check_network_exists $DOCKER_NETWORK_NAME 1272 | 1273 | if [[ ! "$DOCKER_NETWORK_EXISTS" == true ]]; then 1274 | 1275 | run_function docker_network_create $DOCKER_NETWORK_NAME ${ARG_IPv4_SUBNET:-null} $ACTIVATE_IPV6 $ARG_IPv6_SUBNET 1276 | 1277 | if [[ "$ERROR_DOCKER_NETWORK_CREATE" == true ]]; then 1278 | echoerror \ 1279 | "There was an error when creating the docker network $DOCKER_NETWORK_NAME [IPv6 enabled: ${ACTIVATE_IPV6:-'false'} ] \ 1280 | \nPlease try to create the network by yourself using the appropriate options described below and try again: \ 1281 | \nhttps://docs.docker.com/engine/reference/commandline/network_create/" \ 1282 | false 1283 | local_undo_restore 1284 | else 1285 | ACTION_DOCKER_NETWORK_CREATED=true 1286 | fi 1287 | fi 1288 | 1289 | #----------------------------------------------------------------------- 1290 | # Update docker-compose file 1291 | #----------------------------------------------------------------------- 1292 | run_function local_update_docker_compose_file "$SCRIPT_PATH/../" 1293 | 1294 | #----------------------------------------------------------------------- 1295 | # Start proxy 1296 | #----------------------------------------------------------------------- 1297 | run_function docker_compose_start "$SCRIPT_PATH/../" 1298 | 1299 | if [[ "$ERROR_DOCKER_COMPOSE_START" == true ]]; then 1300 | echoerror "There was an error starting the service at '$SCRIPT_PATH/../'" 1301 | local_undo_restore 1302 | fi 1303 | 1304 | #----------------------------------------------------------------------- 1305 | # Show data for the user to take notes 1306 | #----------------------------------------------------------------------- 1307 | echosuccess "Your proxy was started successfully!" 1308 | 1309 | # @todo - testing the proxy 1310 | # 1311 | # attention: 1312 | # 1. if yes don't ask for testing unless splicit 1313 | # 2. timeout optional yes|no as default? 1314 | # 3. url for testing - test dns first 1315 | # 4. option for ssl testing as well 1316 | # 1317 | # without ssl 1318 | # docker run -d -e VIRTUAL_HOST=$DOMAIN --network=$NETWORK --name test-web httpd:alpine 1319 | # 1320 | # with ss 1321 | # docker run -d -e VIRTUAL_HOST=$DOMAIN -e LETSENCRYPT_HOST=$DOMAIN --network=$NETWORK --name $NAME httpd:alpine 1322 | # 1323 | # stop testint - timeout?! 1324 | # docker stop test-web && docker rm test-web 1325 | 1326 | exit 0 1327 | -------------------------------------------------------------------------------- /bin/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #----------------------------------------------------------------------- 4 | # 5 | # Install script - configure the requirements for this project 6 | # 7 | # https://github.com/evertramos/nginx-proxy-automation 8 | # 9 | # Script developed by 10 | # Evert Ramos 11 | # 12 | # Copyright Evert Ramos 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # Bash settings (do not mess with it) 17 | shopt -s nullglob globstar 18 | 19 | # Get the script name and its file real path 20 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 21 | SCRIPT_NAME="${0##*/}" 22 | 23 | # basescript (remove and install) 24 | BASESCRIPT_VERSION=v0.6.2 25 | BASESCRIPT_BASE_PATH=${SCRIPT_PATH}/../src/scripts 26 | mkdir -p ${BASESCRIPT_BASE_PATH} 27 | cd ${BASESCRIPT_BASE_PATH} 28 | rm -rf "basescript" 29 | git clone https://github.com/evertramos/basescript.git &> /dev/null 30 | cd basescript 31 | git checkout ${BASESCRIPT_VERSION} &> /dev/null 32 | cd ${SCRIPT_PATH} 33 | source "${BASESCRIPT_BASE_PATH}/basescript/bootstrap.sh" 34 | BASESCRIPT_LOG_BASE_PATH=${BASESCRIPT_BASE_PATH}/logs 35 | mkdir -p ${BASESCRIPT_LOG_BASE_PATH} 36 | # Source localscripts 37 | #source ${BASESCRIPT_BASE_PATH}"/localscripts/bootstrap.sh" 38 | 39 | log "testing..." 40 | -------------------------------------------------------------------------------- /bin/localscript/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # Server Automation - https://github.com/evertramos/server-automation 4 | # 5 | # Developed by 6 | # Evert Ramos 7 | # 8 | # Copyright Evert Ramos 9 | # 10 | #----------------------------------------------------------------------- 11 | # 12 | # Be careful when editing this file, it is part of a bigger script! 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | #----------------------------------------------------------------------- 17 | # This script has one main objective: 18 | # 1. Load all functions in local folder 19 | #----------------------------------------------------------------------- 20 | 21 | #----------------------------------------------------------------------- 22 | # Fill out local variables 23 | #----------------------------------------------------------------------- 24 | # Get Current directory 25 | LOCAL_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)" 26 | 27 | # Bootstrap file name 28 | BOOTSTRAP_FILE_NAME="bootstrap.sh" 29 | 30 | #----------------------------------------------------------------------- 31 | # Debug message 32 | #----------------------------------------------------------------------- 33 | [[ "$DEBUG" == true ]] && "Reading base script files... [bootstrap.sh]" 34 | 35 | #----------------------------------------------------------------------- 36 | # Read files with extension '.sh' 37 | #----------------------------------------------------------------------- 38 | # Loop the base folder and source all files in root folder 39 | for file in $LOCAL_PATH/*.sh 40 | do 41 | [[ $file != $LOCAL_PATH/$BOOTSTRAP_FILE_NAME ]] && source $file 42 | done 43 | 44 | return 0 45 | -------------------------------------------------------------------------------- /bin/localscript/check-docker-nginx-proxy-automation-env-file.sh: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # Server Automation - https://github.com/evertramos/server-automation 4 | # 5 | # Developed by 6 | # Evert Ramos 7 | # 8 | # Copyright Evert Ramos 9 | # 10 | #----------------------------------------------------------------------- 11 | # 12 | # Be careful when editing this file, it is part of a bigger script! 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | #----------------------------------------------------------------------- 17 | # This script has one main objective: 18 | # 1. Check if the .env file already exists for the 19 | # docker-nginx-proxy-automation 20 | #----------------------------------------------------------------------- 21 | 22 | check_docker_nginx_proxy_automation_env_file_exits() 23 | { 24 | [[ "$DEBUG" == true ]] && echo "Check if '.env' file exists for the nginx-proxy." 25 | 26 | if [[ -e ./../.env ]]; then 27 | DOCKER_NGINX_PROXY_AUTOMATION_ENV_FILE_EXISTS=true 28 | fi 29 | } 30 | -------------------------------------------------------------------------------- /bin/localscript/check-local-env-file.sh: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # Server Automation - https://github.com/evertramos/server-automation 4 | # 5 | # Developed by 6 | # Evert Ramos 7 | # 8 | # Copyright Evert Ramos 9 | # 10 | #----------------------------------------------------------------------- 11 | # 12 | # Be careful when editing this file, it is part of a bigger script! 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | #----------------------------------------------------------------------- 17 | # This script has one main objective: 18 | # 1. Check if the .env file exists in the current folder 19 | #----------------------------------------------------------------------- 20 | 21 | check_local_env_file() 22 | { 23 | [[ "$DEBUG" == true ]] && echo "Check if local '.env' file is set." 24 | 25 | if [[ -e .env ]]; then 26 | source .env 27 | else 28 | MESSAGE="'.env' file not found! \n Cheers!" 29 | return 1 30 | fi 31 | } 32 | -------------------------------------------------------------------------------- /bin/localscript/update-docker-compose-file.sh: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # Server Automation - https://github.com/evertramos/server-automation 4 | # 5 | # Developed by 6 | # Evert Ramos 7 | # 8 | # Copyright Evert Ramos 9 | # 10 | #----------------------------------------------------------------------- 11 | # 12 | # Be careful when editing this file, it is part of a bigger script! 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # ---------------------------------------------------------------------- 17 | # This function has one main objective: 18 | # 1. Update all variables in docker-compose file 19 | # 20 | # You must/might inform the parameters below: 21 | # 1. Path where docker-compose.yml file is located 22 | # 2. [optional] (default: ) 23 | # 24 | # ---------------------------------------------------------------------- 25 | 26 | local_update_docker_compose_file() 27 | { 28 | local LOCAL_FULL_PATH 29 | 30 | LOCAL_FULL_PATH=${1} 31 | 32 | [[ $LOCAL_FULL_PATH == "" || $LOCAL_FULL_PATH == null ]] && echoerror "You must inform the required argument(s) to the function: '${FUNCNAME[0]}'" 33 | 34 | [[ "$DEBUG" == true ]] && echo "Updating all variables in docker-compose.yml file for nginx-proxy (file: ${LOCAL_FULL_PATH})" 35 | 36 | # Services name 37 | run_function docker_compose_replace_string $LOCAL_FULL_PATH "$REPLACE_NGINX_PROXY_SERVICE_NAME" "$NGINX_PROXY_SERVICE_NAME" 38 | run_function docker_compose_replace_string $LOCAL_FULL_PATH "$REPLACE_DOCKER_GEN_SERVICE_NAME" "$DOCKER_GEN_SERVICE_NAME" 39 | run_function docker_compose_replace_string $LOCAL_FULL_PATH "$REPLACE_LETSENCRYPT_SERVICE_NAME" "$LETSENCRYPT_SERVICE_NAME" 40 | 41 | # Uncomment in case of IPv6 activation or comment 42 | [[ "$ACTIVATE_IPV6" == true ]] && run_function file_uncomment_line_with_string ${LOCAL_FULL_PATH%/}"/docker-compose.yml" "IPv6" && run_function file_uncomment_line_with_string ${LOCAL_FULL_PATH%/}"/docker-compose.yml" "IPV6" 43 | [[ ! "$ACTIVATE_IPV6" == true ]] && run_function file_comment_line_with_string ${LOCAL_FULL_PATH%/}"/docker-compose.yml" "IPv6" && run_function file_comment_line_with_string ${LOCAL_FULL_PATH%/}"/docker-compose.yml" "IPV6" 44 | # We are aware that it will set two '#' if the IPv6 is already commented 45 | 46 | # Uncomment in case of Default Host activation 47 | [[ ! $ARG_DEFAULT_HOST == "" ]] && run_function file_uncomment_line_with_string ${LOCAL_FULL_PATH%/}"/docker-compose.yml" "DEFAULT_HOST" 48 | 49 | return 0 50 | } 51 | -------------------------------------------------------------------------------- /bin/localscript/update-env-new-site-variables.sh: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # Server Automation - https://github.com/evertramos/server-automation 4 | # 5 | # Developed by 6 | # Evert Ramos 7 | # 8 | # Copyright Evert Ramos 9 | # 10 | #----------------------------------------------------------------------- 11 | # 12 | # Be careful when editing this file, it is part of a bigger script! 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | #----------------------------------------------------------------------- 17 | # This function has one main objective: 18 | # 1. Update all variables in .env file for fresh start script 19 | # 20 | # You must/might inform the parameters below: 21 | # 1. Path where .env is located 22 | # 2. [optional] (default: ) n/a 23 | # 24 | #----------------------------------------------------------------------- 25 | 26 | local_update_env_new_site_variables() 27 | { 28 | local LOCAL_FILE_PATH 29 | 30 | LOCAL_FILE_PATH=${1:-null} 31 | 32 | [[ $LOCAL_FILE_PATH == "" || $LOCAL_FILE_PATH == null ]] && echoerror "You must inform the required argument(s) to the function: '${FUNCNAME[0]}'" 33 | 34 | [[ "$DEBUG" == true ]] && echo "Updating all variables in .env file for nginx-proxy (file: ${LOCAL_FILE_PATH})" 35 | 36 | # Docker servides and image versions 37 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_WEB_SEVICE_NAME" "$NGINX_PROXY_SERVICE_NAME" 38 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_IMAGE_VERSION" "$NGINX_PROXY_IMAGE_VERSION" 39 | run_function env_update_variable $LOCAL_FILE_PATH "DOCKER_GEN_SEVICE_NAME" "$DOCKER_GEN_SERVICE_NAME" 40 | run_function env_update_variable $LOCAL_FILE_PATH "DOCKER_GEN_IMAGE_VERSION" "$DOCKER_GEN_IMAGE_VERSION" 41 | run_function env_update_variable $LOCAL_FILE_PATH "LETS_ENCRYPT_SEVICE_NAME" "$LETSENCRYPT_SERVICE_NAME" 42 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_PROXY_COMPANION_IMAGE_VERSION" "$LETSENCRYPT_IMAGE_VERSION" 43 | 44 | # IPs 45 | run_function env_update_variable $LOCAL_FILE_PATH "IPv4" "$IP_ADDRESS" 46 | [[ "$ACTIVATE_IPV6" == true ]] && run_function env_update_variable $LOCAL_FILE_PATH "IPv6" "$IPv6_ADDRESS" 47 | 48 | # Network 49 | run_function env_update_variable $LOCAL_FILE_PATH "NETWORK" "$DOCKER_NETWORK_NAME" 50 | 51 | # Data files path 52 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_FILES_PATH" "$DATA_LOCATION" 53 | 54 | # Log variables 55 | # proxy 56 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_WEB_LOG_DRIVER" "$NGINX_PROXY_LOG_DRIVER" 57 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_WEB_LOG_MAX_SIZE" "$NGINX_PROXY_LOG_MAX_SIZE" 58 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_WEB_LOG_MAX_FILE" "$NGINX_PROXY_LOG_MAX_FILE" 59 | # docker-gen 60 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_GEN_LOG_DRIVER" "$DOCKER_GEN_LOG_DRIVER" 61 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_GEN_LOG_MAX_SIZE" "$DOCKER_GEN_LOG_MAX_SIZE" 62 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_GEN_LOG_MAX_FILE" "$DOCKER_GEN_LOG_MAX_FILE" 63 | # Lets Encrypt 64 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_LETSENCRYPT_LOG_DRIVER" "$LETSENCRYPT_LOG_DRIVER" 65 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_LETSENCRYPT_LOG_MAX_SIZE" "$LETSENCRYPT_LOG_MAX_SIZE" 66 | run_function env_update_variable $LOCAL_FILE_PATH "NGINX_LETSENCRYPT_LOG_MAX_FILE" "$LETSENCRYPT_LOG_MAX_FILE" 67 | 68 | # Port bindings 69 | run_function env_update_variable $LOCAL_FILE_PATH "DOCKER_HTTP_" "$DOCKER_HTTP" 70 | run_function env_update_variable $LOCAL_FILE_PATH "DOCKER_HTTPS" "$DOCKER_HTTPS" 71 | 72 | # SSL Policy 73 | run_function env_update_variable $LOCAL_FILE_PATH "SSL_POLICY" "$SSL_POLICY" 74 | 75 | # Default email address 76 | run_function env_update_variable $LOCAL_FILE_PATH "DEFAULT_EMAIL" "$DEFAULT_EMAIL" 77 | 78 | # Default host 79 | [[ ! $ARG_DEFAULT_HOST == "" ]] && run_function env_update_variable $LOCAL_FILE_PATH "DEFAULT_HOST" "${ARG_DEFAULT_HOST}" 80 | 81 | # Docker rootless support 82 | [[ "$USE_DOCKER_ROOTLESS" == true ]] && run_function env_update_variable $LOCAL_FILE_PATH "DOCKER_HOST_ROOTLESS_PATH" "$DOCKER_HOST_ROOTLESS_PATH" 83 | 84 | return 0 85 | } 86 | -------------------------------------------------------------------------------- /bin/localscript/usage-fresh-start.sh: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # 3 | # Server Automation - https://github.com/evertramos/server-automation 4 | # 5 | # Developed by 6 | # Evert Ramos 7 | # 8 | # Copyright Evert Ramos 9 | # 10 | #----------------------------------------------------------------------- 11 | # 12 | # Be careful when editing this file, it is part of a bigger script! 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | #----------------------------------------------------------------------- 17 | # This script has one main objective: 18 | # 1. Show the script usage (helper) 19 | #----------------------------------------------------------------------- 20 | 21 | # 22 | # NGINX use special conf files 23 | # 24 | # In case you want to add some special configuration to your NGINX Web Proxy you could 25 | # add your files to ./conf.d/ folder as of sample file 'uploadsize.conf' 26 | # 27 | # [WARNING] This setting was built to use our `start.sh`. 28 | # 29 | # [WARNING] Once you set this options to true all your files will be copied to data 30 | # folder (./data/conf.d). If you decide to remove this special configuration 31 | # you must delete your files from data folder ./data/conf.d. 32 | # 33 | # USE_NGINX_CONF_FILES=true 34 | 35 | #----------------------------------------------------------------------- 36 | # 37 | # Docker network options 38 | # 39 | # The docker network has many options when creating a new network, you can 40 | # check the url below for more information about the docker network creation 41 | # in our 'fresh_start.sh' script you can enable the network encryption option 42 | # 43 | # https://docs.docker.com/engine/reference/commandline/network_create/ 44 | # 45 | # NETWORK_OPTIONS="--opt encrypted=true" 46 | 47 | usage() 48 | { 49 | cat << USAGE >&2 50 | ${purple} 51 | ============================================================================= 52 | | _____ _____ _ _ _ | 53 | | | __|___ ___ _ _ ___ ___ ___| _ |_ _| |_ ___ _____ ___| |_|_|___ ___ | 54 | | |__ | -_| _| | | -_| _|___| | | | _| . | | .'| _| | . | | | 55 | | |_____|___|_| \_/|___|_| |__|__|___|_| |___|_|_|_|__,|_| |_|___|_|_| | 56 | | | 57 | ============================================================================= 58 | ${reset}${blue} 59 | Usage: 60 | $SCRIPT_NAME -e "john.doe@example.com" 61 | [-d "/server/proxy/data"] 62 | [-pn "proxy"] [-ln "letsencrypt"] [-gn "docker-gen"] 63 | [-net "proxy"] 64 | [--use-nginx-conf-files] [--update-nginx-template] 65 | [--yes] 66 | [--debug] 67 | [--docker-rootless] 68 | 69 | Required 70 | -e | --default-email Default email address require to issue ssl 71 | certificates with Let's Encrypt service 72 | 73 | Basic options 74 | -d | --data-files-location Proxy files location 75 | -pn | --proxy-name Proxy service and container name 76 | -ln | --letsencrypt-name Let's Encrypt service & container name 77 | -gn | --docker-gen-name Docker-gen service and container name 78 | -net | --network-name Docker network name for proxy services 79 | -ip | --ip-address IP address for external connectivity 80 | 81 | Proxy config 82 | --use-nginx-conf-files Add basic config folder to the Proxy 83 | --update-nginx-template Download the latest nginx.tmpl 84 | 85 | Network 86 | -netopt | --network-option Network options please check the docs 87 | --ipv4-subnet You may inform IPv4 subnet to create 88 | a docker network 89 | (default: 172.17.0.0/16) 90 | 91 | Docker image 92 | -piv | --proxy-image-version Proxy image version 93 | -liv | --letsencrypt-image-version Let's Encrypt image version 94 | -giv | --docker-gen-image-version Docker-gen image version 95 | 96 | --skip-docker-image-check Use this option to skip docker image 97 | verification which might takes a few 98 | seconds to check if images exists in 99 | docker hub api 100 | 101 | Docker log 102 | -lpd | --log-nginx-proxy-driver Proxy service log driver 103 | -lpms | --log-nginx-proxy-max_size Proxy service log max file size 104 | -lpmf | --log-nginx-proxy-max_file Proxy service log max files 105 | -lgd | --log-docker-gen-driver Docker-gen service log driver 106 | -lgms | --log-docker-gen-max_size Docker-gen service log max file size 107 | -lgmf | --log-docker-gen-max_file Docker-gen service log max files 108 | -lld | --log-letsencrypt-driver Let's Encrypt service log driver 109 | -llms | --log-letsencrypt-max_size Let's Encrypt service log max size 110 | -llmf | --log-letsencrypt-max_file Let's Encrypt service log max files 111 | 112 | Proxy port binding 113 | -phttp | --port-http Proxy http port (default: 80) 114 | -phttps | --port-https Proxy https port (default: 443) 115 | 116 | Proxy SSL policy 117 | -sp | --ssl-policy Proxy SSL suport 118 | (default: Mozilla-Intermediate) 119 | 120 | Default Host 121 | -df | --default-host The default host where nginx-proxy will redirect all requests to 122 | the container that matches the VIRTUAL_HOST 123 | 124 | IPv6 support 125 | --activate-ipv6 Use to activate IPv6 support 126 | -ipv6 | --ipv6-address IPv6 address for external connectivity 127 | --ipv6-subnet You must inform IPv6 subnet to create 128 | a docker network 129 | (default: 2001:db8:1:1::/112) 130 | 131 | Other options 132 | --yes Set "yes" to all, use it with caution 133 | --debug Show script debug options 134 | --silent Hide all script message 135 | -dr | --docker-rootless Add Docker rootless support by adding the 136 | the current user's $XDG_RUNTIME_DIR and 137 | concat with the '/docker.sock' in the 138 | DOCKER_HOST_ROOTLESS_PATH .env file. 139 | -h | --help Display this help 140 | 141 | ${reset} 142 | USAGE 143 | exit 1 144 | } 145 | -------------------------------------------------------------------------------- /bin/revert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This script revert the fresh start script to git branch 5 | # 6 | # Source: https://github.com/evertramos/nginx-proxy-automation 7 | # 8 | 9 | # Get the script name and its real file path 10 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 11 | SCRIPT_NAME="${0##*/}" 12 | CURRENT_PATH=$(pwd) 13 | 14 | # Go to script path if not there 15 | cd "${SCRIPT_PATH}/../" 16 | 17 | # Stop compose 18 | #export COMPOSE_INTERACTIVE_NO_CLI=1 19 | docker compose down || true 20 | 21 | # Remove newly created files/folder 22 | sudo rm -rf ./data .env docker-compose.yml.backup_* .env.backup_* .env 23 | 24 | # Restore docker-compose.yml 25 | git restore docker-compose.yml 26 | 27 | echo 'Repo restored!' 28 | 29 | exit 0 30 | 31 | -------------------------------------------------------------------------------- /bin/ssl_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #----------------------------------------------------------------------- 4 | # 5 | # test-proxy script - testing nginx-proxy 6 | # 7 | # https://github.com/evertramos/nginx-proxy-automation 8 | # 9 | # Script developed by 10 | # Evert Ramos 11 | # 12 | # Copyright Evert Ramos 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # Set up your DOMAIN 17 | if [ $# -eq 0 ]; then 18 | echo "Please inform your domain name to test your proxy." 19 | echo "./test.sh $1" 20 | exit 1 21 | else 22 | DOMAIN=$1 23 | fi 24 | 25 | # Read your .env file 26 | source ./../.env 27 | 28 | # Testing your proxy 29 | docker run -d -e VIRTUAL_HOST=$DOMAIN -e LETSENCRYPT_HOST=$DOMAIN --network=$NETWORK --rm --name test-web httpd:alpine 30 | 31 | exit 0 32 | -------------------------------------------------------------------------------- /bin/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #----------------------------------------------------------------------- 4 | # 5 | # test-proxy script - testing nginx-proxy 6 | # 7 | # https://github.com/evertramos/nginx-proxy-automation 8 | # 9 | # Script developed by 10 | # Evert Ramos 11 | # 12 | # Copyright Evert Ramos 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # Stop if test is running 17 | docker stop test-web 18 | 19 | exit 0 20 | -------------------------------------------------------------------------------- /bin/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #----------------------------------------------------------------------- 4 | # 5 | # test-proxy script - testing nginx-proxy 6 | # 7 | # https://github.com/evertramos/nginx-proxy-automation 8 | # 9 | # Script developed by 10 | # Evert Ramos 11 | # 12 | # Copyright Evert Ramos 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # Set up your DOMAIN 17 | if [ $# -eq 0 ]; then 18 | echo "Please inform your domain name to test your proxy." 19 | echo "./test.sh $1" 20 | exit 1 21 | else 22 | DOMAIN=$1 23 | fi 24 | 25 | # Read your .env file 26 | source ./../.env 27 | 28 | # Testing your proxy 29 | docker run -d -e VIRTUAL_HOST=$DOMAIN --network=$NETWORK --rm --name test-web httpd:alpine 30 | 31 | exit 0 32 | -------------------------------------------------------------------------------- /bin/update-branch-name.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This script updates the branch name to 'main' 5 | # 6 | # Source: https://github.com/evertramos/nginx-proxy-automation 7 | # 8 | 9 | # Get the script name and its real file path 10 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 11 | SCRIPT_NAME="${0##*/}" 12 | CURRENT_PATH=$(pwd) 13 | 14 | # Go to script path if not there 15 | cd "${SCRIPT_PATH}/../" 16 | 17 | # Check branch name 18 | BRANCH_NAME="$(git symbolic-ref HEAD 2>/dev/null | awk -F'/' '{print $3}')" 19 | if [[ -z ${BRANCH_NAME} ]]; then 20 | echo "[ERROR] No branch was found at ${SCRIPT_PATH}." 21 | fi 22 | 23 | if [[ "${BRANCH_NAME}" == "master" ]]; then 24 | echo "Your local branch 'master' will be renamed to 'main'" 25 | git branch -m master main 26 | git fetch origin 27 | git branch -u origin/main main 28 | git remote set-head origin -a 29 | fi 30 | 31 | if [[ "${BRANCH_NAME}" == "main" ]]; then 32 | echo "Your local branch is already renamed to 'main'" 33 | fi 34 | 35 | if [[ ! "${SCRIPT_PATH}" == "${CURRENT_PATH}" ]]; then 36 | cd - 1>/dev/null 2>/dev/null 37 | fi 38 | 39 | exit 0 40 | 41 | -------------------------------------------------------------------------------- /bin/update-checksum.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #----------------------------------------------------------------------- 4 | # 5 | # Update checksum in .env files 6 | # 7 | # Part of https://github.com/evertramos/nginx-proxy-automation 8 | # 9 | # Script written by 10 | # Evert Ramos 11 | # 12 | # Copyright Evert Ramos 13 | # 14 | #----------------------------------------------------------------------- 15 | 16 | # Bash settings (do not mess with it) 17 | shopt -s nullglob globstar 18 | 19 | # Get the script name and its file real path 20 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 21 | SCRIPT_NAME="${0##*/}" 22 | 23 | # Source basescript functions 24 | source $SCRIPT_PATH"/../basescript/bootstrap.sh" 25 | 26 | # Source localscripts 27 | source $SCRIPT_PATH"/localscript/bootstrap.sh" 28 | 29 | # Log 30 | printf "${energy} Start execution '${SCRIPT_PATH}/${SCRIPT_NAME} " 31 | log "Start execution" 32 | log "$@" 33 | 34 | #----------------------------------------------------------------------- 35 | # Initial check - DO NOT CHANGE SETTINGS BELOW 36 | #----------------------------------------------------------------------- 37 | 38 | # Check if there is an .env file in local folder 39 | run_function check_local_env_file 40 | 41 | # Specific PID File if needs to run multiple scripts 42 | NEW_PID_FILE=${PID_FILE_FRESH_INSTALL:-".update_checksum"} 43 | 44 | # Run initial check function 45 | run_function starts_initial_check $NEW_PID_FILE 46 | 47 | # Save PID 48 | system_save_pid $NEW_PID_FILE 49 | 50 | # DO NOT CHANGE ANY OPTIONS ABOVE THIS LINE! 51 | 52 | #----------------------------------------------------------------------- 53 | # [function] Undo script actions 54 | #----------------------------------------------------------------------- 55 | local_undo_restore() { 56 | # local LOCAL_KEEP_RESTORE_FILES 57 | # 58 | # LOCAL_KEEP_RESTORE_FILES=${1:-$KEEP_RESTORE_FILES} 59 | 60 | echoerror \ 61 | "It seems something went wrong! \ 62 | \nRunning '${FUNCNAME[0]} to try to UNDO all actions done by this script. \ 63 | \nPlease make sure everything was put it back in place." false 64 | 65 | # If docker network was created 66 | # if [[ "$ACTION_DOCKER_NETWORK_CREATED" == true ]]; then 67 | # [[ "$SILENT" != true ]] && echowarning "[undo] Deleting created docker network '$DOCKER_NETWORK_NAME'." 68 | # run_function docker_network_remove $DOCKER_NETWORK_NAME 69 | # ACTION_DOCKER_NETWORK_CREATED=false 70 | # fi 71 | 72 | exit 0 73 | } 74 | 75 | #----------------------------------------------------------------------- 76 | # Verify checksum of docker-compose.yml and .env.sample files 77 | #----------------------------------------------------------------------- 78 | run_function md5_check_checksum "$SCRIPT_PATH/../" "docker-compose.yml" $MD5_SUM_DOCKER_COMPOSE 79 | if [[ ! "$MD5_CHECKSUM" == true ]]; then 80 | DOCKER_COMPOSE_CHECKSUM=$(md5sum "$SCRIPT_PATH/../docker-compose.yml" | awk '{print $1}') 81 | echowarning "Updating the checksum for 'MD5_SUM_DOCKER_COMPOSE'" 82 | run_function env_update_variable "$SCRIPT_PATH" "MD5_SUM_DOCKER_COMPOSE" "$DOCKER_COMPOSE_CHECKSUM" 83 | else 84 | echosuccess "Checksum for 'MD5_SUM_DOCKER_COMPOSE' is just fine!" 85 | fi 86 | 87 | run_function md5_check_checksum "$SCRIPT_PATH/../" ".env.sample" $MD5_SUM_ENV_SAMPLE 88 | if [[ ! "$MD5_CHECKSUM" == true ]]; then 89 | ENV_CHECKSUM=$(md5sum "$SCRIPT_PATH/../.env.sample" | awk '{print $1}') 90 | echowarning "Updating the checksum for 'MD5_SUM_ENV_SAMPLE'" 91 | run_function env_update_variable "$SCRIPT_PATH" "MD5_SUM_ENV_SAMPLE" "$ENV_CHECKSUM" 92 | else 93 | echosuccess "Checksum for 'MD5_SUM_ENV_SAMPLE' is just fine!" 94 | fi 95 | 96 | exit 0 97 | -------------------------------------------------------------------------------- /bin/update-nginx-template.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This script updates the branch name to 'main' 5 | # 6 | # Source: https://github.com/evertramos/nginx-proxy-automation 7 | # 8 | 9 | # Get the script name and its real file path 10 | SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" 11 | SCRIPT_NAME="${0##*/}" 12 | CURRENT_PATH=$(pwd) 13 | 14 | cd "${SCRIPT_PATH}/../" 15 | 16 | # Update template with the latest version of nginx template 17 | curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > nginx.tmpl 18 | 19 | cd - 1>/dev/null 2>/dev/null 20 | 21 | exit 0 22 | 23 | -------------------------------------------------------------------------------- /conf.d/realip.conf: -------------------------------------------------------------------------------- 1 | # 2 | # [WARNING] To enable this files you need to uncomment USE_NGINX_CONF_FILES=true in .env file 3 | # 4 | # [WARNING] Also, read all the comments in .env about NGINX use special conf files 5 | # 6 | 7 | # 8 | # Real IP Settings 9 | # 10 | # This option get user's real ip address 11 | # to be fowared to your service container 12 | 13 | # 14 | # Basic settings 15 | # 16 | # The option 'set_real_ip_from' 17 | # must correspont to your docker network address 18 | set_real_ip_from 172.16.0.0/12; 19 | set_real_ip_from 10.0.0.0/8; 20 | set_real_ip_from 192.168.0.0/16; 21 | 22 | # 23 | # CloudFlare settings 24 | # 25 | # If you CloudFlare and want to forward the 26 | # user's real IP to your app services you 27 | # must uncomment all lines below and be sure 28 | # to comment the lines of the "Basic settings" 29 | set_real_ip_from 103.21.244.0/22; 30 | set_real_ip_from 103.22.200.0/22; 31 | set_real_ip_from 103.31.4.0/22; 32 | set_real_ip_from 104.16.0.0/12; 33 | set_real_ip_from 108.162.192.0/18; 34 | set_real_ip_from 131.0.72.0/22; 35 | set_real_ip_from 141.101.64.0/18; 36 | set_real_ip_from 162.158.0.0/15; 37 | set_real_ip_from 172.64.0.0/13; 38 | set_real_ip_from 173.245.48.0/20; 39 | set_real_ip_from 188.114.96.0/20; 40 | set_real_ip_from 190.93.240.0/20; 41 | set_real_ip_from 197.234.240.0/22; 42 | set_real_ip_from 198.41.128.0/17; 43 | set_real_ip_from 2400:cb00::/32; 44 | set_real_ip_from 2606:4700::/32; 45 | set_real_ip_from 2803:f800::/32; 46 | set_real_ip_from 2405:b500::/32; 47 | set_real_ip_from 2405:8100::/32; 48 | set_real_ip_from 2c0f:f248::/32; 49 | set_real_ip_from 2a06:98c0::/29; 50 | 51 | # 52 | # Header for Real IP Address 53 | # 54 | real_ip_header X-Forwarded-For; 55 | #real_ip_header X-Real-IP; 56 | real_ip_recursive on; 57 | 58 | -------------------------------------------------------------------------------- /conf.d/servertokens.conf: -------------------------------------------------------------------------------- 1 | # 2 | # [WARNING] To enable this files you need to uncomment USE_NGINX_CONF_FILES=true in .env file 3 | # 4 | # [WARNING] Also, read all the comments in .env about NGINX use special conf files 5 | # 6 | 7 | server_tokens off; 8 | -------------------------------------------------------------------------------- /conf.d/uploadsize.conf: -------------------------------------------------------------------------------- 1 | # 2 | # [WARNING] In order to enable this option in the proxy you must run the fresh start script with the option `--use-nginx-conf-files` 3 | # 4 | 5 | client_max_body_size 100m; 6 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | nginx-proxy-automation-web: 3 | image: nginx:${NGINX_IMAGE_VERSION:-stable-alpine} 4 | labels: 5 | com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true" 6 | container_name: ${NGINX_WEB_SEVICE_NAME:-nginx-proxy-automation-web} 7 | restart: always 8 | ports: 9 | - "${IPv4:-0.0.0.0}:${DOCKER_HTTP_:-80}:80" 10 | - "${IPv4:-0.0.0.0}:${DOCKER_HTTPS:-443}:443" 11 | # - "${IPv6:-::0}:${DOCKER_HTTP_:-80}:80" 12 | # - "${IPv6:-::0}:${DOCKER_HTTPS:-443}:443" 13 | environment: 14 | SSL_POLICY: ${SSL_POLICY:-Mozilla-Intermediate} 15 | # DEFAULT_HOST: ${DEFAULT_HOST} 16 | # ENABLE_IPV6: "true" 17 | volumes: 18 | - ${NGINX_FILES_PATH:-./data}/conf.d:/etc/nginx/conf.d 19 | - ${NGINX_FILES_PATH:-./data}/vhost.d:/etc/nginx/vhost.d 20 | - ${NGINX_FILES_PATH:-./data}/html:/usr/share/nginx/html 21 | - ${NGINX_FILES_PATH:-./data}/certs:/etc/nginx/certs:ro 22 | - ${NGINX_FILES_PATH:-./data}/htpasswd:/etc/nginx/htpasswd:ro 23 | logging: 24 | driver: ${NGINX_WEB_LOG_DRIVER:-json-file} 25 | options: 26 | max-size: ${NGINX_WEB_LOG_MAX_SIZE:-4m} 27 | max-file: ${NGINX_WEB_LOG_MAX_FILE:-10} 28 | 29 | nginx-proxy-automation-gen: 30 | image: nginxproxy/docker-gen:${DOCKER_GEN_IMAGE_VERSION:-0.7.7} 31 | command: -notify-sighup ${NGINX_WEB_SEVICE_NAME:-nginx-proxy-automation-web} -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf 32 | container_name: ${DOCKER_GEN_SEVICE_NAME:-nginx-proxy-automation-gen} 33 | restart: always 34 | volumes: 35 | - ${NGINX_FILES_PATH:-./data}/conf.d:/etc/nginx/conf.d 36 | - ${NGINX_FILES_PATH:-./data}/vhost.d:/etc/nginx/vhost.d 37 | - ${NGINX_FILES_PATH:-./data}/html:/usr/share/nginx/html 38 | - ${NGINX_FILES_PATH:-./data}/certs:/etc/nginx/certs:ro 39 | - ${NGINX_FILES_PATH:-./data}/htpasswd:/etc/nginx/htpasswd:ro 40 | - ${DOCKER_HOST_ROOTLESS_PATH:-/var/run/docker.sock}:/tmp/docker.sock:ro 41 | - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro 42 | logging: 43 | driver: ${NGINX_GEN_LOG_DRIVER:-json-file} 44 | options: 45 | max-size: ${NGINX_GEN_LOG_MAX_SIZE:-2m} 46 | max-file: ${NGINX_GEN_LOG_MAX_FILE:-10} 47 | 48 | nginx-proxy-automation-letsencrypt: 49 | image: nginxproxy/acme-companion:${NGINX_PROXY_COMPANION_IMAGE_VERSION:-2.1} 50 | container_name: ${LETS_ENCRYPT_SEVICE_NAME:-nginx-proxy-automation-letsencrypt} 51 | restart: always 52 | volumes: 53 | - ${NGINX_FILES_PATH:-./data}/conf.d:/etc/nginx/conf.d 54 | - ${NGINX_FILES_PATH:-./data}/vhost.d:/etc/nginx/vhost.d 55 | - ${NGINX_FILES_PATH:-./data}/html:/usr/share/nginx/html 56 | - ${NGINX_FILES_PATH:-./data}/certs:/etc/nginx/certs:rw 57 | - ${NGINX_FILES_PATH:-./data}/acme.sh:/etc/acme.sh 58 | - ${DOCKER_HOST_ROOTLESS_PATH:-/var/run/docker.sock}:/var/run/docker.sock:ro 59 | environment: 60 | NGINX_DOCKER_GEN_CONTAINER: ${DOCKER_GEN_SEVICE_NAME:-nginx-proxy-automation-gen} 61 | NGINX_PROXY_CONTAINER: ${NGINX_WEB_SEVICE_NAME:-nginx-proxy-automation-web} 62 | DEFAULT_EMAIL: ${DEFAULT_EMAIL:-mail@yourdomain.tld} 63 | # ACME_CHALLENGE: "DNS-01" 64 | # ACMESH_DNS_API_CONFIG: |- 65 | # DNS_API: dns_cf 66 | # CF_Token: "${CLOUDFLARE_DNS_TOKEN}" 67 | logging: 68 | driver: ${NGINX_LETSENCRYPT_LOG_DRIVER:-json-file} 69 | options: 70 | max-size: ${NGINX_LETSENCRYPT_LOG_MAX_SIZE:-2m} 71 | max-file: ${NGINX_LETSENCRYPT_LOG_MAX_FILE:-10} 72 | 73 | networks: 74 | default: 75 | external: true 76 | name: ${NETWORK:-proxy} 77 | 78 | -------------------------------------------------------------------------------- /docs/HOWTO-Synology.md: -------------------------------------------------------------------------------- 1 | ## Port mapping 2 | Synology default installs a web server on port 80 blocking certificate generation. 3 | 4 | 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: 5 | 6 | # 7 | # Set the local exposed ports for http and https - this will allow you to run with a legacy web 8 | # server already installed for local use 9 | # 10 | # NOTE: For this to function your internet router must forward the official ports to the mapped ports - 11 | # in this example external port 80 to docker host 81 and external port 443 to docker host 444 12 | # 13 | DOCKER_HTTP=81 14 | DOCKER_HTTPS=444 15 | 16 | ## File permissions 17 | 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) 18 | 19 | mkdir -p data/certs 20 | mkdir data/htpasswd 21 | mkdir data/conf.d 22 | mkdir data/vhost.d 23 | mkdir data/html 24 | chgrp -R 101 data 25 | chmod -R g+rwx data 26 | 27 | Contributed by https://github.com/nicolailang/ 28 | -------------------------------------------------------------------------------- /docs/HOWTO-server-at-home.md: -------------------------------------------------------------------------------- 1 | # Home Server Testing 2 | This document provides basic troubleshooting for setting up `nginx-proxy-automation` on a home server. This includes the most common issues, but does not include all possible issues. 3 | 4 | Before following these steps, be sure to understand and follow all instructions in the primary [README](https://github.com/evertramos/nginx-proxy-automation/blob/master/docs/README.md) documentation. 5 | 6 | ## Debugging Failed Connections 7 | 8 | Start diagnosing as close to the server as possible, then move outwards. 9 | 10 | For testing ports, here is a list of common network command line (cli) tools for use: 11 | - [nmap](https://nmap.org) 12 | - [netcat](https://sectools.org/tool/netcat/) 13 | - [telnet](https://manpages.org/telnet) 14 | 15 | 1. Without using `nginx-proxy-automation`, run the container on the server, open the port as you normally would (i.e. `-p 9000:9000`), and attempt to see if the port is available (on the server) after running. You can test if the port is open using one of the common network cli tools, or other possible tools (i.e. [netstat](https://linux.die.net/man/8/netstat)). For example if you have exposed port 9000, running `nmap -p 9000 localhost` on the same server as the running Docker container, and it should return an open port. This tests if you may have a general issue with your docker setup. On failure, double check if you have setup any custom firewall rules or have setup `ufw` with Docker. 16 | 2. Perform the same steps as 1, but try testing the port from a different machine on the same subnet / LAN if possible. For example, running `nmap -p 9000 {SERVER-IP-ADDRESS}` should show an open connection. This tests if the server is exposing ports at all. This tests if you may have a firewall issue on the server that needs diagnosed. On failure, double check if you have setup any custom firewall rules or have setup `ufw` with Docker. 17 | 3. If you are using port forwarding on a router: Without using `nginx-proxy-automation`, run the container on the server, assuming you have successfully tested connecting to the container on another computer in the same LAN, and forward the port from the router to server's open port. Then you can run `nmap -p 9000 {PUBLIC-ROUTER-IP-ADDRESS-OR-DOMAIN-NAME}`, and it will show an open connection. This will test if you have properly forwarded the port. On failure, you will need to diagnose your port forwarding rules, and may need to consult your router manual. Be sure you are **not** using the local IP address of your router (i.e. 192.168.1.1 is a common local IP address, and that will not work for this test). 18 | 19 | ## Port Forwarding 20 | If you are using port forwarding, it is highly recommended to connect via your own registered domain using [DDNS](https://en.wikipedia.org/wiki/Dynamic_DNS). There is a chance your ISP will change the public address of your router. Using DDNS will ensure that the domain pointing to your router is using the latest public IP address of your router. 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # NGINX Proxy Automation 🔥 2 | 3 | ## What this project does 4 | 5 | This script will _power up_ your new server with the [*nginx-proxy*](https://github.com/nginx-proxy/nginx-proxy), where you will be able to host multiple sites, 6 | auto renewing Let´s Encrypt certificates! ❤️ 7 | 8 | We strongly recommend you (please do! 🙏) to read all documentation before starting in production as well as the [nginx-proxy docs](https://github.com/nginx-proxy/nginx-proxy). 9 | 10 | > To access the previous version of this project please access [version 0.4](https://github.com/evertramos/nginx-proxy-automation/tree/v0.4). 11 | 12 | ### Upgrading from previous version 13 | 14 | If you are upgrading from the previous version please follow the guide below carefully: 15 | 16 | https://github.com/evertramos/nginx-proxy-automation/blob/master/docs/upgrade-guide.md 17 | 18 | ## Prerequisites 19 | 20 | 1. 🐧 Linux! (just in case...) 21 | 22 | > Please check all requirements at [requirements](/docs/requirements.md). 23 | 24 | In order to use this compose file (docker-compose.yml) you must have: 25 | 26 | 2. 🐋 Docker installed (https://docs.docker.com/engine/installation/) 27 | 28 | 3. Docker-compose installed (https://docs.docker.com/compose/install/) 29 | 30 | > I have an [easy-server](https://github.com/evertramos/easy-server) for myself which I use to install 31 | > docker and docker-compose in new servers and some aliases and other stuff. Feel free to use it, **but** 32 | > it is not related to this repo and maintainance it's for my own use only. Check './install/docker' folder. 33 | 34 | Also, you will need to make sure you have: 35 | 36 | 4. Port 80 and 443 available for binding - which means apache/nginx or other web services should not be 37 | running in your server 38 | 39 | 5. Server must be accessible by a public IP address 40 | 41 | ## How to use it 42 | 43 | 1. Clone this repository **using the option _--recurse-submodules_**: 44 | 45 | ```bash 46 | git clone --recurse-submodules https://github.com/evertramos/nginx-proxy-automation.git proxy 47 | ``` 48 | 49 | > Make sure you use the option '--recurse-submodules' once we use an external module in this project, please check 50 | > [basescript](https://github.com/evertramos/basescript) 51 | 52 | > Please note we use 'proxy' as folder at the end. But you can change it to whatever fits you better 53 | 54 | 2. 🚀 Run the script 'fresh_start.sh' 55 | 56 | ```bash 57 | cd proxy/bin 58 | ./fresh-start.sh 59 | ``` 60 | This script will walk you through all config process. 61 | 62 | When it finishes you are good to go! :checkered_flag: 63 | 64 | > ✈️ If you are in a 'hurry' just run `$ ./fresh-start.sh --yes -e your_email@domain --skip-docker-image-check` 65 | 66 | > ⚠️ You can check all available options to run the script `$ ./fresh-start.sh --help` 67 | 68 | > 🗒️ From version _v0.3_ the script will output logs to _/var/log/basescript.log_ 69 | 70 | 3. Fire your new site with the following options: 71 | 72 | ```yaml 73 | VIRTUAL_HOST=your.domain.com 74 | LETSENCRYPT_HOST=your.domain.com 75 | LETSENCRYPT_EMAIL=your.email@your.domain.com 76 | NETWORK=proxy 77 | ``` 78 | 79 | The fresh start script asked you for the proxy network name if you changed set a name differente from 80 | the default please update the option *'NETWORK'* in the examples below before running it. 81 | 82 | - Simple site without Let's Encrypt certificate 83 | ```bash 84 | docker run -d -e VIRTUAL_HOST=your.domain.com \ 85 | --network=proxy \ 86 | --name my_app \ 87 | httpd:alpine 88 | ``` 89 | 90 | - To have SSL in your web/app you must add the option `-e LETSENCRYPT_HOST=your.domain.com`, as follow: 91 | 92 | ```bash 93 | docker run -d -e VIRTUAL_HOST=your.domain.com \ 94 | -e LETSENCRYPT_HOST=your.domain.com \ 95 | -e LETSENCRYPT_EMAIL=your.email@your.domain.com \ 96 | --network=proxy \ 97 | --name my_app \ 98 | httpd:alpine 99 | ``` 100 | 101 | > You don´t need to open port *443* in your container, the certificate validation is managed by the web proxy 102 | 103 | > Please note that when running a new container to generate certificates with Let's Encrypt 104 | > (`-e LETSENCRYPT_HOST=your.domain.com`), it may take a few minutes 105 | 106 | 107 | ## Further Options 108 | 109 | 1. Basic Authentication Support 110 | 111 | In order to be able to secure your virtual host with basic authentication, you must create a htpasswd file 112 | within `${NGINX_FILES_PATH}/htpasswd/${VIRTUAL_HOST}` via: 113 | 114 | ```bash 115 | sudo sh -c "echo -n '[username]:' >> ${NGINX_FILES_PATH}/htpasswd/${VIRTUAL_HOST}" 116 | sudo sh -c "openssl passwd -apr1 >> ${NGINX_FILES_PATH}/htpasswd/${VIRTUAL_HOST}" 117 | ``` 118 | 119 | > Please replace the `${NGINX_FILES_PATH}` with real path to information, replace `[username]` with your username and `${VIRTUAL_HOST}` with your host's domain. You will be prompted for a password. 120 | 121 | 2. Using different networks 122 | 123 | If you want to use more than one network to better organize your environment you could set the option `SERVICE_NETWORK` in our `.env.sample` or you can just create your own network and attach all your containers as of: 124 | 125 | ```bash 126 | docker network create myownnetwork 127 | docker network connect myownnetwork nginx-web 128 | docker network connect myownnetwork nginx-gen 129 | docker network connect myownnetwork nginx-letsencrypt 130 | ``` 131 | 132 | 3. Ports 133 | 134 | If your service container runs on port 8545 you probably will need to add the `VIRTUAL_PORT` environment variable to your container, 135 | in the `docker-compose.yml`, so it can be proxied, as of: 136 | 137 | ```bash 138 | parity 139 | image: parity/parity:v1.8.9 140 | [...] 141 | environment: 142 | [...] 143 | VIRTUAL_PORT: 8545 144 | ``` 145 | 146 | Or as of below: 147 | 148 | ```bash 149 | docker run [...] -e VIRTUAL_PORT=8545 [...] 150 | ``` 151 | 152 | 4. Restarting proxy container 153 | 154 | In some cases you will need to restart the proxy in order to read, as an example, the Basic Auth, if you set it after your service container is already up and running. So, the way I use to restart the proxy (NGINX) is as following, which has no downtime: 155 | 156 | ```bash 157 | docker exec -it ${NGINX_WEB} nginx -s reload 158 | ``` 159 | 160 | Where *${NGINX_WEB}* is your proxy container name, which in the original `.env` file is set as *nginx-web*. 161 | 162 | 5. **sudo** options 163 | 164 | If you need to save the nginx-proxy data files in a folder which the user running 'fresh-start.sh' script does not have access, you might accomplish that using _sudo_. In order to allow the script to run some commands with _sudo_ you need to set _true_ to the variable ['ALLOW_RUN_WITH_SUDO'](https://github.com/evertramos/nginx-proxy-automation/blob/d48b2477ed28cbda37738046079e35df219ba3e9/.env.sample#L20) at '.env.sample' file **before** running fresh-start.sh script, as of: 165 | 166 | ```bash 167 | # Allow run commands with sudo if needed 168 | ALLOW_RUN_WITH_SUDO=true 169 | ``` 170 | 171 | ## Testing nginx-proxy 172 | 173 | 1. Run the script `test.sh` informing your domain already configured in your DNS to point out to your server as follow: 174 | 175 | ```bash 176 | ./test.sh your.domain.com 177 | ``` 178 | 179 | or simply run: 180 | 181 | ```bash 182 | docker run -dit -e VIRTUAL_HOST=your.domain.com --network=proxy --name test-web httpd:alpine 183 | ``` 184 | 185 | > If you want to test the Let's Encrypt certificate as well use `ssl_test.sh your.domain.com` 186 | 187 | Access your browser with your domain! 188 | 189 | To stop and remove your test container run our `stop.sh` script: 190 | 191 | ```bash 192 | ./stop.sh 193 | ``` 194 | 195 | Or simply run: 196 | 197 | ```bash 198 | docker stop test-web && docker rm test-web 199 | ``` 200 | 201 | ## **PRODUCTION** ⚠️ [IMPORTANT] 202 | 203 | If you are using this project in production enviroment, check all license involved and consider the following recomendation: 204 | 205 | - [rootless docker](https://docs.docker.com/engine/security/rootless/) 206 | - [docker compose files](https://docs.docker.com/compose/production/) 207 | 208 | ## Other projects using nginx-proxy 209 | Following are links to docker containers using this web proxy: 210 | 1. [docker-wordpress-letsencrypt](https://github.com/evertramos/docker-wordpress-letsencrypt) 211 | 2. [docker-portainer-letsencrypt](https://github.com/evertramos/docker-portainer-letsencrypt) 212 | 3. [docker-nextcloud-letsencrypt](https://github.com/evertramos/docker-nextcloud-letsencrypt) 213 | 4. [docker-registry-letsencrypt](https://github.com/evertramos/docker-registry-letsencrypt) 214 | 5. [gitlab-docker-letsencrypt](https://github.com/steevepay/gitlab-docker-letsencrypt) 215 | 6. [docker-webtrees-letsencrypt](https://github.com/mstroppel/docker-webtrees-letsencrypt) 216 | 217 | ## Running this Proxy on a Synology NAS 218 | Please checkout this [howto](https://github.com/evertramos/nginx-proxy-automation/blob/master/docs/HOWTO-Synlogy.md). 219 | 220 | -------------------------------------------------------------------------------- /docs/cloudflare.md: -------------------------------------------------------------------------------- 1 | # Cloudflare integration 2 | 3 | If using Cloudflare services, an API Token to allow your server to validate your domain with DNS-01 might be needed. 4 | 5 | > We recommend using Cloudflare for a couple of reasons... 6 | 7 | Follow the steps below to use DNS-01: 8 | 9 | ## 1. Generate an API Token for ACME DNS-01 10 | 11 | In Cloudflare go to your profile and find API Token option: 12 | ![image](https://github.com/user-attachments/assets/bbc3d316-7f71-4022-abf5-dfe0e704dadf) 13 | 14 | You can manually create one or use the _'Edit zone DNS'_ template. Remember to add your domains which you would like to allow this token to have access to it and the source IP address: 15 | ![image](https://github.com/user-attachments/assets/42bc2833-6ddb-44ac-9e6b-cea72d0f0ee5) 16 | 17 | Save your token and place it in .env at CLOUDFLARE_DNS_TOKEN. 18 | 19 | ## 2. Activate in your nginx proxy 20 | 21 | Uncomment the following lines: 22 | https://github.com/evertramos/nginx-proxy-automation/blob/462b224ce4fd9dce4b2b796e2b4524d4ee36b084/docker-compose.yml#L63-L66 23 | 24 | And restart your service running `docker compose up &` at your root folder. 25 | 26 | ## Disclaimer 27 | 28 | As of [acme-compnation](https://github.com/nginx-proxy/acme-companion) if we can not comply to use HTTP-01, using DNS-01 could be used, as also per [acme.sh](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) as well. 29 | So, following [acme-compnation instruction ](https://github.com/nginx-proxy/acme-companion/blob/main/docs/Let's-Encrypt-and-ACME.md#dns-01-acme-challenge) a global API Key could be used, but we do not like this idea much due to security resons, reason why we suggest creating a more restrict API Token as indicated above. 30 | 31 | -------------------------------------------------------------------------------- /docs/requirements.md: -------------------------------------------------------------------------------- 1 | # Requirements to run this automation script 2 | 3 | 4 | ## Environment 5 | - Linux 6 | 7 | ## Softwares 8 | - Bash 9 | - Docker 10 | - Docker Compose 11 | - Git 12 | - Curl 13 | - Dpkg 14 | - Md5sum 15 | 16 | ## Used functions 17 | - sudo 18 | - source 19 | - cd 20 | - cp 21 | - mv 22 | - dirname 23 | - type 24 | - command 25 | - systemctl 26 | - echo 27 | - printf 28 | - read 29 | - sed 30 | - awk 31 | - wget 32 | - cat 33 | - cut 34 | - head 35 | - tr 36 | - grep 37 | - rm 38 | - trap 39 | - dpkg 40 | - tput 41 | - md5sum 42 | - ip 43 | - git 44 | - docker 45 | - docker-compose 46 | - curl 47 | -------------------------------------------------------------------------------- /docs/upgrade-guide.md: -------------------------------------------------------------------------------- 1 | # Upgrading guide 2 | 3 | Here we will try to cover all aspects we faced in a real production environment when migrating from the previous version of this project to the newst version. 4 | 5 | ## From v0.4 to v0.5 6 | 7 | The version v0.5 was a big step into automation. We 'conquer the world'! 8 | 9 | > I update one of the production server and got a _96 seconds_ of downtime, with no complaint from clients. 10 | > Some of them did not even notice, but all were advised about the update and the possible downtime in case of failure. 11 | 12 | > If you can not afford this downtime there is a couple way around on this but you will need 13 | a couple things... new server (temporary), set a dns rules to create the new certificates 14 | copy all files to the new server and do the following, after all is ready, redirect the dns 15 | to the new server and than copy the temp server to the production, fire all services, test 16 | and redirect the dns to the new server. Be aware that changes made during this proccess might 17 | need to be updated in the containers when syncing files from one server to another. 18 | 19 | So, let's go. First thing first! 20 | 21 | 1. Backup EVERYTHING! I would suggest backup in the server and somewhere else (not in the server) 22 | 23 | 2. Update the git repo with the new version (:warning:) 24 | 25 | 2.1 Copy _docker-compose.yml_ (or the _docker-compose-multiple-networks.yml_ if you used this option) and _.env_ file 26 | 27 | ```bash 28 | $ cp docker-compose.yml docker-compose-old.yml 29 | $ cp .env .env-old 30 | ``` 31 | 32 | > We will use this do stop the current services 33 | 34 | 2.2 Reset all changes in the repo 35 | 36 | This is required to update to the latest version 37 | 38 | ```bash 39 | $ git reset --hard 40 | ``` 41 | 42 | 2.3 Pull and Checkout master 43 | 44 | ```bash 45 | $ git pull origin master 46 | $ git checkout master 47 | ``` 48 | 49 | 2.4 Set the **basescript** submodule 50 | 51 | If you notice the submodule folder used in this project ([basescript](https://github.com/evertramos/basescript/)) 52 | is present in the master branch we just checkout, but it is empty, so we need to fix it (init and update). 53 | 54 | ```bash 55 | $ git submodule init 56 | $ git submodule update 57 | ``` 58 | 59 | > The _basescript_ folder should not be empty after the commands above 60 | 61 | 3. Run the _fresh-start.sh_ script (:construction:) 62 | 63 | Here we will run the _fresh-start.sh_ script in order to create all new settings that we will use. 64 | Please do it carefully. You might use different names for proxy services. 65 | 66 | ```bash 67 | $ cd bin 68 | $ ./fresh-start.sh 69 | ``` 70 | 71 | In most cases you will get the following _'error'_, which is expected: 72 | 73 | ![fresh-start-expected-error](https://user-images.githubusercontent.com/905951/113016796-33aaa080-9155-11eb-845d-aa712294236d.png) 74 | 75 | The error above is related to port binding, once port 80 is already binded to the current nginx-proxy container. 76 | 77 | > [IMPORTANT] If you use the *same service name* for all containers and the same network name you might not receive the error above 78 | > and you should be ready to go at this point. Check the your running sites at the browser to see if everything is up and running. 79 | 80 | ⚠️ if you do not get the error above and your sites are NOT working, you might checkthe network name and go for the next item. 81 | 82 | 4. Adding the running containers to the new network 83 | 84 | If you keep the same network name you might skip this item, but if not, you must add all running containers to the new network 85 | created by the _fresh-start.sh_ script. 86 | 87 | ```bash 88 | $ docker network connect [YOUR_NEW_NETWORK_NAME] [CONTAINER_NAME] 89 | ``` 90 | 91 | > Run the command above for all containers connected to the proxy and remember to update the network name in the docker-compose file 92 | > for the all sites 93 | 94 | 5. Restart proxy with new service 95 | 96 | At this point all sites should be still up and running, so keep it cool and let's see if all will work as expected. 97 | 98 | After all containers are connected to the new proxy network (if the case) you will stop the current proxy services and start the new one. 99 | We did it in one command line to reduce the downtime. 100 | 101 | ```bash 102 | $ docker-compose --file docker-compose-old.yml down && docker-compose up -d 103 | ``` 104 | 105 | Check your sites to see if it is all running, if some of them are not working, you might check the letsencrypt container logs to see if 106 | there was a problem issuing new certificates. 107 | 108 | If something else happen and you must reverse it quickly just follow the next step. But try to check the logs first, it might take a few 109 | minutes to fire new certificates with Let's Encrypt so, depending on the quantity of sites you are running in your server it might take 110 | some time to issue it all. 111 | 112 | 6. Reverting to the old proxy 113 | 114 | You can retore backup files and start the same exact environmen you had previously this upgrade guide, but there is a quicker way to restore your sites. 115 | Just run the following: 116 | 117 | ```bash 118 | $ docker-compose down && docker-compose --file docker-compose-old.yml --env-file .env-old up -d 119 | ``` 120 | 121 | > The command above will stop the new version and fire the previous version of your proxy, so, after this command evertyhing should 'be back to normal' 122 | > as it was before the update, but keep in mind to find the errors if they occured and update it. 123 | 124 | 7. Clean up 125 | 126 | After having all work done you might remove unused file such as: 127 | 128 | 129 | ```bash 130 | $ rm docker-compose-old.yml .env-old 131 | ``` 132 | 133 | > If you get any erros when updating please post on the [**upgrade discussion**](https://github.com/evertramos/basescript/discussions/5) (avoid creating new issues). 134 | -------------------------------------------------------------------------------- /nginx.tmpl: -------------------------------------------------------------------------------- 1 | # nginx-proxy{{ if $.Env.NGINX_PROXY_VERSION }} version : {{ $.Env.NGINX_PROXY_VERSION }}{{ end }} 2 | 3 | {{- /* 4 | * Global values. Values are stored in this map rather than in individual 5 | * global variables so that the values can be easily passed to embedded 6 | * templates (Go templates cannot access variables outside of their own 7 | * scope) and displayed in the debug endpoint output. 8 | */}} 9 | {{- $globals := dict }} 10 | {{- $_ := set $globals "containers" $ }} 11 | {{- $_ := set $globals "Env" $.Env }} 12 | {{- $_ := set $globals "Docker" $.Docker }} 13 | {{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }} 14 | 15 | {{- $config := dict }} 16 | {{- $_ := set $config "nginx_proxy_version" $.Env.NGINX_PROXY_VERSION }} 17 | {{- $_ := set $config "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 18 | {{- $_ := set $config "external_http_port" ($globals.Env.HTTP_PORT | default "80") }} 19 | {{- $_ := set $config "external_https_port" ($globals.Env.HTTPS_PORT | default "443") }} 20 | {{- $_ := set $config "sha1_upstream_name" ($globals.Env.SHA1_UPSTREAM_NAME | default "false" | parseBool) }} 21 | {{- $_ := set $config "default_root_response" ($globals.Env.DEFAULT_ROOT | default "404") }} 22 | {{- $_ := set $config "trust_default_cert" ($globals.Env.TRUST_DEFAULT_CERT | default "true") }} 23 | {{- $_ := set $config "trust_downstream_proxy" ($globals.Env.TRUST_DOWNSTREAM_PROXY | default "true" | parseBool) }} 24 | {{- $_ := set $config "enable_access_log" ($globals.Env.DISABLE_ACCESS_LOGS | default "false" | parseBool | not) }} 25 | {{- $_ := set $config "enable_ipv6" ($globals.Env.ENABLE_IPV6 | default "false" | parseBool) }} 26 | {{- $_ := set $config "prefer_ipv6_network" ($globals.Env.PREFER_IPV6_NETWORK | default "false" | parseBool) }} 27 | {{- $_ := set $config "ssl_policy" ($globals.Env.SSL_POLICY | default "Mozilla-Intermediate") }} 28 | {{- $_ := set $config "enable_debug_endpoint" ($globals.Env.DEBUG_ENDPOINT | default "false") }} 29 | {{- $_ := set $config "hsts" ($globals.Env.HSTS | default "max-age=31536000") }} 30 | {{- $_ := set $config "acme_http_challenge" ($globals.Env.ACME_HTTP_CHALLENGE_LOCATION | default "true") }} 31 | {{- $_ := set $config "enable_http2" ($globals.Env.ENABLE_HTTP2 | default "true") }} 32 | {{- $_ := set $config "enable_http3" ($globals.Env.ENABLE_HTTP3 | default "false") }} 33 | {{- $_ := set $config "enable_http_on_missing_cert" ($globals.Env.ENABLE_HTTP_ON_MISSING_CERT | default "true") }} 34 | {{- $_ := set $config "https_method" ($globals.Env.HTTPS_METHOD | default "redirect") }} 35 | {{- $_ := set $config "non_get_redirect" ($globals.Env.NON_GET_REDIRECT | default "301") }} 36 | {{- $_ := set $config "default_host" $globals.Env.DEFAULT_HOST }} 37 | {{- $_ := set $config "resolvers" $globals.Env.RESOLVERS }} 38 | {{- /* LOG_JSON is a shorthand that sets logging defaults to JSON format */}} 39 | {{- $_ := set $config "enable_json_logs" ($globals.Env.LOG_JSON | default "false" | parseBool) }} 40 | {{- $_ := set $config "log_format" $globals.Env.LOG_FORMAT }} 41 | {{- $_ := set $config "log_format_escape" $globals.Env.LOG_FORMAT_ESCAPE }} 42 | 43 | {{- $_ := set $globals "config" $config }} 44 | 45 | {{- $_ := set $globals "vhosts" (dict) }} 46 | {{- $_ := set $globals "networks" (dict) }} 47 | # Networks available to the container running docker-gen (which are assumed to 48 | # match the networks available to the container running nginx): 49 | {{- /* 50 | * Note: $globals.CurrentContainer may be nil in some circumstances due to 51 | * . For more context 52 | * see . 53 | */}} 54 | {{- if $globals.CurrentContainer }} 55 | {{- range sortObjectsByKeysAsc $globals.CurrentContainer.Networks "Name" }} 56 | {{- $_ := set $globals.networks .Name . }} 57 | # {{ .Name }} 58 | {{- else }} 59 | # (none) 60 | {{- end }} 61 | {{- else }} 62 | # /!\ WARNING: Failed to find the Docker container running docker-gen. All 63 | # upstream (backend) application containers will appear to be 64 | # unreachable. Try removing the -only-exposed and -only-published 65 | # arguments to docker-gen if you pass either of those. See 66 | # . 67 | {{- end }} 68 | 69 | {{- /* 70 | * Template used as a function to get a container's IP address. This 71 | * template only outputs debug comments; the IP address is "returned" by 72 | * storing the value in the provided dot dict. 73 | * 74 | * The provided dot dict is expected to have the following entries: 75 | * - "globals": Global values. 76 | * - "container": The container's RuntimeContainer struct. 77 | * 78 | * The return value will be added to the dot dict with key "ip". 79 | */}} 80 | {{- define "container_ip" }} 81 | {{- $ipv4 := "" }} 82 | {{- $ipv6 := "" }} 83 | # networks: 84 | {{- range sortObjectsByKeysAsc $.container.Networks "Name" }} 85 | {{- /* 86 | * TODO: Only ignore the "ingress" network for Swarm tasks (in case 87 | * the user is not using Swarm mode and names a network "ingress"). 88 | */}} 89 | {{- if eq .Name "ingress" }} 90 | # {{ .Name }} (ignored) 91 | {{- continue }} 92 | {{- end }} 93 | {{- if eq .Name "host" }} 94 | {{- /* Handle containers in host nework mode */}} 95 | {{- if (index $.globals.networks "host") }} 96 | # both container and proxy are in host network mode, using localhost IP 97 | {{- $ipv4 = "127.0.0.1" }} 98 | {{- continue }} 99 | {{- end }} 100 | {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }} 101 | {{- if and . .Gateway (not .Internal) }} 102 | # container is in host network mode, using {{ .Name }} gateway IP 103 | {{- $ipv4 = .Gateway }} 104 | {{- break }} 105 | {{- end }} 106 | {{- end }} 107 | {{- if $ipv4 }} 108 | {{- continue }} 109 | {{- end }} 110 | {{- end }} 111 | {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} 112 | # {{ .Name }} (unreachable) 113 | {{- continue }} 114 | {{- end }} 115 | {{- /* 116 | * Do not emit multiple `server` directives for this container if it 117 | * is reachable over multiple networks or multiple IP stacks. This avoids 118 | * accidentally inflating the effective round-robin weight of a server due 119 | * to the redundant upstream addresses that nginx sees as belonging to 120 | * distinct servers. 121 | */}} 122 | {{- if or $ipv4 $ipv6 }} 123 | # {{ .Name }} (ignored; reachable but redundant) 124 | {{- continue }} 125 | {{- end }} 126 | # {{ .Name }} (reachable) 127 | {{- if and . .IP }} 128 | {{- $ipv4 = .IP }} 129 | {{- end }} 130 | {{- if and . .GlobalIPv6Address }} 131 | {{- $ipv6 = .GlobalIPv6Address }} 132 | {{- end }} 133 | {{- if and (empty $ipv4) (empty $ipv6) }} 134 | # /!\ No IPv4 or IPv6 for this network! 135 | {{- end }} 136 | {{- else }} 137 | # (none) 138 | {{- end }} 139 | {{ if and $ipv6 $.globals.config.prefer_ipv6_network }} 140 | # IPv4 address: {{ if $ipv4 }}{{ $ipv4 }} (ignored; reachable but IPv6 prefered){{ else }}(none usable){{ end }} 141 | # IPv6 address: {{ $ipv6 }} 142 | {{- $_ := set $ "ip" (printf "[%s]" $ipv6) }} 143 | {{- else }} 144 | # IPv4 address: {{ if $ipv4 }}{{ $ipv4 }}{{ else }}(none usable){{ end }} 145 | # IPv6 address: {{ if $ipv6 }}{{ $ipv6 }}{{ if $ipv4 }} (ignored; reachable but IPv4 prefered){{ end }}{{ else }}(none usable){{ end }} 146 | {{- if $ipv4 }} 147 | {{- $_ := set $ "ip" $ipv4 }} 148 | {{- else if $ipv6}} 149 | {{- $_ := set $ "ip" (printf "[%s]" $ipv6) }} 150 | {{- end }} 151 | {{- end }} 152 | {{- end }} 153 | 154 | {{- /* 155 | * Template used as a function to get the port of the server in the given 156 | * container. This template only outputs debug comments; the port is 157 | * "returned" by storing the value in the provided dot dict. 158 | * 159 | * The provided dot dict is expected to have the following entries: 160 | * - "container": The container's RuntimeContainer struct. 161 | * 162 | * The return value will be added to the dot dict with key "port". 163 | */}} 164 | {{- define "container_port" }} 165 | {{- /* If only 1 port exposed, use that as a default, else 80. */}} 166 | # exposed ports (first ten):{{ range $index, $address := (sortObjectsByKeysAsc $.container.Addresses "Port") }}{{ if lt $index 10 }} {{ $address.Port }}/{{ $address.Proto }}{{ end }}{{ else }} (none){{ end }} 167 | {{- $default_port := when (eq (len $.container.Addresses) 1) (first $.container.Addresses).Port "80" }} 168 | # default port: {{ $default_port }} 169 | {{- $port := eq $.port "default" | ternary $default_port $.port }} 170 | # using port: {{ $port }} 171 | {{- $addr_obj := where $.container.Addresses "Port" $port | first }} 172 | {{- if and $addr_obj $addr_obj.HostPort }} 173 | # /!\ WARNING: Virtual port published on host. Clients 174 | # might be able to bypass nginx-proxy and 175 | # access the container's server directly. 176 | {{- end }} 177 | {{- $_ := set $ "port" $port }} 178 | {{- end }} 179 | 180 | {{- define "ssl_policy" }} 181 | {{- if eq .ssl_policy "Mozilla-Modern" }} 182 | ssl_protocols TLSv1.3; 183 | {{- /* 184 | * This ssl_ciphers directive is not used but necessary to get TLSv1.3 only. 185 | * see https://serverfault.com/questions/1023766/nginx-with-only-tls1-3-cipher-suites 186 | */}} 187 | ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; 188 | ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; 189 | ssl_prefer_server_ciphers off; 190 | {{- else if eq .ssl_policy "Mozilla-Intermediate" }} 191 | ssl_protocols TLSv1.2 TLSv1.3; 192 | 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'; 193 | ssl_prefer_server_ciphers off; 194 | {{- else if eq .ssl_policy "Mozilla-Old" }} 195 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; 196 | 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:@SECLEVEL=0'; 197 | ssl_prefer_server_ciphers on; 198 | {{- else if eq .ssl_policy "AWS-TLS13-1-3-2021-06" }} 199 | ssl_protocols TLSv1.3; 200 | {{- /* 201 | * This ssl_ciphers directive is not used but necessary to get TLSv1.3 only. 202 | * see https://serverfault.com/questions/1023766/nginx-with-only-tls1-3-cipher-suites 203 | */}} 204 | ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; 205 | ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; 206 | ssl_prefer_server_ciphers on; 207 | {{- else if eq .ssl_policy "AWS-TLS13-1-2-2021-06" }} 208 | ssl_protocols TLSv1.2 TLSv1.3; 209 | 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'; 210 | ssl_prefer_server_ciphers on; 211 | {{- else if eq .ssl_policy "AWS-TLS13-1-2-Res-2021-06" }} 212 | ssl_protocols TLSv1.2 TLSv1.3; 213 | ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; 214 | ssl_prefer_server_ciphers on; 215 | {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext1-2021-06" }} 216 | ssl_protocols TLSv1.2 TLSv1.3; 217 | 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'; 218 | ssl_prefer_server_ciphers on; 219 | {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext2-2021-06" }} 220 | ssl_protocols TLSv1.2 TLSv1.3; 221 | 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'; 222 | ssl_prefer_server_ciphers on; 223 | {{- else if eq .ssl_policy "AWS-TLS13-1-1-2021-06" }} 224 | ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; 225 | 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:@SECLEVEL=0'; 226 | ssl_prefer_server_ciphers on; 227 | {{- else if eq .ssl_policy "AWS-TLS13-1-0-2021-06" }} 228 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; 229 | 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:@SECLEVEL=0'; 230 | ssl_prefer_server_ciphers on; 231 | {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2020-10" }} 232 | ssl_protocols TLSv1.2; 233 | ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; 234 | ssl_prefer_server_ciphers on; 235 | {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2019-08" }} 236 | ssl_protocols TLSv1.2; 237 | 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'; 238 | ssl_prefer_server_ciphers on; 239 | {{- else if eq .ssl_policy "AWS-FS-1-2-2019-08" }} 240 | ssl_protocols TLSv1.2; 241 | 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'; 242 | ssl_prefer_server_ciphers on; 243 | {{- else if eq .ssl_policy "AWS-FS-1-1-2019-08" }} 244 | ssl_protocols TLSv1.1 TLSv1.2; 245 | 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:@SECLEVEL=0'; 246 | ssl_prefer_server_ciphers on; 247 | {{- else if eq .ssl_policy "AWS-FS-2018-06" }} 248 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 249 | 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:@SECLEVEL=0'; 250 | ssl_prefer_server_ciphers on; 251 | {{- else if eq .ssl_policy "AWS-TLS-1-2-Ext-2018-06" }} 252 | ssl_protocols TLSv1.2; 253 | 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'; 254 | ssl_prefer_server_ciphers on; 255 | {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} 256 | ssl_protocols TLSv1.2; 257 | 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'; 258 | ssl_prefer_server_ciphers on; 259 | {{- else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} 260 | ssl_protocols TLSv1.1 TLSv1.2; 261 | 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:@SECLEVEL=0'; 262 | ssl_prefer_server_ciphers on; 263 | {{- else if eq .ssl_policy "AWS-2016-08" }} 264 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 265 | 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:@SECLEVEL=0'; 266 | ssl_prefer_server_ciphers on; 267 | {{- else if eq .ssl_policy "AWS-2015-05" }} 268 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 269 | 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:@SECLEVEL=0'; 270 | ssl_prefer_server_ciphers on; 271 | {{- else if eq .ssl_policy "AWS-2015-03" }} 272 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 273 | 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:@SECLEVEL=0'; 274 | ssl_prefer_server_ciphers on; 275 | {{- else if eq .ssl_policy "AWS-2015-02" }} 276 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 277 | 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:@SECLEVEL=0'; 278 | ssl_prefer_server_ciphers on; 279 | {{- end }} 280 | {{- end }} 281 | 282 | {{- define "location" }} 283 | {{- $vpath := .VPath }} 284 | {{- $override := printf "/etc/nginx/vhost.d/%s_%s_location_override" .Host (sha1 .Path) }} 285 | {{- if and (eq .Path "/") (not (exists $override)) }} 286 | {{- $override = printf "/etc/nginx/vhost.d/%s_location_override" .Host }} 287 | {{- end }} 288 | {{- if exists $override }} 289 | include {{ $override }}; 290 | {{- else }} 291 | {{- $keepalive := $vpath.keepalive }} 292 | location {{ .Path }} { 293 | {{- if eq $vpath.network_tag "internal" }} 294 | # Only allow traffic from internal clients 295 | include /etc/nginx/network_internal.conf; 296 | {{- end }} 297 | 298 | {{ $proto := $vpath.proto }} 299 | {{ $upstream := $vpath.upstream }} 300 | {{ $dest := $vpath.dest }} 301 | {{- if eq $proto "uwsgi" }} 302 | include uwsgi_params; 303 | uwsgi_pass {{ trim $proto }}://{{ trim $upstream }}; 304 | {{- else if eq $proto "fastcgi" }} 305 | {{- if (exists "/etc/nginx/fastcgi.conf") }} 306 | include fastcgi.conf; 307 | {{- else if (exists "/etc/nginx/fastcgi_params") }} 308 | include fastcgi_params; 309 | {{- else }} 310 | # neither /etc/nginx/fastcgi.conf nor /etc/nginx/fastcgi_params found, fastcgi won't work 311 | {{- end }} 312 | root {{ trim .VhostRoot }}; 313 | fastcgi_pass {{ trim $upstream }}; 314 | {{- if ne $keepalive "disabled" }} 315 | fastcgi_keep_conn on; 316 | {{- end }} 317 | {{- else if eq $proto "grpc" }} 318 | grpc_pass {{ trim $proto }}://{{ trim $upstream }}; 319 | {{- else if eq $proto "grpcs" }} 320 | grpc_pass {{ trim $proto }}://{{ trim $upstream }}; 321 | {{- else }} 322 | proxy_pass {{ trim $proto }}://{{ trim $upstream }}{{ trim $dest }}; 323 | set $upstream_keepalive {{ if ne $keepalive "disabled" }}true{{ else }}false{{ end }}; 324 | {{- end }} 325 | 326 | {{- if (exists (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path) )) }} 327 | auth_basic "Restricted {{ .Host }}{{ .Path }}"; 328 | auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path)) }}; 329 | {{- else if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} 330 | auth_basic "Restricted {{ .HostIsRegexp | ternary "access" .Host }}"; 331 | auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; 332 | {{- end }} 333 | 334 | {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} 335 | include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; 336 | {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} 337 | include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; 338 | {{- else if (exists "/etc/nginx/vhost.d/default_location") }} 339 | include /etc/nginx/vhost.d/default_location; 340 | {{- end }} 341 | } 342 | {{- end }} 343 | {{- end }} 344 | 345 | {{- define "upstream" }} 346 | {{- $path := .Path }} 347 | {{- $vpath := .VPath }} 348 | upstream {{ $vpath.upstream }} { 349 | {{- $servers := 0 }} 350 | {{- $loadbalance := $vpath.loadbalance }} 351 | {{- if $loadbalance }} 352 | # From the container's loadbalance label: 353 | {{ $loadbalance }} 354 | {{- end }} 355 | {{- range $port, $containers := $vpath.ports }} 356 | {{- range $container := $containers }} 357 | # Container: {{ $container.Name }} 358 | {{- $args := dict "globals" $.globals "container" $container }} 359 | {{- template "container_ip" $args }} 360 | {{- $ip := $args.ip }} 361 | {{- $args = dict "container" $container "path" $path "port" $port }} 362 | {{- template "container_port" $args }} 363 | {{- if $ip }} 364 | {{- $servers = add1 $servers }} 365 | server {{ $ip }}:{{ $args.port }}; 366 | {{- end }} 367 | {{- end }} 368 | {{- end }} 369 | {{- /* nginx-proxy/nginx-proxy#1105 */}} 370 | {{- if lt $servers 1 }} 371 | # Fallback entry 372 | server 127.0.0.1 down; 373 | {{- end }} 374 | {{- $keepalive := $vpath.keepalive }} 375 | {{- if and (ne $keepalive "disabled") (gt $servers 0) }} 376 | {{- if eq $keepalive "auto" }} 377 | keepalive {{ mul $servers 2 }}; 378 | {{- else }} 379 | keepalive {{ $keepalive }}; 380 | {{- end }} 381 | {{- end }} 382 | } 383 | {{- end }} 384 | 385 | {{- /* debug "endpoint" location template */}} 386 | {{- define "debug_location" }} 387 | {{- $debug_paths := dict }} 388 | {{- range $path, $vpath := .VHost.paths }} 389 | {{- $tmp_ports := dict }} 390 | {{- range $port, $containers := $vpath.ports }} 391 | {{- $tmp_containers := list }} 392 | {{- range $container := $containers }} 393 | {{- $tmp_containers = dict "Name" $container.Name | append $tmp_containers }} 394 | {{- end }} 395 | {{- $_ := set $tmp_ports $port $tmp_containers }} 396 | {{- end }} 397 | {{- $debug_vpath := deepCopy $vpath | merge (dict "ports" $tmp_ports) }} 398 | {{- $_ := set $debug_paths $path $debug_vpath }} 399 | {{- end }} 400 | 401 | {{- $debug_vhost := deepCopy .VHost }} 402 | {{- /* If it's a regexp, do not render the Hostname to the response to avoid rendering config breaking characters */}} 403 | {{- $_ := set $debug_vhost "hostname" (.VHost.is_regexp | ternary "Hostname is a regexp and unsafe to include in the debug response." .Hostname) }} 404 | {{- $_ := set $debug_vhost "paths" $debug_paths }} 405 | 406 | {{- $debug_response := dict 407 | "global" .GlobalConfig 408 | "request" (dict 409 | "host" "$host" 410 | "https" "$https" 411 | "http2" "$http2" 412 | "http3" "$http3" 413 | "ssl_cipher" "$ssl_cipher" 414 | "ssl_protocol" "$ssl_protocol" 415 | ) 416 | "vhost" $debug_vhost 417 | }} 418 | 419 | {{- /* 420 | * The maximum line length in an nginx config is 4096 characters. 421 | * If we're nearing this limit (with headroom for the rest 422 | * of the directive), strip vhost.paths from the response. 423 | */}} 424 | {{- if gt (toJson $debug_response | len) 4000 }} 425 | {{- $_ := unset $debug_vhost "paths" }} 426 | {{- $_ := set $debug_response "warning" "Virtual paths configuration for this hostname is too large and has been stripped from response." }} 427 | {{- end }} 428 | 429 | location /nginx-proxy-debug { 430 | default_type application/json; 431 | return 200 '{{ toJson $debug_response }}{{ "\\n" }}'; 432 | } 433 | {{- end }} 434 | 435 | {{- define "access_log" }} 436 | {{- when .Enable "access_log /var/log/nginx/access.log vhost;" "" }} 437 | {{- end }} 438 | 439 | # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the 440 | # scheme used to connect to this server 441 | map $http_x_forwarded_proto $proxy_x_forwarded_proto { 442 | default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; 443 | '' $scheme; 444 | } 445 | 446 | map $http_x_forwarded_host $proxy_x_forwarded_host { 447 | default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$host{{ end }}; 448 | '' $host; 449 | } 450 | 451 | # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the 452 | # server port the client connected to 453 | map $http_x_forwarded_port $proxy_x_forwarded_port { 454 | default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; 455 | '' $server_port; 456 | } 457 | 458 | # Include the port in the Host header sent to the container if it is non-standard 459 | map $server_port $host_port { 460 | default :$server_port; 461 | 80 ''; 462 | 443 ''; 463 | } 464 | 465 | # If the request from the downstream client has an "Upgrade:" header (set to any 466 | # non-empty value), pass "Connection: upgrade" to the upstream (backend) server. 467 | # Otherwise, the value for the "Connection" header depends on whether the user 468 | # has enabled keepalive to the upstream server. 469 | map $http_upgrade $proxy_connection { 470 | default upgrade; 471 | '' $proxy_connection_noupgrade; 472 | } 473 | map $upstream_keepalive $proxy_connection_noupgrade { 474 | # Preserve nginx's default behavior (send "Connection: close"). 475 | default close; 476 | # Use an empty string to cancel nginx's default behavior. 477 | true ''; 478 | } 479 | # Abuse the map directive (see ) to ensure 480 | # that $upstream_keepalive is always defined. This is necessary because: 481 | # - The $proxy_connection variable is indirectly derived from 482 | # $upstream_keepalive, so $upstream_keepalive must be defined whenever 483 | # $proxy_connection is resolved. 484 | # - The $proxy_connection variable is used in a proxy_set_header directive in 485 | # the http block, so it is always fully resolved for every request -- even 486 | # those where proxy_pass is not used (e.g., unknown virtual host). 487 | map "" $upstream_keepalive { 488 | # The value here should not matter because it should always be overridden in 489 | # a location block (see the "location" template) for all requests where the 490 | # value actually matters. 491 | default false; 492 | } 493 | 494 | # Apply fix for very long server names 495 | server_names_hash_bucket_size 128; 496 | 497 | # Default dhparam 498 | {{- if (exists "/etc/nginx/dhparam/dhparam.pem") }} 499 | ssl_dhparam /etc/nginx/dhparam/dhparam.pem; 500 | {{- end }} 501 | 502 | # Set appropriate X-Forwarded-Ssl header based on $proxy_x_forwarded_proto 503 | map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { 504 | default off; 505 | https on; 506 | } 507 | 508 | gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 509 | 510 | 511 | {{- /* See https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format for details and variables 512 | * LOG_FORMAT_ESCAPE sets the escape part of the log format 513 | * LOG_FORMAT sets the log format 514 | */}} 515 | {{- $logEscape := $globals.config.log_format_escape | default "default" | printf "escape=%s" }} 516 | {{- $logFormat := $globals.config.log_format | default `$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr"` }} 517 | 518 | {{- if $globals.config.enable_json_logs }} 519 | # JSON Logging enabled (via LOG_JSON env variable) 520 | {{- $logEscape = $globals.config.log_format_escape | default "json" | printf "escape=%s" }} 521 | {{- $logFormat = $globals.config.log_format | default `{"time_local":"$time_iso8601","client_ip":"$http_x_forwarded_for","remote_addr":"$remote_addr","request":"$request","status":"$status","body_bytes_sent":"$body_bytes_sent","request_time":"$request_time","upstream_response_time":"$upstream_response_time","upstream_addr":"$upstream_addr","http_referrer":"$http_referer","http_user_agent":"$http_user_agent","request_id":"$request_id"}` }} 522 | {{- end }} 523 | 524 | log_format vhost {{ $logEscape }} '{{ $logFormat }}'; 525 | 526 | access_log off; 527 | 528 | {{- /* Lower the SSL policy of the http context 529 | * if at least one vhost use a TLSv1 or TLSv1.1 policy 530 | * so TLSv1 and TLSv1.1 can be enabled on those vhosts 531 | */}} 532 | {{- $httpContextSslPolicy := $globals.config.ssl_policy }} 533 | {{- $inUseSslPolicies := groupByKeys $globals.containers "Env.SSL_POLICY" }} 534 | {{- range $tls1Policy := list "AWS-TLS13-1-1-2021-06" "AWS-TLS13-1-0-2021-06" "AWS-FS-1-1-2019-08" "AWS-FS-2018-06" "AWS-TLS-1-1-2017-01" "AWS-2016-08" "AWS-2015-05" "AWS-2015-03" "AWS-2015-02" "Mozilla-Old" }} 535 | {{- if has $tls1Policy $inUseSslPolicies }} 536 | # Using Mozilla-Old SSL policy on the http context to allow TLSv1 and TLSv1.1 537 | {{- $httpContextSslPolicy = "Mozilla-Old" }} 538 | {{- break }} 539 | {{- end }} 540 | {{- end }} 541 | 542 | {{- template "ssl_policy" (dict "ssl_policy" $httpContextSslPolicy) }} 543 | error_log /dev/stderr; 544 | 545 | {{- if $globals.config.resolvers }} 546 | resolver {{ $globals.config.resolvers }}; 547 | {{- end }} 548 | 549 | {{- if (exists "/etc/nginx/proxy.conf") }} 550 | include /etc/nginx/proxy.conf; 551 | {{- else }} 552 | # HTTP 1.1 support 553 | proxy_http_version 1.1; 554 | proxy_set_header Host $host$host_port; 555 | proxy_set_header Upgrade $http_upgrade; 556 | proxy_set_header Connection $proxy_connection; 557 | proxy_set_header X-Real-IP $remote_addr; 558 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 559 | proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host; 560 | proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; 561 | proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; 562 | proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; 563 | proxy_set_header X-Original-URI $request_uri; 564 | 565 | # Mitigate httpoxy attack (see README for details) 566 | proxy_set_header Proxy ""; 567 | {{- end }} 568 | 569 | {{- /* Precompute and store some information about vhost that use VIRTUAL_HOST_MULTIPORTS. */}} 570 | {{- range $vhosts_yaml, $containers := groupBy $globals.containers "Env.VIRTUAL_HOST_MULTIPORTS" }} 571 | {{- /* Print a warning in the config if VIRTUAL_HOST_MULTIPORTS can't be parsed. */}} 572 | {{- $parsedVhosts := fromYaml $vhosts_yaml }} 573 | {{- if (empty $parsedVhosts) }} 574 | {{- $containerNames := list }} 575 | {{- range $container := $containers }} 576 | {{- $containerNames = append $containerNames $container.Name }} 577 | {{- end }} 578 | # /!\ WARNING: the VIRTUAL_HOST_MULTIPORTS environment variable used for {{ len $containerNames | plural "this container" "those containers" }} is not a valid YAML string: 579 | # {{ $containerNames | join ", " }} 580 | {{- continue }} 581 | {{- end }} 582 | 583 | {{- range $hostname, $vhost := $parsedVhosts }} 584 | {{- $vhost_data := get $globals.vhosts $hostname | default (dict) }} 585 | {{- $paths := $vhost_data.paths | default (dict) }} 586 | 587 | {{- if (empty $vhost) }} 588 | {{ $vhost = dict "/" (dict) }} 589 | {{- end }} 590 | 591 | {{- range $path, $vpath := $vhost }} 592 | {{- if (empty $vpath) }} 593 | {{- $vpath = dict 594 | "dest" "" 595 | "port" "default" 596 | "proto" "http" 597 | }} 598 | {{- end }} 599 | 600 | {{- $dest := $vpath.dest | default "" }} 601 | {{- $port := $vpath.port | default "default" | toString }} 602 | {{- $proto := $vpath.proto | default "http" }} 603 | 604 | {{- $path_data := get $paths $path | default (dict) }} 605 | {{- $path_ports := $path_data.ports | default (dict) }} 606 | {{- $path_port_containers := get $path_ports $port | default (list) | concat $containers }} 607 | {{- $_ := set $path_ports $port $path_port_containers }} 608 | {{- $_ := set $path_data "ports" $path_ports }} 609 | 610 | {{- if (not (hasKey $path_data "dest")) }} 611 | {{- $_ := set $path_data "dest" $dest }} 612 | {{- end }} 613 | 614 | {{- if (not (hasKey $path_data "proto")) }} 615 | {{- $_ := set $path_data "proto" $proto }} 616 | {{- end }} 617 | 618 | {{- $_ := set $paths $path $path_data }} 619 | {{- end }} 620 | {{- $_ := set $vhost_data "paths" $paths }} 621 | {{- $_ := set $globals.vhosts $hostname $vhost_data }} 622 | {{- end }} 623 | {{- end }} 624 | 625 | {{- /* Precompute and store some information about vhost that use VIRTUAL_HOST. */}} 626 | {{- range $hostname, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} 627 | {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} 628 | {{- $hostname = trim $hostname }} 629 | {{- if not $hostname }} 630 | {{- continue }} 631 | {{- end }} 632 | 633 | {{- /* Drop containers with both VIRTUAL_HOST and VIRTUAL_HOST_MULTIPORTS set 634 | * (VIRTUAL_HOST_MULTIPORTS takes precedence thanks to the previous loop). 635 | */}} 636 | {{- range $_, $containers_to_drop := groupBy $containers "Env.VIRTUAL_HOST_MULTIPORTS" }} 637 | {{- range $container := $containers_to_drop }} 638 | {{- $containers = without $containers $container }} 639 | {{- end }} 640 | {{- end }} 641 | {{- if (eq (len $containers) 0) }} 642 | {{- continue }} 643 | {{- end }} 644 | 645 | {{- $vhost_data := get $globals.vhosts $hostname | default (dict) }} 646 | {{- $paths := $vhost_data.paths | default (dict) }} 647 | 648 | {{- $tmp_paths := groupByWithDefault $containers "Env.VIRTUAL_PATH" "/" }} 649 | 650 | {{- range $path, $containers := $tmp_paths }} 651 | {{- $dest := groupByKeys $containers "Env.VIRTUAL_DEST" | first | default "" }} 652 | {{- $proto := groupByKeys $containers "Env.VIRTUAL_PROTO" | first | default "http" | trim }} 653 | 654 | {{- $path_data := get $paths $path | default (dict) }} 655 | {{- $path_ports := $path_data.ports | default (dict) }} 656 | {{- range $port, $containers := groupByWithDefault $containers "Env.VIRTUAL_PORT" "default" }} 657 | {{- $path_port_containers := get $path_ports $port | default (list) | concat $containers }} 658 | {{- $_ := set $path_ports $port $path_port_containers }} 659 | {{- end }} 660 | {{- $_ := set $path_data "ports" $path_ports }} 661 | 662 | {{- if (not (hasKey $path_data "dest")) }} 663 | {{- $_ := set $path_data "dest" $dest }} 664 | {{- end }} 665 | 666 | {{- if (not (hasKey $path_data "proto")) }} 667 | {{- $_ := set $path_data "proto" $proto }} 668 | {{- end }} 669 | 670 | {{- $_ := set $paths $path $path_data }} 671 | {{- end }} 672 | {{- $_ := set $vhost_data "paths" $paths }} 673 | {{- $_ := set $globals.vhosts $hostname $vhost_data }} 674 | {{- end }} 675 | 676 | {{- /* Loop over $globals.vhosts and update it with the remaining informations about each vhost. */}} 677 | {{- range $hostname, $vhost_data := $globals.vhosts }} 678 | {{- $is_regexp := hasPrefix "~" $hostname }} 679 | {{- $upstream_name := or $is_regexp $globals.config.sha1_upstream_name | ternary (sha1 $hostname) $hostname }} 680 | 681 | {{- $vhost_containers := list }} 682 | 683 | {{- range $path, $vpath_data := $vhost_data.paths }} 684 | {{- $vpath_containers := list }} 685 | {{- range $port, $vport_containers := $vpath_data.ports }} 686 | {{ $vpath_containers = concat $vpath_containers $vport_containers }} 687 | {{- end }} 688 | 689 | {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external". */}} 690 | {{- $network_tag := groupByKeys $vpath_containers "Env.NETWORK_ACCESS" | first | default "external" }} 691 | 692 | {{- $loadbalance := groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.loadbalance" | keys | first }} 693 | {{- $keepalive := groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.keepalive" | keys | first | default "auto" }} 694 | 695 | {{- $upstream := $upstream_name }} 696 | {{- if (not (eq $path "/")) }} 697 | {{- $sum := sha1 $path }} 698 | {{- $upstream = printf "%s-%s" $upstream $sum }} 699 | {{- end }} 700 | 701 | {{- $_ := set $vpath_data "network_tag" $network_tag }} 702 | {{- $_ := set $vpath_data "upstream" $upstream }} 703 | {{- $_ := set $vpath_data "loadbalance" $loadbalance }} 704 | {{- $_ := set $vpath_data "keepalive" $keepalive }} 705 | {{- $_ := set $vhost_data.paths $path $vpath_data }} 706 | 707 | {{ $vhost_containers = concat $vhost_containers $vpath_containers }} 708 | {{- end }} 709 | 710 | {{- $userIdentifiedCert := groupByKeys $vhost_containers "Env.CERT_NAME" | first }} 711 | 712 | {{- $vhostCert := "" }} 713 | {{- if exists (printf "/etc/nginx/certs/%s.crt" $hostname) }} 714 | {{- $vhostCert = $hostname }} 715 | {{- end }} 716 | 717 | {{- $parentVhostCert := "" }} 718 | {{- if gt ($hostname | sprigSplit "." | len) 2 }} 719 | {{- $parentHostname := ($hostname | sprigSplitn "." 2)._1 }} 720 | {{- if exists (printf "/etc/nginx/certs/%s.crt" $parentHostname) }} 721 | {{- $parentVhostCert = $parentHostname }} 722 | {{- end }} 723 | {{- end }} 724 | 725 | {{- $trust_default_cert := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.trust-default-cert" | keys | first | default $globals.config.trust_default_cert | parseBool }} 726 | {{- $defaultCert := and $trust_default_cert $globals.config.default_cert_ok | ternary "default" "" }} 727 | 728 | {{- $cert := or $userIdentifiedCert $vhostCert $parentVhostCert $defaultCert }} 729 | {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} 730 | 731 | {{- $enable_debug_endpoint := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first | default $globals.config.enable_debug_endpoint | parseBool }} 732 | {{- $default := eq $globals.config.default_host $hostname }} 733 | {{- $https_method := groupByKeys $vhost_containers "Env.HTTPS_METHOD" | first | default $globals.config.https_method }} 734 | {{- $enable_http_on_missing_cert := groupByKeys $vhost_containers "Env.ENABLE_HTTP_ON_MISSING_CERT" | first | default $globals.config.enable_http_on_missing_cert | parseBool }} 735 | {{- /* When no trusted certs (default and/or vhost) are present we want to ensure that HTTP is enabled; hence switching from 'nohttp' or 'redirect' to 'noredirect' */}} 736 | {{- $https_method_disable_http := list "nohttp" "redirect" | has $https_method }} 737 | {{- if and $https_method_disable_http (not $cert_ok) $enable_http_on_missing_cert }} 738 | {{- $https_method = "noredirect" }} 739 | {{- end }} 740 | {{- $non_get_redirect := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.non-get-redirect" | keys | first | default $globals.config.non_get_redirect }} 741 | 742 | {{- $http2_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable" | keys | first | default $globals.config.enable_http2 | parseBool }} 743 | {{- $http3_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http3.enable" | keys | first | default $globals.config.enable_http3 | parseBool }} 744 | 745 | {{- $acme_http_challenge := groupByKeys $vhost_containers "Env.ACME_HTTP_CHALLENGE_LOCATION" | first | default $globals.config.acme_http_challenge }} 746 | {{- $acme_http_challenge_legacy := eq $acme_http_challenge "legacy" }} 747 | {{- $acme_http_challenge_enabled := false }} 748 | {{- if (not $acme_http_challenge_legacy) }} 749 | {{- $acme_http_challenge_enabled = parseBool $acme_http_challenge }} 750 | {{- end }} 751 | 752 | {{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "". */}} 753 | {{- $server_tokens := groupByKeys $vhost_containers "Env.SERVER_TOKENS" | first | default "" | trim }} 754 | 755 | {{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default). */}} 756 | {{- $ssl_policy := groupByKeys $vhost_containers "Env.SSL_POLICY" | first | default "" }} 757 | 758 | {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000". */}} 759 | {{- $hsts := groupByKeys $vhost_containers "Env.HSTS" | first | default $globals.config.hsts }} 760 | 761 | {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} 762 | {{- $vhost_root := groupByKeys $vhost_containers "Env.VIRTUAL_ROOT" | first | default "/var/www/public" }} 763 | 764 | {{- $vhost_data = merge $vhost_data (dict 765 | "cert" $cert 766 | "cert_ok" $cert_ok 767 | "enable_debug_endpoint" $enable_debug_endpoint 768 | "default" $default 769 | "hsts" $hsts 770 | "https_method" $https_method 771 | "non_get_redirect" $non_get_redirect 772 | "http2_enabled" $http2_enabled 773 | "http3_enabled" $http3_enabled 774 | "is_regexp" $is_regexp 775 | "acme_http_challenge_legacy" $acme_http_challenge_legacy 776 | "acme_http_challenge_enabled" $acme_http_challenge_enabled 777 | "server_tokens" $server_tokens 778 | "ssl_policy" $ssl_policy 779 | "trust_default_cert" $trust_default_cert 780 | "upstream_name" $upstream_name 781 | "vhost_root" $vhost_root 782 | ) }} 783 | {{- $_ := set $globals.vhosts $hostname $vhost_data }} 784 | {{- end }} 785 | 786 | 787 | {{- /* 788 | * If needed, create a catch-all fallback server to send an error code to 789 | * clients that request something from an unknown vhost. 790 | * 791 | * This server must appear first in the generated config because nginx uses 792 | * the first `server` directive to handle requests that don't match any of 793 | * the other `server` directives. An alternative approach would be to add 794 | * the `default_server` option to the `listen` directives inside this 795 | * `server`, but some users inject a custom `server` directive that uses 796 | * `default_server`. Using `default_server` here would cause nginx to fail 797 | * to start for those users. See 798 | * . 799 | */}} 800 | {{- block "fallback_server" $globals }} 801 | {{- $globals := . }} 802 | {{- $http_exists := false }} 803 | {{- $https_exists := false }} 804 | {{- $default_http_exists := false }} 805 | {{- $default_https_exists := false }} 806 | {{- $http3_enabled := false }} 807 | {{- range $vhost := $globals.vhosts }} 808 | {{- $http := ne $vhost.https_method "nohttp" }} 809 | {{- $https := ne $vhost.https_method "nohttps" }} 810 | {{- $http_exists = or $http_exists $http }} 811 | {{- $https_exists = or $https_exists $https }} 812 | {{- $default_http_exists = or $default_http_exists (and $http $vhost.default) }} 813 | {{- $default_https_exists = or $default_https_exists (and $https $vhost.default) }} 814 | {{- $http3_enabled = or $http3_enabled $vhost.http3_enabled }} 815 | {{- end }} 816 | {{- $fallback_http := not $default_http_exists }} 817 | {{- $fallback_https := not $default_https_exists }} 818 | {{- /* 819 | * If there are no vhosts at all, create fallbacks for both plain http 820 | * and https so that clients get something more useful than a connection 821 | * refused error. 822 | */}} 823 | {{- if and (not $http_exists) (not $https_exists) }} 824 | {{- $fallback_https = true }} 825 | {{- end }} 826 | {{- if or $fallback_http $fallback_https }} 827 | server { 828 | server_name _; # This is just an invalid value which will never trigger on a real hostname. 829 | server_tokens off; 830 | {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} 831 | http2 on; 832 | {{- if $fallback_http }} 833 | listen {{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} 834 | {{- if $globals.config.enable_ipv6 }} 835 | listen [::]:{{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} 836 | {{- end }} 837 | {{- end }} 838 | {{- if $fallback_https }} 839 | listen {{ $globals.config.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} 840 | {{- if $globals.config.enable_ipv6 }} 841 | listen [::]:{{ $globals.config.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} 842 | {{- end }} 843 | {{- if $http3_enabled }} 844 | http3 on; 845 | listen {{ $globals.config.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} 846 | {{- if $globals.config.enable_ipv6 }} 847 | listen [::]:{{ $globals.config.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} 848 | {{- end }} 849 | {{- end }} 850 | ssl_session_cache shared:SSL:50m; 851 | ssl_session_tickets off; 852 | {{- end }} 853 | {{- if $globals.config.default_cert_ok }} 854 | ssl_certificate /etc/nginx/certs/default.crt; 855 | ssl_certificate_key /etc/nginx/certs/default.key; 856 | {{- else }} 857 | # No default certificate found, so reject SSL handshake; 858 | ssl_reject_handshake on; 859 | {{- end }} 860 | 861 | {{- if (exists "/usr/share/nginx/html/errors/50x.html") }} 862 | error_page 500 502 503 504 /50x.html; 863 | location /50x.html { 864 | root /usr/share/nginx/html/errors; 865 | internal; 866 | } 867 | {{- end }} 868 | location ^~ / { 869 | return 503; 870 | } 871 | } 872 | {{- end }} 873 | {{- end }} 874 | 875 | {{- range $hostname, $vhost := $globals.vhosts }} 876 | {{- $default_server := when $vhost.default "default_server" "" }} 877 | 878 | {{- range $path, $vpath := $vhost.paths }} 879 | # {{ $hostname }}{{ $path }} 880 | {{ template "upstream" (dict "globals" $globals "Path" $path "VPath" $vpath) }} 881 | {{- end }} 882 | 883 | {{- if (eq $vhost.https_method "redirect") }} 884 | server { 885 | server_name {{ $hostname }}; 886 | {{- if $vhost.server_tokens }} 887 | server_tokens {{ $vhost.server_tokens }}; 888 | {{- end }} 889 | {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} 890 | listen {{ $globals.config.external_http_port }} {{ $default_server }}; 891 | {{- if $globals.config.enable_ipv6 }} 892 | listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; 893 | {{- end }} 894 | 895 | {{- if (or $vhost.acme_http_challenge_legacy $vhost.acme_http_challenge_enabled) }} 896 | # Do not HTTPS redirect Let's Encrypt ACME challenge 897 | location ^~ /.well-known/acme-challenge/ { 898 | auth_basic off; 899 | auth_request off; 900 | allow all; 901 | root /usr/share/nginx/html; 902 | try_files $uri =404; 903 | break; 904 | } 905 | {{- end }} 906 | 907 | {{- if $vhost.enable_debug_endpoint }} 908 | {{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }} 909 | {{- end }} 910 | 911 | location / { 912 | {{- $redirect_uri := "https://$host$request_uri" }} 913 | {{- if ne $globals.config.external_https_port "443" }} 914 | {{- $redirect_uri = printf "https://$host:%s$request_uri" $globals.config.external_https_port }} 915 | {{- end}} 916 | if ($request_method ~ (OPTIONS|POST|PUT|PATCH|DELETE)) { 917 | return {{ $vhost.non_get_redirect }} {{ $redirect_uri }}; 918 | } 919 | return 301 {{ $redirect_uri }}; 920 | } 921 | } 922 | {{- end }} 923 | 924 | server { 925 | {{- if $vhost.is_regexp }} 926 | {{- if or 927 | (printf "/etc/nginx/vhost.d/%s" $hostname | exists) 928 | (printf "/etc/nginx/vhost.d/%s_location" $hostname | exists) 929 | (printf "/etc/nginx/vhost.d/%s_location_override" $hostname | exists) 930 | (printf "/etc/nginx/htpasswd/%s" $hostname | exists) 931 | }} 932 | # https://github.com/nginx-proxy/nginx-proxy/issues/2529#issuecomment-2437609249 933 | # Support for vhost config file(s) named like a regexp ({{ $hostname }}) has been removed from nginx-proxy. 934 | # Please name your vhost config file(s) with the sha1 of the regexp instead ({{ $hostname }} -> {{ sha1 $hostname }}) : 935 | # - /etc/nginx/vhost.d/{{ sha1 $hostname }} 936 | # - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location 937 | # - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location_override 938 | # - /etc/nginx/htpasswd/{{ sha1 $hostname }} 939 | {{- end }} 940 | {{- end }} 941 | 942 | server_name {{ $hostname }}; 943 | {{- if $vhost.server_tokens }} 944 | server_tokens {{ $vhost.server_tokens }}; 945 | {{- end }} 946 | {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} 947 | {{- if $vhost.http2_enabled }} 948 | http2 on; 949 | {{- end }} 950 | {{- if or (eq $vhost.https_method "nohttps") (eq $vhost.https_method "noredirect") }} 951 | listen {{ $globals.config.external_http_port }} {{ $default_server }}; 952 | {{- if $globals.config.enable_ipv6 }} 953 | listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; 954 | {{- end }} 955 | 956 | {{- if (and (eq $vhost.https_method "noredirect") $vhost.acme_http_challenge_enabled) }} 957 | location /.well-known/acme-challenge/ { 958 | auth_basic off; 959 | allow all; 960 | root /usr/share/nginx/html; 961 | try_files $uri =404; 962 | break; 963 | } 964 | {{- end }} 965 | {{- end }} 966 | {{- if ne $vhost.https_method "nohttps" }} 967 | listen {{ $globals.config.external_https_port }} ssl {{ $default_server }}; 968 | {{- if $globals.config.enable_ipv6 }} 969 | listen [::]:{{ $globals.config.external_https_port }} ssl {{ $default_server }}; 970 | {{- end }} 971 | 972 | {{- if $vhost.http3_enabled }} 973 | http3 on; 974 | add_header alt-svc 'h3=":{{ $globals.config.external_https_port }}"; ma=86400;'; 975 | listen {{ $globals.config.external_https_port }} quic {{ $default_server }}; 976 | {{- if $globals.config.enable_ipv6 }} 977 | listen [::]:{{ $globals.config.external_https_port }} quic {{ $default_server }}; 978 | {{- end }} 979 | {{- end }} 980 | 981 | {{- if $vhost.cert_ok }} 982 | {{- template "ssl_policy" (dict "ssl_policy" $vhost.ssl_policy) }} 983 | 984 | ssl_session_timeout 5m; 985 | ssl_session_cache shared:SSL:50m; 986 | ssl_session_tickets off; 987 | 988 | ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $vhost.cert) }}; 989 | ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $vhost.cert) }}; 990 | 991 | {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $vhost.cert)) }} 992 | ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $vhost.cert }}; 993 | {{- end }} 994 | 995 | {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $vhost.cert)) }} 996 | ssl_stapling on; 997 | ssl_stapling_verify on; 998 | ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $vhost.cert }}; 999 | {{- end }} 1000 | 1001 | {{- if (not (or (eq $vhost.https_method "noredirect") (eq $vhost.hsts "off"))) }} 1002 | set $sts_header ""; 1003 | if ($https) { 1004 | set $sts_header "{{ trim $vhost.hsts }}"; 1005 | } 1006 | add_header Strict-Transport-Security $sts_header always; 1007 | {{- end }} 1008 | {{- else if not $vhost.trust_default_cert | and $globals.config.default_cert_ok }} 1009 | # No certificate found for this vhost, and the default certificate isn't trusted, so reject SSL handshake. 1010 | ssl_reject_handshake on; 1011 | {{- else }} 1012 | # No certificate for this vhost nor default certificate found, so reject SSL handshake. 1013 | ssl_reject_handshake on; 1014 | {{- end }} 1015 | {{- end }} 1016 | 1017 | {{- $vhostFileName := $vhost.is_regexp | ternary (sha1 $hostname) $hostname }} 1018 | 1019 | {{- if (exists (printf "/etc/nginx/vhost.d/%s" $vhostFileName)) }} 1020 | include {{ printf "/etc/nginx/vhost.d/%s" $vhostFileName }}; 1021 | {{- else if (exists "/etc/nginx/vhost.d/default") }} 1022 | include /etc/nginx/vhost.d/default; 1023 | {{- end }} 1024 | 1025 | {{- if $vhost.enable_debug_endpoint }} 1026 | {{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }} 1027 | {{- end }} 1028 | 1029 | {{- range $path, $vpath := $vhost.paths }} 1030 | {{- template "location" (dict 1031 | "Path" $path 1032 | "Host" $vhostFileName 1033 | "HostIsRegexp" $vhost.is_regexp 1034 | "VhostRoot" $vhost.vhost_root 1035 | "VPath" $vpath 1036 | ) }} 1037 | {{- end }} 1038 | 1039 | {{- if and (not (contains $vhost.paths "/")) (ne $globals.config.default_root_response "none")}} 1040 | location / { 1041 | return {{ $globals.config.default_root_response }}; 1042 | } 1043 | {{- end }} 1044 | } 1045 | {{- end }} 1046 | --------------------------------------------------------------------------------