User's Guide

Introduction & Design Philosophy

acmetool is an easy-to-use command line tool for automatically acquiring TLS certificates from ACME servers such as Let's Encrypt, designed to flexibly integrate into your webserver setup to enable automatic verification.

Non-interference. Unlike the official Let's Encrypt client, this doesn't modify your web server configuration.

Target-oriented and idempotent. acmetool is designed to work like “make”: you specify what certificates you want, and acmetool obtains certificates as necessary to satisfy those requirements. If the requirements are already satisfied, acmetool doesn't do anything when invoked. Thus, acmetool is ideally suited for use on a cron job; it will do nothing until certificates are near expiry, and then obtain new ones.

Clear and minimal state. acmetool is designed to minimise the use of state and be transparent in the state that it does use. All state, including certificates, is stored in a single directory, by default /var/lib/acme. The schema for this directory is simple, comprehensible and documented.

Stable filenames. The certificate for a given hostname example.com always lives at /var/lib/acme/live/example.com/{cert,chain,privkey}. This is a symlink to the real certificate directory and gets changed as certificates are renewed.

Fully automatic renewal. acmetool can automatically reload your webserver when it changes the target of a live symlink. In conjunction with acmetool's use of stable filenames and idempotent design, this means that renewal can be fully automatic.

Flexible validation methods. acmetool supports six different validation methods:

Non-root operation. If you don't want to trust acmetool, you can setup acmetool to operate without running as root. If you don't have root access to a system, you may still be able to use acmetool by configuring it to use a local directory and webroot mode.

Designed for automation. acmetool is designed to be fully automatable. Response files allow you to run the quickstart wizard automatically.

Installation

You can install acmetool by building from source or by using a binary release. Both are easy.

Installing: using binary releases. Binary releases are found here. Unpack, copy the binary to /usr/local/bin/acmetool (or wherever you like), and you're done.

_cgo releases are preferred over non-_cgo releases where available, but non-_cgo releases may be more compatible with older OSes. (The main drawback of non-_cgo releases is that they exhibit reduced functionality in relation to privilege dropping and daemonization functionality for the redirector daemon.)

Installing: Ubuntu users. A binary release PPA, ppa:hlandau/rhea (package acmetool) is available.

$ sudo add-apt-repository ppa:hlandau/rhea
$ sudo apt-get update
$ sudo apt-get install acmetool

You can also download .deb files manually.

(Note: There is no difference between the .deb files for different Ubuntu release codenames; they are interchangeable and completely equivalent.)

Installing: Debian users. The Ubuntu binary release PPA also works with Debian:

# echo 'deb http://ppa.launchpad.net/hlandau/rhea/ubuntu xenial main' > /etc/apt/sources.list.d/rhea.list
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9862409EF124EC763B84972FF5AC9651EDB58DFA
# apt-get update
# apt-get install acmetool

You can also download .deb files manually.

(Note: There is no difference between the .deb files for different Ubuntu release codenames; they are interchangeable and completely equivalent.)

Installing: RPM-based distros: A copr RPM repository is available.

If you have dnf installed:

$ sudo dnf copr enable hlandau/acmetool
$ sudo dnf install acmetool

Otherwise use the .repo files on the repository page and use yum, or download RPMs and use rpm directly.

Installing: Arch Linux users. An AUR PKGBUILD for building from source is available.

$ wget https://aur.archlinux.org/cgit/aur.git/snapshot/acmetool-git.tar.gz
$ tar xvf acmetool-git.tar.gz
$ cd acmetool-git
$ makepkg -s
$ sudo pacman -U ./acmetool*.pkg.tar.xz

Installing: Alpine Linux users. An APKBUILD for building from source is available.

Installing: from source. Clone, make, make install. You will need Go 1.5.2 or later installed to build from source.

If you are using Linux, you will need to make sure the development files for libcap are installed. This is probably a package for your distro called libcap-dev or libcap-devel or similar.

# This is necesary to work around a change in Git's default configuration
# which hasn't yet been accounted for in some places.
$ git config --global http.followRedirects true

