├── Dockerfile ├── LICENSE ├── README.md ├── dns-01.md ├── examples ├── docker-compose.dns-01.yml └── docker-compose.http-01.yml ├── http-01.md └── root ├── etc ├── dehydrated │ └── config.j2 ├── periodic │ └── weekly │ │ └── dehydrated └── s6.d │ ├── .s6-svscan │ └── finish │ ├── cron │ ├── finish │ └── run │ └── dehydrated │ └── run └── usr └── local └── bin └── lexicon-hook /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/alpine:3.11 2 | LABEL maintainer="Jan Christian Grünhage " 3 | 4 | ENV UID=1337 \ 5 | GID=1337 6 | 7 | RUN apk add --no-cache \ 8 | --virtual .build-deps \ 9 | git \ 10 | python3-dev \ 11 | libffi-dev \ 12 | build-base \ 13 | openssl-dev \ 14 | py2-pip \ 15 | && apk add --no-cache \ 16 | --virtual .runtime-deps \ 17 | openssl \ 18 | curl \ 19 | sed \ 20 | grep \ 21 | bash \ 22 | s6 \ 23 | su-exec \ 24 | libxml2-utils \ 25 | py2-pip \ 26 | python3 \ 27 | && mkdir -p /opt \ 28 | && git clone https://github.com/lukas2511/dehydrated.git /opt/dehydrated \ 29 | && pip3 install requests[security] \ 30 | && pip3 install dns-lexicon \ 31 | && pip2 install j2cli[yaml] \ 32 | && apk del .build-deps 33 | 34 | ENV \ 35 | DEHYDRATED_CA="https://acme-staging-v02.api.letsencrypt.org/directory" \ 36 | DEHYDRATED_CHALLENGE="http-01" \ 37 | DEHYDRATED_KEYSIZE="4096" \ 38 | DEHYDRATED_KEY_ALGO="rsa" \ 39 | DEHYDRATED_HOOK="" \ 40 | DEHYDRATED_RENEW_DAYS="30" \ 41 | DEHYDRATED_KEY_RENEW="yes" \ 42 | DEHYDRATED_ACCEPT_TERMS="no" \ 43 | DEHYDRATED_EMAIL="user@example.org" \ 44 | DEHYDRATED_GENERATE_CONFIG="yes" 45 | 46 | ADD root / 47 | 48 | VOLUME /data 49 | 50 | CMD ["/bin/s6-svscan", "/etc/s6.d"] 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-dehydrated 2 | 3 | [![Stars](https://img.shields.io/docker/stars/matrixdotorg/dehydrated.svg)](https://hub.docker.com/r/matrixdotorg/dehydrated/) [![Pulls](https://img.shields.io/docker/pulls/matrixdotorg/dehydrated.svg)](https://hub.docker.com/r/matrixdotorg/dehydrated/) [![Automated](https://img.shields.io/docker/automated/matrixdotorg/dehydrated.svg)](https://hub.docker.com/r/matrixdotorg/dehydrated/) [![Build Status](https://img.shields.io/docker/build/matrixdotorg/dehydrated.svg)](https://hub.docker.com/r/matrixdotorg/dehydrated/) 4 | 5 | We use this internally for automating our certificate management using [dehydrated](https://github.com/lukas2511/dehydrated). We do not support this further than needed for our usage, but feel free to use it if you want. 6 | 7 | ## Usage 8 | We have short tutorials for two different modi operandi: The `dns-01` and `http-01` challenge. 9 | Both are fairly easy to use. The `dns-01` challenge requires less effort if your DNS provider 10 | is supported by [lexicon](https://github.com/AnalogJ/lexicon/#providers), the `http-01` challenge otherwise. 11 | 12 | For a short tutorial of getting a certificate with this container and the `dns-01` challenge, 13 | go [here](dns-01.md), for the same using the `http-01` challenge, go [here](http-01.md). 14 | 15 | ## Behaviour 16 | By default the container will attempt to generate a config as `/data/config` 17 | with the default values for all the environment variables. 18 | The defaults are explicitly meant to not work. Things you need to change: 19 | - set `DEHYDRATED_ACCEPT_TERMS` to yes, ***after reading letsencrypts ToS*** 20 | - set `DEHYDRATED_EMAIL` to an email address you own 21 | - set `DEHYDRATED_CA` to a production ACME CA, for example letsencrypt's ACME v2 endpoint, "https://acme-v02.api.letsencrypt.org/directory" 22 | - Only do this ***after*** you have tried it with the default staging endpoint 23 | and it worked and you got the certificates you want. If this fails too often, 24 | letsencrypt will block your IP and domain for a week, so do your experiments 25 | on the staging endpoint. 26 | 27 | ### Advanced configuration 28 | - `DEHYDRATED_CA`: 29 | This controls which ACME endpoint dehydrated contacts. The most common value for 30 | production environments is "https://acme-v02.api.letsencrypt.org/directory", 31 | while you should use "https://acme-staging-v02.api.letsencrypt.org/directory" 32 | for experiments. 33 | - `DEHYDRATED_CHALLENGE`: 34 | You can either put `dns-01` or `http-01` here, depending on how you want letsencrypt 35 | to verify that you are allowed to obtain this certificate. 36 | - `DEHYDRATED_KEYSIZE`: 37 | This defaults to `4096`, but you could also put `2048` or `3072` here, if you want 38 | less secure but slightly faster keys. This only makes sense if your host or your clients 39 | are *very slow*. 40 | - `DEHYDRATED_KEY_ALGO`: 41 | This defaults to `rsa` but you could also put `prime256v1` or `secp384r1` here. 42 | `DEHYDRATED_KEYSIZE` is only relevant for `rsa` certs, but still controls the acocunt key size. 43 | - `DEHYDRATED_HOOK`: 44 | If you use the `dns-01` challenge, you need to supply a hook script, 45 | which dehydrated will use to set dns records. The container ships with 46 | lexicon installed and a lexicon hook in `/usr/local/bin/lexicon-hook`. 47 | Apart from the `dns-01` challenge, you can also use hooks to deploy newly created 48 | certificates. For more info see [dehydrated's project page](https://github.com/lukas2511/dehydrated). 49 | - `DEHYDRATED_RENEW_DAYS`: 50 | When dehydrated runs, it will check if any certificates need renewal and renew those. 51 | All certificates which expire in the next `n` days will be renewed, where `n` is the 52 | number you set here. Default is 30 53 | - `DEHYDRATED_KEY_RENEW`: 54 | Set this to yes to make dehydrated renew keys too when renewing certificates, or to 55 | no to keep the keys. 56 | - `DEHYDRATED_ACCEPT_TERMS`: 57 | For the first run this needs to be set to yes, else dehydrated will not work. 58 | Read the terms of service of letsencrypt before setting this to yes. 59 | - `DEHYDRATED_EMAIL`: 60 | Set your email address here. 61 | - `DEHYDRATED_GENERATE_CONFIG`: 62 | Set to yes by default. If you want to use a config supplied by you, 63 | change this to no and put your own config in `/data/config` 64 | - `UID` and `GID`: You can set the UID and GID of the things run in the docker container here.s 65 | -------------------------------------------------------------------------------- /dns-01.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | For using the container with the `dns-01`-challenge, you need on your machine: 4 | 5 | - docker-compose (and docker obviously) 6 | 7 | Download [the docker-compose example](https://raw.githubusercontent.com/matrix-org/docker-dehydrated/master/examples/docker-compose.dns-01.yml) 8 | as `docker-compose.yml` into an empty folder. Inside that folder, create the folder `data`. 9 | 10 | Now, create a file `data/domains.txt` in which you list the domains you want to create certificates for, 11 | using the following format: 12 | 13 | - each certificate on a new line 14 | - each line can contain a list of (sub)domains, separated by spaces 15 | 16 | For more information on the format, see [the dehydrated documentation](https://github.com/lukas2511/dehydrated/blob/master/docs/domains_txt.md). 17 | 18 | Before running, you need to set a few things in the `docker-compose.yml` file, 19 | as explained [here in the README](https://github.com/matrix-org/docker-dehydrated#behaviour) 20 | 21 | ## Configuring DNS API access 22 | 23 | Dehydrated needs to be able to add and remove DNS entries. For this, 24 | the `docker-compose.yml` file contains an example how this works with Cloudflare. 25 | Set your email and token there, and if you use another provider from 26 | [this list](https://github.com/AnalogJ/lexicon/#providers), do the same but replace 27 | cloudflare with your provider everywhere. 28 | 29 | ## Using docker-dehydrated 30 | 31 | Inside the folder where you put the `docker-compose.yml` file, run this command: 32 | 33 | ```bash 34 | docker-compose up 35 | ``` 36 | 37 | This will create the requested certificates, if possible. 38 | It will also check once per week whether the certificates need to be renewed, 39 | and do so if necessary. To start the container in the background, add ` -d` 40 | to the end of the command above. 41 | 42 | Please note that the container will `chown` the folders passed to it, so make sure your webserver can 43 | still serve the contents of `data/wellknown`. You can configure the UID and GID 44 | that the container uses by adding a UID and GID environment variable to the 45 | `docker-compose.yml` file. 46 | 47 | After the challenges have been run, the certificates will be stored in `data/certs`. 48 | -------------------------------------------------------------------------------- /examples/docker-compose.dns-01.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | dehydrated: 4 | image: docker.io/matrixdotorg/dehydrated 5 | restart: unless-stopped 6 | volumes: 7 | - ./data:/data 8 | environment: 9 | - DEHYDRATED_GENERATE_CONFIG="yes" 10 | - DEHYDRATED_CA="https://acme-v02.api.letsencrypt.org/directory" 11 | - DEHYDRATED_CHALLENGE="dns-01" 12 | - DEHYDRATED_KEYSIZE="4096" 13 | - DEHYDRATED_HOOK="/usr/local/bin/lexicon-hook" 14 | - DEHYDRATED_RENEW_DAYS="30" 15 | - DEHYDRATED_KEY_RENEW="yes" 16 | - DEHYDRATED_EMAIL="user@example.org" 17 | - DEHYDRATED_ACCEPT_TERMS=no 18 | - PROVIDER=cloudflare 19 | - LEXICON_CLOUDFLARE_USERNAME=user@example.org 20 | - LEXICON_CLOUDFLARE_TOKEN=abcdefghijklmnopqrstuvwxyz01234567890 21 | -------------------------------------------------------------------------------- /examples/docker-compose.http-01.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | dehydrated: 4 | image: docker.io/matrixdotorg/dehydrated 5 | restart: unless-stopped 6 | volumes: 7 | - ./data:/data 8 | environment: 9 | - DEHYDRATED_GENERATE_CONFIG="yes" 10 | - DEHYDRATED_CA="https://acme-v02.api.letsencrypt.org/directory" 11 | - DEHYDRATED_CHALLENGE="http-01" 12 | - DEHYDRATED_KEYSIZE="4096" 13 | - DEHYDRATED_RENEW_DAYS="30" 14 | - DEHYDRATED_KEY_RENEW="yes" 15 | - DEHYDRATED_EMAIL="user@example.org" 16 | - DEHYDRATED_ACCEPT_TERMS=no 17 | -------------------------------------------------------------------------------- /http-01.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | These are the things that you need to setup / already have set up in order to 4 | use this container for creating certificates using the `http-01`-challenge: 5 | 6 | - A working internet connection, with port 80 of your machine available publicly 7 | - An http server to serve the `.well-known` folder 8 | - docker-compose 9 | 10 | Download [the docker-compose example](https://raw.githubusercontent.com/matrix-org/docker-dehydrated/master/examples/docker-compose.http-01.yml) 11 | as `docker-compose.yml` into an empty folder. Inside that folder, create the folder `data/wellknown`. 12 | Configure your Webserver to serve the contents of this folder under `domain/.well-known/acme-challenge` 13 | (for all domains for which you want to create certificates). 14 | 15 | Now, create a file `data/domains.txt` in which you list the domains you want to create certificates for, 16 | using the following format: 17 | 18 | - each certificate on a new line 19 | - each line can contain a list of (sub)domains, separated by spaces 20 | 21 | For more information on the format, see [the dehydrated documentation](https://github.com/lukas2511/dehydrated/blob/master/docs/domains_txt.md). 22 | 23 | Before running, you need to set a few things in the `docker-compose.yml` file, 24 | as explained [here in the README](https://github.com/matrix-org/docker-dehydrated#behaviour) 25 | 26 | ## Using docker-dehydrated 27 | 28 | Inside the folder where you put the `docker-compose.yml` file, run this command: 29 | 30 | ```bash 31 | docker-compose up 32 | ``` 33 | 34 | This will create the requested certificates, if possible. 35 | It will also check once per week whether the certificates need to be renewed, 36 | and do so if necessary. To start the container in the background, add ` -d` 37 | to the end of the command above. 38 | 39 | Please note that the container will `chown` the folders passed to it, so make sure your webserver can 40 | still serve the contents of `data/wellknown`. You can configure the UID and GID 41 | that the container uses by adding a UID and GID environment variable to the 42 | `docker-compose.yml` file. 43 | 44 | After the challenges have been run, the certificates will be stored in `data/certs`. 45 | -------------------------------------------------------------------------------- /root/etc/dehydrated/config.j2: -------------------------------------------------------------------------------- 1 | ######################################################## 2 | # This is the main config file for dehydrated # 3 | # # 4 | # This file is looked for in the following locations: # 5 | # $SCRIPTDIR/config (next to this script) # 6 | # /usr/local/etc/dehydrated/config # 7 | # /etc/dehydrated/config # 8 | # ${PWD}/config (in current working-directory) # 9 | # # 10 | # Default values of this config are in comments # 11 | ######################################################## 12 | 13 | # Which user should dehydrated run as? This will be implictly enforced when running as root 14 | #DEHYDRATED_USER= 15 | 16 | # Which group should dehydrated run as? This will be implictly enforced when running as root 17 | #DEHYDRATED_GROUP= 18 | 19 | # Resolve names to addresses of IP version only. (curl) 20 | # supported values: 4, 6 21 | # default: 22 | #IP_VERSION= 23 | 24 | # Path to certificate authority (default: https://acme-v02.api.letsencrypt.org/directory) 25 | CA={{ DEHYDRATED_CA }} 26 | 27 | # Path to old certificate authority 28 | # Set this value to your old CA value when upgrading from ACMEv1 to ACMEv2 under a different endpoint. 29 | # If dehydrated detects an account-key for the old CA it will automatically reuse that key 30 | # instead of registering a new one. 31 | # default: https://acme-v01.api.letsencrypt.org/directory 32 | #OLDCA="https://acme-v01.api.letsencrypt.org/directory" 33 | 34 | # Which challenge should be used? Currently http-01 and dns-01 are supported 35 | CHALLENGETYPE={{ DEHYDRATED_CHALLENGE }} 36 | 37 | # Path to a directory containing additional config files, allowing to override 38 | # the defaults found in the main configuration file. Additional config files 39 | # in this directory needs to be named with a '.sh' ending. 40 | # default: 41 | #CONFIG_D= 42 | 43 | # Base directory for account key, generated certificates and list of domains (default: $SCRIPTDIR -- uses config directory if undefined) 44 | BASEDIR=/data 45 | 46 | # File containing the list of domains to request certificates for (default: $BASEDIR/domains.txt) 47 | #DOMAINS_TXT="${BASEDIR}/domains.txt" 48 | 49 | # Output directory for generated certificates 50 | #CERTDIR="${BASEDIR}/certs" 51 | 52 | # Directory for account keys and registration information 53 | #ACCOUNTDIR="${BASEDIR}/accounts" 54 | 55 | # Output directory for challenge-tokens to be served by webserver or deployed in HOOK (default: /var/www/dehydrated) 56 | WELLKNOWN=/data/wellknown 57 | 58 | # Default keysize for private keys (default: 4096) 59 | keysize={{ DEHYDRATED_KEYSIZE }} 60 | 61 | # Path to openssl config file (default: - tries to figure out system default) 62 | #OPENSSL_CNF= 63 | 64 | # Path to OpenSSL binary (default: "openssl") 65 | #OPENSSL="openssl" 66 | 67 | # Extra options passed to the curl binary (default: ) 68 | #CURL_OPTS= 69 | 70 | # Program or function called in certain situations 71 | # 72 | # After generating the challenge-response, or after failed challenge (in this case altname is empty) 73 | # Given arguments: clean_challenge|deploy_challenge altname token-filename token-content 74 | # 75 | # After successfully signing certificate 76 | # Given arguments: deploy_cert domain path/to/privkey.pem path/to/cert.pem path/to/fullchain.pem 77 | # 78 | # BASEDIR and WELLKNOWN variables are exported and can be used in an external program 79 | # default: 80 | HOOK={{ DEHYDRATED_HOOK }} 81 | 82 | # Chain clean_challenge|deploy_challenge arguments together into one hook call per certificate (default: no) 83 | #HOOK_CHAIN="no" 84 | 85 | # Minimum days before expiration to automatically renew certificate (default: 30) 86 | RENEW_DAYS={{ DEHYDRATED_RENEW_DAYS }} 87 | 88 | # Regenerate private keys instead of just signing new certificates on renewal (default: yes) 89 | PRIVATE_KEY_RENEW={{ DEHYDRATED_KEY_RENEW }} 90 | 91 | # Create an extra private key for rollover (default: no) 92 | #PRIVATE_KEY_ROLLOVER="no" 93 | 94 | # Which public key algorithm should be used? Supported: rsa, prime256v1 and secp384r1 95 | KEY_ALGO={{ DEHYDRATED_KEY_ALGO }} 96 | 97 | # E-mail to use during the registration (default: ) 98 | CONTACT_EMAIL={{ DEHYDRATED_EMAIL }} 99 | 100 | # Lockfile location, to prevent concurrent access (default: $BASEDIR/lock) 101 | #LOCKFILE="${BASEDIR}/lock" 102 | 103 | # Option to add CSR-flag indicating OCSP stapling to be mandatory (default: no) 104 | #OCSP_MUST_STAPLE="no" 105 | 106 | # Fetch OCSP responses (default: no) 107 | #OCSP_FETCH="no" 108 | 109 | # Issuer chain cache directory (default: $BASEDIR/chains) 110 | #CHAINCACHE="${BASEDIR}/chains" 111 | 112 | # Automatic cleanup (default: no) 113 | #AUTO_CLEANUP="no" 114 | 115 | # ACME API version (default: auto) 116 | #API=auto 117 | -------------------------------------------------------------------------------- /root/etc/periodic/weekly/dehydrated: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chown -R ${UID}:${GID} /data 3 | # Run dehydrated 4 | su-exec ${UID}:${GID} /opt/dehydrated/dehydrated --config /data/config --cron --keep-going 5 | -------------------------------------------------------------------------------- /root/etc/s6.d/.s6-svscan/finish: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | -------------------------------------------------------------------------------- /root/etc/s6.d/cron/finish: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | -------------------------------------------------------------------------------- /root/etc/s6.d/cron/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec crond -f 3 | -------------------------------------------------------------------------------- /root/etc/s6.d/dehydrated/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | s6-svc -O /etc/s6.d/dehydrated 3 | 4 | # If config generation is turned on, generate a config from the template and current env vars 5 | if [[ "$DEHYDRATED_GENERATE_CONFIG" == "yes" ]]; then 6 | j2 /etc/dehydrated/config.j2 > /data/config 7 | fi 8 | 9 | # Set ownership to dehydrated on the relevant folders 10 | chown -R ${UID}:${GID} /data 11 | 12 | # Register to the CA 13 | if [[ "$DEHYDRATED_ACCEPT_TERMS" == "yes" ]]; then 14 | su-exec ${UID}:${GID} /opt/dehydrated/dehydrated --config /data/config --register --accept-terms 15 | fi 16 | 17 | # Run the weekly script once 18 | /etc/periodic/weekly/dehydrated 19 | -------------------------------------------------------------------------------- /root/usr/local/bin/lexicon-hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Example how to deploy a DNS challenge using lexicon 4 | 5 | set -e 6 | set -u 7 | set -o pipefail 8 | 9 | export PROVIDER=${PROVIDER:-"cloudflare"} 10 | 11 | function deploy_challenge { 12 | local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" 13 | 14 | echo "deploy_challenge called: ${DOMAIN}, ${TOKEN_FILENAME}, ${TOKEN_VALUE}" 15 | 16 | lexicon --config-dir=/data $PROVIDER create ${DOMAIN} TXT --name="_acme-challenge.${DOMAIN}." --content="${TOKEN_VALUE}" 17 | 18 | sleep 30 19 | 20 | # This hook is called once for every domain that needs to be 21 | # validated, including any alternative names you may have listed. 22 | # 23 | # Parameters: 24 | # - DOMAIN 25 | # The domain name (CN or subject alternative name) being 26 | # validated. 27 | # - TOKEN_FILENAME 28 | # The name of the file containing the token to be served for HTTP 29 | # validation. Should be served by your web server as 30 | # /.well-known/acme-challenge/${TOKEN_FILENAME}. 31 | # - TOKEN_VALUE 32 | # The token value that needs to be served for validation. For DNS 33 | # validation, this is what you want to put in the _acme-challenge 34 | # TXT record. For HTTP validation it is the value that is expected 35 | # be found in the $TOKEN_FILENAME file. 36 | } 37 | 38 | function clean_challenge { 39 | local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" 40 | 41 | echo "clean_challenge called: ${DOMAIN}, ${TOKEN_FILENAME}, ${TOKEN_VALUE}" 42 | 43 | lexicon --config-dir=/data $PROVIDER delete ${DOMAIN} TXT --name="_acme-challenge.${DOMAIN}." --content="${TOKEN_VALUE}" 44 | 45 | # This hook is called after attempting to validate each domain, 46 | # whether or not validation was successful. Here you can delete 47 | # files or DNS records that are no longer needed. 48 | # 49 | # The parameters are the same as for deploy_challenge. 50 | } 51 | 52 | function invalid_challenge() { 53 | local DOMAIN="${1}" RESPONSE="${2}" 54 | 55 | echo "invalid_challenge called: ${DOMAIN}, ${RESPONSE}" 56 | 57 | # This hook is called if the challenge response has failed, so domain 58 | # owners can be aware and act accordingly. 59 | # 60 | # Parameters: 61 | # - DOMAIN 62 | # The primary domain name, i.e. the certificate common 63 | # name (CN). 64 | # - RESPONSE 65 | # The response that the verification server returned 66 | } 67 | 68 | function deploy_cert { 69 | local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" 70 | 71 | echo "deploy_cert called: ${DOMAIN}, ${KEYFILE}, ${CERTFILE}, ${FULLCHAINFILE}, ${CHAINFILE}" 72 | 73 | cat ${FULLCHAINFILE} ${KEYFILE} > $(dirname ${CERTFILE})/combined.pem 74 | chmod 'u=rw,g=r,o=' "${KEYFILE}" "${CERTFILE}" "${FULLCHAINFILE}" "${CHAINFILE}" "$(dirname ${CERTFILE})/combined.pem" 75 | 76 | # This hook is called once for each certificate that has been 77 | # produced. Here you might, for instance, copy your new certificates 78 | # to service-specific locations and reload the service. 79 | # 80 | # Parameters: 81 | # - DOMAIN 82 | # The primary domain name, i.e. the certificate common 83 | # name (CN). 84 | # - KEYFILE 85 | # The path of the file containing the private key. 86 | # - CERTFILE 87 | # The path of the file containing the signed certificate. 88 | # - FULLCHAINFILE 89 | # The path of the file containing the full certificate chain. 90 | # - CHAINFILE 91 | # The path of the file containing the intermediate certificate(s). 92 | } 93 | 94 | function unchanged_cert { 95 | local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" 96 | 97 | echo "unchanged_cert called: ${DOMAIN}, ${KEYFILE}, ${CERTFILE}, ${FULLCHAINFILE}, ${CHAINFILE}" 98 | 99 | # This hook is called once for each certificate that is still 100 | # valid and therefore wasn't reissued. 101 | # 102 | # Parameters: 103 | # - DOMAIN 104 | # The primary domain name, i.e. the certificate common 105 | # name (CN). 106 | # - KEYFILE 107 | # The path of the file containing the private key. 108 | # - CERTFILE 109 | # The path of the file containing the signed certificate. 110 | # - FULLCHAINFILE 111 | # The path of the file containing the full certificate chain. 112 | # - CHAINFILE 113 | # The path of the file containing the intermediate certificate(s). 114 | } 115 | 116 | exit_hook() { 117 | # This hook is called at the end of a dehydrated command and can be used 118 | # to do some final (cleanup or other) tasks. 119 | 120 | : 121 | } 122 | 123 | startup_hook() { 124 | # This hook is called before the dehydrated command to do some initial tasks 125 | # (e.g. starting a webserver). 126 | 127 | : 128 | } 129 | 130 | HANDLER=$1; shift; 131 | if [ -n "$(type -t $HANDLER)" ] && [ "$(type -t $HANDLER)" = function ]; then 132 | $HANDLER "$@" 133 | fi 134 | --------------------------------------------------------------------------------