Let's assume your domain is example.com
and you want to issue a Let's Encrypt
wildcard certificate for it. Therefor you would need to create a TXT resource
record for _acme-challenge.example.com
. But you cannot or do not want to give
any ACME client your credentials for DNS server or hoster API.
- you need a host with a static public IP with
docker
set up and no service running on public port 53 - let's assume the host has IP1.2.3.4
- without changing the docker-compose file, we can bind the container just to
one IP address (v4 or v6) - in this example we stick with
1.2.3.4
- you should create an
A
(orAAAA
) record for this server in this example we chosetmp-ns.example.com
pointing to1.2.3.4
- come up with a zone name you do not run any service under and do not plan to do so
we will use
acme-challenge-zone.example.com
- add a
NS
record foracme-challenge-zone.example.com
with the valuetmp-ns.example.com
to your DNS - to get a wildcard certificate for
example.com
you would need to create aTXT
record for_acme-challenge.example.com
- let's delegate this to our newly created zone with a
CNAME
record for_acme-challenge.example.com
pointing to_acme-challenge.acme-challenge-zone.example.com
- for every other domain that you want to get certificates for, create another
CNAME
record eg:_acme-challenge.internal.example2.com
to_acme-challenge.acme-challenge-zone.example.com
- copy/clone this repository to your host
tmp-ns.example.com
(1.2.3.4
) - if you already have an Let's Encrypt RSA acoount key that you want to keep using, place it in certs/account.key - a new will be generated otherwise
- for each certificate you want to request, create a .cfg file in certs/
- in these .cfg files empty lines and lines starting with
#
(hash) will be ignored - put as many domain names in these .cfg files as that certificate should be valid for
- the fist domain name will be used as the certificates common name - the following will become alternative names
- for our example, create a file
certs/example.com.cfg
with content:# common name example.com # alt name *.example.com
- if you already have an RSA key for
example.com
that you wish to keep, place it atcerts/example.com.key
(the name before .key needs to match the name of the .cfg file before .cfg) - copy
.env.example
in the project root to.env
and set values accordingly - build the docker images initially
docker-compose build --pull
- to get the CSR (and maybe missing key files) run in the project root folder:
docker-compose run --no-deps --rm --user "$(id -u):$(id -g)" acme prepare
- to get the certificate for the CSR, run:
that's also what you need to run to renew your certificate(s)
docker-compose run --rm --user "$(id -u):$(id -g)" acme ; docker-compose down --volumes
To test the setup (in dev branch?) you could do:
-
ensure to use a separate directory (do not mix with config, certificates and keys you need for production)
-
setup DNS as described above
-
copy and fill
.env
as described above ensure to setACME_SERVER=staging
for testing -
place this script in the root of your test directory:
#!/bin/sh MY_DOMAIN='example.com' set -e cleanup() { docker-compose down --volumes } trap cleanup EXIT INT if [ -e ./certs/account.key ]; then unlink ./certs/account.key; fi if [ -e ./certs/${MY_DOMAIN}.csr ]; then unlink ./certs/${MY_DOMAIN}.csr; fi if [ -e ./certs/${MY_DOMAIN}.key ]; then unlink ./certs/${MY_DOMAIN}.key; fi if [ -e ./certs/${MY_DOMAIN}.pem ]; then unlink ./certs/${MY_DOMAIN}.pem; fi { echo '# common name' echo "${MY_DOMAIN}" echo '' echo '# alternative names' echo "*.${MY_DOMAIN}" } >./certs/${MY_DOMAIN}.cfg docker-compose build --pull docker-compose run --no-deps --rm --user "$(id -u):$(id -g)" acme prepare docker-compose run --rm --user "$(id -u):$(id -g)" acme TXT_CERT="$(openssl x509 -text -in ./certs/${MY_DOMAIN}.pem)" echo "${TXT_CERT}" | grep 'Issuer:' echo "${TXT_CERT}" | grep 'Validity' -A 2 echo "${TXT_CERT}" | grep 'Subject:' echo "${TXT_CERT}" | grep 'Subject Alternative Name' -A 1