$ git clone https://github.com/hlandau/acme
$ cd acme
$ make && sudo make install

Installing: from source (existing GOPATH). The Makefile is intended to make things easy for users unfamiliar with Go packaging conventions. If you know what a GOPATH is and have one set up, you can and should instead simply do:

$ git config --global http.followRedirects true
$ go get -u github.com/hlandau/acme/cmd/acmetool
$ sudo cp $GOPATH/bin/acmetool /usr/local/bin/acmetool

(Note: Although use of cgo is recommended, building without cgo is supported.)

After installation

Initial configuration. Having installed acmetool, run the quickstart wizard for a guided setup. You may wish to ensure you have dialog in your PATH, but acmetool will fallback to basic stdio prompts if it's not available.

$ sudo acmetool quickstart

If you don't want to run acmetool as root, see the non-root setup guide.

Pass --expert to quickstart if you want to choose what key parameters to use (RSA or ECDSA, RSA key size, ECDSA curve). By default 2048-bit RSA is used.

If you want to automate the quickstart process, see the section on response files below.

It is safe to rerun quickstart at any time.

Configuring your web server. Once you've completed the quickstart, you should configure your web server as necessary to enable validation. See the Web server configuration section below.

Obtaining certificates. Once everything's ready, simply run:

$ sudo acmetool want example.com www.example.com

This adds a target desiring a certificate for hostnames example.com and www.example.com. You can specify as many hostnames (SANs) as you like. Whenever you run acmetool in the future, it'll make sure that a certificate for these hostnames is available and not soon to expire.

acmetool lumps hostnames together in the same certificate. If you want example.com and www.example.com to be separate certificates, use separate want commands to configure them as separate targets:

$ sudo acmetool want example.com
$ sudo acmetool want www.example.com

If all went well, your certificate should be available at /var/lib/acme/live/example.com. This is a directory containing PEM files cert, chain, fullchain and privkey. The use of these files varies by application; typically you will use only a subset of these files.

Troubleshooting. If all didn't go well, you might find it helpful to run with debug logging:

$ sudo acmetool --xlog.severity=debug

(There's no need to run “want” again; the targets are recorded even if reconciliation is not successful.)

Auto-renewal. acmetool offers to install a cronjob during the quickstart process. This simply runs acmetool --batch, which will idempotently ensure that all configured targets are satisfied by certificates not soon to expire. (--batch here ensures that acmetool doesn't try to ask any questions.)

Auto-renewal: reloading your webserver. When acmetool refreshes a certificate, it changes the symlink in live and executes hook scripts to reload your web server or do whatever you want. Specifically, it executes any executable files in /usr/lib/acme/hooks (or /usr/libexec/acme/hooks if on a distro that uses libexec). You can drop your own executable files here, and acmetool will invoke them when it changes certificates. (For information on the calling convention, see SCHEMA.md.)

acmetool quickstart installs some default hooks applicable to common webservers. These hooks contain the string #!acmetool-managed!#. acmetool reserves the right to overwrite any file containing this string with a newer version of the script, in the event that the default scripts are updated in subsequent versions of acmetool. If you make changes to a default script and do not wish them to be overwritten, you should remove this line to ensure that your changes are not overwritten. However, note that the default hook scripts are designed to be configurable and it will be rare that you need to modify the scripts themselves. If you encounter a situation where you need to change the script itself, you may consider whether it would be appropriate to file an enhancement request. The string #!acmetool-managed!# must be present near the start of the file in order to be detected.

If you want to disable a default hook entirely, you should replace it with an empty file rather than deleting it, as acmetool quickstart will automatically install absent default hooks.

Default hook scripts: the reload hook. The reload hook is a default hook installed by acmetool quickstart. It reloads a list of services using commands specific to the distro. The correct command is detected automatically; service $SERVICE reload, systemctl reload $SERVICE, and /etc/init.d/$SERVICE reload are supported.

A default list of services is provided which includes the most common webserver service names. This list can be customised using the reload hook configuration file.

The reload hook configuration file is located at /etc/conf.d/acme-reload or /etc/default/acme-reload; the correct path depends on the conventions of your distro. It is a sourced shell file which can modify the default configuration variables of the reload script. Currently, the only variable is the SERVICES variable, a space-separated list of service names.

You can overwrite the services list outright, or append to it like so:

# Example reload hook configuration file adding a service to the list of
# services to be restarted.
SERVICES="$SERVICES cherokee"

Default hook scripts: the haproxy hook. The haproxy hook is a default hook which acmetool quickstart can optionally install. It only offers to install this hook if HAProxy is detected as being installed on the system.

HAProxy is rather bizarre in its TLS configuration requirements; it requires certificates and private key to be appended together in the same file. acmetool does not support this natively and is unlikely ever to as a default configuration for security reasons. Instead, the haproxy hook creates the necessary files for HAProxy from the certificate and private key files whenever they are updated. Thus, additional copies of the private key are only made when necessary to support HAProxy.

Inside the state directory. acmetool aims to minimise the use of state and be transparent about the state it does keep. When you run acmetool want, acmetool does these things:

To demonstrate, you can replicate the function of acmetool want:

$ sudo touch /var/lib/acme/desired/example.com
$ sudo acmetool

Target files live in the desired directory. An empty target file defaults to its filename as the target hostname.

More information on the format of the acmetool state directory and target files.

Web server configuration: challenges

What web server configuration you need to do depends on the validation method you have selected.

Redirector mode. No configuration required, but ensure that your web server is not listening on port 80 and that the redirector service (acmetool redirector --service.daemon --service.uid=uid-to-drop-privileges-to) is started.

Proxy mode: nginx/tengine. You can configure nginx/tengine for use with acmetool in proxy mode as follows:

http {
  server {
    ... your configuration ...

    location /.well-known/acme-challenge/ {
      proxy_pass http://acmetool;
    }
  }

  upstream acmetool {
    # (Change to port 4402 if using non-root mode.)
    server 127.0.0.1:402;
  }
}

This configuration will need to be repeated for each vhost. You may wish to avoid duplication by placing the applicable configuration in a separate file and including it in each vhost.

Proxy mode: Apache httpd.

# (Change to port 4402 if using non-root mode.)
ProxyPass "/.well-known/acme-challenge" "http://127.0.0.1:402/.well-known/acme-challenge"

Ensure you load the modules mod_proxy and mod_proxy_http.

Proxy mode: Changing port. If you need to change the ports on which acmetool listens, see the request: challenge: http-ports directive. See State storage schema.

Webroot mode. If you don't have a particular webroot path in mind, consider using /var/run/acme/acme-challenge as a recommended standard. acmetool defaults to this as a webroot path if you don't explicitly configure one. (See “Challenge Completion Philosophy” below.)

Webroot mode: nginx/tengine.

http {
  server {
    location /.well-known/acme-challenge/ {
      alias /var/run/acme/acme-challenge/;
    }
  }
}

Note that the configuration will need to be repeated for each vhost. You may wish to avoid duplication by placing the applicable configuration in a separate file and including it in each vhost.

Webroot mode: Apache httpd.

Alias "/.well-known/acme-challenge/" "/var/run/acme/acme-challenge/"
<Directory "/var/run/acme/acme-challenge">
  AllowOverride None
  Options None

  # If using Apache 2.4+
  Require all granted

  # If using Apache 2.2 and lower
  Order allow, deny
  Allow from all
</Directory>

Hook mode. See Challenge Hooks.

Stateless mode. In stateless mode, you configure your webserver to respond to challenge requests without consulting acmetool. A single account key is nominated. This is one of the most reliable and least error-prone methods for simple cases.

Stateless mode: nginx/Tengine.

Replace ACCOUNT_THUMBPRINT in the example below with your account thumbprint. You can retrieve your account thumbprint by running acmetool account-thumbprint. The first part of each line output is the account thumbprint.

http {
  server {
    location ~ "^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$" {
      default_type text/plain;
      return 200 "$1.ACCOUNT_THUMBPRINT";
    }
  }
}

Stateless mode: Apache. It does not appear that the configuration system of Apache can currently express the needed behaviour.

Web server configuration: TLS

Mozilla has a TLS configuration generator that you can use to generate configurations for common web servers.

Challenge completion philosophy

acmetool's philosophy to completing challenges is to try absolutely anything that might work. So long as something works, acmetool doesn't care what it was that worked. When acmetool quickstart asks you what method to use, this is asked purely to determine a) whether to ask you for a webroot path (if you selected webroot mode) and b) whether to ask you if you want to install the redirector service (if you selected redirector mode and are using systemd, for which automatic service installation is supported). It doesn't determine what strategies acmetool does or doesn't use, so it's normal to see log output relating to a failure to use methods other than the one you chose.

