prepare for v3
This commit is contained in:
parent
216384e096
commit
4e447ec9cd
27
README.md
27
README.md
|
@ -57,7 +57,7 @@ greenlock --email jon@example.com \
|
||||||
Robust configurations for Greenlock as a system service
|
Robust configurations for Greenlock as a system service
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo greenlock --install systemd --conf /etc/greenlock/greenlock.yml
|
sudo greenlock --install systemd --config /etc/greenlock/greenlock.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
See explanations below in the **Usage** section.
|
See explanations below in the **Usage** section.
|
||||||
|
@ -95,7 +95,7 @@ These commands are shown using the **testing server**.
|
||||||
|
|
||||||
Want to use the **live server**?
|
Want to use the **live server**?
|
||||||
|
|
||||||
1. change server to `--server https://acme-v01.api.letsencrypt.org/directory`
|
1. change server to `--server https://acme-v02.api.letsencrypt.org/directory`
|
||||||
|
|
||||||
**Note**: This has really only been tested with single domains so if
|
**Note**: This has really only been tested with single domains so if
|
||||||
multiple domains doesn't work for you, file a bug.
|
multiple domains doesn't work for you, file a bug.
|
||||||
|
@ -111,8 +111,9 @@ greenlock certonly \
|
||||||
--agree-tos --email john.doe@example.com \
|
--agree-tos --email john.doe@example.com \
|
||||||
--standalone \
|
--standalone \
|
||||||
--domains example.com,www.example.com \
|
--domains example.com,www.example.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory \
|
--server https://acme-staging-v02.api.letsencrypt.org/directory \
|
||||||
--config-dir ~/letsencrypt/etc
|
--acme-version draft-11
|
||||||
|
--config-dir ~/acme/etc
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
@ -122,8 +123,9 @@ greenlock certonly \
|
||||||
--agree-tos --email john.doe@example.com \
|
--agree-tos --email john.doe@example.com \
|
||||||
--standalone --tls-sni-01-port 443 \
|
--standalone --tls-sni-01-port 443 \
|
||||||
--domains example.com,www.example.com \
|
--domains example.com,www.example.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory \
|
--server https://acme-staging-v02.api.letsencrypt.org/directory \
|
||||||
--config-dir ~/letsencrypt/etc
|
--acme-version draft-11
|
||||||
|
--config-dir ~/acme/etc
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you can see your certs at `~/letsencrypt/etc/live`.
|
Then you can see your certs at `~/letsencrypt/etc/live`.
|
||||||
|
@ -150,7 +152,8 @@ sudo greenlock certonly \
|
||||||
--webroot --webroot-path /srv/www/example.com \
|
--webroot --webroot-path /srv/www/example.com \
|
||||||
--config-dir /etc/letsencrypt \
|
--config-dir /etc/letsencrypt \
|
||||||
--domains example.com,www.example.com \
|
--domains example.com,www.example.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory
|
--server https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
--acme-version draft-11
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that we use `sudo` because in this example we are using `/etc/letsencrypt`
|
Note that we use `sudo` because in this example we are using `/etc/letsencrypt`
|
||||||
|
@ -181,9 +184,10 @@ The process works something like this. You would run:
|
||||||
sudo greenlock certonly \
|
sudo greenlock certonly \
|
||||||
--agree-tos --email john.doe@example.com \
|
--agree-tos --email john.doe@example.com \
|
||||||
--hooks --hooks-server apache2-debian \
|
--hooks --hooks-server apache2-debian \
|
||||||
--config-dir /etc/letsencrypt \
|
--config-dir /etc/acme \
|
||||||
--domains example.com,www.example.com \
|
--domains example.com,www.example.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory
|
--server https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
--acme-version draft-11
|
||||||
```
|
```
|
||||||
|
|
||||||
Three files are then generated:
|
Three files are then generated:
|
||||||
|
@ -239,9 +243,10 @@ will be printed to the screen and you will be given time to copy it wherever
|
||||||
sudo greenlock certonly \
|
sudo greenlock certonly \
|
||||||
--agree-tos --email john.doe@example.com \
|
--agree-tos --email john.doe@example.com \
|
||||||
--manual
|
--manual
|
||||||
--config-dir /etc/letsencrypt \
|
--config-dir /etc/acme \
|
||||||
--domains example.com,www.example.com \
|
--domains example.com,www.example.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory
|
--server https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
--acme-version draft-11
|
||||||
```
|
```
|
||||||
|
|
||||||
## Test with a free domain
|
## Test with a free domain
|
||||||
|
|
|
@ -5,42 +5,46 @@ var cli = require('cli');
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp');
|
||||||
|
|
||||||
cli.parse({
|
cli.parse({
|
||||||
server: [ false, " ACME Directory Resource URI.", 'string', '' ]
|
'acme-version':
|
||||||
, email: [ false, " Email used for registration and recovery contact. (default: null)", 'email' ]
|
[ false, " v01 (Let's Encrypt v01) or draft-11 (Let's Encrypt v02) (default: draft-11)", 'string', 'draft-11' ]
|
||||||
, 'agree-tos': [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ]
|
, 'acme-url':
|
||||||
, domains: [ false, " Domain names to apply. For multiple domains you can enter a comma separated list of domains as a parameter. (default: [])", 'string' ]
|
[ false, " ACME API Directory URL (default: https://acme-v02.api.letsencrypt.org/directory", 'string', '' ]
|
||||||
, 'renew-within': [ false, " Renew certificates this many days before expiry", 'int', 7 ]
|
, config:
|
||||||
, duplicate: [ false, " Allow getting a certificate that duplicates an existing one/is an early renewal", 'boolean', false ]
|
[ 'c', " Path to configuration file --config /etc/greenlock/greenlock.yml (default: '')", 'string' ]
|
||||||
, 'rsa-key-size': [ false, " Size (in bits) of the RSA key.", 'int', 2048 ]
|
, serve:
|
||||||
, 'cert-path': [ false, " Path to where new cert.pem is saved", 'string',':configDir/live/:hostname/cert.pem' ]
|
[ false, " Run as webserver (default: false)", 'boolean', false ]
|
||||||
, 'fullchain-path': [ false, " Path to where new fullchain.pem (cert + chain) is saved", 'string', ':configDir/live/:hostname/fullchain.pem' ]
|
, email:
|
||||||
, 'chain-path': [ false, " Path to where new chain.pem is saved", 'string', ':configDir/live/:hostname/chain.pem' ]
|
[ false, " Email used for registration and recovery contact (default: '')", 'email', '' ]
|
||||||
, 'domain-key-path': [ false, " Path to privkey.pem to use for domain (default: generate new)", 'string' ]
|
, analytics:
|
||||||
, 'account-key-path': [ false, " Path to privkey.pem to use for account (default: generate new)", 'string' ]
|
[ false, " Share analytics with greenlock (default: false)", 'boolean', false ]
|
||||||
, 'config-dir': [ false, " Configuration directory.", 'string', '~/letsencrypt/etc/' ]
|
, community:
|
||||||
, 'tls-sni-01-port': [ false, " Use TLS-SNI-01 challenge type with this port (only port 443 is valid with most production servers)", 'int' ]
|
[ false, " Join the greenlock community to get important updates (default: false)", 'boolean', false ]
|
||||||
, 'http-01-port': [ false, " Use HTTP-01 challenge type with this port (only port 80 is valid with most production servers) (default: 80)", 'int' ]
|
, 'agree-tos':
|
||||||
, 'dns-01': [ false, " Use DNS-01 challange type", 'boolean', false ]
|
[ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ]
|
||||||
, standalone: [ false, " Obtain certs using a \"standalone\" webserver.", 'boolean', false ]
|
, domains:
|
||||||
, manual: [ false, " Print the token and key to the screen and wait for you to hit enter, giving you time to copy it somewhere before continuing (default: false)", 'boolean', false ]
|
[ false, " Comma-separated list of domains to secure (default: [])", 'string' ]
|
||||||
, webroot: [ false, " Obtain certs by placing files in a webroot directory.", 'boolean', false ]
|
, 'config-dir':
|
||||||
, 'webroot-path': [ false, " public_html / webroot path.", 'string' ]
|
[ false, " Configuration directory.", 'string', '~/acme/etc/' ]
|
||||||
, hooks: [ false, " Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges.", 'boolean', false ]
|
, 'cert-path':
|
||||||
, 'hooks-path': [ false, " Path in which to store files for hooks.", 'string' ]
|
[ false, " Path where new cert.pem is saved", 'string',':configDir/live/:hostname/cert.pem' ]
|
||||||
, 'hooks-server': [ false, " Type of webserver to configure.", 'string' ]
|
, 'fullchain-path':
|
||||||
, 'hooks-template': [ false, " Template to use for hooks configuration file.", 'string' ]
|
[ false, " Path where new fullchain.pem (cert + chain) is saved", 'string', ':configDir/live/:hostname/fullchain.pem' ]
|
||||||
, 'hooks-bind': [ false, " IP address to use in configuration for hooks.", 'string' ]
|
, 'chain-path':
|
||||||
, 'hooks-port': [ false, " Port to use in configuration for hooks.", 'string' ]
|
[ false, " Path where new chain.pem is saved", 'string', ':configDir/live/:hostname/chain.pem' ]
|
||||||
, 'hooks-webroot': [ false, " Webroot to use in configuration for hooks (e.g. empty dir).", 'string' ]
|
, 'bundle-path':
|
||||||
, 'hooks-pre-enable': [ false, " Hook to check the webserver configuration prior to enabling.", 'string' ]
|
[ false, " Path where new bundle.pem (fullchain + privkey) is saved", 'string', ':configDir/live/:hostname/bundle.pem' ]
|
||||||
, 'hooks-enable': [ false, " Hook to enable the webserver configuration.", 'string' ]
|
, 'privkey-path':
|
||||||
, 'hooks-pre-reload': [ false, " Hook to check the webserver configuration prior to reloading.", 'string' ]
|
[ false, " Path where (new or existing) domain privkey.pem is saved", 'string', ':configDir/live/:hostname/privkey.pem' ]
|
||||||
, 'hooks-reload': [ false, " Hook to reload the webserver.", 'string' ]
|
, 'root':
|
||||||
, 'hooks-disable': [ false, " Hook to disable the webserver configuration.", 'string' ]
|
[ false, " public_html / webroot path /srv/www/:hostname", 'string' ]
|
||||||
//, 'standalone-supported-challenges': [ false, " Supported challenges, order preferences are randomly chosen. (default: http-01,tls-sni-01)", 'string', 'http-01,tls-sni-01']
|
, 'renew-within':
|
||||||
, debug: [ false, " show traces and logs", 'boolean', false ]
|
[ false, " Renew certificates this many days before expiry", 'int', 11 ]
|
||||||
, 'work-dir': [ false, "(ignored)", 'string', '~/letsencrypt/var/lib/' ]
|
, standalone:
|
||||||
, 'logs-dir': [ false, "(ignored)", 'string', '~/letsencrypt/var/log/' ]
|
[ false, " Obtain certs using a \"standalone\" webserver.", 'boolean', false ]
|
||||||
|
, manual:
|
||||||
|
[ false, " Print the token and key to the screen and wait for you to hit enter, giving you time to copy it somewhere before continuing (default: false)", 'boolean', false ]
|
||||||
|
, debug:
|
||||||
|
[ false, " show traces and logs", 'boolean', false ]
|
||||||
});
|
});
|
||||||
|
|
||||||
// ignore certonly and extraneous arguments
|
// ignore certonly and extraneous arguments
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
daemon: true
|
||||||
|
http_port: 80
|
||||||
|
https_port: 443
|
||||||
|
version: draft-11
|
||||||
|
server: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
webroot_path: /srv/www
|
||||||
|
store:
|
||||||
|
module: 'le-store-certbot'
|
||||||
|
options:
|
||||||
|
config_dir: /etc/greenlock/
|
||||||
|
domains:
|
||||||
|
'*':
|
||||||
|
check:
|
||||||
|
module: 'fs-exists'
|
||||||
|
options:
|
||||||
|
path: /srv/www/:hostname
|
||||||
|
email: MY_EMAIL
|
||||||
|
agree_tos: MY_AGREE
|
||||||
|
analytics: true
|
||||||
|
challenges:
|
||||||
|
'https-01':
|
||||||
|
module: 'le-challenge-fs'
|
||||||
|
'example.com,www.example.com':
|
||||||
|
path: /srv/www/example.com
|
||||||
|
email: MY_EMAIL
|
||||||
|
agree_tos: MY_AGREE
|
||||||
|
analytics: true
|
||||||
|
challenges:
|
||||||
|
'dns-01':
|
||||||
|
module: 'le-challenge-cloudflare'
|
||||||
|
options:
|
||||||
|
email: 'jon@example.com'
|
||||||
|
key: 'xxxxxxxxxxxxxxxxx'
|
||||||
|
'.example.com':
|
||||||
|
check: null
|
||||||
|
path: /srv/www/example.com
|
||||||
|
email: MY_EMAIL
|
||||||
|
agree_tos: MY_AGREE
|
||||||
|
analytics: true
|
||||||
|
challenges:
|
||||||
|
'dns-01':
|
||||||
|
module: 'le-challenge-digitalocean'
|
||||||
|
options:
|
||||||
|
email: 'jon@example.com'
|
||||||
|
key: 'xxxxxxxxxxxxxxxxx'
|
|
@ -0,0 +1,22 @@
|
||||||
|
daemon: true
|
||||||
|
http_port: 80
|
||||||
|
https_port: 443
|
||||||
|
version: draft-11
|
||||||
|
server: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
webroot_path: /srv/www
|
||||||
|
store:
|
||||||
|
module: 'le-store-certbot'
|
||||||
|
options:
|
||||||
|
config_dir: /etc/greenlock/
|
||||||
|
domains:
|
||||||
|
'*':
|
||||||
|
email: MY_EMAIL
|
||||||
|
agree_tos: MY_AGREE
|
||||||
|
analytics: true
|
||||||
|
checks:
|
||||||
|
- module: 'greenlock-plugin-approve-fs'
|
||||||
|
options:
|
||||||
|
www: false
|
||||||
|
path: /srv/www/:hostname
|
||||||
|
challenges:
|
||||||
|
module: 'le-challenge-fs'
|
|
@ -0,0 +1,69 @@
|
||||||
|
[Unit]
|
||||||
|
Description=MY_DESC
|
||||||
|
Documentation=MY_DOCS
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target systemd-networkd-wait-online.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# Restart on crash (bad signal), and on 'clean' failure (error exit code)
|
||||||
|
# Allow up to 3 restarts within 10 seconds
|
||||||
|
# (it's unlikely that a user or properly-running script will do this)
|
||||||
|
Restart=on-failure
|
||||||
|
StartLimitInterval=10
|
||||||
|
StartLimitBurst=3
|
||||||
|
|
||||||
|
# The v8 VM will output a "clean" exit for JavaScript errors.
|
||||||
|
# If we knew we were never going to accidentally exit cleanly
|
||||||
|
# we would use on-abnormal:
|
||||||
|
; Restart=on-abnormal
|
||||||
|
|
||||||
|
# User and group the process will run as
|
||||||
|
# (www-data is the de facto standard on most systems)
|
||||||
|
User=MY_USER
|
||||||
|
Group=MY_GROUP
|
||||||
|
|
||||||
|
# If we need to pass environment variables in the future
|
||||||
|
Environment=NODE_PATH=MY_GREENLOCK_PATH/lib/node_modules NPM_CONFIG_PREFIX=MY_GREENLOCK_PATH
|
||||||
|
|
||||||
|
# Set a sane working directory, sane flags, and specify how to reload the config file
|
||||||
|
WorkingDirectory=MY_GREENLOCK_PATH
|
||||||
|
ExecStart=MY_GREENLOCK_PATH/bin/node MY_GREENLOCK_PATH/bin/greenlock --daemon --config MY_CONFIG_PATH
|
||||||
|
ExecReload=/bin/kill -USR1 $MAINPID
|
||||||
|
|
||||||
|
# Limit the number of file descriptors and processes; see `man systemd.exec` for more limit settings.
|
||||||
|
# Unmodified greenlock is not expected to use more than this.
|
||||||
|
LimitNOFILE=1048576
|
||||||
|
LimitNPROC=64
|
||||||
|
|
||||||
|
# Use private /tmp and /var/tmp, which are discarded after greenlock stops.
|
||||||
|
PrivateTmp=true
|
||||||
|
# Use a minimal /dev
|
||||||
|
PrivateDevices=true
|
||||||
|
# Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
|
||||||
|
ProtectHome=true
|
||||||
|
# Make /usr, /boot, /etc and possibly some more folders read-only.
|
||||||
|
ProtectSystem=full
|
||||||
|
# … except TLS/SSL, ACME, and Let's Encrypt certificates
|
||||||
|
# and /var/log/greenlock, because we want a place where logs can go.
|
||||||
|
# This merely retains r/w access rights, it does not add any new. Must still be writable on the host!
|
||||||
|
ReadWriteDirectories=MY_RW_DIRS
|
||||||
|
# you may also want to add other directories such as /opt/greelock /etc/acme /etc/letsencrypt
|
||||||
|
|
||||||
|
# Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories
|
||||||
|
; ReadWritePaths=/etc/greenlock /var/log/greenlock
|
||||||
|
|
||||||
|
# The following additional security directives only work with systemd v229 or later.
|
||||||
|
# They further retrict privileges that can be gained.
|
||||||
|
# Note that you may have to add capabilities required by any plugins in use.
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
# Caveat: Some plugins need additional capabilities.
|
||||||
|
# For example "upload" needs CAP_LEASE
|
||||||
|
; CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_LEASE
|
||||||
|
; AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_LEASE
|
||||||
|
; NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
2
index.js
2
index.js
|
@ -86,7 +86,7 @@ module.exports.run = function (args) {
|
||||||
if (args.tlsSni01Port) {
|
if (args.tlsSni01Port) {
|
||||||
servers.startServers(
|
servers.startServers(
|
||||||
[], args.tlsSni01Port
|
[], args.tlsSni01Port
|
||||||
, { debug: args.debug, httpsOptions: le.httpsOptions }
|
, { debug: args.debug, tlsOptions: le.tlsOptions }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports.install = function (opts, cb) {
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var service = '/etc/systemd/system/greenlock.service';
|
||||||
|
var rwDirs = [ '/etc/greenlock', '/srv/www', '/var/log/greenlock', '/opt/greenlock' ];
|
||||||
|
|
||||||
|
fs.readFile(path.join(__dirname, '../dist', service), 'utf8', function (e, text) {
|
||||||
|
if (e) { throw e; }
|
||||||
|
|
||||||
|
text = text
|
||||||
|
.replace(/MY_DESC/g, opts.description || 'Greenlock Secure Web Server')
|
||||||
|
.replace(/MY_DOCS/g, opts.homepage || 'https://git.coolaj86.com/coolaj86/greenlock-cli.js')
|
||||||
|
.replace(/MY_GREENLOCK_PATH/g, opts.greenlockPath || '/opt/greenlock')
|
||||||
|
.replace(/MY_CONFIG_PATH/g, opts.greenlockPath || '/etc/greenlock/greenlock.yml')
|
||||||
|
.replace(/MY_USER/g, opts.user || 'greenlock')
|
||||||
|
.replace(/MY_GROUP/g, opts.user || 'greenlock')
|
||||||
|
.replace(/MY_RW_DIRS/g, (opts.writableDirs || rwDirs).join(' '))
|
||||||
|
;
|
||||||
|
fs.writeFile(service, text, 'utf8', function (e) {
|
||||||
|
if (e) { throw e; }
|
||||||
|
|
||||||
|
console.log("Now reload configs and enable to start on boot:");
|
||||||
|
console.log("");
|
||||||
|
console.log("\tsudo systemctl daemon-reload");
|
||||||
|
console.log("\tsudo systemctl enable greenlock");
|
||||||
|
cb(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
|
@ -25,7 +25,7 @@ module.exports.create = function (challenge) {
|
||||||
, startServers: function (plainPorts, tlsPorts, opts) {
|
, startServers: function (plainPorts, tlsPorts, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
var httpsOptions = opts.httpsOptions || require('localhost.daplie.me-certificates');
|
var tlsOptions = opts.tlsOptions;
|
||||||
var https = require('https');
|
var https = require('https');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ module.exports.create = function (challenge) {
|
||||||
|
|
||||||
// tls-sni-01-port
|
// tls-sni-01-port
|
||||||
tlsPorts.forEach(function (port) {
|
tlsPorts.forEach(function (port) {
|
||||||
var server = https.createServer(httpsOptions, servers.httpResponder);
|
var server = https.createServer(tlsOptions, servers.httpResponder);
|
||||||
|
|
||||||
servers._servers.push(server);
|
servers._servers.push(server);
|
||||||
server.listen(port, function () {
|
server.listen(port, function () {
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
"le-challenge-sni": "^2.0.0",
|
"le-challenge-sni": "^2.0.0",
|
||||||
"le-challenge-standalone": "^2.0.0",
|
"le-challenge-standalone": "^2.0.0",
|
||||||
"le-store-certbot": "^2.0.2",
|
"le-store-certbot": "^2.0.2",
|
||||||
"localhost.daplie.me-certificates": "^1.3.2",
|
|
||||||
"mkdirp": "^0.5.1"
|
"mkdirp": "^0.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue