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:
Webroot: acmetool places challenge files in a given directory, allowing your normal web server to serve them. You must ensure the directory is served at /.well-known/acme-challenge/
.
Proxy: When acmetool needs to validate for a domain, it temporarily spins up a built-in web server on port 402 or 4402 (if being used under the non-root validation mode). You configure your web server to proxy requests for /.well-known/acme-challenge/
to this server at the same path.
Stateless: You configure your webserver to respond statelessly to challenges for a given account key without consulting acmetool. This requires nothing more than a one-time web server configuration change and no “moving parts”.
Redirector: If the only thing you want to do with port 80 is redirect people to port 443, you can use acmetool's built in redirector HTTP server. You must ensure that your existing web server does not listen on port 80. acmetool redirects requests to HTTPS, but its control of port 80 ensures it can complete validation.
Listen: Listen on port 80 or 443. This is only really useful for development purposes.
Hook: You can write custom shell scripts or binary executables which acmetool invokes to provision challenges at the desired location.
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.
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.)
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:
It configures a new target by writing a YAML file to /var/lib/acme/desired/
describing the desired hostnames.
It runs the default command, reconcile
, to ensure that all targets are met.
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.
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.
Mozilla has a TLS configuration generator that you can use to generate configurations for common web servers.
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 always fail the self-test 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. You can tell acmetool to proceed anyway by setting request:
, challenge:
, http-self-test: false
in the default target file, or in the specific targets where this is needed.)
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.
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 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.
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".
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.
See the acmetool(8) manual page.
Passing --xlog.severity=debug
increases the logging verbosity of acmetool and should be your first troubleshooting strategy.
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.
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.
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:
Create a new user acme
(or whatever you want).
Create the directory /var/lib/acme
and change the owning user and group to acme
. (You can use a different directory, but you must then make sure you pass --state PATH
to all invocations of acmetool.)
Create the directory /usr/lib/acme/hooks
(/usr/libexec/acme/hooks
on distros which use libexec). Make it writable by acme
for the time being by changing the group to acme
and making the directory group-writable. (You can make this read-only after running the quickstart process, which places some shell scripts in here to reload servers. You can audit these scripts yourself or use your own if you wish.)
Change to the user acme
and run acmetool quickstart
.
$ sudo -u acme acmetool quickstart
A crontab will be installed automatically as the acme
user; you may wish to examine it.
As root, make the hooks
directory root-owned/not group writable once more. Ensure that the scripts are root-owned:
# chown -R root:root /usr/lib*/acme/hooks
# chmod 755 /usr/lib*/acme/hooks
Inspect the hook scripts if you wish. Mark the hook scripts setuid:
# chmod u+s /usr/lib*/acme/hooks/*
UNIX systems don't support setuid shell scripts, so this bit is ignored. Rather, acmetool takes it as a flag to tell it to run these scripts via sudo
. This is necessary so that web servers, etc. can be reloaded.
The conditions for running using sudo
are that the files have the setuid bit set, that they be owned by root, that they be scripts and not binaries, and that acmetool is not being run as root.
Setup sudo. You will need to edit the sudoers file so that the hook scripts (which you have inspected and trust) can be executed by acmetool. It is essential that these have the NOPASSWD
flag as the scripts must be executable noninteractively.
# visudo
Add the line:
acme ALL=(root) NOPASSWD: /usr/lib/acme/hooks/
Setup your challenge method:
Webroot: Make sure the acme
user can write to the webroot directory you configured.
Redirector: Make sure the directory /var/run/acme/acme-challenge
is writable by the acme
user. acmetool
puts challenges here because the redirector looks here (internally it's a glorified webroot mode).
Note that /var/run
will be a tmpfs on many modern OSes, so the directory ceases to exist on reboots. The redirector will try to create the directory (as user root, mode 0755) if it doesn't exist. This happens before the redirector drops privileges from root. (It has to run as root initially to bind to port 80.)
A configuration option has been added to make the redirector ensure that the directory is writable by a certain group when starting up. When this option is used, mode 0775 is used instead and the group owner is changed to a given GID.
Pass --challenge-gid=GID
to acmetool redirector
(edit your service manager's configuration, e.g. the systemd unit file), where GID is the numeric group ID of the group owner for the challenge directory (i.e. the GID of the acme
group). (Group names rather than IDs may be supported on some platforms, but this is not guaranteed and will vary. Use of a GID is recommended.)
Proxy: If you are using the proxy method, you won't be able to listen on port 402 as a non-root user. Use port 4402 instead, which acmetool will try also try to use.
Listener: This is not usable under non-root operation unless you can enable acmetool to bind to ports 80/443. On Linux you can do this by running setcap 'cap_net_bind_service=+ep' /path/to/acmetool
as root. Other POSIX platforms may have sysctls to allow non-root processes to bind to low ports. However, this mode is not really useful for anything other than development anyway.
Hook: See Challenge Hooks.
The list of various tutorials, hook scripts and other integrations people have made for acmetool is now maintained in the wiki.