acmetool always tries to listen on port 402 and 4402 when completing challenges, in case something proxies to it. It always tries to listen on ports 80 and 443, in case you're not running a webserver yet. And it always tries to place challenge files in any webroot paths you have configured. Finally, it always tries to place challenge files in /var/run/acme/acme-challenge; this serves as a standard location for challenge files, and the redirector daemon works by looking here.

Failure to complete any of these efforts is non-fatal. Ultimately, all acmetool cares about is that a challenge completes successfully after having attempted all possible preparations. It doesn't know or care why a challenge succeeds, only that it succeeded.

(For HTTP-based challenges, acmetool self-tests its ability to complete the challenge by issuing a request for the same URL which will be requested by the ACME server, and does not proceed if this does not validate. Thus, HTTP-based challenges will never work if you are running some sort of weird split-horizon configuration where challenge files are retrievable only from the internet but not the local machine.)

The state storage schema

The format of acmetool's state directory is authoritatively documented here. What follows is a summary of the more important parts.

live directory: Contains symlinks from hostnames to certificate directories. Each certificate directory contains cert, chain, fullchain and privkey files. (If you are using HAProxy and have chosen to install the HAProxy hook script, a haproxy file will also be available containing key, certificate and chain all in one.)

You should configure your web server in terms of paths like /var/lib/acme/live/example.com/{cert,chain,fullchain,privkey}.

desired directory: Contains targetfiles. These determine the certificates which will be requested. Each target file is a YAML file, split into two principal sections: the satisfy section and the request section.

The satisfy section dictates what conditions must be met in order for a certificate to meet a target (and thus be selected for symlinking under the live directory). The request section dictates the parameters for requesting new certificates, but nothing under it determines whether a certificate is requested.

Finally, the priority value determines which target is used for a hostname when there are multiple targets for the same hostname. Higher priorities take precedence. The default priority is 0.

In most cases, you will set only satisfy.names in a target file, and will set all other settings in the default target file, which is located at conf/target. The quickstart wizard sets this file up for you. All settings in the default target file are inherited by targets, but can be overridden individually.

satisfy:
  names:
    - example.com       # The names you want on the certificate.
    - www.example.com

request:
  provider:               # ACME Directory URL. Normally set in conf/target only.
  ocsp-must-staple: true  # Request OCSP Must Staple. Use with care.
  challenge:
    webroot-paths:        # You can specify custom webroot paths.
      - /var/www
    http-ports:           # You can specify different ports for proxying.
      - 123               # Defaults to listening on localhost.
      - 456
      - 0.0.0.0:789       # Global listen.
    http-self-test: false # Defaults to true. If false, will not perform self-test
                          # but will assume challenge can be completed. Rarely needed.
    env:                  # Optionally set environment variables to be passed to hooks.
      FOO: BAR
  key:                    # What sort of key will be used for this certificate?
    type: rsa|ecdsa
    rsa-size: 2048
    ecdsa-curve: nistp256
    id: krzh2akn...       # If specified, the key ID to use to generate new certificates.
                          # If not specified, a new private key will always be generated.
                          # Useful for key pinning.

