:lock: acmetool, an automatic certificate acquisition tool for ACME (Let's Encrypt)

acmetool

[webchat: freenode #acmetool]
[download count] [version]
[ppa
debian/ubuntu] Build Status

acmetool is an easy-to-use command line tool for automatically acquiring certificates from ACME servers (such as Let's Encrypt). Designed to flexibly integrate into your webserver setup to enable automatic verification. Unlike the official Let's Encrypt client, this doesn't modify your web server configuration.

Zero-downtime autorenewal
Supports any webserver
Fully automatable
Single-file dependency-free binary
Idempotent
Fast setup

You can perform verifications using port 80 or 443 (if you don't yet have a server running on one of them); via webroot; by configuring your webserver to proxy requests for /.well-known/acme-challenge/ to a special port (402) which acmetool can listen on; or by configuring your webserver not to listen on port 80, and instead running acmetool's built in HTTPS redirector (and challenge responder) on port 80. This is useful if all you want to do with port 80 is redirect people to port 443.

You can run acmetool on a cron job to renew certificates automatically (acmetool --batch). The preferred certificate for a given hostname is always at /var/lib/acme/live/HOSTNAME/{cert,chain,fullchain,privkey}. You can configure acmetool to reload your webserver automatically when it renews a certificate.

acmetool is intended to be "magic-free". All of acmetool's state is stored in a simple, comprehensible directory of flat files. The schema for this directory is documented.

acmetool is intended to work like "make". The state directory expresses target domain names, and whenever acmetool is invoked, it ensures that valid certificates are available to meet those names. Certificates which will expire soon are renewed. acmetool is thus idempotent and minimises the use of state.

acmetool can optionally be used without running it as root. If you have existing certificates issued using the official client, acmetool can import those certificates, keys and account keys (acmetool import-le).

acmetool supports both RSA and ECDSA keys and certificates. acmetool's notification hooks system allows you to write arbitrary shell scripts to be executed when new certificates are obtained. By default, this is used to reload webservers automatically, but it can also be used to distribute certificates to other servers or for other purposes.

Getting Started

Binary releases: Binary releases are available.

Download the release appropriate for your platform and simply copy the acmetool binary to /usr/bin.

_cgo releases are preferred over non-_cgo releases where available, but non-_cgo releases may be more compatible with older OSes.

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

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

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.

Void Linux users: acmetool is in the repositories:

$ sudo xbps-install acmetool

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

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

FreeBSD users: FreeBSD port is available.

Building from source: You will need Go installed to build from source.

If you are on 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 necessary 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

  # (People familiar with Go with a GOPATH setup can alternatively use go get/go install:)
  $ git config --global http.followRedirects true
  $ go get github.com/hlandau/acme/cmd/acmetool

After installation

# Run the quickstart wizard. Sets up account, cronjob, etc.
# (If you want to use ECDSA keys or set RSA key size, pass "--expert".)
$ sudo acmetool quickstart

# Configure your webserver to serve challenges if necessary.
# See https://hlandau.github.io/acmetool/userguide#web-server-configuration
$ ...

# Request the hostnames you want:
$ sudo acmetool want example.com www.example.com

# Now you have certificates:
$ ls -l /var/lib/acme/live/example.com/

The quickstart subcommand is a recommended wizard which guides you through the setup of ACME on your system.

The want subcommand states that you want a certificate for the given hostnames. (If you want separate certificates for each of the hostnames, run the want subcommand separately for each hostname.)

The default subcommand, reconcile, is like "make" and makes sure all desired hostnames are satisfied by valid certificates which aren't soon to expire. want calls reconcile automatically.

If you run acmetool reconcile on a cronjob to facilitate automatic renewal, pass --batch to ensure it doesn't attempt to interact with a terminal.

You can increase logging severity for debugging purposes by passing --xlog.severity=debug.

Validation Options

[screenshot]

Webroot: acmetool can place challenge files in a given directory, allowing your normal web server to serve them. The files must be served from the path you specify at /.well-known/acme-challenge/.

Information on configuring your web server.

Proxy: acmetool can respond to validation challenges by serving them on port 402. In order for this to be useful, you must configure your webserver to proxy requests under /.well-known/acme-challenge/ to http://127.0.0.1:402/.well-known/acme-challenge.

Information on configuring your web server.

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". Information on configuring stateless challenges.

Redirector: acmetool redirector starts an HTTP server on port 80 which redirects all requests to HTTPS, as well as serving any necessary validation responses. The acmetool quickstart wizard can set it up for you if you use systemd. Otherwise, you'll need to configure your system to run acmetool redirector --service.uid=USERNAME --service.daemon=1 as a service, where USERNAME is the username you want the daemon to drop to.

Make sure your web server is not listening on port 80.

Listen: If you are for some reason not running anything on port 80 or 443, acmetool will use those ports. Either port being available is sufficient. This is only really useful for development purposes.

Hook: You can write custom shell scripts (or binary executables) which acmetool invokes to provision challenge files at the desired location. For example, you could rsync challenge files to a directory on a remote server. More information.

Renewal

acmetool will try to renew certificates automatically once they are 30 days from expiry, or 66% through their validity period, whichever is lower. Note that Let's Encrypt currently issues 90 day certificates.

acmetool will exit with an error message with nonzero exit status if it cannot renew a certificate, so it is suitable for use in a cronjob. Ensure your system is configured so that you get notifications of failing cronjobs.

If a cronjob fails, you should intervene manually to see what went wrong by running acmetool (possibly with --xlog.severity=debug for verbose logging).

Library

The client library which these utilities use can be used independently by any Go code. README and source code. Godoc.

Comparison with...

certbot: A heavyweight Python implementation which is a bit too “magic” for my tastes. Tries to mutate your webserver configuration automatically.

acmetool is a single-file binary which only depends on basic system libraries (on Linux, these are libc, libpthread, libcap, libattr). It doesn't do anything to your webserver; it just places certificates at a standard location and can also reload your webserver (whichever webserver it is) by executing hook shell scripts.

acmetool isn't based around individual transactions for obtaining certificates; it's about satisfying expressed requirements by any means necessary. Its comprehensible, magic-free state directory makes it as stateless and idempotent as possible.

lego: Like acmetool, xenolf/lego provides a library and client utility. The utility provides commands for creating certificates, but doesn't provide a compelling system for managing the lifetime of the short-lived certificates offered by Let's Encrypt. The user is expected to generate and install all certificates manually.

gethttpsforfree: diafygi/gethttpsforfree provides an HTML file which uses JavaScript to make requests to an ACME server and obtain certificates. It's a functional user interface, but like lego it provides no answer for the automation issue, and is thus impractical given the short lifetime of certificates issued by Let's Encrypt.

Comparison, list of client implementations

acmetool certbot lego gethttpsforfree
Automatic renewal Yes Not yet No No
SAN support Yes Yes Yes Yes
ECC support Yes No No No
OCSP Must Staple support Yes No No No
Revocation support Yes Yes Yes No
State management Yes† Yes
Single-file binary Yes No Yes Yes
Quickstart wizard Yes Yes No No
Modifies webserver config No By default No No
Non-root support Optional Optional Optional
Supports Apache Yes Yes
Supports nginx Yes Experimental
Supports HAProxy Yes No
Supports Hitch Yes No
Supports any web server Yes Webroot‡
Authorization via webroot Yes Yes Manual
Authorization via port 80 redirector Yes No No No
Authorization via proxy Yes No No No
Authorization via listener§ Yes Yes Yes No
Authorization via DNS Hook only No Yes No
Authorization via custom hook Yes No No No
Import state from official client Yes
Windows (basic) support No No Yes
Windows integration support No No No

† acmetool has a different philosophy to state management and configuration to the Let's Encrypt client; see the beginning of this README.

‡ The webroot method does not appear to provide any means of reloading the webserver once the certificate has been changed, which means auto-renewal requires manual intervention.

§ Requires downtime.

This table is maintained in good faith; I believe the above comparison to be accurate. If notified of any inaccuracies, I will rectify the table and publish a notice of correction here:

  • This table previously stated that the official Let's Encrypt client doesn't support non-root operation. This was incorrect; it can be installed at user level and be configured to use user-writable directories.

Documentation & Support

For more documentation see:

If your question or issue isn't resolved by any of the above, file an issue.

IRC: #acmetool on Freenode (webchat).

Licence

© 2015—2019 Hugo Landau <[email protected]>    MIT License

Licenced under the licence with SHA256 hash fd80a26fbb3f644af1fa994134446702932968519797227e07a1368dea80f0bc, a copy of which can be found here.

Comments
  • Can't add more than one host

    Can't add more than one host

    I added a host and it works without any issues, when adding another one using acmetool want example.tv I got below errors:

    20160923144412 [ERROR] acme.storageops: could not obtain authorization for www.example.tv: failed all combinations 20160923144412 [ERROR] acme.storageops: Target(www.example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed to request certificate: failed all combinations 20160923144412 [ERROR] acme.storageops: error while processing targets: the following errors occurred: error satisfying Target(www.example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations 20160923144412 [ERROR] acme.storageops: failed to reconcile: the following errors occurred: error satisfying Target(www.example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations 20160923144412 [CRITICAL] acmetool: fatal: reconcile: the following errors occurred: error satisfying Target(www.example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations

    I made it again with debug and found got these:

    root@cache [~]# acmetool --xlog.severity=debug want example.tv 20160923144117 [DEBUG] fdb: enforce permissions: tmp/symlink.258794367 0/0 0/0 20160923144117 [DEBUG] fdb: enforce permissions: desired/example.tv-yvblotgi6ncjfjzunqvbmtxzkm 0/0 0/0 20160923144117 [DEBUG] fdb: enforce permissions: tmp/symlink.876249810 0/0 0/0 20160923144117 [DEBUG] acme.storageops: Certificate(whlxskruvxedl6h7sdbadoxpppc4vc62uecsmtq6sbsi4zln7ibq) cannot satisfy Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0) because required hostname "example.tv" is not listed on it: []string{"example-main.com"} 20160923144117 [DEBUG] acme.storageops: Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): best certificate satisfying is , err=Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): no certificate satisfies this target 20160923144117 [DEBUG] acme.storageops: Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): requesting certificate 20160923144117 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/directory 20160923144118 [DEBUG] acme.api: response: &{200 OK 200 HTTP/1.1 1 1 map[Replay-Nonce:[O8928CVDZ97v0-uVuxPzvkQe_1iHF25314kc4Zdydl4] Expires:[Fri, 23 Sep 2016 14:41:30 GMT] Pragma:[no-cache] Connection:[keep-alive] X-Frame-Options:[DENY] Strict-Transport-Security:[max-age=604800] Cache-Control:[max-age=0, no-cache, no-store] Date:[Fri, 23 Sep 2016 14:41:30 GMT] Server:[nginx] Content-Type:[application/json] Content-Length:[280] Boulder-Request-Id:[Qi_YL9xNVUKYBtCpd56GuNASDZ674aCzz5QHynjcHZk]] 0xc420286040 280 [] false false map[] 0xc4201f8ff0 0xc4200b8630} 20160923144118 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/new-reg 20160923144118 [DEBUG] acme.api: response: &{409 Conflict 409 HTTP/1.1 1 1 map[Server:[nginx] Content-Type:[application/problem+json] Location:[https://acme-v01.api.letsencrypt.org/acme/reg/4548967] Replay-Nonce:[kuqTMiptLGxAtl7iBWfY3mgNtFO6z4IntkbCCFXMic8] Expires:[Fri, 23 Sep 2016 14:41:31 GMT] Cache-Control:[max-age=0, no-cache, no-store] Content-Length:[107] Boulder-Request-Id:[Ac7un8dNHog6mAq04HkALXrCQ9d1icK5849NmCMxh-c] Boulder-Requester:[4548967] Pragma:[no-cache] Date:[Fri, 23 Sep 2016 14:41:31 GMT]] 0xc420187340 107 [] true false map[] 0xc4201f85a0 0xc4200b8630} 20160923144118 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/reg/4548967 20160923144118 [DEBUG] acme.api: response: &{202 Accepted 202 HTTP/1.1 1 1 map[Connection:[keep-alive] Boulder-Request-Id:[tqqYNzMHx0dObSLC-MfpXkfYpQ5Ymwp_MrxqEEyp-SM] Boulder-Requester:[4548967] Link:[https://acme-v01.api.letsencrypt.org/acme/new-authz;rel="next" https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf;rel="terms-of-service"] Replay-Nonce:[vuPVSHJllL12QZJQWWhhplTv4FnnZUAGJmQsZroCEpI] Cache-Control:[max-age=0, no-cache, no-store] Date:[Fri, 23 Sep 2016 14:41:31 GMT] Server:[nginx] Content-Type:[application/json] Content-Length:[631] Expires:[Fri, 23 Sep 2016 14:41:31 GMT] Pragma:[no-cache]] 0xc4203b4080 631 [] false false map[] 0xc4201f8c30 0xc4201d8000} 20160923144118 [DEBUG] acme.storageops: trying to obtain authorization for "example.tv" 20160923144118 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/new-authz 20160923144118 [DEBUG] acme.api: response: &{201 Created 201 HTTP/1.1 1 1 map[Expires:[Fri, 23 Sep 2016 14:41:31 GMT] Cache-Control:[max-age=0, no-cache, no-store] Date:[Fri, 23 Sep 2016 14:41:31 GMT] Connection:[keep-alive] Boulder-Request-Id:[w5hmbvNF4lgfhFoMgHIUVfH2OMEYu3JXeYKbo9FMfzo] X-Frame-Options:[DENY] Link:[https://acme-v01.api.letsencrypt.org/acme/new-cert;rel="next"] Content-Type:[application/json] Content-Length:[999] Boulder-Requester:[4548967] Strict-Transport-Security:[max-age=604800] Pragma:[no-cache] Server:[nginx] Replay-Nonce:[HCrvZnPl1oMHTgZUqxLYoRpvduEO9vLTbo4a0Vbfr2c] Location:[https://acme-v01.api.letsencrypt.org/acme/authz/dWfR6ySQHavmStNagQzJNkSgDl_GV4ZapWmu1wPQ4M8]] 0xc42000d540 999 [] false false map[] 0xc4201f92c0 0xc4201d8000} 20160923144118 [DEBUG] acme.solver: attempting challenge type tls-sni-01 20160923144118 [DEBUG] acme.responder: failed to start TLS-SNI listener: listen tcp :443: listen: address already in use 20160923144118 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/haproxy 20160923144118 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/reload 20160923144118 [DEBUG] acme.responder: tls-sni-01 self-test failed: remote error: tls: internal error 20160923144118 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/haproxy 20160923144118 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/reload 20160923144118 [DEBUG] acme.solver: challenge start failed: remote error: tls: internal error 20160923144118 [DEBUG] acme.solver: attempting challenge type http-01 20160923144118 [DEBUG] acme.responder: failed to listen on [::]:80: listen tcp [::]:80: bind: address already in use 20160923144118 [DEBUG] acme.responder: failed to listen on :80: listen tcp :80: bind: address already in use 20160923144118 [DEBUG] acme.responder: listening on [::1]:4402 20160923144118 [DEBUG] acme.responder: listening on 127.0.0.1:4402 20160923144118 [DEBUG] acme.responder: listening on [::1]:402 20160923144118 [DEBUG] acme.responder: listening on 127.0.0.1:402 20160923144118 [DEBUG] acme.responder: writing 1 webroot challenge files 20160923144118 [DEBUG] acme.responder: writing webroot file /var/run/acme/acme-challenge/aqicqpddAgRuDJos_i9T4g2TfgPsddNYj7-JxlRYQ6U 20160923144118 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/haproxy 20160923144118 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/reload 20160923144118 [DEBUG] acme.responder: http-01 self test 20160923144119 [INFO] acme.responder: http-01 self test failed: got 200 response when doing self-test, but with the wrong data 20160923144119 [DEBUG] acme.responder: removing webroot file /var/run/acme/acme-challenge/aqicqpddAgRuDJos_i9T4g2TfgPsddNYj7-JxlRYQ6U 20160923144119 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/haproxy 20160923144119 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/reload 20160923144119 [DEBUG] acme.solver: challenge start failed: got 200 response when doing self-test, but with the wrong data 20160923144119 [DEBUG] acme.solver: attempting challenge type dns-01 20160923144119 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/haproxy 20160923144119 [DEBUG] acme.hooks: calling hook script: /usr/libexec/acme/hooks/reload 20160923144119 [DEBUG] acme.solver: challenge start failed: could not install DNS challenge, no hooks succeeded 20160923144119 [ERROR] acme.storageops: could not obtain authorization for example.tv: failed all combinations 20160923144119 [ERROR] acme.storageops: Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed to request certificate: failed all combinations 20160923144119 [DEBUG] acme.storageops: Certificate(whlxskruvxedl6h7sdbadoxpppc4vc62uecsmtq6sbsi4zln7ibq) satisfies Target(example-main.com;https://acme-v01.api.letsencrypt.org/directory;0) 20160923144119 [DEBUG] acme.storageops: Target(example-main.com;https://acme-v01.api.letsencrypt.org/directory;0): best certificate satisfying is Certificate(whlxskruvxedl6h7sdbadoxpppc4vc62uecsmtq6sbsi4zln7ibq), err= 20160923144119 [DEBUG] acme.storageops: Certificate(whlxskruvxedl6h7sdbadoxpppc4vc62uecsmtq6sbsi4zln7ibq) needsRenewing=false notAfter=2016-12-22 12:55:00 +0000 UTC 20160923144119 [DEBUG] acme.storageops: Target(example-main.com;https://acme-v01.api.letsencrypt.org/directory;0): have best certificate which does not need renewing, skipping target 20160923144119 [DEBUG] acme.storageops: done processing targets, reconciliation complete, 1 errors occurred 20160923144119 [ERROR] acme.storageops: error while processing targets: the following errors occurred: error satisfying Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations 20160923144119 [ERROR] acme.storageops: failed to reconcile: the following errors occurred: error satisfying Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations 20160923144119 [DEBUG] fdb: enforce permissions: tmp/symlink.108478473 0/0 0/0 20160923144119 [DEBUG] acme.storageops: disjoint hostname mapping: example.tv -> Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0) 20160923144119 [DEBUG] acme.storageops: disjoint hostname mapping: example-main.com -> Target(example-main.com;https://acme-v01.api.letsencrypt.org/directory;0) 20160923144119 [DEBUG] acme.storageops: Certificate(whlxskruvxedl6h7sdbadoxpppc4vc62uecsmtq6sbsi4zln7ibq) cannot satisfy Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0) because required hostname "example.tv" is not listed on it: []string{"example-main.com"} 20160923144119 [DEBUG] acme.storageops: could not find certificate satisfying Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): no certificate satisfies this target 20160923144119 [DEBUG] acme.storageops: Certificate(whlxskruvxedl6h7sdbadoxpppc4vc62uecsmtq6sbsi4zln7ibq) satisfies Target(example-main.com;https://acme-v01.api.letsencrypt.org/directory;0) 20160923144119 [CRITICAL] acmetool: fatal: reconcile: the following errors occurred: error satisfying Target(example.tv;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations

    example-main (is the first host I added and is working) example.tv (is the new one I'm trying to add)

    Any suggestions?

    I'm working on CentOS 7, Varnish 5 with Hitch and HTTP 2.

    Best regards,

  • acmetool's HTTP self-test parameters differ from those used by boulder

    acmetool's HTTP self-test parameters differ from those used by boulder

    I am a new user to acmetool, while I am running letsencrypt certificates already. My problem seems to be related to acmetool not writing the challenge file to the setup webroot. Using the tool I receive the following output:

    sudo acmetool want iepenbierferfier.frl www.iepenbierferfier.frl
    20160827000257 [ERROR] acme.storageops: could not obtain authorization for iepenbierferfier.frl: failed all combinations
    20160827000257 [ERROR] acme.storageops: Target(iepenbierferfier.frl,www.iepenbierferfier.frl;https://acme-v01.api.letsencrypt.org/directory;0): failed to request certificate: failed all combinations
    20160827000257 [ERROR] acme.storageops: error while processing targets: the following errors occurred:
    error satisfying Target(iepenbierferfier.frl,www.iepenbierferfier.frl;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations
    20160827000257 [ERROR] acme.storageops: failed to reconcile: the following errors occurred:
    error satisfying Target(iepenbierferfier.frl,www.iepenbierferfier.frl;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations
    20160827000257 [CRITICAL] acmetool: fatal: reconcile: the following errors occurred:
    error satisfying Target(iepenbierferfier.frl,www.iepenbierferfier.frl;https://acme-v01.api.letsencrypt.org/directory;0): failed all combinations
    
    acmetool status
    Settings:
      ACME_STATE_DIR: /var/lib/acme
      ACME_HOOKS_DIR: /usr/lib/acme/hooks
      Default directory URL: https://acme-v01.api.letsencrypt.org/directory
      Preferred key type: rsa-2048
      Additional webroots:
        /opt/cherokee/var/www/.well-known/acme-challenge
    
    Available accounts:
      Account(acme-v01.api.letsencrypt.org%2fdirectory/a3n2fi3vvxvlkvnehrdaadxildvuhhqsgbgoxq6wihvzsxuggiya)
        thumbprint: wHdGj50hMqTQj2oE7KsqXMxeQ8ofB_4luUyLRiIdZUk
    
    Target(iepenbierferfier.frl,www.iepenbierferfier.frl;https://acme-v01.api.letsencrypt.org/directory;0)
      error: Target(iepenbierferfier.frl,www.iepenbierferfier.frl;https://acme-v01.api.letsencrypt.org/directory;0): no certificate satisfies this target
    

    Using a small shell script I am monitoring the webfolder, but it remains empty. I also notice that the challenges itself do come in via the webserver:

    2001:bc8:3020:300::1 - - [27/Aug/2016:00:02:57 +0200] "GET /.well-known/acme-challenge/1bFyh5fDOAZvX5juOzW7ssDqUbW4UamNN_0eQ8DOs98 HTTP/1.1" 404 672 "http://iepenbierferfier.frl/.well-known/acme-challenge/1bFyh5fDOAZvX5juOzW7ssDqUbW4UamNN_0eQ8DOs98" "Go-http-client/1.1"
    

    Any advises what I can do to monitor that the file itself is written... somewhere?

    Additionally I have attempted the proxy configuration, which also didn't complete.

  • License out of date?

    License out of date?

    Getting the below when trying to request any cert

    { "type": "urn:acme:error:malformed", "detail": "Provided agreement URL [https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf] does not match current agreement URL [https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf]", "status": 400 }

  • Update ToS agreement verification logic when ACME protocol is clarified

    Update ToS agreement verification logic when ACME protocol is clarified

    Currently acmetool asks for UniqueID: "acme-agreement:" + e.URI (or looks for the anwser) to TOS agreement, but why isn't there a way to auto accept the TOS (e.g. for use in a cron job)?

  • The `want` command won’t work if LE limit is reached for *any* domains

    The `want` command won’t work if LE limit is reached for *any* domains

    I’m trying Let’s Encrypt via your tool since two days now and it works great. But yesterday I hit the beta limit after generating 5 certificates for subdomains of belfalas.eu (my domain). The problem is that now when I want to generate certificates for other unrelated domains, I got this error:

    20151209140116 [CRITICAL] acmetool: fatal: reconcile: HTTP error: 429 Unknown
    map[Server:[nginx] Replay-Nonce:[kfgpHwkR70jXVF8yD9gLEdvA86ieMJUP1Vxv3-leBo8] Expires:[Wed, 09 Dec 2015 13:01:11 GMT] Date:[Wed, 09 Dec 2015 13:01:11 GMT] Content-Type:[application/problem+json] Content-Length:[142] Cache-Control:[max-age=0, no-cache, no-store] Pragma:[no-cache]]
    {"type":"urn:acme:error:rateLimited","detail":"Error creating new cert :: Too many certificates already issued for: belfalas.eu","status":429}
    

    I tried with the official client, I could generate the wanted certificate without any problem, so there’s a bug in your client I think. In the error it seems it tries to do a reconcile and I think this is the problem. The cron job this night didn’t work either and output the same error.

  • End of Life Plan for ACMEv1

    End of Life Plan for ACMEv1

    Now that the ACME protocol is an IETF standard[1], Let's Encrypt have announced an end-of-life plan[2] for the ACMEv1 endpoints. The first date of significance is Nov 2019 when new account creation will stop working.

    I'd really like to continue using acme-tool as it suits my workflow perfectly.

    Is anyone working on a fork to get the ACMEv2 protocol stuff to completion?

    Have people migrated to different tools, if so what?

    Thanks.

    [1] https://letsencrypt.org/2019/03/11/acme-protocol-ietf-standard.html [2] https://community.letsencrypt.org/t/end-of-life-plan-for-acmev1/88430

  • FreeBSD: hooks/reload fails because bash path is nonexistent

    FreeBSD: hooks/reload fails because bash path is nonexistent

    I'm running acmetool on Freebsd:

    # freebsd-version
    10.2-RELEASE-p12
    

    The reload hook fails:

    # /usr/libexec/acme/hooks/reload
    /usr/libexec/acme/hooks/reload: Command not found.
    

    because the script looks for /bin/bash in the shebang line:

    #!/bin/bash
    ## This file was installed by acmetool. Any updates to this script will
    ## overwrite changes you make. If you don't want acmetool to manage
    ## this file, remove the following line.
    

    Since bash is only available as a port (in /usr/local/bin/bash) I would recommend to use /bin/sh. A quick test revealed that the script seems to be working using #!/bin/sh. I am not aware of the consequences on other systems.

  • Figure out what to do about pinning

    Figure out what to do about pinning

    Currently, a new private key is always generated for each new certificate. This causes issues if using HPKP to pin end entity certificates rather than CA certificates. Should probably find a workable solution for that for people that want to use HPKP.

  • webroot request hanging

    webroot request hanging

    Hi, I am trying to request a test certificate and while I see letsencrypt accessing my well-known URL, I get no answer:

    20151206105359 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/directory
    20151206105400 [DEBUG] acme.api: response: &{200 OK 200 HTTP/1.1 1 1 map[Connection:[keep-alive] Server:[nginx] Content-Length:[263] Strict-Transport-Security:[max-age=604800] Expires:[Sun, 06 Dec 2015 09:54:00 GMT] Cache-Control:[max-age=0, no-cache, no-store] Content-Type:[application/json] Replay-Nonce:[2YAuMdK60eFTRP3gAD4Ypaui2MD-M2R0Ff_bcbHpRew] X-Frame-Options:[DENY] Pragma:[no-cache] Date:[Sun, 06 Dec 2015 09:54:00 GMT]] 0xc820340d80 263 [] false map[] 0xc820309420 0xc82021a9a0} <nil>
    20151206105400 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/new-reg
    20151206105400 [DEBUG] acme.api: response: &{409 Conflict 409 HTTP/1.1 1 1 map[Content-Length:[94] Cache-Control:[max-age=0, no-cache, no-store] Pragma:[no-cache] Date:[Sun, 06 Dec 2015 09:54:00 GMT] Expires:[Sun, 06 Dec 2015 09:54:00 GMT] Server:[nginx] Content-Type:[application/problem+json] Location:[https://acme-v01.api.letsencrypt.org/acme/reg/48696] Replay-Nonce:[Gor7ZLBKqlFHmyT7wBP0a4Qav_ZeZKAKdFp6Zj2PyA8]] 0xc82024e100 94 [] true map[] 0xc82024d880 0xc82021a9a0} <nil>
    20151206105400 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/reg/48696
    20151206105400 [DEBUG] acme.api: response: &{202 Accepted 202 HTTP/1.1 1 1 map[Pragma:[no-cache] Server:[nginx] Content-Length:[576] Cache-Control:[max-age=0, no-cache, no-store] Expires:[Sun, 06 Dec 2015 09:54:00 GMT] Date:[Sun, 06 Dec 2015 09:54:00 GMT] Connection:[keep-alive] Content-Type:[application/json] Link:[<https://acme-v01.api.letsencrypt.org/acme/new-authz>;rel="next" <https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf>;rel="terms-of-service"] Replay-Nonce:[vtsqaFSHLAaa1wAk66yRfJacCRBHZ084B6SI41IX5Fc]] 0xc8202e0100 576 [] false map[] 0xc8200d7ea0 0xc82016d290} <nil>
    20151206105400 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/directory
    20151206105400 [DEBUG] acme.api: response: &{200 OK 200 HTTP/1.1 1 1 map[Server:[nginx] X-Frame-Options:[DENY] Pragma:[no-cache] Date:[Sun, 06 Dec 2015 09:54:00 GMT] Content-Type:[application/json] Content-Length:[263] Replay-Nonce:[GO4clmMvNX5hGr12udwIL4JZawg97_yk3QIfcLBGkIA] Strict-Transport-Security:[max-age=604800] Expires:[Sun, 06 Dec 2015 09:54:00 GMT] Cache-Control:[max-age=0, no-cache, no-store] Connection:[keep-alive]] 0xc8202e04c0 263 [] false map[] 0xc8202bc1c0 0xc82016d290} <nil>
    20151206105400 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/new-authz
    20151206105400 [DEBUG] acme.api: response: &{201 Created 201 HTTP/1.1 1 1 map[Content-Length:[569] Link:[<https://acme-v01.api.letsencrypt.org/acme/new-cert>;rel="next"] Location:[https://acme-v01.api.letsencrypt.org/acme/authz/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM] Replay-Nonce:[QQTKkLXXIPVOAmiKUwxCFrbrWNHpGPNKGdWBKqzNwRI] X-Frame-Options:[DENY] Strict-Transport-Security:[max-age=604800] Expires:[Sun, 06 Dec 2015 09:54:00 GMT] Date:[Sun, 06 Dec 2015 09:54:00 GMT] Connection:[keep-alive] Server:[nginx] Content-Type:[application/json] Cache-Control:[max-age=0, no-cache, no-store] Pragma:[no-cache]] 0xc8204e8280 569 [] false map[] 0xc82055a0e0 0xc82016d290} <nil>
    20151206105400 [DEBUG] acme.solver: attempting challenge type tls-sni-01
    20151206105400 [DEBUG] acme.solver: challenge start failed: listen tcp :443: bind: address already in use
    20151206105400 [DEBUG] acme.solver: attempting challenge type http-01
    20151206105400 [DEBUG] acme.responder: http-01 self test
    20151206105401 [DEBUG] acme.responder: http-01 started
    20151206105401 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/challenge/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM/1031567
    20151206105401 [DEBUG] acme.api: response: &{202 Accepted 202 HTTP/1.1 1 1 map[Content-Length:[312] Location:[https://acme-v01.api.letsencrypt.org/acme/challenge/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM/1031567] Expires:[Sun, 06 Dec 2015 09:54:01 GMT] Pragma:[no-cache] Content-Type:[application/json] Link:[<https://acme-v01.api.letsencrypt.org/acme/authz/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM>;rel="up"] Replay-Nonce:[Ku79VytL_dm71iwa8q5uaX8hW1Ygi7TQqn37ejpABCM] Cache-Control:[max-age=0, no-cache, no-store] Date:[Sun, 06 Dec 2015 09:54:01 GMT] Connection:[keep-alive] Server:[nginx]] 0xc82024e0c0 312 [] false map[] 0xc820523420 0xc82016d290} <nil>
    20151206105406 [DEBUG] acme.api: request: https://acme-v01.api.letsencrypt.org/acme/challenge/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM/1031567
    20151206105406 [DEBUG] acme.api: response: &{202 Accepted 202 HTTP/1.1 1 1 map[Connection:[keep-alive] Link:[<https://acme-v01.api.letsencrypt.org/acme/authz/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM>;rel="up"] Replay-Nonce:[YY0xW99e6Lp2Kf9aGW87p1SgIuALmI5flC0kat0wvEE] Cache-Control:[max-age=0, no-cache, no-store] Date:[Sun, 06 Dec 2015 09:54:06 GMT] Expires:[Sun, 06 Dec 2015 09:54:06 GMT] Pragma:[no-cache] Server:[nginx] Content-Type:[application/json] Content-Length:[548] Location:[https://acme-v01.api.letsencrypt.org/acme/challenge/qXCrJhNlZupNvU29A-JewLDN7zUVCr8NfiLKBjyJzIM/1031567]] 0xc820340bc0 548 [] false map[] 0xc8202c8000 0xc82016d290} <nil>
    

    at this point nothing happens anymore…

    the access log shows:

    185.11.136.221 - - [06/Dec/2015:10:54:01 +0100] "GET /.well-known/acme-challenge/SlmxjpPu7MxyVRQvvoY-id-iQ0UksEfbBot02rYoR7k HTTP/1.1" 200 275 "-" "Go-http-client/1.1"
    66.133.109.36 - - [06/Dec/2015:10:54:01 +0100] "GET /.well-known/acme-challenge/SlmxjpPu7MxyVRQvvoY-id-iQ0UksEfbBot02rYoR7k HTTP/1.1" 200 294 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
    

    Any hints?

  • Configured webroot path not being used

    Configured webroot path not being used

    Hello,

    After updating the acmetool binary I noticed that the webroot config file is no longer used. The directory structure doc tells me that the option is deprecated, acmetool logs pointed me to new location in /var/run.

    Readme still says that webroot is a configurable path, but it looks like that's no longer the case? Please update documentation on how this should be used. Also: could you mention breaking changes like these on the release page, in the future? Thanks!

  • acmetool asks repeatedly for

    acmetool asks repeatedly for "Terms of Service" confirmation

    I'm not sure if this is an issue related to acmetool, but I already googled for solutions and found nothing from "Let's encrypt" themself, so I guess I should ask here.

    Let me say first that acmetool is a great tool - I use it for 7 months now and it never let me down.

    Issue is: since some days ago, acmetool's cron job "/usr/bin/acmetool --batch reconcile" throws the following error message:

    20160721234602 [ERROR] acme.storageops: Target(mydomain.com;https://acme-v01.api.letsencrypt.org/directory;0): failed to request certificate: cannot prompt the user: currently non-interactive

    So I called the command manually. acmetool outputs the "Terms of service" confirmation dialog then. After confirmation with return or "y" it asks for an email address. After that it seems to work fine and renews a certificate. The whole process is somewhat annoying, because it outputs the dialog for every single domain which has to be renewed in a loop. Any ideas what's causing this? Or is this intended behaviour?

    thanks for any hints...

  • Building from source is difficult

    Building from source is difficult

    I love the design and actual use of acmetool but would like to include it into our ports tree by building from source. That would also help us cross-compile for Raspberry Pi.

    Your otherwise excellent documentation just says "building from source is easy". Go is of course new territory to some, but while building v0.2.1 I am also encountering:

    • References to git.devever.net/hlandau/acmetool which does not exist
    • An import path from github.com/hlandau/acmetool/cli that I could not get to work by setting $GOROOT and/or $GOPATH
    • Apparent assumption that the source is in a directory named src and built with go build src/main.go so that a plain import cli can work
    • Failure to find standard library utilities, also after setting $GOPATH to either packages or sources

    What I'm saying is that there seem to be assumptions about the environment in which the package is built that are useful to describe. Part of this may be my lack of experience programming with Go, but not everything, I suppose.

    Could you please describe the building process? I would be happy to test-ride any text you might churn out.

  • /var/lib/acme/conf/target file permission

    /var/lib/acme/conf/target file permission

    Hey,

    Thanks for maintaining acmetool. It seems exactly what I was after — an idempotent and declarative ACME client.

    I'm setting up a DNS hook and added the TSIG key as an environment variable to /var/lib/acme/conf/target. However on running acmetool, it warns of its permissions:

    20220313183755 [WARN] fdb: "conf/target" has wrong mode -rw-r-----, changing to -rw-r--r--
    

    Why is that? Given the target file now contains credentials, I'd definitely not want it to be world-readable.

    Thanks!

  • lookup git.devever.net: no such host

    lookup git.devever.net: no such host

    When running make:

    go get git.devever.net/hlandau/acmetool/...: unrecognized import path "git.devever.net/hlandau/acmetool": https fetch: Get "https://git.devever.net/hlandau/acmetool?go-get=1": dial tcp: lookup git.devever.net: no such host

  • Support for specifying alternate chain (like --preferred-chain in certbot) ?

    Support for specifying alternate chain (like --preferred-chain in certbot) ?

    Would it be possible to support alternate chains, like implemented in https://github.com/certbot/certbot/pull/8080?

    It is needed for usage as https://community.letsencrypt.org/t/production-chain-changes/150739 etc.

  • Adding flock() support

    Adding flock() support

    I am automating seamless DANE support after acmetool, and this process triggers a sequence of simple atomic and idempotent actions with its own timing. This raises concerns about atomicity of the /var/lib/acme/live directory contents. Multiple files cannot be written all at the same time, and concurrent programs might interact and see half-way results.

    I therefore started wrapping acmetool with a voluntary lock, using flock(). I use the same lock for the scripts that work with /var/lib/acme.

    I think it is generally a good idea to use flock() in the tool itself, precisely because it is a command that runs as a cronjob and occasionally at the user's request. There should be no interference between any two calls of the tool and, given the neat documentation of the /var/lib/acme directory, it would be good if any other tools could follow a compatible practice.

Let's Encrypt client and ACME library written in Go
Let's Encrypt client and ACME library written in Go

Let's Encrypt client and ACME library written in Go. Features ACME v2 RFC 8555 Register with CA Obtain certificates, both from scratch or with an exis

Dec 30, 2022
step-ca is an online certificate authority for secure, automated certificate management.
step-ca is an online certificate authority for secure, automated certificate management.

??️ A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH.

Jan 6, 2023
Automatic HTTPS for any Go program: fully-managed TLS certificate issuance and renewal
Automatic HTTPS for any Go program: fully-managed TLS certificate issuance and renewal

Easy and Powerful TLS Automation The same library used by the Caddy Web Server Caddy's automagic TLS features—now for your own Go programs—in one powe

Jan 6, 2023
Cloud IP address ranges lookup tool + DNS subdomain enumeration + Certificate Transparency
Cloud IP address ranges lookup tool + DNS subdomain enumeration + Certificate Transparency

Cloud edge Lookup an IP to find the cloud provider and other details based on the provider's published JSON data Cloud edge is a recon tool focused on

Dec 12, 2022
Order TLS certificates using ACME TLS-ALPN-01

Order TLS certificates using ACME TLS-ALPN-01

Jan 4, 2023
Proto-find is a tool for researchers that lets you find client side prototype pollution vulnerability.

proto-find proto-find is a tool for researchers that lets you find client side prototype pollution vulnerability. How it works proto-find open URL in

Dec 6, 2022
Go package to embed the Mozilla Included CA Certificate List

rootcerts Package rootcerts provides an embedded copy of the Mozilla Included CA Certificate List, more specifically the PEM of Root Certificates in M

Oct 21, 2022
Retrieve SSL certificate information

cert Retrieve SSL certificate information from provided hostname. Why I just simply want to retrieve a website's SSL certificate information in my ter

Oct 5, 2021
🌰 encrypt/decrypt using ssh keys

ssh-vault ?? encrypt/decrypt using ssh private keys Documentation https://ssh-vault.com Usage $ ssh-vault -h Example: $ echo "secret" | ssh-vault -u

Dec 30, 2022
Encrypt your files or notes by your GPG key and save to MinIO or Amazon S3 easily!
Encrypt your files or notes by your GPG key and save to MinIO or Amazon S3 easily!

Super Dollop Super Dollop can encrypt your files and notes by your own GPG key and save them in S3 or minIO to keep them safe and portability, also yo

Jul 11, 2022
Encrypt embedded go files using age.

encembed Encrypt embedded resource in compiled binary using age. Meant for usage with go generate. This tool will generate a go source file that embed

Nov 20, 2022
CS http Dynamic Encrypt Bridge.
CS http Dynamic Encrypt Bridge.

CS http Dynamic Encrypt Bridge.

Nov 25, 2022
Automatic Linux privesc via exploitation of low-hanging fruit
Automatic Linux privesc via exploitation of low-hanging fruit

Traitor Automatically exploit low-hanging fruit to pop a root shell. Linux privilege escalation made easy! Traitor packages up a bunch of methods to e

Jan 1, 2023
DirDar is a tool that searches for (403-Forbidden) directories to break it and get dir listing on it
DirDar is a tool that searches for (403-Forbidden) directories to break it and get dir listing on it

DirDar v1.0 Description ??‍☠️ bypass forbidden directories - find and identify dir listing - you can use it as directory brute-forcer as well Compatab

Jan 1, 2023
SSRFuzz is a tool to find Server Side Request Forgery vulnerabilities, with CRLF chaining capabilities

SSRFuzz is a tool to find Server Side Request Forgery vulnerabilities, with CRLF chaining capabilities Why?

Dec 8, 2022
A fast tool to mass scan for a vulnerability on Microsoft Exchange Server that allows an attacker bypassing the authentication and impersonating as the admin (CVE-2021-26855).
A fast tool to mass scan for a vulnerability on Microsoft Exchange Server that allows an attacker bypassing the authentication and impersonating as the admin (CVE-2021-26855).

proxylogscan This tool to mass scan for a vulnerability on Microsoft Exchange Server that allows an attacker bypassing the authentication and imperson

Dec 26, 2022
A scalable overlay networking tool with a focus on performance, simplicity and security

What is Nebula? Nebula is a scalable overlay networking tool with a focus on performance, simplicity and security. It lets you seamlessly connect comp

Dec 29, 2022
A tool to check for vulnerabilities in your Golang dependencies, powered by Sonatype OSS Index
A tool to check for vulnerabilities in your Golang dependencies, powered by Sonatype OSS Index

Nancy nancy is a tool to check for vulnerabilities in your Golang dependencies, powered by Sonatype OSS Index, and as well, works with Nexus IQ Server

Dec 22, 2022
A fast tool to scan CRLF vulnerability written in Go
A fast tool to scan CRLF vulnerability written in Go

CRLFuzz A fast tool to scan CRLF vulnerability written in Go Resources Installation from Binary from Source from GitHub Usage Basic Usage Flags Target

Jan 1, 2023