Compare commits

...

8 Commits
master ... v3

Author SHA1 Message Date
AJ ONeal 6a770303f0 tested installer with unzip 2018-05-16 01:52:19 -06:00
AJ ONeal 8cf13b329a making progress 2018-05-13 01:31:44 -06:00
AJ ONeal c30e25e25b standalone 2018-05-12 23:03:42 -06:00
AJ ONeal 4e447ec9cd prepare for v3 2018-05-12 22:55:05 -06:00
AJ ONeal 216384e096 add bundle.pem for HAProxy 2018-05-12 15:56:09 -06:00
AJ ONeal 0217bae134 update messaging 2018-05-12 15:52:52 -06:00
AJ ONeal 5da8c6aa2d add another demo 2018-05-12 15:48:33 -06:00
AJ ONeal 6a0f25c685 add installer and features 2018-05-12 15:39:59 -06:00
14 changed files with 611 additions and 195 deletions

347
README.md
View File

@ -1,44 +1,216 @@
# greenlock-cli (letsencrypt-cli for node.js)
![Greenlock Logo](https://git.coolaj86.com/coolaj86/greenlock.js/raw/branch/master/logo/greenlock-1063x250.png "Greenlock Logo")
| [greenlock (library)](https://git.coolaj86.com/coolaj86/greenlock.js)
| **greenlock-cli**
| [greenlock-express](https://git.coolaj86.com/coolaj86/greenlock-express.js)
| [greenlock-koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js)
| [greenlock-hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js)
|
# Greenlock™ Certificate Manager for Web Servers
CLI for node-greenlock modeled after the official client.
A server-friendly commandline tool for Free SSL, Free Wildcard SSL, and Fully Automated HTTPS
<small>certificates issued by Let's Encrypt v2 via ACME</small>
* Free SSL Certificates
* 90-day certificate lifetime
* One-off standalone registration / renewal
* On-the-fly registration / renewal via webroot
Greenlock is also available
[for Browsers](https://git.coolaj86.com/coolaj86/greenlock.html),
[for node.js](https://git.coolaj86.com/coolaj86/greenlock-express.js),
and [for API integrations](https://git.coolaj86.com/coolaj86/greenlock.js)
## Install Node
Why use Greenlock? Two Reasons:
===============================
For **Windows**:
One
---
Choose **Stable** from <https://nodejs.org/en/>
For Linux and **OS X**:
```
curl -L bit.ly/nodejs-min | bash
```
# Install Greenlock
You want to be able to run a command like this:
```bash
npm install -g greenlock-cli@2.x
sudo greenlock --domains example.com --config /etc/greenlock/greenlock.yml
```
## Usage
And then get awesome results like this:
```
/etc/ssl/acme
├── accounts
│   └── acme-staging-v02.api.letsencrypt.org/directory
│   └── c07a31a70c691d64f6b4d31f51a6dd9c
│  ├── meta.json
│  ├── private_key.json
│  └── regr.json
└── live
   └── example.com <-- Free SSL like magic! Wow!
   ├── bundle.pem
   ├── cert.pem
   ├── chain.pem
    ├── fullchain.pem
    └── privkey.pem
```
That you use with your existing webserver - Apache, Nginx, HAProxy, node.js, etc
And install to renew so that you never worry about ssl again.
Two
---
You want to be able to run a command like this:
```bash
sudo greenlock --install systemd --config /etc/greenlock.yml --webroot '/srv/www/:hostname'
```
To immediately secure and publish any and all sites you have in a web root like this:
```
/srv/www/
├── coolsite.rocks
├── example.com
└── whatever.app
```
Features
========
- [x] Works with Windows, Mac, and Linux
- [x] Works with Apache, Nginx, node.js, HAProxy, etc
- [x] Great for VPS services - AWS, Digital Ocean, Vultr, etc
- [x] Great for Tiny Computers - Raspberry Pi, etc
- [x] Automatic HTTPS
- [x] Free SSL
- [x] Free Wildcard SSL
- [x] Multiple domain support (up to 100 altnames per SAN)
- [x] Virtual Hosting (vhost)
- [x] Automatical renewal (10 to 14 days before expiration)
- [x] Let's Encrypt v2 ACME API
- [x] Extensible via Plugins
- [x] HTTP Challenge Plugins - AWS S3, Azure, Consul, etcd
- [x] DNS Challenge Plugins - AWS Route53, CloudFlare, Digital Ocean
- [x] Account & Certificate Storage Plugins - AWS S3, Redis
- [x] Built-in WebServer
Install
=======
Mac
---
Open Terminal and run this install script:
```bash
curl -fsS https://get.greenlock.app/ | bash
```
Linux
-----
Open Terminal and run this install script:
```bash
curl -fsS https://get.greenlock.app/ | bash
```
Windows & Node.js
-----------------
1. Install [node.js](https://nodejs.org)
2. Open _Node.js_
2. Run the command `npm install -g greenlock-cli`
Important: How to Not Get Blocked
===================
PLEASE READ ALL THREE SENTENCES:
* These examples use the PRODUCTION ENVIRONMENT (where you can be blocked)
* If an example DOESN'T WORK on the first try, STOP!
* UNCOMMENT the `--staging` flag and see the TROUBLESHOOTING SECTION
Quick Examples
==============
The most basic options are exposed as commandline flags,
just so that we can do little domes like this.
The config file is explained after the troubleshooting section.
### The Greenlock HTTPS WebServer
Easy to run on your server, nothing else required:
```bash
sudo greenlock --webserver \
--agree-tos --email jon@example.com \
--domains example.com,www.example.com \
--webroot /srv/www/example.com \
--config-dir ~/acme/etc #--staging
```
### Add SSL to an Existing WebServer
For all the Apache, Nginx, and HAProxy fans out there:
(use your existing webroot)
```bash
sudo greenlock --agree-tos --email jon@example.com \
--domains example.com,www.example.com \
--webroot /srv/www/example.com \
--privkey-path /etc/ssl/example.com/privkey.pem \
--fullchain-path /etc/ssl/example.com/fullchain.pem \
--bundle-path /etc/ssl/example.com/bundle.pem \
--config-dir /etc/ssl/acme #--staging
```
### Get SSL Certificates Interactively
Run this manual process on your laptop and copy the certificates
to you server afterwards:
```bash
greenlock --agree-tos --email jon@example.com \
--domains example.com,www.example.com \
--privkey-path /etc/ssl/example.com/privkey.pem \
--fullchain-path /etc/ssl/example.com/fullchain.pem \
--bundle-path /etc/ssl/example.com/bundle.pem \
--manual \
--config-dir /etc/ssl/acme #--staging
```
### Standalone SSL Certificate Retrieval
Run this on a server standalone just to retrieve
certificates:
```bash
sudo greenlock --agree-tos --email jon@example.com \
--domains example.com,www.example.com \
--privkey-path /etc/ssl/example.com/privkey.pem \
--fullchain-path /etc/ssl/example.com/fullchain.pem \
--bundle-path /etc/ssl/example.com/bundle.pem \
--standalone \
--config-dir ~/etc/ssl/acme #--staging
```
Troubleshooting
===============
Watch the [Troubleshooting Screencast](https://youtu.be/e8vaR4CEZ5s?t=397)
**Note**: Replace `whatever.com` with your domain, use your real email, etc.
0. Use the `--staging` flag while troubleshooting
1. Do you have a valid A record for `whatever.com`?
2. When you `ping whatever.com` do you see that same address?
3. Can you confirm that's your server's address with `ifconfig` or `ipconfig`?
4. Do you have write access to all of the directories you've specified?
**Important**: Don't forget to delete the directory specified in `--config-dir`
when you get things figured out and remove `--staging`.
Usage
=====
These commands are shown using the **testing 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
multiple domains doesn't work for you, file a bug.
@ -54,8 +226,9 @@ greenlock certonly \
--agree-tos --email john.doe@example.com \
--standalone \
--domains example.com,www.example.com \
--server https://acme-staging.api.letsencrypt.org/directory \
--config-dir ~/letsencrypt/etc
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--acme-version draft-11
--config-dir ~/acme/etc
```
or
@ -65,8 +238,9 @@ greenlock certonly \
--agree-tos --email john.doe@example.com \
--standalone --tls-sni-01-port 443 \
--domains example.com,www.example.com \
--server https://acme-staging.api.letsencrypt.org/directory \
--config-dir ~/letsencrypt/etc
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--acme-version draft-11
--config-dir ~/acme/etc
```
Then you can see your certs at `~/letsencrypt/etc/live`.
@ -79,7 +253,7 @@ This option is great for testing, but since it requires the use of
the same ports that your webserver needs, it isn't a good choice
for production.
### WebRoot (production option 1)
### WebRoot
You can specify the path to where you keep your `index.html` with `webroot`, as
long as your server is serving plain HTTP on port 80.
@ -93,7 +267,8 @@ sudo greenlock certonly \
--webroot --webroot-path /srv/www/example.com \
--config-dir /etc/letsencrypt \
--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`
@ -108,70 +283,6 @@ ls /etc/letsencrypt/live/
You can use a cron job to run the script above every 80 days (the certificates expire after 90 days)
so that you always have fresh certificates.
### Hooks (production option 2)
You can also integrate with a secure server. This is more complicated than the
webroot option, but it allows you to obtain certificates with only port 443
open. This facility can work with any web server as long as it supports server
name indication (SNI) and you can provide a configuration file template and
shell hooks to install and uninstall the configuration (without downtime). In
fact, it doesn't even need to be a webserver (though it must run on port 443);
it could be another server that performs SSL/TLS negotiation with SNI.
The process works something like this. You would run:
```bash
sudo greenlock certonly \
--agree-tos --email john.doe@example.com \
--hooks --hooks-server apache2-debian \
--config-dir /etc/letsencrypt \
--domains example.com,www.example.com \
--server https://acme-staging.api.letsencrypt.org/directory
```
Three files are then generated:
* a configuration fragment: `some-long-string.conf`
* a challenge-fulfilling certificate: `the-same-long-string.crt`
* a private key: `the-same-long-string.key`
A hook is then run to enable the fragment, e.g. by linking it (it should not be
moved) into a `conf.d` directory (for Apache on Debian, `sites-enabled`). A
second hook is then run to check the configuration is valid, to avoid
accidental downtime, and then another to signal to the server to reload the
configuration. The server will now serve the generated certificate on a special
domain to prove you own the domain you're getting a certificate for.
After the domain has been validated externally, hooks are run to disable the
configuration fragment, and again check and reload the configuration.
You can then find your brand new certs in:
```
ls /etc/letsencrypt/live/
```
Tailor to your server and distro using the `--hooks-server` option. So far, the
following are supported (contributions for additional servers welcome):
* apache2-debian
To tweak it for your setup and taste, see all the `hooks-` options in the
Command Line Options section below. Also note that the following substitutions
are available for use in the hooks and the template:
* `{{{token}}}`: the token
* `{{{domain}}}`: the domain for which a certificate is being sought (beware of
this if using multiple domains per certificate)
* `{{{subject}}}`: the domain for which the generated challenge-fulfilling
certificate must be used (only available when generating it)
* `{{{cert}}}`: the path to the generated certificate: `hooks-path/token.crt`
* `{{{privkey}}}`: the path to the generated private key: `hooks-path/token.key`
* `{{{conf}}}`: the path to the generated config file: `hooks-path/token.conf`
* `{{{bind}}}`: the value of the `hooks-bind` option
* `{{{port}}}`: the value of the `hooks-port` option
* `{{{webroot}}}`: the value of the `hooks-webroot` option
### Interactive (for debugging)
The token (for all challenge types) and keyAuthorization (only for https-01)
@ -182,9 +293,10 @@ will be printed to the screen and you will be given time to copy it wherever
sudo greenlock certonly \
--agree-tos --email john.doe@example.com \
--manual
--config-dir /etc/letsencrypt \
--config-dir /etc/acme \
--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
@ -248,11 +360,6 @@ Options:
--renew-within [NUMBER] Renew certificates this many days before expiry. (default: 7)
--duplicate BOOLEAN Allow getting a certificate that duplicates an existing one/is
an early renewal.
--rsa-key-size [NUMBER] Size (in bits) of the RSA key. (Default is 2048)
--cert-path STRING Path to where new cert.pem is saved
(Default is :conf/live/:hostname/cert.pem)
@ -264,13 +371,8 @@ Options:
--domain-key-path STRING Path to privkey.pem to use for domain (default: generate new)
--account-key-path STRING Path to privkey.pem to use for account (default: generate new)
--config-dir STRING Configuration directory. (Default is ~/letsencrypt/etc/)
--tls-sni-01-port NUMBER Use TLS-SNI-01 challenge type with this port.
(must be 443 with most production servers) (Boulder allows 5001 in testing mode)
--http-01-port [NUMBER] Use HTTP-01 challenge type with this port, used for SimpleHttp challenge. (Default is 80)
(must be 80 with most production servers)
@ -285,35 +387,6 @@ Options:
--webroot-path STRING public_html / webroot path.
--hooks BOOLEAN Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges.
--hooks-path STRING Path in which to store files for hooks.
(Default is ~/letsencrypt/apache)
--hooks-server STRING Type of webserver to configure. Sets defaults for all the following --hooks- options.
Either --hooks-server or --hooks-template must be given.
(See the Hooks section above for a list of supported servers.)
--hooks-template STRING Template to use for hooks configuration file.
Either --hooks-server or --hooks-template must be given.
--hooks-bind STRING IP address to use in configuration for hooks. (Default is *)
--hooks-port STRING Port to use in configuration for hooks. (Default is 443)
--hooks-webroot STRING Webroot to use in configuration for hooks (e.g. empty dir).
Nothing should actually be served from here. (Default is /var/www)
--hooks-pre-enable STRING Hook to check the webserver configuration prior to enabling.
--hooks-enable STRING Hook to enable the webserver configuration.
--hooks-pre-reload STRING Hook to check the webserver configuration prior to reloading.
--hooks-reload STRING Hook to reload the webserver.
--hooks-disable STRING Hook to disable the webserver configuration.
--debug BOOLEAN show traces and logs
-h, --help Display help and usage details

View File

@ -5,49 +5,76 @@ var cli = require('cli');
var mkdirp = require('mkdirp');
cli.parse({
server: [ false, " ACME Directory Resource URI.", 'string', '' ]
, email: [ false, " Email used for registration and recovery contact. (default: null)", 'email' ]
, 'agree-tos': [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ]
, domains: [ false, " Domain names to apply. For multiple domains you can enter a comma separated list of domains as a parameter. (default: [])", 'string' ]
, 'renew-within': [ false, " Renew certificates this many days before expiry", 'int', 7 ]
, duplicate: [ false, " Allow getting a certificate that duplicates an existing one/is an early renewal", 'boolean', false ]
, 'rsa-key-size': [ false, " Size (in bits) of the RSA key.", 'int', 2048 ]
, 'cert-path': [ false, " Path to where new cert.pem is saved", 'string',':configDir/live/:hostname/cert.pem' ]
, 'fullchain-path': [ false, " Path to where new fullchain.pem (cert + chain) is saved", 'string', ':configDir/live/:hostname/fullchain.pem' ]
, 'chain-path': [ false, " Path to where new chain.pem is saved", 'string', ':configDir/live/:hostname/chain.pem' ]
, 'domain-key-path': [ false, " Path to privkey.pem to use for domain (default: generate new)", 'string' ]
, 'account-key-path': [ false, " Path to privkey.pem to use for account (default: generate new)", 'string' ]
, 'config-dir': [ false, " Configuration directory.", 'string', '~/letsencrypt/etc/' ]
, 'tls-sni-01-port': [ false, " Use TLS-SNI-01 challenge type with this port (only port 443 is valid with most production servers)", 'int' ]
, 'http-01-port': [ false, " Use HTTP-01 challenge type with this port (only port 80 is valid with most production servers) (default: 80)", 'int' ]
, 'dns-01': [ false, " Use DNS-01 challange type", 'boolean', false ]
, standalone: [ 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 ]
, webroot: [ false, " Obtain certs by placing files in a webroot directory.", 'boolean', false ]
, 'webroot-path': [ false, " public_html / webroot path.", 'string' ]
, hooks: [ false, " Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges.", 'boolean', false ]
, 'hooks-path': [ false, " Path in which to store files for hooks.", 'string' ]
, 'hooks-server': [ false, " Type of webserver to configure.", 'string' ]
, 'hooks-template': [ false, " Template to use for hooks configuration file.", 'string' ]
, 'hooks-bind': [ false, " IP address to use in configuration for hooks.", 'string' ]
, 'hooks-port': [ false, " Port to use in configuration for hooks.", 'string' ]
, 'hooks-webroot': [ false, " Webroot to use in configuration for hooks (e.g. empty dir).", 'string' ]
, 'hooks-pre-enable': [ false, " Hook to check the webserver configuration prior to enabling.", 'string' ]
, 'hooks-enable': [ false, " Hook to enable the webserver configuration.", 'string' ]
, 'hooks-pre-reload': [ false, " Hook to check the webserver configuration prior to reloading.", 'string' ]
, 'hooks-reload': [ false, " Hook to reload the webserver.", 'string' ]
, 'hooks-disable': [ false, " Hook to disable the webserver configuration.", 'string' ]
//, 'standalone-supported-challenges': [ false, " Supported challenges, order preferences are randomly chosen. (default: http-01,tls-sni-01)", 'string', 'http-01,tls-sni-01']
, debug: [ false, " show traces and logs", 'boolean', false ]
, 'work-dir': [ false, "(ignored)", 'string', '~/letsencrypt/var/lib/' ]
, 'logs-dir': [ false, "(ignored)", 'string', '~/letsencrypt/var/log/' ]
'acme-version':
[ false, " v01 (Let's Encrypt v01) or draft-11 (Let's Encrypt v02) (default: draft-11)", 'string'
, 'draft-11' ]
, 'acme-url':
[ false, " ACME API Directory URL (default: https://acme-v02.api.letsencrypt.org/directory", 'string'
, 'https://acme-staging-v02.api.letsencrypt.org/directory' ]
, 'aol-keyword-www':
[ false, " Travel back in time to 1995 where we redirect bare domains as to have a triple-w prefix", 'string'
, false ]
, config:
[ 'c', " Path to configuration file --config /etc/greenlock/greenlock.yml (default: '')", 'string' ]
, serve:
[ false, " Run as webserver (default: false)", 'boolean'
, false ]
, email:
[ false, " Email used for registration and recovery contact (default: '')", 'email' ]
, analytics:
[ false, " Share analytics with greenlock (default: false)", 'boolean'
, false ]
, community:
[ false, " Join the greenlock community to get important updates (default: false)", 'boolean'
, false ]
, 'agree-tos':
[ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean'
, false ]
, domains:
[ false, " Comma-separated list of domains to secure (default: [])", 'string' ]
, 'config-dir':
[ false, " Configuration directory.", 'string'
, '~/acme/etc/' ]
, 'cert-path':
[ false, " Path where new cert.pem is saved", 'string'
, ':configDir/live/:hostname/cert.pem' ]
, 'fullchain-path':
[ false, " Path where new fullchain.pem (cert + chain) is saved", 'string'
, ':configDir/live/:hostname/fullchain.pem' ]
, 'chain-path':
[ false, " Path where new chain.pem is saved", 'string'
, ':configDir/live/:hostname/chain.pem' ]
, 'bundle-path':
[ false, " Path where new bundle.pem (fullchain + privkey) is saved", 'string'
, ':configDir/live/:hostname/bundle.pem' ]
, 'privkey-path':
[ false, " Path where (new or existing) domain privkey.pem is saved", 'string'
, ':configDir/live/:hostname/privkey.pem' ]
, 'webroot':
[ false, " public_html / webroot path such as /srv/www/:hostname", 'string' ]
, 'renew-within':
[ false, " Renew certificates this many days before expiry", 'int'
, 11 ]
, staging:
[ false, " Use Let's Encrypt v02 staging API", 'boolean'
, false ]
, standalone:
[ 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
cli.main(function(_, options) {
console.log('');
var args = {};
var homedir = require('homedir')();
var homedir = require('os').homedir();
Object.keys(options).forEach(function (key) {
var val = options[key];

View File

@ -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'

22
dist/etc/greenlock/greenlock.yml vendored Normal file
View File

@ -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'

View File

@ -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

View File

@ -1,8 +0,0 @@
#!/bin/bash
node bin/letsencrypt certonly \
--agree-tos --email 'john.doe@gmail.com' \
--standalone \
--domains example.com,www.example.com \
--server https://acme-staging.api.letsencrypt.org/directory \
--config-dir ~/letsencrypt.test/etc

8
examples/server.sh Normal file
View File

@ -0,0 +1,8 @@
#!/bin/bash
greenlock \
--agree-tos --email 'john.doe@gmail.com' \
--serve
--root /root/www/example.com \
--domains example.com,www.example.com \
--config-dir ~/acme.test/etc

7
examples/standalone.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
greenlock \
--agree-tos --email 'john.doe@gmail.com' \
--standalone \
--domains example.com,www.example.com \
--config-dir ~/acme.test/etc

7
examples/webroot.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
greenlock \
--agree-tos --email 'john.doe@gmail.com' \
--root /root/www/example.com \
--domains example.com,www.example.com \
--config-dir ~/acme.test/etc

View File

@ -86,7 +86,7 @@ module.exports.run = function (args) {
if (args.tlsSni01Port) {
servers.startServers(
[], args.tlsSni01Port
, { debug: args.debug, httpsOptions: le.httpsOptions }
, { debug: args.debug, tlsOptions: le.tlsOptions }
);
}
else {

140
installer/get.sh Executable file
View File

@ -0,0 +1,140 @@
#!/bin/bash
# This is a 3 step process
# 1. First we need to figure out whether to use wget or curl for fetching remote files
# 2. Next we need to figure out whether to use unzip or tar for downloading releases
# 3. We need to actually install the stuff
set -e
set -u
###############################
# #
# http_get #
# boilerplate for curl / wget #
# #
###############################
# See https://git.coolaj86.com/coolaj86/snippets/blob/master/bash/http-get.sh
_my_http_get=""
_my_http_opts=""
_my_http_out=""
detect_http_get()
{
set +e
if type -p curl >/dev/null 2>&1; then
_my_http_get="curl"
_my_http_opts="-fsSL"
_my_http_out="-o"
elif type -p wget >/dev/null 2>&1; then
_my_http_get="wget"
_my_http_opts="--quiet"
_my_http_out="-O"
else
echo "Aborted, could not find curl or wget"
return 7
fi
set -e
}
http_get()
{
$_my_http_get $_my_http_opts $_my_http_out "$2" "$1"
touch "$2"
}
http_bash()
{
_http_url=$1
my_args=${2:-}
rm -rf my-tmp-runner.sh
$_my_http_get $_my_http_opts $_my_http_out my-tmp-runner.sh "$_http_url"; bash my-tmp-runner.sh $my_args; rm my-tmp-runner.sh
}
detect_http_get
###############################
## END HTTP_GET ##
###############################
echo ""
echo ""
echo ""
if [ -z "${GREENLOCK_PATH:-}" ]; then
echo 'GREENLOCK_PATH="'${GREENLOCK_PATH:-}'"'
GREENLOCK_PATH=/opt/greenlock
fi
echo "Installing Greenlock to '$GREENLOCK_PATH'"
echo ""
echo "sudo mkdir -p '$GREENLOCK_PATH'"
sudo mkdir -p "$GREENLOCK_PATH"
echo "sudo chown -R $(whoami) '$GREENLOCK_PATH'"
sudo chown -R $(whoami) "$GREENLOCK_PATH"
echo "Installing node.js dependencies into $GREENLOCK_PATH"
# until node v10.x gets fix for ursa we have no advantage to switching from 8.x
export NODEJS_VER=v8.11.1
export NODE_PATH="$GREENLOCK_PATH/lib/node_modules"
export NPM_CONFIG_PREFIX="$GREENLOCK_PATH"
export PATH="$GREENLOCK_PATH/bin:$PATH"
sleep 1
http_bash https://git.coolaj86.com/coolaj86/node-installer.sh/raw/branch/master/install.sh --no-dev-deps >/dev/null 2>/dev/null
my_tree="master"
my_node="$GREENLOCK_PATH/bin/node"
my_npm="$my_node $GREENLOCK_PATH/bin/npm"
my_tmp="$GREENLOCK_PATH/tmp"
mkdir -p $my_tmp
echo "Installing Greenlock into $GREENLOCK_PATH"
set +e
my_unzip=$(type -p unzip)
my_tar=$(type -p tar)
if [ -n "$my_unzip" ]; then
rm -f $my_tmp/greenlock-$my_tree.zip
http_get https://git.coolaj86.com/coolaj86/greenlock-cli.js/archive/$my_tree.zip $my_tmp/greenlock-$my_tree.zip
# -o means overwrite, and there is no option to strip
$my_unzip -o $my_tmp/greenlock-$my_tree.zip -d $GREENLOCK_PATH/ > /dev/null
cp -ar $GREENLOCK_PATH/greenlock-cli.js/* $GREENLOCK_PATH/ > /dev/null
rm -rf $GREENLOCK_PATH/greenlock-cli.js
elif [ -n "$my_tar" ]; then
rm -f $my_tmp/greenlock-$my_tree.tar.gz
http_get https://git.coolaj86.com/coolaj86/greenlock-cli.js/archive/$my_tree.tar.gz $my_tmp/greenlock-$my_tree.tar.gz
ls -lah $my_tmp/greenlock-$my_tree.tar.gz
$my_tar -xzf $my_tmp/greenlock-$my_tree.tar.gz --strip 1 -C $GREENLOCK_PATH/
else
echo "Neither tar nor unzip found. Abort."
exit 13
fi
set -e
pushd $GREENLOCK_PATH >/dev/null
$my_npm install >/dev/null 2>/dev/null
popd >/dev/null
cat << EOF > $GREENLOCK_PATH/bin/greenlock
#!/bin/bash
$my_node $GREENLOCK_PATH/bin/greenlock.js
EOF
chmod a+x $GREENLOCK_PATH/bin/greenlock
echo "Creating link to 'greenlock' in /usr/local/bin"
ln -sf $GREENLOCK_PATH/bin/greenlock /usr/local/bin/greenlock
echo ""
echo ""
echo "Installed successfully. Try it out:"
echo ""
echo " greenlock --help"
echo ""
echo ""
#sudo setcap cap_net_bind_service=+ep $GREENLOCK_PATH/bin/node
#https://git.coolaj86.com/coolaj86/greenlock-cli.js.git
#https://git.coolaj86.com/coolaj86/greenlock-cli.js/archive/:tree:.tar.gz
#https://git.coolaj86.com/coolaj86/greenlock-cli.js/archive/:tree:.zip

31
lib/install-systemd.js Normal file
View File

@ -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);
});
});
};

View File

@ -25,7 +25,7 @@ module.exports.create = function (challenge) {
, startServers: function (plainPorts, tlsPorts, opts) {
opts = opts || {};
var httpsOptions = opts.httpsOptions || require('localhost.daplie.me-certificates');
var tlsOptions = opts.tlsOptions;
var https = require('https');
var http = require('http');
@ -56,7 +56,7 @@ module.exports.create = function (challenge) {
// tls-sni-01-port
tlsPorts.forEach(function (port) {
var server = https.createServer(httpsOptions, servers.httpResponder);
var server = https.createServer(tlsOptions, servers.httpResponder);
servers._servers.push(server);
server.listen(port, function () {

View File

@ -34,16 +34,11 @@
},
"homepage": "https://git.coolaj86.com/coolaj86/greenlock-cli.js",
"dependencies": {
"cli": "^0.11.1",
"greenlock": "^2.1.16",
"homedir": "^0.6.0",
"le-acme-core": "^2.0.5",
"le-challenge-hooks": "^2.0.0",
"le-challenge-manual": "^2.0.0",
"le-challenge-sni": "^2.0.0",
"le-challenge-standalone": "^2.0.0",
"le-store-certbot": "^2.0.2",
"localhost.daplie.me-certificates": "^1.3.2",
"cli": "^1.0.1",
"greenlock": "^2.2.11",
"le-challenge-manual": "^2.1.0",
"le-challenge-standalone": "^2.1.0",
"le-store-certbot": "^2.1.0",
"mkdirp": "^0.5.1"
}
}