## File: README.md # acme-companion [](https://github.com/nginx-proxy/acme-companion/actions/workflows/test.yml) [](https://github.com/nginx-proxy/acme-companion/releases) [](https://hub.docker.com/r/nginxproxy/acme-companion "Click to view the image on Docker Hub") [](https://hub.docker.com/r/nginxproxy/acme-companion "Click to view the image on Docker Hub") [](https://hub.docker.com/r/nginxproxy/acme-companion "Click to view the image on Docker Hub") **acme-companion** is a lightweight companion container for [**nginx-proxy**](https://github.com/nginx-proxy/nginx-proxy). It handles the automated creation, renewal and use of SSL certificates for proxied Docker containers through the ACME protocol. ### Features: * Automated creation/renewal of Let's Encrypt (or other ACME CAs) certificates using [**acme.sh**](https://github.com/acmesh-official/acme.sh). * Let's Encrypt / ACME domain validation through `HTTP-01` (by default) or [`DNS-01`](https://github.com/nginx-proxy/acme-companion/blob/main/docs/Let's-Encrypt-and-ACME.md#dns-01-acme-challenge) challenge. * Automated update and reload of nginx config on certificate creation/renewal. * Support creation of [Multi-Domain (SAN) Certificates](https://github.com/nginx-proxy/acme-companion/blob/main/docs/Let's-Encrypt-and-ACME.md#multi-domains-certificates). * Support creation of [Wildcard Certificates](https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578) (with `DNS-01` challenge only). * Creation of a strong [RFC7919 Diffie-Hellman Group](https://datatracker.ietf.org/doc/html/rfc7919#appendix-A) at startup. * Work with all versions of docker. ### HTTP-01 challenge requirements: * Your host **must** be publicly reachable on **both** port [`80`](https://letsencrypt.org/docs/allow-port-80/) and [`443`](https://github.com/nginx-proxy/acme-companion/discussions/873#discussioncomment-1410225). * Check your firewall rules and [**do not attempt to block port `80`**](https://letsencrypt.org/docs/allow-port-80/) as that will prevent `HTTP-01` challenges from completing. * For the same reason, you can't use nginx-proxy's [`HTTPS_METHOD=nohttp`](https://github.com/nginx-proxy/nginx-proxy#how-ssl-support-works). * 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` and `443`. If you can't meet these requirements, you can use the `DNS-01` challenge instead. Please refer to the [documentation](https://github.com/nginx-proxy/acme-companion/blob/main/docs/Let's-Encrypt-and-ACME.md#dns-01-acme-challenge) 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](https://letsencrypt.org/docs/caa/). Let's Encrypt do not require that you set a CAA record on your domain, just that your DNS provider answers correctly. ## Basic usage (with the nginx-proxy container) 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 write `http-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](./docs/Persistent-data.md). Example of use: ### Step 1 - nginx-proxy Start **nginx-proxy** with the two additional volumes declared: ```shell $ 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**. ### Step 2 - acme-companion Start the **acme-companion** container, getting the volumes from **nginx-proxy** with `--volumes-from`: ```shell $ 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 "DEFAULT_EMAIL=mail@yourdomain.tld" \ 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. ### Step 3 - proxied container(s) Once both **nginx-proxy** and **acme-companion** containers are up and running, start any container you want proxied with environment variables `VIRTUAL_HOST` and `ACME_HOST` both set to the domain(s) your proxied container is going to use. [`VIRTUAL_HOST`](https://github.com/nginx-proxy/nginx-proxy#usage) controls proxying by **nginx-proxy** and `ACME_HOST` controls certificate creation and SSL enabling by **acme-companion**. Certificates will only be issued for containers that have both `VIRTUAL_HOST` and `ACME_HOST` variables set to domain(s) that correctly resolve to the host, provided the host is publicly reachable. ```shell $ docker run --detach \ --name your-proxied-app \ --env "VIRTUAL_HOST=subdomain.yourdomain.tld" \ --env "ACME_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`](https://github.com/nginx-proxy/nginx-proxy#multiple-ports) environment variable. Example using [Grafana](https://hub.docker.com/r/grafana/grafana/) (expose and listen on port 3000): ```shell $ docker run --detach \ --name grafana \ --env "VIRTUAL_HOST=othersubdomain.yourdomain.tld" \ --env "VIRTUAL_PORT=3000" \ --env "ACME_HOST=othersubdomain.yourdomain.tld" \ --env "ACME_EMAIL=mail@yourdomain.tld" \ grafana/grafana ``` Repeat [Step 3](#step-3---proxied-containers) for any other container you want to proxy. ## Additional documentation Please check the [docs section](https://github.com/nginx-proxy/acme-companion/tree/main/docs) and the [environment variables reference](https://github.com/nginx-proxy/acme-companion/blob/main/docs/Environment-variables-reference.md) for more information about the available configuration options. ## About this repository > [!NOTE] > This repository is officially maintained by **ZeroSSL** as part of our commitment to secure and reliable SSL/TLS solutions. > We welcome contributions and feedback from the community! > For more information about our services, including free and paid SSL/TLS certificates, visit https://zerossl.com. --- ## File: docs/Advanced-usage.md ## Advanced usage (with the nginx and docker-gen containers) **nginx-proxy** can also be run as two separate containers using the [nginx-proxy/**docker-gen**](https://github.com/nginx-proxy/docker-gen) image and the official [**nginx**](https://hub.docker.com/_/nginx/) image. You may want to do this to prevent having the docker socket bound to a publicly exposed container service (ie avoid mounting the docker socket in the nginx exposed container). Please read and try [basic usage](./Basic-usage.md), and **validate that you have a working two containers setup** before using the three containers setup. In addition to the steps described there, running **nginx-proxy** as two separate containers with **acme-companion** requires the following: 1) Download and mount the template file [nginx.tmpl](https://github.com/nginx-proxy/nginx-proxy/blob/main/nginx.tmpl) into the **docker-gen** container. You can get the nginx.tmpl file with a command like: ``` curl https://raw.githubusercontent.com/nginx-proxy/nginx-proxy/main/nginx.tmpl > /path/to/nginx.tmpl ``` 2) Use the `com.github.nginx-proxy.docker-gen` label on the **docker-gen** container, or explicitly set the `NGINX_DOCKER_GEN_CONTAINER` environment variable on the **acme-companion** container to the name or id of the **docker-gen** container (we'll use the later method in the example). 3) Declare `/etc/nginx/conf.d` as a volume on the nginx container so that it can be shared with the **docker-gen** container. Example: ### Step 1 - nginx * Start nginx [(official image)](https://hub.docker.com/_/nginx/) with the required volumes: ```shell $ docker run --detach \ --name nginx-proxy \ --publish 80:80 \ --publish 443:443 \ --volume conf:/etc/nginx/conf.d \ --volume html:/usr/share/nginx/html \ --volume certs:/etc/nginx/certs \ nginx ``` ### Step 2 - docker-gen * Start the **docker-gen** container with the shared volumes (with `--volume-from`), the template file and the docker socket: ```shell $ docker run --detach \ --name nginx-proxy-gen \ --volumes-from nginx-proxy \ --volume /path/to/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro \ --volume /var/run/docker.sock:/tmp/docker.sock:ro \ nginxproxy/docker-gen \ -notify-sighup nginx-proxy -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf ``` Note that you must pass the exact name of the **nginx** container to **docker-gen** `-notify-sighup` argument (here `nginx-proxy`). ### Step 3 - acme-companion * Start the **acme-companion** container with the `NGINX_DOCKER_GEN_CONTAINER` environment variable correctly set: ```shell $ 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 "NGINX_DOCKER_GEN_CONTAINER=nginx-proxy-gen" \ --env "DEFAULT_EMAIL=mail@yourdomain.tld" \ nginxproxy/acme-companion ``` ### Step 4 - proxied container(s) * Once the three containers are up, start any containers to be proxied as described in [basic usage](./Basic-usage.md). ```shell $ docker run --detach \ --name your-proxyed-app \ --env "VIRTUAL_HOST=subdomain.yourdomain.tld" \ --env "ACME_HOST=subdomain.yourdomain.tld" \ nginx ``` If you are experiencing issues with this setup, fall back to the [basic setup](./Basic-usage.md). The advanced setup is not meant to be obligatory. --- ## File: docs/Basic-usage.md ## Basic usage (with the nginx-proxy container) 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 write `HTTP-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](./Persistent-data.md). Example of use: ### Step 1 - nginx-proxy Start **nginx-proxy** with the two additional volumes declared: ```shell $ 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**. ### Step 2 - acme-companion Start the **acme-companion** container, getting the volumes from **nginx-proxy** with `--volumes-from`: ```shell $ 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 "DEFAULT_EMAIL=mail@yourdomain.tld" \ 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. ### Step 3 - proxied container(s) Once both **nginx-proxy** and **acme-companion** containers are up and running, start any container you want proxied with environment variables `VIRTUAL_HOST` and `ACME_HOST` both set to the domain(s) your proxied container is going to use. Multiple hosts can be separated using commas. [`VIRTUAL_HOST`](https://github.com/nginx-proxy/nginx-proxy#usage) controls proxying by **nginx-proxy** and `ACME_HOST` controls certificate creation and SSL enabling by **acme-companion**. Certificates will only be issued for containers that have both `VIRTUAL_HOST` and `ACME_HOST` variables set to domain(s) that correctly resolve to the host, provided the host is publicly reachable. ```shell $ docker run --detach \ --name your-proxyed-app \ --env "VIRTUAL_HOST=subdomain.yourdomain.tld" \ --env "ACME_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`](https://github.com/nginx-proxy/nginx-proxy#multiple-ports) environment variable. Example using [Grafana](https://hub.docker.com/r/grafana/grafana/) (expose and listen on port 3000): ```shell $ docker run --detach \ --name grafana \ --env "VIRTUAL_HOST=othersubdomain.yourdomain.tld" \ --env "VIRTUAL_PORT=3000" \ --env "ACME_HOST=othersubdomain.yourdomain.tld" \ --env "ACME_EMAIL=mail@yourdomain.tld" \ grafana/grafana ``` Repeat [Step 3](#step-3---proxyed-containers) for any other container you want to proxy. --- ## File: docs/Container-configuration.md ## Optional container environment variables for custom configuration. * `ACME_CA_URI` - Directory URI for the CA ACME API endpoint (defaults to ``https://acme-v02.api.letsencrypt.org/directory``). If you set this environment variable value to `https://acme-staging-v02.api.letsencrypt.org/directory` the container will obtain its certificates from Let's Encrypt test API endpoint that don't have the [5 certs/week/domain limit](https://letsencrypt.org/docs/rate-limits/) (but are not trusted by browsers). For example ```bash $ docker run --detach \ --name nginx-proxy-acme \ --volumes-from nginx-proxy \ --volume /var/run/docker.sock:/var/run/docker.sock:ro \ --volume certs:/etc/nginx/certs:rw \ --volume acme:/etc/acme.sh \ --env "ACME_CA_URI=https://acme-staging-v02.api.letsencrypt.org/directory" \ nginxproxy/acme-companion ``` You can also create test certificates per container (see [Test certificates](./Let's-Encrypt-and-ACME.md#test-certificates)) * `DEBUG` - Set it to `1` to enable debugging of the entrypoint script and generation of LetsEncrypt certificates, which could help you pinpoint any configuration issues. When enabled, `acme.sh`'s own detailed log is also sent to the container output (visible through `docker logs`) instead of being discarded, which is especially useful for diagnosing DNS-01 challenge failures. * `RENEW_PRIVATE_KEYS` - Set it to `false` to make `acme.sh` reuse previously generated private key for each certificate instead of creating a new one on certificate renewal. Reusing private keys can help if you intend to use [HPKP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning), but please note that HPKP has been deprecated by Google's Chrome and that it is therefore strongly discouraged to use it at all. This can also be set per proxied container by setting `ACME_RENEW_PRIVATE_KEYS` on that container, which overrides the global value for its certificate (e.g. to keep a stable key for a DANE/TLSA mail certificate while still rotating keys elsewhere). * `DHPARAM_BITS` - Change the key size of the RFC7919 Diffie-Hellman group used by the container from the default value of 4096 bits. Supported values are `2048`, `3072` and `4096`. The DH group file will be located in the container at `/etc/nginx/certs/dhparam.pem`. Mounting a different `dhparam.pem` file at that location will override the RFC7919 group creation by the acme-companion container. **COMPATIBILITY WARNING**: some older clients (like Java 6 and 7) do not support DH keys with over 1024 bits. In order to support these clients, you must provide your own `dhparam.pem`. * `DHPARAM_SKIP` - Set it to `true` to disable the Diffie-Hellman group creation by the container entirely. * `ACME_CA_BUNDLE` - This variable changes the trusted root CA used by `acme.sh`, from the default Alpine trust store to the CA bundle file located at the provided path (inside the container). This can be useful if you are running your own ACME CA. * `CERTS_UPDATE_INTERVAL` - 3600 seconds by default, this defines how often the container will check if the certificates require update. * `ACME_PRE_HOOK` - The provided command will be run before every certificate issuance. The action is limited to the commands available inside the **acme-companion** container. For example `--env "ACME_PRE_HOOK=echo 'start'"`. For more information see [Pre- and Post-Hook](./Hooks.md) * `ACME_POST_HOOK` - The provided command will be run after every certificate issuance. The action is limited to the commands available inside the **acme-companion** container. For example `--env "ACME_POST_HOOK=echo 'end'"`. For more information see [Pre- and Post-Hook](./Hooks.md) * `ACME_RENEW_AFTER` - 60 days by default, this defines the number of days between certificate renewals attempts. For certificates issued by certain Certificate Authorities, such as Buypass, which have a lifespan of 180 days, it may be advisable to initiate the renewal process on day 150 rather than the default day 60. See [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA) for more detail. This can also be set per-container (see [Certificate renewal timing](./Let's-Encrypt-and-ACME.md#certificate-renewal-timing)). * `DEFAULT_RENEW` - **DEPRECATED**: This variable is deprecated and replaced by `ACME_RENEW_AFTER`. It still works for backward compatibility, but a warning will be logged on container startup. Please migrate to `ACME_RENEW_AFTER`. * `ACME_HTTP_CHALLENGE_LOCATION` - Previously **acme-companion** automatically added the ACME HTTP challenge location to the nginx configuration through files generated in `/etc/nginx/vhost.d`. Recent versions of **nginx-proxy** (>= `1.6`) already include the required location configuration, which remove the need for **acme-companion** to attempt to dynamically add them. If you're running and older version of **nginx-proxy** (or **docker-gen** with an older version of the `nginx.tmpl` file), you can re-enable this behaviour by setting `ACME_HTTP_CHALLENGE_LOCATION` to `true`. * `ENABLE_IPV6` - Set it to `true` to make the **standalone** ACME HTTP challenge configuration (used for domains not served by **nginx-proxy**, e.g. `ACME_STANDALONE_CERTS`) also listen over IPv6 (`listen [::]:80;`) in addition to IPv4. This matches **nginx-proxy**'s [`ENABLE_IPV6`](https://github.com/nginx-proxy/nginx-proxy#ipv6-support) option, so set the same value on both containers. Leave it unset (or `false`) unless your host and its Docker networking actually support IPv6, otherwise nginx may fail to bind the IPv6 socket. Only the standalone challenge config is affected; challenges served through nginx-proxy already follow nginx-proxy's own IPv6 setting. * `RELOAD_NGINX_ONLY_ONCE` - The companion reload nginx configuration after every new or renewed certificate. Previously this was done only once per service loop, at the end of the loop (this was causing delayed availability of HTTPS enabled application when multiple new certificates where requested at once, see [issue #1147](https://github.com/nginx-proxy/acme-companion/issues/1147)). You can restore the previous behaviour if needed by setting the environment variable `RELOAD_NGINX_ONLY_ONCE` to `true`. * `DOCKER_CONTAINER_FILTERS` - You can filter which containers are considered by acme-companion by using the `DOCKER_CONTAINER_FILTERS` environment variable (by default, acme-companion will consider all running containers). It takes a comma separated list of `key=value` pairs. For example, setting `DOCKER_CONTAINER_FILTERS` environment variable to `network=mynetwork` will cause acme-companion to consider only containers connected to the `mynetwork` network. See the [Docker CLI documentation](https://docs.docker.com/reference/cli/docker/container/ls/#filter) for details on available filters. * `DOCKER_HOST` - The Docker API endpoint acme-companion talks to. Defaults to `unix:///var/run/docker.sock` (the mounted Docker socket). To connect to a remote or TLS-protected Docker daemon over TCP, set it to `tcp://:` (the conventional Docker TLS port is `2376`). * `DOCKER_TLS_VERIFY` and `DOCKER_CERT_PATH` - Enable TLS client-certificate authentication when connecting to the Docker daemon over `tcp://`. Set `DOCKER_TLS_VERIFY` to `true` and `DOCKER_CERT_PATH` to the **in-container** path of a directory containing `ca.pem`, `cert.pem` and `key.pem`. These variable names and file names match the [Docker CLI convention](https://docs.docker.com/engine/security/protect-access/) and the ones used by **docker-gen**, so the same certificate directory can be shared across containers. > **Important:** `DOCKER_CERT_PATH` is a path **inside the container**. You must mount your certificate directory into the container with a volume, otherwise the files will not be found and the container will exit on startup with an error. For example, connecting to a TLS-protected Docker daemon over TCP (note that the Docker socket is **not** mounted in this case): ```bash $ docker run --detach \ --name nginx-proxy-acme \ --volumes-from nginx-proxy \ --volume certs:/etc/nginx/certs:rw \ --volume acme:/etc/acme.sh \ --volume /path/to/docker/certs:/docker-certs:ro \ --env "DOCKER_HOST=tcp://docker-host.example.com:2376" \ --env "DOCKER_TLS_VERIFY=true" \ --env "DOCKER_CERT_PATH=/docker-certs" \ nginxproxy/acme-companion ``` --- ## File: docs/Container-utilities.md The container provide the following utilities (replace `nginx-proxy-acme` with the name or ID of your **acme-companion** container when executing the commands): ### Force certificates renewal If needed, you can force a running **acme-companion** container to renew all certificates that are currently in use with the following command: ```bash $ docker exec nginx-proxy-acme force_renew ``` ### Manually trigger the service loop You can trigger the execution of the service loop before the hourly execution with: ```bash $ docker exec nginx-proxy-acme signal_le_service ``` Unlike the previous command, this won't force renewal of certificates that don't need to be renewed. ### Show certificates informations To display informations about your existing certificates, use the following command: ```bash $ docker exec nginx-proxy-acme cert_status ``` --- ## File: docs/Docker-Compose.md ## Usage with Docker Compose As stated by its repository, [Docker Compose](https://github.com/docker/compose) is a tool for defining and running multi-container Docker applications using a single _Compose file_. This Wiki page is not meant to be a definitive reference on how to run **nginx-proxy** and **acme-companion** with Docker Compose, as the number of possible setups is quite extensive and they can't be all covered. ### Before your start Be sure to be familiar with both the [basic](./Basic-usage.md) and [advanced](./Advanced-usage.md) non compose setups, and Docker Compose usage. The following examples are minimal, clean starting points, not a definitive reference. They follow current Docker Compose conventions: * The top-level `version:` key is intentionally omitted: it is obsolete in the [Compose Specification](https://docs.docker.com/reference/compose-file/) and ignored by Docker Compose. * They do not use `volumes_from` (a compose file version 2 only feature): every volume is mounted explicitly on each container instead. * **acme-companion** finds the **nginx**/**nginx-proxy** (and **docker-gen**) container through the `label` method, see [getting container IDs](./Getting-containers-IDs.md). The `NGINX_PROXY_CONTAINER` / `NGINX_DOCKER_GEN_CONTAINER` environment variable method documented there is an equally valid alternative. If you still rely on a `volumes_from` based compose file, see [getting container IDs](./Getting-containers-IDs.md) for the `docker run --volumes-from` method (still supported) and this page's git history for the previous examples. The use of named containers and volumes is not required but helps keeping everything clear and organized. ### Two containers example ```yaml services: nginx-proxy: image: nginxproxy/nginx-proxy container_name: nginx-proxy ports: - "80:80" - "443:443" labels: - "com.github.nginx-proxy.nginx" volumes: - certs:/etc/nginx/certs:ro - html:/usr/share/nginx/html - /var/run/docker.sock:/tmp/docker.sock:ro # The vhost and conf volumes are only required # if you plan to obtain standalone certificates # - vhost:/etc/nginx/vhost.d # - conf:/etc/nginx/conf.d acme-companion: image: nginxproxy/acme-companion container_name: nginx-proxy-acme environment: - DEFAULT_EMAIL=mail@yourdomain.tld volumes: - certs:/etc/nginx/certs:rw - html:/usr/share/nginx/html:rw - acme:/etc/acme.sh - /var/run/docker.sock:/var/run/docker.sock:ro # The vhost and conf volumes are only required # if you plan to obtain standalone certificates # - vhost:/etc/nginx/vhost.d # - conf:/etc/nginx/conf.d # A user-defined network is optional; Compose creates a default one per project. #networks: # default: # name: nginx-proxy volumes: certs: html: acme: # vhost: # conf: ``` ### Three containers example ```yaml services: nginx: image: nginx:alpine container_name: nginx-proxy ports: - "80:80" - "443:443" labels: - "com.github.nginx-proxy.nginx" volumes: - conf:/etc/nginx/conf.d:ro - html:/usr/share/nginx/html - certs:/etc/nginx/certs:ro # The vhost volume is only required if you # plan to obtain standalone certificates # - vhost:/etc/nginx/vhost.d docker-gen: image: nginxproxy/docker-gen container_name: nginx-proxy-gen command: -notify-sighup nginx-proxy -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf labels: - "com.github.nginx-proxy.docker-gen" volumes: - conf:/etc/nginx/conf.d:rw - certs:/etc/nginx/certs:ro - /path/to/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro - /var/run/docker.sock:/tmp/docker.sock:ro # The vhost volume is only required if you # plan to obtain standalone certificates # - vhost:/etc/nginx/vhost.d acme-companion: image: nginxproxy/acme-companion container_name: nginx-proxy-acme environment: - DEFAULT_EMAIL=mail@yourdomain.tld volumes: - certs:/etc/nginx/certs:rw - html:/usr/share/nginx/html:rw - acme:/etc/acme.sh - /var/run/docker.sock:/var/run/docker.sock:ro # The vhost and conf volumes are only required # if you plan to obtain standalone certificates # - vhost:/etc/nginx/vhost.d # - conf:/etc/nginx/conf.d #networks: # default: # name: nginx-proxy volumes: conf: html: certs: acme: # vhost: ``` **Note:** don't forget to replace `/path/to/nginx.tmpl` with the actual path to the [`nginx.tmpl`](https://raw.githubusercontent.com/nginx-proxy/nginx-proxy/main/nginx.tmpl) file you downloaded. ### Other (external) examples **Warning:** some of those examples might be outdated and not working properly with version >= `2.0` of this project. If you want other examples how to use this container with Docker Compose, look at: * [Nicolas Duchon's Examples](https://github.com/buchdag/letsencrypt-nginx-proxy-companion-compose) - with automated testing * [Evert Ramos's Examples](https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion) - using docker-compose version '3' * [Karl Fathi's Examples](https://github.com/fatk/docker-letsencrypt-nginx-proxy-companion-examples) * [More examples from Karl](https://github.com/pixelfordinner/pixelcloud-docker-apps/tree/master/nginx-proxy) * [George Ilyes' Examples](https://github.com/gilyes/docker-nginx-letsencrypt-sample) * [Dmitry's simple docker-compose example](https://github.com/dmitrym0/simple-lets-encrypt-docker-compose-sample) * [Radek's docker-compose jenkins example](https://github.com/dataminelab/docker-jenkins-nginx-letsencrypt) --- ## File: docs/Getting-containers-IDs.md ## Getting nginx-proxy/nginx/docker-gen containers IDs For **acme-companion** to work properly, it needs to know the ID of the **nginx**/**nginx-proxy** container (in both [two](./Basic-usage.md) and [three](./Advanced-usage.md) containers setups), plus the ID of the **docker-gen** container in a [three container setup](./Advanced-usage.md). There are three methods to inform the **acme-companion** container of the **nginx**/**nginx-proxy** container ID: * `label` method: add the label `com.github.nginx-proxy.nginx` to the **nginx**/**nginx-proxy** container. * `environment variable` method: assign a fixed name to the **nginx**/**nginx-proxy** container with `container_name:` and set the environment variable `NGINX_PROXY_CONTAINER` to this name on the **acme-companion** container. * `volumes_from` method. Using this method, the **acme-companion** container will get the **nginx**/**nginx-proxy** container ID from the volumes it got using the `volumes_from` option. And two methods to inform the **acme-companion** container of the **docker-gen** container ID: * `label` method: add the label `com.github.nginx-proxy.docker-gen` to the **docker-gen** container. * `environment variable` method: assign a fixed name to the **docker-gen** container with `container_name:` and set the environment variable `NGINX_DOCKER_GEN_CONTAINER` to this name on the **acme-companion** container. The methods for each container are sorted by order of precedence, meaning that if you use both the label and the volumes_from method, the ID of the **nginx**/**nginx-proxy** container that will be used will be the one found using the label. **There is no point in using more than one method at a time for either the nginx/nginx-proxy or docker-gen container beside potentially confusing yourself**. The advantage the `label` methods have over the `environment variable` (and `volumes_from`) methods is enabling the use of the **acme-companion** in environments where containers names are dynamic, like in Swarm Mode or in Docker Cloud. However if you intend to do so, as upstream **docker-gen** lacks the ability to identify containers from labels, you'll need both to either use the two containers setup or to replace nginx-proxy/docker-gen with a fork that has this ability like [herlderco/docker-gen](https://github.com/helderco/docker-gen). Be advised that for now, this works to a very limited extent [(everything has to be on the same node)](https://github.com/nginx-proxy/acme-companion/pull/231#issuecomment-330624331). #### Examples with three containers setups: `label` method. ``` $ docker run --detach \ [...] --label com.github.nginx-proxy.nginx \ nginx $ docker run --detach \ [...] --label com.github.nginx-proxy.docker-gen \ nginxproxy/docker-gen $ docker run --detach \ [...] nginxproxy/acme-companion ``` `environment variable` method ``` $ docker run --detach \ [...] --name unique-container-name \ nginx $ docker run --detach \ [...] --name another-unique-container-name \ nginxproxy/docker-gen $ docker run --detach \ [...] --env NGINX_PROXY_CONTAINER=unique-container-name \ --env NGINX_DOCKER_GEN_CONTAINER=another-unique-container-name \ nginxproxy/acme-companion ``` `volumes_from` (**nginx**) + `label` (**docker-gen**) method ``` $ docker run --detach \ [...] --name unique-container-name \ nginx $ docker run --detach \ [...] --label com.github.nginx-proxy.docker-gen \ nginxproxy/docker-gen $ docker run --detach \ [...] --volumes-from unique-container-name \ nginxproxy/acme-companion ``` `volumes_from` (**nginx**) + `environment variable` (**docker-gen**) method ``` $ docker run --detach \ [...] --name unique-container-name \ nginx $ docker run --detach \ [...] --name another-unique-container-name \ nginxproxy/docker-gen $ docker run --detach \ [...] --volumes-from unique-container-name \ --env NGINX_DOCKER_GEN_CONTAINER=another-unique-container-name \ nginxproxy/acme-companion ``` --- ## File: docs/Google-Trust-Services.md ## Google Trust Services [Google Trust Service](https://pki.goog/) is an ACME CA with generous default quota and high ubiquity. Using Google Trust Services through an ACME client, like in this container, allows for unlimited 90 days and multi-domains (SAN) certificates. ### Activation Google Trust Services support is activated when the `ACME_CA_URI` environment variable is set to the Google Trust Services ACME endpoint (`https://dv.acme-v02.api.pki.goog/directory`). ### Account Google Trust Services requires the use of an externally bound account. First create a [Google Trust Services account](https://cloud.google.com/certificate-manager/docs/public-ca-tutorial#request-key-hmac): - provide the pre-generated [EAB credentials](https://tools.ietf.org/html/rfc8555#section-7.3.4) using the `ACME_EAB_KID` and `ACME_EAB_HMAC_KEY` environment variables. These variables can be set on the proxied containers or directly on the **acme-companion** container. When registering a new ACME account with EAB, Google Trust Services expects a contact email. Set either `ACME_EMAIL` on the proxied container or `DEFAULT_EMAIL` on the **acme-companion** container so the initial `acme.sh --register-account` call includes it. If both are unset or blank, **acme-companion** will still try to register the EAB account without an email and log a warning, but Google Trust Services may reject the registration. --- ## File: docs/Hooks.md ## Pre-Hooks and Post-Hooks The Pre- and Post-Hooks of [acme.sh](https://github.com/acmesh-official/acme.sh/) are available through the corresponding environment variables. This allows to trigger actions just before and after certificates are issued (see [acme.sh documentation](https://github.com/acmesh-official/acme.sh/wiki/Using-pre-hook-post-hook-renew-hook-reloadcmd)). If you set `ACME_PRE_HOOK` and/or `ACME_POST_HOOK` on the **acme-companion** container, **the actions for all certificates will be the same**. If you want specific actions to be run for specific certificates, set the `ACME_PRE_HOOK` / `ACME_POST_HOOK` environment variable(s) on the proxied container(s) instead. Default (on the **acme-companion** container) and per-container `ACME_PRE_HOOK` / `ACME_POST_HOOK` environment variables aren't combined : if both default and per-container variables are set for a given proxied container, the per-container variables will take precedence over the default. If you want to run the same default hooks for most containers but not for some of them, you can set the `ACME_PRE_HOOK` / `ACME_POST_HOOK` environment variables to the Bash noop operator (ie, `ACME_PRE_HOOK=:`) on those containers. #### Pre-Hook: `ACME_PRE_HOOK` This command will be run before certificates are issued. For example `echo 'start'` on the **acme-companion** container (setting a default Pre-Hook): ```shell $ 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 "DEFAULT_EMAIL=mail@yourdomain.tld" \ --env "ACME_PRE_HOOK=echo 'start'" \ nginxproxy/acme-companion ``` And on a proxied container (setting a per-container Pre-Hook): ```shell $ docker run --detach \ --name your-proxyed-app \ --env "VIRTUAL_HOST=yourdomain.tld" \ --env "ACME_HOST=yourdomain.tld" \ --env "ACME_PRE_HOOK=echo 'start'" \ nginx ``` #### Post-Hook: `ACME_POST_HOOK` This command will be run after certificates are issued. For example `echo 'end'` on the **acme-companion** container (setting a default Post-Hook): ```shell $ 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 "DEFAULT_EMAIL=mail@yourdomain.tld" \ --env "ACME_POST_HOOK=echo 'end'" \ nginxproxy/acme-companion ``` And on a proxied container (setting a per-container Post-Hook): ```shell $ docker run --detach \ --name your-proxyed-app \ --env "VIRTUAL_HOST=yourdomain.tld" \ --env "ACME_HOST=yourdomain.tld" \ --env "ACME_POST_HOOK=echo 'start'" \ nginx ``` #### Verification: If you want to check wether the hook-command is delivered properly to [acme.sh](https://github.com/acmesh-official/acme.sh/), you should check `/etc/acme.sh/[EMAILADDRESS]/[DOMAIN]/[DOMAIN].conf`. The variable `Le_PreHook` contains the Pre-Hook-Command base64 encoded. The variable `Le_PostHook` contains the Post-Hook-Command base64 encoded. #### Limitations * The commands that can be used in the hooks are limited to the commands available inside the **acme-companion** container. `curl` and `wget` are available, therefore it is possible to communicate with tools outside the container via HTTP, allowing for complex actions to be implemented outside or in other containers. #### Use-cases * Changing some firewall rules just for the ACME authorization, so the ports 80 and/or 443 don't have to be publicly reachable at all time. * Certificate "post processing" / conversion to another format. * Monitoring.