acme-companion Documentation

Automated ACME SSL certificate generation for nginx-proxy

7,703 stars Shell Shell 1 file ยท ~9,794 tokens #acme#acme-protocol#acme-v2#buypass#docker#letsencrypt#nginx-proxy#ssl
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy acme-companion on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name acme-companion -p 14000:14000 --restart always ghcr.io/letsencrypt/pebble:${PEBBLE_VERSION}
Configured Services & Ports
โš™๏ธ pebble
image: ghcr.io/letsencrypt/pebble:${PEBBLE_VERSION}
๐Ÿ”Œ Ports: 14000:14000, 15000:15000
โš™๏ธ challtestsrv
image: ghcr.io/letsencrypt/pebble-challtestsrv:${PEBBLE_VERSION}
๐Ÿ”Œ Ports: 8055:8055
docker-compose.yml
yaml (docker-compose.yml)
services:
  pebble:
    image: "ghcr.io/letsencrypt/pebble:${PEBBLE_VERSION}"
    container_name: pebble
    volumes:
      - "./${PEBBLE_CONFIG}:/test/config/pebble-config.json"
    environment:
      - PEBBLE_VA_NOSLEEP=1
      - PEBBLE_WFE_NONCEREJECT=0
    command: -config /test/config/pebble-config.json -dnsserver 10.30.50.3:8053
    ports:
      - 14000:14000 # HTTPS ACME API
      - 15000:15000 # HTTPS Management API
    networks:
      acme_net:
        ipv4_address: 10.30.50.2

  challtestsrv:
    image: "ghcr.io/letsencrypt/pebble-challtestsrv:${PEBBLE_VERSION}"
    container_name: challtestserv
    command: -defaultIPv6 "" -defaultIPv4 10.30.50.3
    ports:
      - 8055:8055 # HTTP Management API
    networks:
      acme_net:
        ipv4_address: 10.30.50.3

networks:
  acme_net:
    name: acme_net
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 10.30.50.0/24

File: README.md

acme-companion





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.

Features:

  • 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) or DNS-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.

HTTP-01 challenge requirements:

  • Your host must be publicly reachable on both port 80 and 443.
  • Check your firewall rules and do not attempt to block 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.
  • 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 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.

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.

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 "[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.

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 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 environment variable.

Example using 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 "[email protected]" \
    grafana/grafana

Repeat Step 3 for any other container you want to proxy.

Additional documentation

Please check the docs section and the environment variables reference 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 image and the official 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, 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 into the docker-gen container. You can get the nginx.tmpl file with a command like:
text
curl https://raw.githubusercontent.com/nginx-proxy/nginx-proxy/main/nginx.tmpl > /path/to/nginx.tmpl
  1. 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).

  2. 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

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 "[email protected]" \
    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.
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. 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.

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 "[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.

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 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 environment variable.

Example using 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 "[email protected]" \
    grafana/grafana

Repeat Step 3 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 (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)

  • 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, 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

  • 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

  • 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 for more detail. This can also be set per-container (see 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 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). 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 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://<host>: (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 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 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 and advanced 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 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. 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 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:
      - [email protected]
    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:
      - [email protected]
    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 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:


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 and three containers setups), plus the ID of the docker-gen container in a three container setup.

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. Be advised that for now, this works to a very limited extent (everything has to be on the same node).

Examples with three containers setups:

label method.

text
$ 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

text
$ 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

text
$ 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

text
$ 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 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:

  • provide the pre-generated EAB credentials 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 are available through the corresponding environment variables. This allows to trigger actions just before and after certificates are issued (see acme.sh documentation).

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 "[email protected]" \
    --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 "[email protected]" \
    --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, 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.