mirror of
https://github.com/dehydrated-io/dehydrated.git
synced 2026-01-14 07:33:34 +01:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
992beecbdb | ||
|
|
6192b33ac2 | ||
|
|
47602dea04 | ||
|
|
3a66a7f8d2 | ||
|
|
624ce4436a | ||
|
|
d81eb58536 | ||
|
|
117d5d6228 | ||
|
|
34565c193d | ||
|
|
ca0249c46c | ||
|
|
afabfff06e | ||
|
|
bd9cc5b0c4 | ||
|
|
194464b04b | ||
|
|
364bcccf74 | ||
|
|
44aca90cd7 | ||
|
|
2042b177c7 | ||
|
|
ae98ff6767 | ||
|
|
194d543fa1 | ||
|
|
df292dece2 | ||
|
|
f4138efab9 | ||
|
|
034ec30c7d | ||
|
|
ec48906992 | ||
|
|
64864f5fa6 | ||
|
|
620c7eb23e | ||
|
|
4e8f944b72 | ||
|
|
8e77ba5e02 | ||
|
|
0d8b928923 | ||
|
|
785ffa5539 | ||
|
|
d5b285868e | ||
|
|
722430039b | ||
|
|
41aae07343 | ||
|
|
a3e5ed361b |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,8 +1,8 @@
|
||||
private_key.pem
|
||||
private_key.json
|
||||
domains.txt
|
||||
config.sh
|
||||
config
|
||||
hook.sh
|
||||
certs/*
|
||||
archive/*
|
||||
.acme-challenges/*
|
||||
accounts/*
|
||||
|
||||
22
CHANGELOG
22
CHANGELOG
@@ -2,6 +2,28 @@
|
||||
This file contains a log of major changes in letsencrypt.sh
|
||||
|
||||
## [x.x.x] - xxxx-xx-xx
|
||||
## Changed
|
||||
- ...
|
||||
|
||||
## [0.3.0] - 2016-09-07
|
||||
## Changed
|
||||
- Config is now named `config` instead of `config.sh`!
|
||||
- Location of domains.txt is now configurable via DOMAINS_TXT config variable
|
||||
- Location of certs directory is now configurable via CERTDIR config variable
|
||||
- signcsr command now also outputs chain certificate if --full-chain/-fc is set
|
||||
- Location of account-key(s) changed
|
||||
- Default WELLKNOWN location is now `/var/www/letsencrypt`
|
||||
- New version of Let's Encrypt Subscriber Agreement
|
||||
|
||||
## Added
|
||||
- Added option to add CSR-flag indicating OCSP stapling to be mandatory
|
||||
- Initial support for configuration on per-certificate base
|
||||
- Support for per-CA account keys and custom config for output cert directory, license, etc.
|
||||
- Added option to select IP version of name to address resolution
|
||||
- Added option to run letsencrypt.sh without locks
|
||||
|
||||
## Fixed
|
||||
- letsencrypt.sh no longer stores account keys from invalid registrations
|
||||
|
||||
## [0.2.0] - 2016-05-22
|
||||
### Changed
|
||||
|
||||
@@ -41,11 +41,18 @@ Commands:
|
||||
--env (-e) Output configuration variables for use in other scripts
|
||||
|
||||
Parameters:
|
||||
--full-chain (-fc) Print full chain when using --signcsr
|
||||
--ipv4 (-4) Resolve names to IPv4 addresses only
|
||||
--ipv6 (-6) Resolve names to IPv6 addresses only
|
||||
--domain (-d) domain.tld Use specified domain name(s) instead of domains.txt entry (one certificate!)
|
||||
--keep-going (-g) Keep going after encountering an error while creating/renewing multiple certificates in cron mode
|
||||
--force (-x) Force renew of certificate even if it is longer valid than value in RENEW_DAYS
|
||||
--no-lock (-n) Don't use lockfile (potentially dangerous!)
|
||||
--ocsp Sets option in CSR indicating OCSP stapling to be mandatory
|
||||
--privkey (-p) path/to/key.pem Use specified private key instead of account key (useful for revocation)
|
||||
--config (-f) path/to/config.sh Use specified config file
|
||||
--config (-f) path/to/config Use specified config file
|
||||
--hook (-k) path/to/hook.sh Use specified script for hooks
|
||||
--out (-o) certs/directory Output certificates into the specified directory
|
||||
--challenge (-t) http-01|dns-01 Which challenge should be used? Currently http-01 and dns-01 are supported
|
||||
--algo (-a) rsa|prime256v1|secp384r1 Which public key algorithm should be used? Supported: rsa, prime256v1 and secp384r1
|
||||
```
|
||||
|
||||
@@ -4,7 +4,7 @@ This script also supports the new `dns-01`-type verification. This type of verif
|
||||
|
||||
You need a hook script that deploys the challenge to your DNS server!
|
||||
|
||||
The hook script (indicated in the config.sh file or the --hook/-k command line argument) gets four arguments: an operation name (clean_challenge, deploy_challenge, or deploy_cert) and some operands for that. For deploy_challenge $2 is the domain name for which the certificate is required, $3 is a "challenge token" (which is not needed for dns-01), and $4 is a token which needs to be inserted in a TXT record for the domain.
|
||||
The hook script (indicated in the config file or the --hook/-k command line argument) gets four arguments: an operation name (clean_challenge, deploy_challenge, or deploy_cert) and some operands for that. For deploy_challenge $2 is the domain name for which the certificate is required, $3 is a "challenge token" (which is not needed for dns-01), and $4 is a token which needs to be inserted in a TXT record for the domain.
|
||||
|
||||
Typically, you will need to split the subdomain name in two, the subdomain name and the domain name separately. For example, for "my.example.com", you'll need "my" and "example.com" separately. You then have to prefix "_acme-challenge." before the subdomain name, as in "_acme-challenge.my" and set a TXT record for that on the domain (e.g. "example.com") which has the value supplied in $4
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
### Elliptic Curve Cryptography (ECC)
|
||||
|
||||
This script also supports certificates with Elliptic Curve public keys!
|
||||
Be aware that at the moment this is not available on the production servers from letsencrypt.
|
||||
Please read https://community.letsencrypt.org/t/ecdsa-testing-on-staging/8809/ for the current state of ECC support.
|
||||
Simply set the `KEY_ALGO` variable in one of the config files.
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# This is the main config file for letsencrypt.sh #
|
||||
# #
|
||||
# This file is looked for in the following locations: #
|
||||
# $SCRIPTDIR/config.sh (next to this script) #
|
||||
# /usr/local/etc/letsencrypt.sh/config.sh #
|
||||
# /etc/letsencrypt.sh/config.sh #
|
||||
# ${PWD}/config.sh (in current working-directory) #
|
||||
# $SCRIPTDIR/config (next to this script) #
|
||||
# /usr/local/etc/letsencrypt.sh/config #
|
||||
# /etc/letsencrypt.sh/config #
|
||||
# ${PWD}/config (in current working-directory) #
|
||||
# #
|
||||
# Default values of this config are in comments #
|
||||
########################################################
|
||||
|
||||
# Resolve names to addresses of IP version only. (curl)
|
||||
# supported values: 4, 6
|
||||
# default: <unset>
|
||||
#IP_VERSION=
|
||||
|
||||
# Path to certificate authority (default: https://acme-v01.api.letsencrypt.org/directory)
|
||||
#CA="https://acme-v01.api.letsencrypt.org/directory"
|
||||
|
||||
# Path to license agreement (default: https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf)
|
||||
#LICENSE="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
|
||||
# Path to license agreement (default: https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf)
|
||||
#LICENSE="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
|
||||
|
||||
# Which challenge should be used? Currently http-01 and dns-01 are supported
|
||||
#CHALLENGETYPE="http-01"
|
||||
@@ -30,14 +33,17 @@
|
||||
# Base directory for account key, generated certificates and list of domains (default: $SCRIPTDIR -- uses config directory if undefined)
|
||||
#BASEDIR=$SCRIPTDIR
|
||||
|
||||
# Output directory for challenge-tokens to be served by webserver or deployed in HOOK (default: $BASEDIR/.acme-challenges)
|
||||
#WELLKNOWN="${BASEDIR}/.acme-challenges"
|
||||
# File containing the list of domains to request certificates for (default: $BASEDIR/domains.txt)
|
||||
#DOMAINS_TXT="${BASEDIR}/domains.txt"
|
||||
|
||||
# Location of private account key (default: $BASEDIR/private_key.pem)
|
||||
#ACCOUNT_KEY="${BASEDIR}/private_key.pem"
|
||||
# Output directory for generated certificates
|
||||
#CERTDIR="${BASEDIR}/certs"
|
||||
|
||||
# Location of private account registration information (default: $BASEDIR/private_key.json)
|
||||
#ACCOUNT_KEY_JSON="${BASEDIR}/private_key.json"
|
||||
# Directory for account keys and registration information
|
||||
#ACCOUNTDIR="${BASEDIR}/accounts"
|
||||
|
||||
# Output directory for challenge-tokens to be served by webserver or deployed in HOOK (default: /var/www/letsencrypt)
|
||||
#WELLKNOWN="/var/www/letsencrypt"
|
||||
|
||||
# Default keysize for private keys (default: 4096)
|
||||
#KEYSIZE="4096"
|
||||
@@ -74,3 +80,6 @@
|
||||
|
||||
# Lockfile location, to prevent concurrent access (default: $BASEDIR/lock)
|
||||
#LOCKFILE="${BASEDIR}/lock"
|
||||
|
||||
# Option to add CSR-flag indicating OCSP stapling to be mandatory (default: no)
|
||||
#OCSP_MUST_STAPLE="no"
|
||||
@@ -9,7 +9,7 @@ See below for an example on how the calls change:
|
||||
|
||||
### HOOK_CHAIN="no" (default behaviour)
|
||||
```
|
||||
# INFO: Using main config file /etc/letsencrypt.sh/config.sh
|
||||
# INFO: Using main config file /etc/letsencrypt.sh/config
|
||||
Processing lukas.im with alternative names: www.lukas.im
|
||||
+ Checking domain name(s) of existing cert... unchanged.
|
||||
+ Checking expire date of existing cert...
|
||||
@@ -37,7 +37,7 @@ HOOK: deploy_cert lukas.im /etc/letsencrypt.sh/certs/lukas.im/privkey.pem /etc/l
|
||||
|
||||
### HOOK_CHAIN="yes"
|
||||
```
|
||||
# INFO: Using main config file /etc/letsencrypt.sh/config.sh
|
||||
# INFO: Using main config file /etc/letsencrypt.sh/config
|
||||
Processing lukas.im with alternative names: www.lukas.im
|
||||
+ Checking domain name(s) of existing cert... unchanged.
|
||||
+ Checking expire date of existing cert...
|
||||
|
||||
18
docs/per-certificate-config.md
Normal file
18
docs/per-certificate-config.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Config on per-certificate base
|
||||
|
||||
letsencrypt.sh allows a few configuration variables to be set on a per-certificate base.
|
||||
|
||||
To use this feature create a `config` file in the certificates output directory (e.g. `certs/example.org/config`).
|
||||
|
||||
Currently supported options:
|
||||
|
||||
- PRIVATE_KEY_RENEW
|
||||
- KEY_ALGO
|
||||
- KEYSIZE
|
||||
- OCSP_MUST_STAPLE
|
||||
- CHALLENGETYPE
|
||||
- HOOK
|
||||
- HOOK_CHAIN
|
||||
- WELLKNOWN
|
||||
- OPENSSL_CNF
|
||||
- RENEW_DAYS
|
||||
@@ -1,15 +1,12 @@
|
||||
# Staging
|
||||
|
||||
Let’s Encrypt has stringent rate limits in place during the public beta period.
|
||||
Let’s Encrypt has stringent rate limits in place.
|
||||
|
||||
If you start testing using the production endpoint (which is the default),
|
||||
you will quickly hit these limits and find yourself locked out.
|
||||
|
||||
To avoid this, please set the CA property to the Let’s Encrypt staging server URL in your `config.sh` file:
|
||||
To avoid this, please set the CA property to the Let’s Encrypt staging server URL in your config file:
|
||||
|
||||
```bash
|
||||
CA="https://acme-staging.api.letsencrypt.org/directory"
|
||||
```
|
||||
|
||||
Please keep in mind that at the time of writing this letsencrypt.sh doesn't have support for registration management,
|
||||
so if you change CA you'll have to move your `private_key.pem` (and, if you care, `private_key.json`) out of the way.
|
||||
|
||||
@@ -54,3 +54,15 @@ Alias /.well-known/acme-challenge /var/www/letsencrypt
|
||||
</IfModule>
|
||||
</Directory>
|
||||
```
|
||||
|
||||
### Lighttpd example config
|
||||
|
||||
With Lighttpd just add this to your config and it should work in any VHost:
|
||||
|
||||
```lighttpd
|
||||
modules += "alias"
|
||||
|
||||
alias.url += (
|
||||
"/.well-known/acme-challenge/" => "/var/www/letsencrypt/"
|
||||
)
|
||||
```
|
||||
|
||||
314
letsencrypt.sh
314
letsencrypt.sh
@@ -35,6 +35,7 @@ check_dependencies() {
|
||||
_sed "" < /dev/null > /dev/null 2>&1 || _exiterr "This script requires sed with support for extended (modern) regular expressions."
|
||||
command -v grep > /dev/null 2>&1 || _exiterr "This script requires grep."
|
||||
_mktemp -u > /dev/null 2>&1 || _exiterr "This script requires mktemp."
|
||||
diff -u /dev/null /dev/null || _exiterr "This script requires diff."
|
||||
|
||||
# curl returns with an error code in some ancient versions so we have to catch that
|
||||
set +e
|
||||
@@ -46,14 +47,57 @@ check_dependencies() {
|
||||
fi
|
||||
}
|
||||
|
||||
store_configvars() {
|
||||
__KEY_ALGO="${KEY_ALGO}"
|
||||
__OCSP_MUST_STAPLE="${OCSP_MUST_STAPLE}"
|
||||
__PRIVATE_KEY_RENEW="${PRIVATE_KEY_RENEW}"
|
||||
__KEYSIZE="${KEYSIZE}"
|
||||
__CHALLENGETYPE="${CHALLENGETYPE}"
|
||||
__HOOK="${HOOK}"
|
||||
__WELLKNOWN="${WELLKNOWN}"
|
||||
__HOOK_CHAIN="${HOOK_CHAIN}"
|
||||
__OPENSSL_CNF="${OPENSSL_CNF}"
|
||||
__RENEW_DAYS="${RENEW_DAYS}"
|
||||
__IP_VERSION="${IP_VERSION}"
|
||||
}
|
||||
|
||||
reset_configvars() {
|
||||
KEY_ALGO="${__KEY_ALGO}"
|
||||
OCSP_MUST_STAPLE="${__OCSP_MUST_STAPLE}"
|
||||
PRIVATE_KEY_RENEW="${__PRIVATE_KEY_RENEW}"
|
||||
KEYSIZE="${__KEYSIZE}"
|
||||
CHALLENGETYPE="${__CHALLENGETYPE}"
|
||||
HOOK="${__HOOK}"
|
||||
WELLKNOWN="${__WELLKNOWN}"
|
||||
HOOK_CHAIN="${__HOOK_CHAIN}"
|
||||
OPENSSL_CNF="${__OPENSSL_CNF}"
|
||||
RENEW_DAYS="${__RENEW_DAYS}"
|
||||
IP_VERSION="${__IP_VERSION}"
|
||||
}
|
||||
|
||||
# verify configuration values
|
||||
verify_config() {
|
||||
[[ "${CHALLENGETYPE}" =~ (http-01|dns-01) ]] || _exiterr "Unknown challenge type ${CHALLENGETYPE}... can not continue."
|
||||
if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then
|
||||
_exiterr "Challenge type dns-01 needs a hook script for deployment... can not continue."
|
||||
fi
|
||||
if [[ "${CHALLENGETYPE}" = "http-01" && ! -d "${WELLKNOWN}" ]]; then
|
||||
_exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN} and set appropriate permissions."
|
||||
fi
|
||||
[[ "${KEY_ALGO}" =~ ^(rsa|prime256v1|secp384r1)$ ]] || _exiterr "Unknown public key algorithm ${KEY_ALGO}... can not continue."
|
||||
if [[ -n "${IP_VERSION}" ]]; then
|
||||
[[ "${IP_VERSION}" = "4" || "${IP_VERSION}" = "6" ]] || _exiterr "Unknown IP version ${IP_VERSION}... can not continue."
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup default config values, search for and load configuration files
|
||||
load_config() {
|
||||
# Check for config in various locations
|
||||
if [[ -z "${CONFIG:-}" ]]; then
|
||||
for check_config in "/etc/letsencrypt.sh" "/usr/local/etc/letsencrypt.sh" "${PWD}" "${SCRIPTDIR}"; do
|
||||
if [[ -e "${check_config}/config.sh" ]]; then
|
||||
if [[ -f "${check_config}/config" ]]; then
|
||||
BASEDIR="${check_config}"
|
||||
CONFIG="${check_config}/config.sh"
|
||||
CONFIG="${check_config}/config"
|
||||
break
|
||||
fi
|
||||
done
|
||||
@@ -61,14 +105,16 @@ load_config() {
|
||||
|
||||
# Default values
|
||||
CA="https://acme-v01.api.letsencrypt.org/directory"
|
||||
LICENSE="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
|
||||
LICENSE="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
|
||||
CERTDIR=
|
||||
ACCOUNTDIR=
|
||||
CHALLENGETYPE="http-01"
|
||||
CONFIG_D=
|
||||
DOMAINS_D=
|
||||
DOMAINS_TXT=
|
||||
HOOK=
|
||||
HOOK_CHAIN="no"
|
||||
RENEW_DAYS="30"
|
||||
ACCOUNT_KEY=
|
||||
ACCOUNT_KEY_JSON=
|
||||
KEYSIZE="4096"
|
||||
WELLKNOWN=
|
||||
PRIVATE_KEY_RENEW="yes"
|
||||
@@ -76,12 +122,14 @@ load_config() {
|
||||
OPENSSL_CNF="$(openssl version -d | cut -d\" -f2)/openssl.cnf"
|
||||
CONTACT_EMAIL=
|
||||
LOCKFILE=
|
||||
OCSP_MUST_STAPLE="no"
|
||||
IP_VERSION=
|
||||
|
||||
if [[ -z "${CONFIG:-}" ]]; then
|
||||
echo "#" >&2
|
||||
echo "# !! WARNING !! No main config file found, using default config!" >&2
|
||||
echo "#" >&2
|
||||
elif [[ -e "${CONFIG}" ]]; then
|
||||
elif [[ -f "${CONFIG}" ]]; then
|
||||
echo "# INFO: Using main config file ${CONFIG}"
|
||||
BASEDIR="$(dirname "${CONFIG}")"
|
||||
# shellcheck disable=SC1090
|
||||
@@ -115,20 +163,37 @@ load_config() {
|
||||
# Check BASEDIR and set default variables
|
||||
[[ -d "${BASEDIR}" ]] || _exiterr "BASEDIR does not exist: ${BASEDIR}"
|
||||
|
||||
[[ -z "${ACCOUNT_KEY}" ]] && ACCOUNT_KEY="${BASEDIR}/private_key.pem"
|
||||
[[ -z "${ACCOUNT_KEY_JSON}" ]] && ACCOUNT_KEY_JSON="${BASEDIR}/private_key.json"
|
||||
[[ -z "${WELLKNOWN}" ]] && WELLKNOWN="${BASEDIR}/.acme-challenges"
|
||||
CAHASH="$(echo "${CA}" | urlbase64)"
|
||||
[[ -z "${ACCOUNTDIR}" ]] && ACCOUNTDIR="${BASEDIR}/accounts"
|
||||
mkdir -p "${ACCOUNTDIR}/${CAHASH}"
|
||||
[[ -f "${ACCOUNTDIR}/${CAHASH}/config" ]] && . "${ACCOUNTDIR}/${CAHASH}/config"
|
||||
ACCOUNT_KEY="${ACCOUNTDIR}/${CAHASH}/account_key.pem"
|
||||
ACCOUNT_KEY_JSON="${ACCOUNTDIR}/${CAHASH}/registration_info.json"
|
||||
|
||||
if [[ -f "${BASEDIR}/private_key.pem" ]] && [[ ! -f "${ACCOUNT_KEY}" ]]; then
|
||||
echo "! Moving private_key.pem to ${ACCOUNT_KEY}"
|
||||
mv "${BASEDIR}/private_key.pem" "${ACCOUNT_KEY}"
|
||||
fi
|
||||
if [[ -f "${BASEDIR}/private_key.json" ]] && [[ ! -f "${ACCOUNT_KEY_JSON}" ]]; then
|
||||
echo "! Moving private_key.json to ${ACCOUNT_KEY_JSON}"
|
||||
mv "${BASEDIR}/private_key.json" "${ACCOUNT_KEY_JSON}"
|
||||
fi
|
||||
|
||||
[[ -z "${CERTDIR}" ]] && CERTDIR="${BASEDIR}/certs"
|
||||
[[ -z "${DOMAINS_TXT}" ]] && DOMAINS_TXT="${BASEDIR}/domains.txt"
|
||||
[[ -z "${WELLKNOWN}" ]] && WELLKNOWN="/var/www/letsencrypt"
|
||||
[[ -z "${LOCKFILE}" ]] && LOCKFILE="${BASEDIR}/lock"
|
||||
[[ -n "${PARAM_NO_LOCK:-}" ]] && LOCKFILE=""
|
||||
|
||||
[[ -n "${PARAM_HOOK:-}" ]] && HOOK="${PARAM_HOOK}"
|
||||
[[ -n "${PARAM_CERTDIR:-}" ]] && CERTDIR="${PARAM_CERTDIR}"
|
||||
[[ -n "${PARAM_CHALLENGETYPE:-}" ]] && CHALLENGETYPE="${PARAM_CHALLENGETYPE}"
|
||||
[[ -n "${PARAM_KEY_ALGO:-}" ]] && KEY_ALGO="${PARAM_KEY_ALGO}"
|
||||
[[ -n "${PARAM_OCSP_MUST_STAPLE:-}" ]] && OCSP_MUST_STAPLE="${PARAM_OCSP_MUST_STAPLE}"
|
||||
[[ -n "${PARAM_IP_VERSION:-}" ]] && IP_VERSION="${PARAM_IP_VERSION}"
|
||||
|
||||
[[ "${CHALLENGETYPE}" =~ (http-01|dns-01) ]] || _exiterr "Unknown challenge type ${CHALLENGETYPE}... can not continue."
|
||||
if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then
|
||||
_exiterr "Challenge type dns-01 needs a hook script for deployment... can not continue."
|
||||
fi
|
||||
[[ "${KEY_ALGO}" =~ ^(rsa|prime256v1|secp384r1)$ ]] || _exiterr "Unknown public key algorithm ${KEY_ALGO}... can not continue."
|
||||
verify_config
|
||||
store_configvars
|
||||
}
|
||||
|
||||
# Initialize system
|
||||
@@ -136,11 +201,13 @@ init_system() {
|
||||
load_config
|
||||
|
||||
# Lockfile handling (prevents concurrent access)
|
||||
LOCKDIR="$(dirname "${LOCKFILE}")"
|
||||
[[ -w "${LOCKDIR}" ]] || _exiterr "Directory ${LOCKDIR} for LOCKFILE ${LOCKFILE} is not writable, aborting."
|
||||
( set -C; date > "${LOCKFILE}" ) 2>/dev/null || _exiterr "Lock file '${LOCKFILE}' present, aborting."
|
||||
remove_lock() { rm -f "${LOCKFILE}"; }
|
||||
trap 'remove_lock' EXIT
|
||||
if [[ -n "${LOCKFILE}" ]]; then
|
||||
LOCKDIR="$(dirname "${LOCKFILE}")"
|
||||
[[ -w "${LOCKDIR}" ]] || _exiterr "Directory ${LOCKDIR} for LOCKFILE ${LOCKFILE} is not writable, aborting."
|
||||
( set -C; date > "${LOCKFILE}" ) 2>/dev/null || _exiterr "Lock file '${LOCKFILE}' present, aborting."
|
||||
remove_lock() { rm -f "${LOCKFILE}"; }
|
||||
trap 'remove_lock' EXIT
|
||||
fi
|
||||
|
||||
# Get CA URLs
|
||||
CA_DIRECTORY="$(http_request get "${CA}")"
|
||||
@@ -152,7 +219,7 @@ init_system() {
|
||||
_exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA points to the directory entrypoint."
|
||||
|
||||
# Export some environment variables to be used in hook script
|
||||
export WELLKNOWN BASEDIR CONFIG
|
||||
export WELLKNOWN BASEDIR CERTDIR CONFIG
|
||||
|
||||
# Checking for private key ...
|
||||
register_new_key="no"
|
||||
@@ -182,16 +249,21 @@ init_system() {
|
||||
echo "+ Registering account key with letsencrypt..."
|
||||
[[ ! -z "${CA_NEW_REG}" ]] || _exiterr "Certificate authority doesn't allow registrations."
|
||||
# If an email for the contact has been provided then adding it to the registration request
|
||||
FAILED=false
|
||||
if [[ -n "${CONTACT_EMAIL}" ]]; then
|
||||
signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"], "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}"
|
||||
(signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"], "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true
|
||||
else
|
||||
signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}"
|
||||
(signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true
|
||||
fi
|
||||
if [[ "${FAILED}" = "true" ]]; then
|
||||
echo
|
||||
echo
|
||||
echo "Error registering account key. See message above for more information."
|
||||
rm "${ACCOUNT_KEY}" "${ACCOUNT_KEY_JSON}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${CHALLENGETYPE}" = "http-01" && ! -d "${WELLKNOWN}" ]]; then
|
||||
_exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN} and set appropriate permissions."
|
||||
fi
|
||||
}
|
||||
|
||||
# Different sed version for different os types...
|
||||
@@ -254,15 +326,19 @@ _openssl() {
|
||||
http_request() {
|
||||
tempcont="$(_mktemp)"
|
||||
|
||||
if [[ -n "${IP_VERSION:-}" ]]; then
|
||||
ip_version="-${IP_VERSION}"
|
||||
fi
|
||||
|
||||
set +e
|
||||
if [[ "${1}" = "head" ]]; then
|
||||
statuscode="$(curl -s -w "%{http_code}" -o "${tempcont}" "${2}" -I)"
|
||||
statuscode="$(curl ${ip_version:-} -s -w "%{http_code}" -o "${tempcont}" "${2}" -I)"
|
||||
curlret="${?}"
|
||||
elif [[ "${1}" = "get" ]]; then
|
||||
statuscode="$(curl -s -w "%{http_code}" -o "${tempcont}" "${2}")"
|
||||
statuscode="$(curl ${ip_version:-} -s -w "%{http_code}" -o "${tempcont}" "${2}")"
|
||||
curlret="${?}"
|
||||
elif [[ "${1}" = "post" ]]; then
|
||||
statuscode="$(curl -s -w "%{http_code}" -o "${tempcont}" "${2}" -d "${3}")"
|
||||
statuscode="$(curl ${ip_version:-} -s -w "%{http_code}" -o "${tempcont}" "${2}" -d "${3}")"
|
||||
curlret="${?}"
|
||||
else
|
||||
set -e
|
||||
@@ -271,7 +347,7 @@ http_request() {
|
||||
set -e
|
||||
|
||||
if [[ ! "${curlret}" = "0" ]]; then
|
||||
_exiterr "Problem connecting to server (curl returned with ${curlret})"
|
||||
_exiterr "Problem connecting to server (${1} for ${2}; curl returned with ${curlret})"
|
||||
fi
|
||||
|
||||
if [[ ! "${statuscode:0:1}" = "2" ]]; then
|
||||
@@ -279,6 +355,8 @@ http_request() {
|
||||
echo >&2
|
||||
echo "Details:" >&2
|
||||
cat "${tempcont}" >&2
|
||||
echo >&2
|
||||
echo >&2
|
||||
rm -f "${tempcont}"
|
||||
|
||||
# Wait for hook script to clean the challenge if used
|
||||
@@ -503,19 +581,19 @@ sign_domain() {
|
||||
fi
|
||||
|
||||
# If there is no existing certificate directory => make it
|
||||
if [[ ! -e "${BASEDIR}/certs/${domain}" ]]; then
|
||||
echo " + Creating new directory ${BASEDIR}/certs/${domain} ..."
|
||||
mkdir -p "${BASEDIR}/certs/${domain}"
|
||||
if [[ ! -e "${CERTDIR}/${domain}" ]]; then
|
||||
echo " + Creating new directory ${CERTDIR}/${domain} ..."
|
||||
mkdir -p "${CERTDIR}/${domain}" || _exiterr "Unable to create directory ${CERTDIR}/${domain}"
|
||||
fi
|
||||
|
||||
privkey="privkey.pem"
|
||||
# generate a new private key if we need or want one
|
||||
if [[ ! -r "${BASEDIR}/certs/${domain}/privkey.pem" ]] || [[ "${PRIVATE_KEY_RENEW}" = "yes" ]]; then
|
||||
if [[ ! -r "${CERTDIR}/${domain}/privkey.pem" ]] || [[ "${PRIVATE_KEY_RENEW}" = "yes" ]]; then
|
||||
echo " + Generating private key..."
|
||||
privkey="privkey-${timestamp}.pem"
|
||||
case "${KEY_ALGO}" in
|
||||
rsa) _openssl genrsa -out "${BASEDIR}/certs/${domain}/privkey-${timestamp}.pem" "${KEYSIZE}";;
|
||||
prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" -out "${BASEDIR}/certs/${domain}/privkey-${timestamp}.pem";;
|
||||
rsa) _openssl genrsa -out "${CERTDIR}/${domain}/privkey-${timestamp}.pem" "${KEYSIZE}";;
|
||||
prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" -out "${CERTDIR}/${domain}/privkey-${timestamp}.pem";;
|
||||
esac
|
||||
fi
|
||||
|
||||
@@ -530,33 +608,36 @@ sign_domain() {
|
||||
tmp_openssl_cnf="$(_mktemp)"
|
||||
cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}"
|
||||
printf "[SAN]\nsubjectAltName=%s" "${SAN}" >> "${tmp_openssl_cnf}"
|
||||
openssl req -new -sha256 -key "${BASEDIR}/certs/${domain}/${privkey}" -out "${BASEDIR}/certs/${domain}/cert-${timestamp}.csr" -subj "/CN=${domain}/" -reqexts SAN -config "${tmp_openssl_cnf}"
|
||||
if [ "${OCSP_MUST_STAPLE}" = "yes" ]; then
|
||||
printf "\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "${tmp_openssl_cnf}"
|
||||
fi
|
||||
openssl req -new -sha256 -key "${CERTDIR}/${domain}/${privkey}" -out "${CERTDIR}/${domain}/cert-${timestamp}.csr" -subj "/CN=${domain}/" -reqexts SAN -config "${tmp_openssl_cnf}"
|
||||
rm -f "${tmp_openssl_cnf}"
|
||||
|
||||
crt_path="${BASEDIR}/certs/${domain}/cert-${timestamp}.pem"
|
||||
crt_path="${CERTDIR}/${domain}/cert-${timestamp}.pem"
|
||||
# shellcheck disable=SC2086
|
||||
sign_csr "$(< "${BASEDIR}/certs/${domain}/cert-${timestamp}.csr" )" ${altnames} 3>"${crt_path}"
|
||||
sign_csr "$(< "${CERTDIR}/${domain}/cert-${timestamp}.csr" )" ${altnames} 3>"${crt_path}"
|
||||
|
||||
# Create fullchain.pem
|
||||
echo " + Creating fullchain.pem..."
|
||||
cat "${crt_path}" > "${BASEDIR}/certs/${domain}/fullchain-${timestamp}.pem"
|
||||
http_request get "$(openssl x509 -in "${BASEDIR}/certs/${domain}/cert-${timestamp}.pem" -noout -text | grep 'CA Issuers - URI:' | cut -d':' -f2-)" > "${BASEDIR}/certs/${domain}/chain-${timestamp}.pem"
|
||||
if ! grep -q "BEGIN CERTIFICATE" "${BASEDIR}/certs/${domain}/chain-${timestamp}.pem"; then
|
||||
openssl x509 -in "${BASEDIR}/certs/${domain}/chain-${timestamp}.pem" -inform DER -out "${BASEDIR}/certs/${domain}/chain-${timestamp}.pem" -outform PEM
|
||||
cat "${crt_path}" > "${CERTDIR}/${domain}/fullchain-${timestamp}.pem"
|
||||
http_request get "$(openssl x509 -in "${CERTDIR}/${domain}/cert-${timestamp}.pem" -noout -text | grep 'CA Issuers - URI:' | cut -d':' -f2-)" > "${CERTDIR}/${domain}/chain-${timestamp}.pem"
|
||||
if ! grep -q "BEGIN CERTIFICATE" "${CERTDIR}/${domain}/chain-${timestamp}.pem"; then
|
||||
openssl x509 -in "${CERTDIR}/${domain}/chain-${timestamp}.pem" -inform DER -out "${CERTDIR}/${domain}/chain-${timestamp}.pem" -outform PEM
|
||||
fi
|
||||
cat "${BASEDIR}/certs/${domain}/chain-${timestamp}.pem" >> "${BASEDIR}/certs/${domain}/fullchain-${timestamp}.pem"
|
||||
cat "${CERTDIR}/${domain}/chain-${timestamp}.pem" >> "${CERTDIR}/${domain}/fullchain-${timestamp}.pem"
|
||||
|
||||
# Update symlinks
|
||||
[[ "${privkey}" = "privkey.pem" ]] || ln -sf "privkey-${timestamp}.pem" "${BASEDIR}/certs/${domain}/privkey.pem"
|
||||
[[ "${privkey}" = "privkey.pem" ]] || ln -sf "privkey-${timestamp}.pem" "${CERTDIR}/${domain}/privkey.pem"
|
||||
|
||||
ln -sf "chain-${timestamp}.pem" "${BASEDIR}/certs/${domain}/chain.pem"
|
||||
ln -sf "fullchain-${timestamp}.pem" "${BASEDIR}/certs/${domain}/fullchain.pem"
|
||||
ln -sf "cert-${timestamp}.csr" "${BASEDIR}/certs/${domain}/cert.csr"
|
||||
ln -sf "cert-${timestamp}.pem" "${BASEDIR}/certs/${domain}/cert.pem"
|
||||
ln -sf "chain-${timestamp}.pem" "${CERTDIR}/${domain}/chain.pem"
|
||||
ln -sf "fullchain-${timestamp}.pem" "${CERTDIR}/${domain}/fullchain.pem"
|
||||
ln -sf "cert-${timestamp}.csr" "${CERTDIR}/${domain}/cert.csr"
|
||||
ln -sf "cert-${timestamp}.pem" "${CERTDIR}/${domain}/cert.pem"
|
||||
|
||||
# Wait for hook script to clean the challenge and to deploy cert if used
|
||||
export KEY_ALGO
|
||||
[[ -n "${HOOK}" ]] && "${HOOK}" "deploy_cert" "${domain}" "${BASEDIR}/certs/${domain}/privkey.pem" "${BASEDIR}/certs/${domain}/cert.pem" "${BASEDIR}/certs/${domain}/fullchain.pem" "${BASEDIR}/certs/${domain}/chain.pem" "${timestamp}"
|
||||
[[ -n "${HOOK}" ]] && "${HOOK}" "deploy_cert" "${domain}" "${CERTDIR}/${domain}/privkey.pem" "${CERTDIR}/${domain}/cert.pem" "${CERTDIR}/${domain}/fullchain.pem" "${CERTDIR}/${domain}/chain.pem" "${timestamp}"
|
||||
|
||||
unset challenge_token
|
||||
echo " + Done!"
|
||||
@@ -570,8 +651,10 @@ command_sign_domains() {
|
||||
if [[ -n "${PARAM_DOMAIN:-}" ]]; then
|
||||
DOMAINS_TXT="$(_mktemp)"
|
||||
printf -- "${PARAM_DOMAIN}" > "${DOMAINS_TXT}"
|
||||
elif [[ -e "${BASEDIR}/domains.txt" ]]; then
|
||||
DOMAINS_TXT="${BASEDIR}/domains.txt"
|
||||
elif [[ -e "${DOMAINS_TXT}" ]]; then
|
||||
if [[ ! -r "${DOMAINS_TXT}" ]]; then
|
||||
_exiterr "domains.txt found but not readable"
|
||||
fi
|
||||
else
|
||||
_exiterr "domains.txt not found and --domain not given"
|
||||
fi
|
||||
@@ -580,10 +663,11 @@ command_sign_domains() {
|
||||
ORIGIFS="${IFS}"
|
||||
IFS=$'\n'
|
||||
for line in $(<"${DOMAINS_TXT}" tr -d '\r' | tr '[:upper:]' '[:lower:]' | _sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e 's/[[:space:]]+/ /g' | (grep -vE '^(#|$)' || true)); do
|
||||
reset_configvars
|
||||
IFS="${ORIGIFS}"
|
||||
domain="$(printf '%s\n' "${line}" | cut -d' ' -f1)"
|
||||
morenames="$(printf '%s\n' "${line}" | cut -s -d' ' -f2-)"
|
||||
cert="${BASEDIR}/certs/${domain}/cert.pem"
|
||||
cert="${CERTDIR}/${domain}/cert.pem"
|
||||
|
||||
force_renew="${PARAM_FORCE:-no}"
|
||||
|
||||
@@ -593,6 +677,46 @@ command_sign_domains() {
|
||||
echo "Processing ${domain} with alternative names: ${morenames}"
|
||||
fi
|
||||
|
||||
# read cert config
|
||||
# for now this loads the certificate specific config in a subshell and parses a diff of set variables.
|
||||
# we could just source the config file but i decided to go this way to protect people from accidentally overriding
|
||||
# variables used internally by this script itself.
|
||||
if [[ -n "${DOMAINS_D}" ]]; then
|
||||
certconfig="${DOMAINS_D}/${domain}"
|
||||
else
|
||||
certconfig="${CERTDIR}/${domain}/config"
|
||||
fi
|
||||
|
||||
if [ -f "${certconfig}" ]; then
|
||||
echo " + Using certificate specific config file!"
|
||||
ORIGIFS="${IFS}"
|
||||
IFS=$'\n'
|
||||
for cfgline in $(
|
||||
beforevars="$(_mktemp)"
|
||||
aftervars="$(_mktemp)"
|
||||
set > "${beforevars}"
|
||||
# shellcheck disable=SC1090
|
||||
. "${certconfig}"
|
||||
set > "${aftervars}"
|
||||
diff -u "${beforevars}" "${aftervars}" | grep -E '^\+[^+]'
|
||||
rm "${beforevars}"
|
||||
rm "${aftervars}"
|
||||
); do
|
||||
config_var="$(echo "${cfgline:1}" | cut -d'=' -f1)"
|
||||
config_value="$(echo "${cfgline:1}" | cut -d'=' -f2-)"
|
||||
case "${config_var}" in
|
||||
KEY_ALGO|OCSP_MUST_STAPLE|PRIVATE_KEY_RENEW|KEYSIZE|CHALLENGETYPE|HOOK|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS)
|
||||
echo " + ${config_var} = ${config_value}"
|
||||
declare -- "${config_var}=${config_value}"
|
||||
;;
|
||||
_) ;;
|
||||
*) echo " ! Setting ${config_var} on a per-certificate base is not (yet) supported"
|
||||
esac
|
||||
done
|
||||
IFS="${ORIGIFS}"
|
||||
fi
|
||||
verify_config
|
||||
|
||||
if [[ -e "${cert}" ]]; then
|
||||
printf " + Checking domain name(s) of existing cert..."
|
||||
|
||||
@@ -623,7 +747,7 @@ command_sign_domains() {
|
||||
else
|
||||
# Certificate-Names unchanged and cert is still valid
|
||||
echo "Skipping renew!"
|
||||
[[ -n "${HOOK}" ]] && "${HOOK}" "unchanged_cert" "${domain}" "${BASEDIR}/certs/${domain}/privkey.pem" "${BASEDIR}/certs/${domain}/cert.pem" "${BASEDIR}/certs/${domain}/fullchain.pem" "${BASEDIR}/certs/${domain}/chain.pem"
|
||||
[[ -n "${HOOK}" ]] && "${HOOK}" "unchanged_cert" "${domain}" "${CERTDIR}/${domain}/privkey.pem" "${CERTDIR}/${domain}/cert.pem" "${CERTDIR}/${domain}/fullchain.pem" "${CERTDIR}/${domain}/chain.pem"
|
||||
continue
|
||||
fi
|
||||
else
|
||||
@@ -632,7 +756,12 @@ command_sign_domains() {
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
sign_domain ${line}
|
||||
if [[ "${PARAM_KEEP_GOING:-}" = "yes" ]]; then
|
||||
sign_domain ${line} &
|
||||
wait $! || true
|
||||
else
|
||||
sign_domain ${line}
|
||||
fi
|
||||
done
|
||||
|
||||
# remove temporary domains.txt file if used
|
||||
@@ -655,7 +784,33 @@ command_sign_csr() {
|
||||
_exiterr "Could not read certificate signing request ${csrfile}"
|
||||
fi
|
||||
|
||||
sign_csr "$(< "${csrfile}" )"
|
||||
# gen cert
|
||||
certfile="$(_mktemp)"
|
||||
sign_csr "$(< "${csrfile}" )" 3> "${certfile}"
|
||||
|
||||
# print cert
|
||||
echo "# CERT #" >&3
|
||||
cat "${certfile}" >&3
|
||||
echo >&3
|
||||
|
||||
# print chain
|
||||
if [ -n "${PARAM_FULL_CHAIN:-}" ]; then
|
||||
# get and convert ca cert
|
||||
chainfile="$(_mktemp)"
|
||||
http_request get "$(openssl x509 -in "${certfile}" -noout -text | grep 'CA Issuers - URI:' | cut -d':' -f2-)" > "${chainfile}"
|
||||
|
||||
if ! grep -q "BEGIN CERTIFICATE" "${chainfile}"; then
|
||||
openssl x509 -inform DER -in "${chainfile}" -outform PEM -out "${chainfile}"
|
||||
fi
|
||||
|
||||
echo "# CHAIN #" >&3
|
||||
cat "${chainfile}" >&3
|
||||
|
||||
rm "${chainfile}"
|
||||
fi
|
||||
|
||||
# cleanup
|
||||
rm "${certfile}"
|
||||
|
||||
exit 0
|
||||
}
|
||||
@@ -702,7 +857,7 @@ command_cleanup() {
|
||||
fi
|
||||
|
||||
# Loop over all certificate directories
|
||||
for certdir in "${BASEDIR}/certs/"*; do
|
||||
for certdir in "${CERTDIR}/"*; do
|
||||
# Skip if entry is not a folder
|
||||
[[ -d "${certdir}" ]] || continue
|
||||
|
||||
@@ -771,7 +926,7 @@ command_help() {
|
||||
command_env() {
|
||||
echo "# letsencrypt.sh configuration"
|
||||
load_config
|
||||
typeset -p CA LICENSE CHALLENGETYPE HOOK HOOK_CHAIN RENEW_DAYS ACCOUNT_KEY ACCOUNT_KEY_JSON KEYSIZE WELLKNOWN PRIVATE_KEY_RENEW OPENSSL_CNF CONTACT_EMAIL LOCKFILE
|
||||
typeset -p CA LICENSE CERTDIR CHALLENGETYPE DOMAINS_D DOMAINS_TXT HOOK HOOK_CHAIN RENEW_DAYS ACCOUNT_KEY ACCOUNT_KEY_JSON KEYSIZE WELLKNOWN PRIVATE_KEY_RENEW OPENSSL_CNF CONTACT_EMAIL LOCKFILE
|
||||
}
|
||||
|
||||
# Main method (parses script arguments and calls command_* methods)
|
||||
@@ -828,6 +983,24 @@ main() {
|
||||
set_command cleanup
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --full-chain (-fc)
|
||||
# PARAM_Description: Print full chain when using --signcsr
|
||||
--full-chain|-fc)
|
||||
PARAM_FULL_CHAIN="1"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --ipv4 (-4)
|
||||
# PARAM_Description: Resolve names to IPv4 addresses only
|
||||
--ipv4|-4)
|
||||
PARAM_IP_VERSION="4"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --ipv6 (-6)
|
||||
# PARAM_Description: Resolve names to IPv6 addresses only
|
||||
--ipv6|-6)
|
||||
PARAM_IP_VERSION="6"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --domain (-d) domain.tld
|
||||
# PARAM_Description: Use specified domain name(s) instead of domains.txt entry (one certificate!)
|
||||
--domain|-d)
|
||||
@@ -840,6 +1013,11 @@ main() {
|
||||
fi
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --keep-going (-g)
|
||||
# PARAM_Description: Keep going after encountering an error while creating/renewing multiple certificates in cron mode
|
||||
--keep-going|-g)
|
||||
PARAM_KEEP_GOING="yes"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --force (-x)
|
||||
# PARAM_Description: Force renew of certificate even if it is longer valid than value in RENEW_DAYS
|
||||
@@ -847,6 +1025,18 @@ main() {
|
||||
PARAM_FORCE="yes"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --no-lock (-n)
|
||||
# PARAM_Description: Don't use lockfile (potentially dangerous!)
|
||||
--no-lock|-n)
|
||||
PARAM_NO_LOCK="yes"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --ocsp
|
||||
# PARAM_Description: Sets option in CSR indicating OCSP stapling to be mandatory
|
||||
--ocsp)
|
||||
PARAM_OCSP_MUST_STAPLE="yes"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --privkey (-p) path/to/key.pem
|
||||
# PARAM_Description: Use specified private key instead of account key (useful for revocation)
|
||||
--privkey|-p)
|
||||
@@ -855,7 +1045,7 @@ main() {
|
||||
PARAM_ACCOUNT_KEY="${1}"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --config (-f) path/to/config.sh
|
||||
# PARAM_Usage: --config (-f) path/to/config
|
||||
# PARAM_Description: Use specified config file
|
||||
--config|-f)
|
||||
shift 1
|
||||
@@ -871,6 +1061,14 @@ main() {
|
||||
PARAM_HOOK="${1}"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --out (-o) certs/directory
|
||||
# PARAM_Description: Output certificates into the specified directory
|
||||
--out|-o)
|
||||
shift 1
|
||||
check_parameters "${1:-}"
|
||||
PARAM_CERTDIR="${1}"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --challenge (-t) http-01|dns-01
|
||||
# PARAM_Description: Which challenge should be used? Currently http-01 and dns-01 are supported
|
||||
--challenge|-t)
|
||||
|
||||
27
test.sh
27
test.sh
@@ -96,10 +96,10 @@ mkdir -p .acme-challenges/.well-known/acme-challenge
|
||||
) &
|
||||
|
||||
# Generate config and create empty domains.txt
|
||||
echo 'CA="https://testca.kurz.pw/directory"' > config.sh
|
||||
echo 'LICENSE="https://testca.kurz.pw/terms/v1"' >> config.sh
|
||||
echo 'WELLKNOWN=".acme-challenges/.well-known/acme-challenge"' >> config.sh
|
||||
echo 'RENEW_DAYS="14"' >> config.sh
|
||||
echo 'CA="https://testca.kurz.pw/directory"' > config
|
||||
echo 'LICENSE="https://testca.kurz.pw/terms/v1"' >> config
|
||||
echo 'WELLKNOWN=".acme-challenges/.well-known/acme-challenge"' >> config
|
||||
echo 'RENEW_DAYS="14"' >> config
|
||||
touch domains.txt
|
||||
|
||||
# Check if help command is working
|
||||
@@ -114,13 +114,13 @@ _CHECK_ERRORLOG
|
||||
_TEST "First run in cron mode, checking if private key is generated and registered"
|
||||
./letsencrypt.sh --cron > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Registering account key"
|
||||
_CHECK_FILE "private_key.pem"
|
||||
_CHECK_FILE accounts/*/account_key.pem
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Temporarily move config out of the way and try signing certificate by using temporary config location
|
||||
_TEST "Try signing using temporary config location and with domain as command line parameter"
|
||||
mv config.sh tmp_config.sh
|
||||
./letsencrypt.sh --cron --domain "${TMP_URL}" --domain "${TMP2_URL}" -f tmp_config.sh > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
mv config tmp_config
|
||||
./letsencrypt.sh --cron --domain "${TMP_URL}" --domain "${TMP2_URL}" -f tmp_config > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_NOT_LOG "Checking domain name(s) of existing cert"
|
||||
_CHECK_LOG "Generating private key"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP_URL}"
|
||||
@@ -129,11 +129,7 @@ _CHECK_LOG "Challenge is valid!"
|
||||
_CHECK_LOG "Creating fullchain.pem"
|
||||
_CHECK_LOG "Done!"
|
||||
_CHECK_ERRORLOG
|
||||
mv tmp_config.sh config.sh
|
||||
|
||||
# Move private key and add new location to config
|
||||
mv private_key.pem account_key.pem
|
||||
echo 'PRIVATE_KEY="./account_key.pem"' >> config.sh
|
||||
mv tmp_config config
|
||||
|
||||
# Add third domain to command-lime, should force renewal.
|
||||
_TEST "Run in cron mode again, this time adding third domain, should force renewal."
|
||||
@@ -161,7 +157,7 @@ _CHECK_LOG "Skipping renew"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Disable private key renew
|
||||
echo 'PRIVATE_KEY_RENEW="no"' >> config.sh
|
||||
echo 'PRIVATE_KEY_RENEW="no"' >> config
|
||||
|
||||
# Run in cron mode one last time, with domain in domains.txt and force-resign (should find certificate, resign anyway, and not generate private key)
|
||||
_TEST "Run in cron mode one last time, with domain in domains.txt and force-resign"
|
||||
@@ -184,12 +180,9 @@ _CHECK_LOG "BEGIN CERTIFICATE"
|
||||
_CHECK_LOG "END CERTIFICATE"
|
||||
_CHECK_NOT_LOG "ERROR"
|
||||
|
||||
# Delete account key (not needed anymore)
|
||||
rm account_key.pem
|
||||
|
||||
# Check if renewal works
|
||||
_TEST "Run in cron mode again, to check if renewal works"
|
||||
echo 'RENEW_DAYS="300"' >> config.sh
|
||||
echo 'RENEW_DAYS="300"' >> config
|
||||
./letsencrypt.sh --cron > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Checking domain name(s) of existing cert... unchanged."
|
||||
_CHECK_LOG "Renewing!"
|
||||
|
||||
Reference in New Issue
Block a user