priority: 0

HAProxy support: If you have chosen to install the HAProxy hook script, each certificate directory will also have a coalesced haproxy file containing certificate chain and private key. There will also be a haproxy directory mapping from hostnames directly to these files.

accounts directory: ACME account keys and state information. You don't need to worry about this.

certs and keys: Contains certificates and keys used to satisfy targets. However, you should never need to reference these directories directly.

Please note that it is a requirement that the state directory not straddle filesystem boundaries. That is, all files under /var/lib/acme must lie on the same filesystem.

Response files

It is possible to automatically provide responses to any question acmetool can ask.

To do this, you provide the --response-file flag, with the path to a YAML file containing response information. An example of such a file is here.

If you don't provide a --response-file flag, acmetool will try to look for one at /var/lib/acme/conf/responses. If using a response file, it's recommended that you place it at this location.

The file specifies key-value pairs. Each key is a prompt ID. (You can find these by grepping the source code for UniqueID.)

(For messages which simply require acknowledgement, specify true to bypass them. Yes/no prompts should have a boolean value specified. The example response file is demonstrative.)

You should specify --batch when using a response file to prevent acmetool from trying to prompt the user and fail instead, in case it tries to ask anything which you don't have a response for in your response file.

Hooks

Hooks provide a means to extend acmetool with arbitrary behaviour. Hooks are executable files installed by default at /usr/lib/acme/hooks (or, on systems which use /usr/libexec, /usr/libexec/acme/hooks).

The event type is always passed as the first argument. A hook must exit with exit code 42 for event types it doesn't handle.

There are currently two types of hook: notification hooks and challenge hooks.

Notification hooks

The quickstart wizard installs default notification hooks to reload common webservers and other services after acmetool changes the preferred certificate for a hostname. These hooks are executable shell scripts and you can, if you wish, substitute your own. The default hooks are good bases from which to make your own customisations.

You can use notification hooks to reload webservers, distribute certificates and private keys to other servers, or convert certificates and private keys into another format which is required by some daemon. For example, HAProxy support is implemented entirely via hook.

The event type is "live-updated".

Challenge hooks

In some complex use cases, it may be necessary to install HTTP challenge files via some arbitrary programmatic means, rather than via one of the standard methods of webroot, proxy, redirector or listener.

Challenge hooks are executed when challenge files need to be added or removed. Your hook must be synchronous; it must exit only when the challenge file is definitely in place and is globally accessible.

See the specification for more information.

Challenge hooks are supported for HTTP, TLS-SNI and DNS challenges. A list of third party challenge hook scripts can be found here.

Command line options

See the acmetool(8) manual page.

Troubleshooting

Passing --xlog.severity=debug increases the logging verbosity of acmetool and should be your first troubleshooting strategy.

FAQ

I've selected the (webroot/proxy/redirector/listener) challenge method, but I'm seeing log entries for other methods, or for webroots other than the one I configured.

This is normal. By design, acmetool always tries anything which might work, and these errors are nonfatal as long as something works. The challenge method you select in the quickstart wizard determines only whether to ask you for a webroot path, and whether to install the redirector (if you are using system). The webroot path /var/run/acme/acme-challenge, as a standard location, will always be tried in addition to any webroot you specify, as will proxy and listener mode ports.

Fore more information, see challenge completion philosophy.

Annex: Root-configured non-root operation

The following steps describe how you can, as root, take a series of steps that allows you to invoke acmetool as a non-root user, thereby limiting your attack surface and the degree to which you trust acmetool.

It is also possible to use acmetool without you having access to root at all. In this case, place acmetool in a location of your choice and pass the --state and --hooks flags with appropriate paths of your choice to all invocations of acmetool.

Rootless setup as root

acmetool has experimental support for root-free operation.

In order to run root-free, after installing acmetool in /usr/local/bin (or wherever you want it), before running acmetool, do the following:

Annex: External resources and third party extentions

The list of various tutorials, hook scripts and other integrations people have made for acmetool is now maintained in the wiki.