2015-06-13 02:45:04 +00:00
# lego
2015-10-19 17:58:04 +00:00
Let's Encrypt client and ACME library written in Go
2015-06-13 02:45:04 +00:00
2015-10-18 23:02:44 +00:00
[![GoDoc ](https://godoc.org/github.com/xenolf/lego/acme?status.svg )](https://godoc.org/github.com/xenolf/lego/acme)
2015-06-13 19:23:27 +00:00
[![Build Status ](https://travis-ci.org/xenolf/lego.svg?branch=master )](https://travis-ci.org/xenolf/lego)
2015-12-23 22:23:21 +00:00
[![Dev Chat ](https://img.shields.io/badge/dev%20chat-gitter-blue.svg?label=dev+chat )](https://gitter.im/xenolf/lego)
2015-06-13 19:23:27 +00:00
2015-12-15 21:27:41 +00:00
#### General
This is a work in progress. Please do *NOT* run this on a production server and please report any bugs you find!
2015-06-13 02:45:04 +00:00
2015-12-15 21:27:41 +00:00
#### Installation
lego supports both binary installs and install from source.
To get the binary just download the latest release for your OS/Arch from [the release page ](https://github.com/xenolf/lego/releases )
and put the binary somewhere convenient. lego does not assume anything about the location you run it from.
To install from source, just run
```
go get -u github.com/xenolf/lego
```
2015-10-20 20:55:00 +00:00
2016-03-23 18:12:47 +00:00
#### Features
- Register with CA
- Obtain certificates
- Renew certificates
- Revoke certificates
- Robust implementation of all ACME challenges
- HTTP (http-01)
- TLS with Server Name Indication (tls-sni-01)
- DNS (dns-01)
- SAN certificate support
- Comes with multiple optional [DNS providers ](https://github.com/xenolf/lego/tree/master/providers/dns )
- [Custom challenge solvers ](https://github.com/xenolf/lego/wiki/Writing-a-Challenge-Solver )
- Certificate bundling
- OCSP helper function
2015-06-13 02:45:04 +00:00
Please keep in mind that CLI switches and APIs are still subject to change.
2016-01-08 22:43:36 +00:00
When using the standard `--path` option, all certificates and account configurations are saved to a folder *.lego* in the current working directory.
2015-06-13 02:45:04 +00:00
2015-10-18 23:02:44 +00:00
#### Sudo
2015-12-15 21:27:41 +00:00
The CLI does not require root permissions but needs to bind to port 80 and 443 for certain challenges.
2016-02-10 11:19:29 +00:00
To run the CLI without sudo, you have three options:
2015-12-15 21:27:41 +00:00
- Use setcap 'cap_net_bind_service=+ep' /path/to/program
2016-01-08 22:43:36 +00:00
- Pass the `--http` or/and the `--tls` option and specify a custom port to bind to. In this case you have to forward port 80/443 to these custom ports (see [Port Usage ](#port-usage )).
2016-03-13 15:36:13 +00:00
- Pass the `--webroot` option and specify the path to your webroot folder. In this case the challenge will be written in a file in `.well-known/acme-challenge/` inside your webroot.
2015-12-15 21:27:41 +00:00
#### Port Usage
By default lego assumes it is able to bind to ports 80 and 443 to solve challenges.
2016-01-08 22:43:36 +00:00
If this is not possible in your environment, you can use the `--http` and `--tls` options to instruct
lego to listen on that interface:port for any incoming challenges.
2015-12-15 21:27:41 +00:00
2015-12-27 19:34:30 +00:00
If you are using this option, make sure you proxy all of the following traffic to these ports.
HTTP Port:
2016-03-23 18:12:47 +00:00
- All plaintext HTTP requests to port 80 which begin with a request path of `/.well-known/acme-challenge/` for the HTTP challenge.
2015-12-27 19:34:30 +00:00
TLS Port:
2016-03-23 18:12:47 +00:00
- All TLS handshakes on port 443 for the TLS-SNI challenge.
2015-12-15 21:27:41 +00:00
This traffic redirection is only needed as long as lego solves challenges. As soon as you have received your certificates you can deactivate the forwarding.
2015-06-13 02:45:04 +00:00
#### Usage
```
NAME:
2016-03-23 18:12:47 +00:00
lego - Let's Encrypt client written in Go
2015-06-13 02:45:04 +00:00
USAGE:
2015-10-19 17:58:04 +00:00
./lego [global options] command [command options] [arguments...]
2015-12-03 19:04:55 +00:00
2015-06-13 02:45:04 +00:00
VERSION:
2016-03-23 18:12:47 +00:00
0.3.0
2015-12-03 19:04:55 +00:00
2015-06-13 02:45:04 +00:00
COMMANDS:
2015-10-19 17:58:04 +00:00
run Register an account, then create and install a certificate
revoke Revoke a certificate
renew Renew a certificate
help, h Shows a list of commands or help for one command
2015-12-03 19:04:55 +00:00
2015-06-13 02:45:04 +00:00
GLOBAL OPTIONS:
2015-10-19 17:58:04 +00:00
--domains, -d [--domains option --domains option] Add domains to the process
2015-12-03 19:04:55 +00:00
--server, -s "https://acme-v01.api.letsencrypt.org/directory" CA hostname (and optionally :port). The server certificate must be trusted in order to avoid further modifications to the client.
2015-10-19 17:58:04 +00:00
--email, -m Email used for registration and recovery contact.
--rsa-key-size, -B "2048" Size of the RSA key.
2016-01-30 23:10:46 +00:00
--path "${CWD}/.lego" Directory to use for storing the data
2015-12-27 19:34:30 +00:00
--exclude, -x [--exclude option --exclude option] Explicitly disallow solvers by name from being used. Solvers: "http-01", "tls-sni-01".
2016-02-10 11:19:29 +00:00
--webroot Set the webroot folder to use for HTTP based challenges to write directly in a file in .well-known/acme-challenge
2016-01-30 01:43:35 +00:00
--http Set the port and interface to use for HTTP based challenges to listen on. Supported: interface:port or :port
--tls Set the port and interface to use for TLS based challenges to listen on. Supported: interface:port or :port
2016-02-14 00:42:47 +00:00
--dns Solve a DNS challenge using the specified provider. Disables all other solvers.
2016-01-30 01:43:35 +00:00
Credentials for providers have to be passed through environment variables.
For a more detailed explanation of the parameters, please see the online docs.
Valid providers:
cloudflare: CLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY
digitalocean: DO_AUTH_TOKEN
dnsimple: DNSIMPLE_EMAIL, DNSIMPLE_API_KEY
2016-03-12 16:13:24 +00:00
gandi: GANDI_API_KEY
2016-03-14 21:28:40 +00:00
namecheap: NAMECHEAP_API_USER, NAMECHEAP_API_KEY
2016-01-30 23:10:46 +00:00
route53: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION
2016-02-28 14:42:09 +00:00
rfc2136: RFC2136_TSIG_KEY, RFC2136_TSIG_SECRET, RFC2136_TSIG_ALGORITHM, RFC2136_NAMESERVER
2016-02-07 07:10:36 +00:00
dyn: DYN_CUSTOMER_NAME, DYN_USER_NAME, DYN_PASSWORD
2016-01-30 01:43:35 +00:00
manual: none
2015-10-19 17:58:04 +00:00
--help, -h show help
--version, -v print the version
2015-06-13 02:45:04 +00:00
```
2015-10-17 21:02:52 +00:00
2015-12-08 02:33:40 +00:00
##### CLI Example
Assumes the `lego` binary has permission to bind to ports 80 and 443. You can get a pre-built binary from the [releases ](https://github.com/xenolf/lego/releases ) page.
2015-12-15 21:27:41 +00:00
If your environment does not allow you to bind to these ports, please read [Port Usage ](#port-usage ).
2015-12-08 02:33:40 +00:00
Obtain a certificate:
```bash
$ lego --email="foo@bar.com" --domains="example.com" run
```
(Find your certificate in the `.lego` folder of current working directory.)
To renew the certificate:
```bash
$ lego --email="foo@bar.com" --domains="example.com" renew
```
2015-10-17 21:02:52 +00:00
2016-02-05 10:40:41 +00:00
Obtain a certificate using the DNS challenge and AWS Route 53:
```bash
2016-02-14 00:23:50 +00:00
$ AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID=my_id AWS_SECRET_ACCESS_KEY=my_key lego --email="foo@bar.com" --domains="example.com" --dns="route53" run
2016-02-05 10:40:41 +00:00
```
2016-02-14 00:23:50 +00:00
Note that `--dns=foo` implies `--exclude=http-01` and `--exclude=tls-sni-01` . lego will not attempt other challenges if you've told it to use DNS instead.
2016-02-08 21:27:06 +00:00
lego defaults to communicating with the production Let's Encrypt ACME server. If you'd like to test something without issuing real certificates, consider using the staging endpoint instead:
```bash
$ lego --server=https://acme-staging.api.letsencrypt.org/directory …
```
2016-02-05 10:40:41 +00:00
#### DNS Challenge API Details
##### AWS Route 53
The following AWS IAM policy document describes the permissions required for lego to complete the DNS challenge.
Replace `<INSERT_YOUR_HOSTED_ZONE_ID_HERE>` with the Route 53 zone ID of the domain you are authorizing.
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
2016-02-07 01:00:10 +00:00
"Action": [ "route53:ListHostedZones", "route53:GetChange" ],
2016-02-05 10:40:41 +00:00
"Resource": [
2016-02-07 01:00:10 +00:00
"*"
2016-02-05 10:40:41 +00:00
]
},
{
"Effect": "Allow",
2016-02-07 01:00:10 +00:00
"Action": ["route53:ChangeResourceRecordSets"],
2016-02-05 10:40:41 +00:00
"Resource": [
2016-02-07 01:00:10 +00:00
"arn:aws:route53:::hostedzone/< INSERT_YOUR_HOSTED_ZONE_ID_HERE > "
2016-02-05 10:40:41 +00:00
]
}
]
}
```
2015-10-17 21:02:52 +00:00
#### ACME Library Usage
A valid, but bare-bones example use of the acme package:
```go
// You'll need a user or account type that implements acme.User
type MyUser struct {
Email string
Registration *acme.RegistrationResource
2016-03-24 22:26:49 +00:00
key crypto.PrivateKey
2015-10-17 21:02:52 +00:00
}
func (u MyUser) GetEmail() string {
return u.Email
}
func (u MyUser) GetRegistration() *acme.RegistrationResource {
return u.Registration
}
2016-03-24 22:26:49 +00:00
func (u MyUser) GetPrivateKey() crypto.PrivateKey {
2015-10-17 21:02:52 +00:00
return u.key
}
// Create a user. New accounts need an email and private key to start.
2015-10-17 21:07:14 +00:00
const rsaKeySize = 2048
2015-10-17 21:02:52 +00:00
privateKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
if err != nil {
log.Fatal(err)
}
myUser := MyUser{
Email: "you@yours.com",
key: privateKey,
}
// A client facilitates communication with the CA server. This CA URL is
// configured for a local dev instance of Boulder running in Docker in a VM.
2016-03-24 22:26:49 +00:00
client, err := acme.NewClient("http://192.168.99.100:4000", & myUser, acme.RSA2048)
2015-12-07 11:18:58 +00:00
if err != nil {
2015-10-27 23:00:42 +00:00
log.Fatal(err)
}
2015-10-17 21:02:52 +00:00
2016-03-23 18:12:47 +00:00
// We specify an http port of 5002 and an tls port of 5001 on all interfaces
// because we aren't running as root and can't bind a listener to port 80 and 443
// (used later when we attempt to pass challenges). Keep in mind that we still
// need to proxy challenge traffic to port 5002 and 5001.
2016-01-08 22:43:36 +00:00
client.SetHTTPAddress(":5002")
client.SetTLSAddress(":5001")
2015-12-27 19:34:30 +00:00
2016-03-23 18:12:47 +00:00
// New users will need to register
2015-10-17 21:02:52 +00:00
reg, err := client.Register()
if err != nil {
log.Fatal(err)
}
myUser.Registration = reg
2016-03-23 18:12:47 +00:00
// SAVE THE USER.
2015-10-17 21:02:52 +00:00
// The client has a URL to the current Let's Encrypt Subscriber
// Agreement. The user will need to agree to it.
2015-10-23 08:15:57 +00:00
err = client.AgreeToTOS()
2015-10-17 21:02:52 +00:00
if err != nil {
log.Fatal(err)
}
// The acme library takes care of completing the challenges to obtain the certificate(s).
2016-03-23 18:12:47 +00:00
// The domains must resolve to this machine or you have to use the DNS challenge.
2015-12-07 11:21:54 +00:00
bundle := false
2016-01-24 11:47:13 +00:00
certificates, failures := client.ObtainCertificate([]string{"mydomain.com"}, bundle, nil)
if len(failures) > 0 {
log.Fatal(failures)
2015-10-17 21:02:52 +00:00
}
2015-10-18 23:02:44 +00:00
// Each certificate comes back with the cert bytes, the bytes of the client's
2016-03-23 18:12:47 +00:00
// private key, and a certificate URL. SAVE THESE TO DISK.
2015-10-17 21:02:52 +00:00
fmt.Printf("%#v\n", certificates)
// ... all done.
```