acme-companion is a lightweight companion container for nginx-proxy.
It handles the automated creation, renewal and use of SSL certificates for proxied Docker containers through the ACME protocol.
- Automated creation/renewal of Let's Encrypt (or other ACME CAs) certificates using acme.sh.
- Let's Encrypt / ACME domain validation through
HTTP-01
(by default) orDNS-01
challenge. - Automated update and reload of nginx config on certificate creation/renewal.
- Support creation of Multi-Domain (SAN) Certificates.
- Support creation of Wildcard Certificates (with
DNS-01
challenge only). - Creation of a strong RFC7919 Diffie-Hellman Group at startup.
- Work with all versions of docker.
- Your host must be publicly reachable on both port
80
and443
. - Check your firewall rules and do not attempt to block port
80
as that will preventHTTP-01
challenges from completing. - For the same reason, you can't use nginx-proxy's
HTTPS_METHOD=nohttp
. - The (sub)domains you want to issue certificates for must correctly resolve to the host.
- If your (sub)domains have AAAA records set, the host must be publicly reachable over IPv6 on port
80
and443
.
If you can't meet these requirements, you can use the DNS-01
challenge instead. Please refer to the documentation for more information.
In addition to the above, please ensure that your DNS provider answers correctly to CAA record requests. If your DNS provider answer with an error, Let's Encrypt won't issue a certificate for your domain. Let's Encrypt do not require that you set a CAA record on your domain, just that your DNS provider answers correctly.
Two writable volumes must be declared on the nginx-proxy container so that they can be shared with the acme-companion container:
/etc/nginx/certs
to store certificates and private keys (readonly for the nginx-proxy container)./usr/share/nginx/html
to writehttp-01
challenge files.
Additionally, a third volume must be declared on the acme-companion container to store acme.sh
configuration and state: /etc/acme.sh
.
Please also read the doc about data persistence.
Example of use:
Start nginx-proxy with the two additional volumes declared:
$ docker run --detach \
--name nginx-proxy \
--publish 80:80 \
--publish 443:443 \
--volume certs:/etc/nginx/certs \
--volume html:/usr/share/nginx/html \
--volume /var/run/docker.sock:/tmp/docker.sock:ro \
nginxproxy/nginx-proxy
Binding the host docker socket (/var/run/docker.sock
) inside the container to /tmp/docker.sock
is a requirement of nginx-proxy.
Start the acme-companion container, getting the volumes from nginx-proxy with --volumes-from
:
$ docker run --detach \
--name nginx-proxy-acme \
--volumes-from nginx-proxy \
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
--volume acme:/etc/acme.sh \
--env "[email protected]" \
nginxproxy/acme-companion
The host docker socket has to be bound inside this container too, this time to /var/run/docker.sock
.
Albeit optional, it is recommended to provide a valid default email address through the DEFAULT_EMAIL
environment variable, so that Let's Encrypt can warn you about expiring certificates and allow you to recover your account.
Once both nginx-proxy and acme-companion containers are up and running, start any container you want proxied with environment variables VIRTUAL_HOST
and LETSENCRYPT_HOST
both set to the domain(s) your proxied container is going to use.
VIRTUAL_HOST
control proxying by nginx-proxy and LETSENCRYPT_HOST
control certificate creation and SSL enabling by acme-companion.
Certificates will only be issued for containers that have both VIRTUAL_HOST
and LETSENCRYPT_HOST
variables set to domain(s) that correctly resolve to the host, provided the host is publicly reachable.
$ docker run --detach \
--name your-proxied-app \
--env "VIRTUAL_HOST=subdomain.yourdomain.tld" \
--env "LETSENCRYPT_HOST=subdomain.yourdomain.tld" \
nginx
The containers being proxied must expose the port to be proxied, either by using the EXPOSE
directive in their Dockerfile or by using the --expose
flag to docker run
or docker create
.
If the proxied container listen on and expose another port than the default 80
, you can force nginx-proxy to use this port with the VIRTUAL_PORT
environment variable.
Example using Grafana (expose and listen on port 3000):
$ docker run --detach \
--name grafana \
--env "VIRTUAL_HOST=othersubdomain.yourdomain.tld" \
--env "VIRTUAL_PORT=3000" \
--env "LETSENCRYPT_HOST=othersubdomain.yourdomain.tld" \
--env "[email protected]" \
grafana/grafana
Repeat Step 3 for any other container you want to proxy.
Please check the docs section.