mirror of
https://github.com/m8tin/cis.git
synced 2025-12-06 07:48:26 +01:00
Solution for issuing and renewing certificates
This commit is contained in:
20
script/ssl/Dockerfile
Normal file
20
script/ssl/Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
###########################################################################
|
||||||
|
# Dockerfile to build a Container to update TLS Certificates automatically.
|
||||||
|
# Based on latest Ubuntu LTS
|
||||||
|
###########################################################################
|
||||||
|
# See https://hub.docker.com/_/ubuntu
|
||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
|
# Update repositories
|
||||||
|
RUN echo Version 20251030v1
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y apt-utils
|
||||||
|
|
||||||
|
#### BEGIN INSTALLATION ###################################################
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y cron curl dnsutils openssh-client
|
||||||
|
|
||||||
|
ADD acme.sh-3.1.1.tar.gz /tmp/acme.sh-setup/
|
||||||
|
COPY renewCerts.sh /renewCerts.sh
|
||||||
|
COPY start.sh /start.sh
|
||||||
|
|
||||||
|
# Run the command on container startup
|
||||||
|
CMD ["bash", "/start.sh"]
|
||||||
52
script/ssl/README.md
Normal file
52
script/ssl/README.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
Issuing SSL certificates
|
||||||
|
========================
|
||||||
|
There are two modes you can use the script `renewCerts.sh`.
|
||||||
|
|
||||||
|
1. dns
|
||||||
|
2. http
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Dns mode
|
||||||
|
--------
|
||||||
|
This mode is meant to use inside a docker container defined by the `Dockerfile`.
|
||||||
|
To configure, build and run the Container there is a file `docker-compose.yml.template`.
|
||||||
|
You can copy this file to `docker-compose.yml` and set the needed environment variables there.
|
||||||
|
|
||||||
|
- __AUTOACME_CONTAINER_HOSTNAME__
|
||||||
|
is used to enable the use of the host name within the container.
|
||||||
|
For example, for meaningful commit messages.
|
||||||
|
- __AUTOACME_GIT_REPOSITORY_VIA_SSH__ (optional)
|
||||||
|
is used to specify a Git repository to which the keys and certificates are transferred.
|
||||||
|
Therefore, SSH keys are generated on first launch (`docker compose up -d`) and the repository is cloned to `~/acmeResults/`.
|
||||||
|
The public key must be granted __write access__ to the repository
|
||||||
|
(e.g. as repository's deploy key).
|
||||||
|
The key can be viewed via `docker compose logs`.
|
||||||
|
- __AUTOACME_PATH_IN_GIT_REPOSITORY__ (optional)
|
||||||
|
specifies a path inside the repository were the certiticates are saved.
|
||||||
|
(e.g. AUTOACME_PATH_IN_GIT_REPOSITORY="/foo/bar/" => /root/autoACME/foo/bar/your-domain.net/fullchain.crt)
|
||||||
|
- __AUTOACME_DNS_PROVIDER__
|
||||||
|
sets the provider modul of acme.sh used to communicate with your domain provider.
|
||||||
|
(For further information see: https://github.com/acmesh-official/acme.sh/wiki/dnsapi)
|
||||||
|
|
||||||
|
You may have to set additional environment variables depending on your provider...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Manual docker commands
|
||||||
|
Instead of using `docker compose` you can build and run the container manually:
|
||||||
|
```
|
||||||
|
docker build -t cis/autoacme .
|
||||||
|
docker run --name autoacme -d cis/autoacme
|
||||||
|
```
|
||||||
|
This may be useful for investiagtion...
|
||||||
|
|
||||||
|
|
||||||
|
Http mode
|
||||||
|
---------
|
||||||
|
If you plan to use `renewCerts.sh` directly on your host computer this mode may fit your needs.
|
||||||
|
Here you need a `nginx` webserver. The domain have to point to it and following configuration is needed:
|
||||||
|
|
||||||
|
1. The content of folder `/var/www/letsencrypt/.well-known/acme-challenge/` has to be accessable via `http://your-domain.net/.well-known/acme-challenge/`
|
||||||
|
2. The certificates are stored to `/etc/nginx/ssl`. If this folder is a git repository then changes will be commited and pushed.
|
||||||
|
3. An entry into the crontab is needed to do automatic updates.
|
||||||
BIN
script/ssl/acme.sh-3.1.1.tar.gz
Normal file
BIN
script/ssl/acme.sh-3.1.1.tar.gz
Normal file
Binary file not shown.
18
script/ssl/docker-compose.yml.template
Normal file
18
script/ssl/docker-compose.yml.template
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
autoacme:
|
||||||
|
container_name: autoacme
|
||||||
|
image: cis/autoacme
|
||||||
|
build: .
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
environment:
|
||||||
|
AUTOACME_CONTAINER_HOSTNAME: ${HOSTNAME:?"HINT - You may run 'export HOSTNAME' first."}
|
||||||
|
AUTOACME_GIT_REPOSITORY_VIA_SSH: 'ssh://git@git.your-domain.net/your-repo.git'
|
||||||
|
# Optionally you can set a path inside the git repository, requires a repository.
|
||||||
|
AUTOACME_PATH_IN_GIT_REPOSITORY: 'hosts/all/etc/ssl/domains/'
|
||||||
|
# See: https://github.com/acmesh-official/acme.sh/wiki/dnsapi and search your provider like 'hetzner' e.g.
|
||||||
|
AUTOACME_DNS_PROVIDER: 'dns_hetzner'
|
||||||
|
HETZNER_Token: 'your-token'
|
||||||
|
|
||||||
550
script/ssl/renewCerts.sh
Executable file
550
script/ssl/renewCerts.sh
Executable file
@@ -0,0 +1,550 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# curl http://your.domain.net/.well-known/acme-challenge/test
|
||||||
|
# curl http://85.183.145.8/.well-known/acme-challenge/test
|
||||||
|
# /var/www/letsencrypt/.well-known/acme-challenge
|
||||||
|
|
||||||
|
function checkConfigViaHttp() {
|
||||||
|
local _DOMAIN _MODE _LOCAL_FOLDER
|
||||||
|
_MODE="${1:?"checkConfigViaHttp(): Missing first parameter MODE"}"
|
||||||
|
_DOMAIN="${2:?"checkConfigViaHttp(): Missing second parameter DOMAIN"}"
|
||||||
|
_LOCAL_FOLDER="/var/www/letsencrypt/.well-known/acme-challenge/"
|
||||||
|
readonly _DOMAIN _MODE _LOCAL_FOLDER
|
||||||
|
|
||||||
|
local _LOCAL_FILE _LOCAL_URL _PUBLIC_URL
|
||||||
|
_LOCAL_FILE="${_LOCAL_FOLDER}${_DOMAIN}"
|
||||||
|
_LOCAL_URL="http://localhost/.well-known/acme-challenge/${_DOMAIN}"
|
||||||
|
_PUBLIC_URL="http://${_DOMAIN}/.well-known/acme-challenge/${_DOMAIN}"
|
||||||
|
readonly _LOCAL_FILE _LOCAL_URL _PUBLIC_URL
|
||||||
|
|
||||||
|
# Skip check if mode is not http
|
||||||
|
[ "${_MODE}" != "http" ] \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
# Fail because wildcard certificate
|
||||||
|
[ "${_MODE}" == "http" ] \
|
||||||
|
&& isWildcardCertificate "${_DOMAIN}" \
|
||||||
|
&& echo "Wildcard certificates are not supported via HTTP." \
|
||||||
|
&& return 1
|
||||||
|
|
||||||
|
_CHECK="Available on $(hostname)@$(date)"
|
||||||
|
|
||||||
|
echo -n "Check domain '${_DOMAIN}'..." \
|
||||||
|
&& [ -d "${_LOCAL_FOLDER}" ] \
|
||||||
|
&& echo "${_CHECK}" > "${_LOCAL_FILE}" \
|
||||||
|
&& curl -4s "${_PUBLIC_URL}" | grep -q "${_CHECK}" \
|
||||||
|
&& echo " Done" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "FAILED: configuration of domain '${_DOMAIN}' is INCORRECT:"
|
||||||
|
echo -n " ${_PUBLIC_URL} was not found."
|
||||||
|
|
||||||
|
curl -4s "${_LOCAL_URL}" | grep -q "${_CHECK}" \
|
||||||
|
&& echo " (check DNS first)" \
|
||||||
|
|| echo " (check Webserver first)"
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActive() {
|
||||||
|
local _DOMAIN _MODE _RESULT_CERTS
|
||||||
|
_RESULT_CERTS="${RESULT_CERTS:?"isActive(): Missing global parameter RESULT_CERTS"}"
|
||||||
|
_MODE="${1:?"isActive(): Missing first parameter MODE"}"
|
||||||
|
_DOMAIN="${2:?"isActive(): Missing second parameter DOMAIN"}"
|
||||||
|
readonly _DOMAIN _MODE _RESULT_CERTS
|
||||||
|
|
||||||
|
# If mode is dns the domain is active always
|
||||||
|
[ "${_MODE}" == "dns" ] \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
nginx -T 2> /dev/null | grep -q "${_RESULT_CERTS}${_DOMAIN}/fullchain.crt" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "Domain '${_DOMAIN}' is inaktiv and therefore it will be skipped."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGitRepository() {
|
||||||
|
local _FOLDER
|
||||||
|
_FOLDER="${1:?"isGitRepository(): Missing first parameter FOLDER"}"
|
||||||
|
readonly _FOLDER
|
||||||
|
|
||||||
|
git -C "${_FOLDER}" ls-tree main &> /dev/null \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWildcardCertificate() {
|
||||||
|
local _DOMAIN
|
||||||
|
_DOMAIN="${1:?"isWildcardCertificate(): Missing first parameter DOMAIN"}"
|
||||||
|
readonly _DOMAIN
|
||||||
|
|
||||||
|
echo "${_DOMAIN}" | grep -q -F "_." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "${_DOMAIN}" | grep -q -F "*." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryGitPush() {
|
||||||
|
local _DOMAIN _NOW _RESULT_CERTS
|
||||||
|
_RESULT_CERTS="${RESULT_CERTS:?"tryGitPush(): Missing global parameter RESULT_CERTS"}"
|
||||||
|
_DOMAIN="${1:?"tryGitPush(): Missing first parameter DOMAIN"}"
|
||||||
|
_NOW="$(date +%Y%m%d_%H%M)"
|
||||||
|
readonly _DOMAIN _NOW _RESULT_CERTS
|
||||||
|
|
||||||
|
! isGitRepository "${_RESULT_CERTS}" \
|
||||||
|
&& echo \
|
||||||
|
&& echo "Folder '${_RESULT_CERTS}' is not part of a git repository, therefore nothing will be pushed." \
|
||||||
|
&& return 1
|
||||||
|
|
||||||
|
pushd "${_RESULT_CERTS}" > /dev/null
|
||||||
|
git pull > /dev/null
|
||||||
|
git add * > /dev/null
|
||||||
|
git commit -m "${_NOW} - Certificate for '${_DOMAIN}' was updated." \
|
||||||
|
&& git push > /dev/null \
|
||||||
|
&& popd > /dev/null \
|
||||||
|
&& echo "SUCCESS: certificate for '${_DOMAIN}' pushed." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
popd > /dev/null
|
||||||
|
echo "FAILED: unable to push certificate for '${_DOMAIN}'."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function own() {
|
||||||
|
! [ -d "${RESULT_CERTS:?"own(): Missing global parameter RESULT_CERTS"}" ] \
|
||||||
|
&& echo "Trying to derive domain names from subfolders of '${RESULT_CERTS}', but it is not a folder!" \
|
||||||
|
&& return 1
|
||||||
|
|
||||||
|
local _DOMAINS _MODE
|
||||||
|
_DOMAINS=("${RESULT_CERTS}"*)
|
||||||
|
_MODE="${1:?"own(): Missing first parameter MODE"}"
|
||||||
|
readonly _DOMAINS _MODE
|
||||||
|
|
||||||
|
local _domain
|
||||||
|
for _domain in "${_DOMAINS[@]}"; do
|
||||||
|
# just take names of folders
|
||||||
|
! [ -d "${_domain}" ] && continue
|
||||||
|
# cut pfad (like basename)
|
||||||
|
_domain="${_domain##*/}"
|
||||||
|
|
||||||
|
# folder default => skip
|
||||||
|
[ "${_domain}" == "default" ] && continue
|
||||||
|
|
||||||
|
case "${_MODE}" in
|
||||||
|
dns)
|
||||||
|
# dns supports all options
|
||||||
|
;;
|
||||||
|
http)
|
||||||
|
# http and wildcard certifikate => skip
|
||||||
|
isWildcardCertificate "${_domain}" && continue
|
||||||
|
# ssl on domain inaktiv => skip
|
||||||
|
! isActive "{_MODE}" "${_domain}" && continue
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown mode: ${_MODE}"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
single "${_MODE}" "${_domain}" "${2}"
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function continueIssuingCertificate() {
|
||||||
|
local _CERT_FILE_FULLCHAIN _DOMAIN
|
||||||
|
_CERT_FILE_FULLCHAIN="${1:?"continueIssuingCertificate(): Missing first parameter CERT_FILE_FULLCHAIN"}"
|
||||||
|
_DOMAIN="${2:?"continueIssuingCertificate(): Missing second parameter DOMAIN"}"
|
||||||
|
local _CERT_FILE_FULLCHAIN _DOMAIN
|
||||||
|
|
||||||
|
local _PRETTY_DOMAIN
|
||||||
|
_PRETTY_DOMAIN="$(printPrettyDomain ${_DOMAIN})"
|
||||||
|
readonly _PRETTY_DOMAIN
|
||||||
|
|
||||||
|
# forced => should be issued
|
||||||
|
[ "${3:-""}" == "--force" ] \
|
||||||
|
&& echo "Certificate for domain '${_PRETTY_DOMAIN}' is forced to be issued." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
# no cert => should be issued
|
||||||
|
! [ -f "${_CERT_FILE_FULLCHAIN}" ] \
|
||||||
|
&& echo "No certificate for domain '${_PRETTY_DOMAIN}', so it will be issued." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
local _ENDDATE _NOW _REMAINING_DAYS
|
||||||
|
_ENDDATE="$(openssl x509 -enddate -noout -in ${_CERT_FILE_FULLCHAIN} | cut -d= -f2)"
|
||||||
|
_ENDDATE="$(date --date="${_ENDDATE}" --utc +%s)"
|
||||||
|
|
||||||
|
_NOW="$(date --date now +%s)"
|
||||||
|
_REMAINING_DAYS="$(( (_ENDDATE - _NOW) / 86400 ))"
|
||||||
|
readonly _ENDDATE _NOW _REMAINING_DAYS
|
||||||
|
|
||||||
|
# less than 30 days remaining => should be issued
|
||||||
|
[ "${_REMAINING_DAYS}" -le "30" ] \
|
||||||
|
&& echo "Certificate for domain '${_PRETTY_DOMAIN}' (${_REMAINING_DAYS} days remaining) will be issued." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "Certificate for domain '${_PRETTY_DOMAIN}' (${_REMAINING_DAYS} days remaining) will be skipped."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function printBaseDomain() {
|
||||||
|
local _DOMAIN
|
||||||
|
_DOMAIN="${1:?"printBaseDomain(): Missing first parameter DOMAIN"}"
|
||||||
|
readonly _DOMAIN
|
||||||
|
|
||||||
|
local _BASE_DOMAIN
|
||||||
|
# cut front '*.' or '_.'
|
||||||
|
_BASE_DOMAIN="${_DOMAIN#\*.}"
|
||||||
|
_BASE_DOMAIN="${_BASE_DOMAIN#_.}"
|
||||||
|
readonly _BASE_DOMAIN
|
||||||
|
|
||||||
|
echo "${_BASE_DOMAIN}" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPrettyDomain() {
|
||||||
|
local _BASE_DOMAIN _DOMAIN
|
||||||
|
_DOMAIN="${1:?"printPrettyDomain(): Missing first parameter DOMAIN"}"
|
||||||
|
_BASE_DOMAIN="$(printBaseDomain ${_DOMAIN})"
|
||||||
|
readonly _BASE_DOMAIN _DOMAIN
|
||||||
|
|
||||||
|
isWildcardCertificate "${_DOMAIN}" \
|
||||||
|
&& echo "*.${_BASE_DOMAIN}" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "${_DOMAIN}" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function printFullDomainFolder() {
|
||||||
|
local _BASE_DOMAIN _DOMAIN _RESULT_CERTS
|
||||||
|
_RESULT_CERTS="${RESULT_CERTS:?"printFullDomainFolder(): Missing global parameter RESULT_CERTS"}"
|
||||||
|
_DOMAIN="${1:?"printFullDomainFolder(): Missing first parameter DOMAIN"}"
|
||||||
|
_BASE_DOMAIN="$(printBaseDomain ${_DOMAIN})"
|
||||||
|
readonly _BASE_DOMAIN _DOMAIN _RESULT_CERTS
|
||||||
|
|
||||||
|
isWildcardCertificate "${_DOMAIN}" \
|
||||||
|
&& echo "${_RESULT_CERTS}_.${_BASE_DOMAIN}/" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "${_RESULT_CERTS}${_DOMAIN}/" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareFullDomainFolder() {
|
||||||
|
local _DOMAIN _DOMAIN_FOLDER
|
||||||
|
_DOMAIN="${1:?"prepareFullDomainFolder(): Missing first parameter DOMAIN"}"
|
||||||
|
_DOMAIN_FOLDER="$(printFullDomainFolder "${_DOMAIN}")"
|
||||||
|
readonly _DOMAIN _DOMAIN_FOLDER
|
||||||
|
|
||||||
|
[ -d "${_DOMAIN_FOLDER}" ] \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
# create folder for results
|
||||||
|
echo -n "Creating folder '${_DOMAIN_FOLDER}'... " \
|
||||||
|
&& mkdir -p "${_DOMAIN_FOLDER}" \
|
||||||
|
&& echo "Done"
|
||||||
|
|
||||||
|
[ -d "${_DOMAIN_FOLDER}" ] \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareAndCheckAliasDomain() {
|
||||||
|
local _ALIAS_DOMAIN _DOMAIN
|
||||||
|
_DOMAIN="${1:?"prepareAndCheckAliasDomain(): Missing first parameter DOMAIN"}"
|
||||||
|
_ALIAS_DOMAIN="${2:?"prepareAndCheckAliasDomain(): Missing second parameter ALIAS_DOMAIN"}"
|
||||||
|
readonly _ALIAS_DOMAIN _DOMAIN
|
||||||
|
|
||||||
|
local _BASE_DOMAIN _CHALLENGE_ALIAS_DOMAIN_FILE _DOMAIN_FOLDER
|
||||||
|
_BASE_DOMAIN="$(printBaseDomain ${_DOMAIN})"
|
||||||
|
_DOMAIN_FOLDER="$(printFullDomainFolder ${_DOMAIN})"
|
||||||
|
_CHALLENGE_ALIAS_DOMAIN_FILE="${_DOMAIN_FOLDER}challenge-alias-domain"
|
||||||
|
readonly _BASE_DOMAIN _CHALLENGE_ALIAS_DOMAIN_FILE _DOMAIN_FOLDER
|
||||||
|
|
||||||
|
[ -d "${_DOMAIN_FOLDER}" ] \
|
||||||
|
&& [ "$(dig +short _acme-challenge.${_BASE_DOMAIN} CNAME)" == "_acme-challenge.${_ALIAS_DOMAIN}." ] \
|
||||||
|
&& echo "${_ALIAS_DOMAIN}" > "${_CHALLENGE_ALIAS_DOMAIN_FILE}" \
|
||||||
|
&& echo "SUCCESS: alias domain '${_ALIAS_DOMAIN}' is used when issuing certificates for '${_BASE_DOMAIN}' via DNS." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "FAILED: unable to use alias domain '${_ALIAS_DOMAIN}' to issue certificates for '${_BASE_DOMAIN}'."
|
||||||
|
echo " You have to configure your domain '${_BASE_DOMAIN}' first before you can use the alias domain as proof."
|
||||||
|
echo " So check if there is a CNAME entry '_acme-challenge.${_BASE_DOMAIN}' pointing to:"
|
||||||
|
echo " - '_acme-challenge.${_ALIAS_DOMAIN}'"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function single() {
|
||||||
|
local _ACME_FILE _DOMAIN _MODE _RESULT_CERTS
|
||||||
|
_RESULT_CERTS="${RESULT_CERTS:?"single(): Missing global parameter RESULT_CERTS"}"
|
||||||
|
_ACME_FILE="${ACME_FILE:?"single(): Missing global parameter ACME_FILE"}"
|
||||||
|
_MODE="${1:?"single(): Missing first parameter MODE"}"
|
||||||
|
_DOMAIN="${2:?"single(): Missing second parameter DOMAIN"}"
|
||||||
|
readonly _ACME_FILE _DOMAIN _MODE _RESULT_CERTS
|
||||||
|
|
||||||
|
local _BASE_DOMAIN _CHALLENGE_ALIAS_DOMAIN_FILE _DOMAIN_FOLDER _PRETTY_DOMAIN
|
||||||
|
_BASE_DOMAIN="$(printBaseDomain ${_DOMAIN})"
|
||||||
|
_DOMAIN_FOLDER="$(printFullDomainFolder ${_DOMAIN})"
|
||||||
|
_PRETTY_DOMAIN="$(printPrettyDomain ${_DOMAIN})"
|
||||||
|
_CHALLENGE_ALIAS_DOMAIN_FILE="${_DOMAIN_FOLDER}challenge-alias-domain"
|
||||||
|
readonly _BASE_DOMAIN _CHALLENGE_ALIAS_DOMAIN_FILE _DOMAIN_FOLDER _PRETTY_DOMAIN
|
||||||
|
|
||||||
|
! [ -f "${_ACME_FILE}" ] \
|
||||||
|
&& echo "Program 'acme.sh' seams not to be installed. Try run 'renewCerts.sh --setup'." \
|
||||||
|
&& return 1
|
||||||
|
|
||||||
|
# cancel on broken configuration
|
||||||
|
! checkConfigViaHttp "${_MODE}" "${_DOMAIN}" \
|
||||||
|
&& return 1
|
||||||
|
|
||||||
|
# cancel if folder is not prepared
|
||||||
|
! [ -d "${_DOMAIN_FOLDER}" ] \
|
||||||
|
&& echo "Certificate of domain '${_PRETTY_DOMAIN}' skipped because of missing folder:" \
|
||||||
|
&& echo " - '${_DOMAIN_FOLDER}'" \
|
||||||
|
&& return 1
|
||||||
|
|
||||||
|
# check enddate if third parameter is not --force
|
||||||
|
! continueIssuingCertificate "${_DOMAIN_FOLDER}fullchain.crt" "${_DOMAIN}" "${3:-""}" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
# backup the keys
|
||||||
|
[ -f "${_DOMAIN_FOLDER}fullchain.crt" ] \
|
||||||
|
&& cp "${_DOMAIN_FOLDER}fullchain.crt" "${_DOMAIN_FOLDER}fullchain.crt.bak"
|
||||||
|
[ -f "${_DOMAIN_FOLDER}private.key" ] \
|
||||||
|
&& cp --preserve=mode,ownership "${_DOMAIN_FOLDER}private.key" "${_DOMAIN_FOLDER}private.key.bak"
|
||||||
|
|
||||||
|
local _OPTIONS
|
||||||
|
# always --force because we check expiring on ourself
|
||||||
|
# _OPTIONS="--issue --force --test"
|
||||||
|
_OPTIONS="--issue --force"
|
||||||
|
if [ "${_MODE}" == "dns" ]; then
|
||||||
|
_OPTIONS="${_OPTIONS} --dns ${AUTOACME_DNS_PROVIDER:?"single(): Missing global parameter AUTOACME_DNS_PROVIDER"}"
|
||||||
|
[ -f "${_CHALLENGE_ALIAS_DOMAIN_FILE}" ] \
|
||||||
|
&& _OPTIONS="${_OPTIONS} --challenge-alias $(cat "${_CHALLENGE_ALIAS_DOMAIN_FILE}")"
|
||||||
|
isWildcardCertificate "${_DOMAIN}" \
|
||||||
|
&& _OPTIONS="${_OPTIONS} --domain ${_PRETTY_DOMAIN}"
|
||||||
|
elif [ "${_MODE}" == "http" ]; then
|
||||||
|
_OPTIONS="${_OPTIONS} --webroot /var/www/letsencrypt"
|
||||||
|
fi
|
||||||
|
readonly _OPTIONS
|
||||||
|
|
||||||
|
${_ACME_FILE} ${_OPTIONS} \
|
||||||
|
--domain "${_BASE_DOMAIN}" \
|
||||||
|
--server "letsencrypt" \
|
||||||
|
--keylength "ec-384" \
|
||||||
|
--fullchain-file "${_DOMAIN_FOLDER}fullchain.crt" \
|
||||||
|
--key-file "${_DOMAIN_FOLDER}private.key" \
|
||||||
|
&& openssl pkcs12 -export -in "${_DOMAIN_FOLDER}fullchain.crt" -inkey "${_DOMAIN_FOLDER}private.key" -out "${_DOMAIN_FOLDER}bundle.pkx" -passout pass: \
|
||||||
|
&& echo "Certificate of domain '${_PRETTY_DOMAIN}' was updated." \
|
||||||
|
&& tryGitPush "${_PRETTY_DOMAIN}" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "Certificate of domain '${_PRETTY_DOMAIN}' remains unchanged."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInstalled() {
|
||||||
|
local _ACME_FILE
|
||||||
|
_ACME_FILE="${ACME_FILE:?"isInstalled(): Missing global parameter ACME_FILE"}"
|
||||||
|
readonly _ACME_FILE
|
||||||
|
|
||||||
|
[ -f "${_ACME_FILE}" ] \
|
||||||
|
&& echo "Following version of acme.sh is installed:" \
|
||||||
|
&& echo "------------------------------------------" \
|
||||||
|
&& ${_ACME_FILE} --version | tail -n 1 \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTarArchive() {
|
||||||
|
local _ACME_SETUP_FILE _ACME_TAR_FILE
|
||||||
|
_ACME_SETUP_FILE="${ACME_SETUP_FILE:?"extractTarArchive(): Missing global parameter ACME_SETUP_FILE"}"
|
||||||
|
_ACME_TAR_FILE="${ACME_TAR_FILE:?"extractTarArchive(): Missing global parameter ACME_TAR_FILE"}"
|
||||||
|
readonly _ACME_SETUP_FILE _ACME_TAR_FILE
|
||||||
|
|
||||||
|
# extracted file already exists
|
||||||
|
[ -f "${_ACME_SETUP_FILE}" ] \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
[ -f "${_ACME_TAR_FILE}" ] \
|
||||||
|
&& mkdir -p "/tmp/acme.sh-setup/" \
|
||||||
|
&& tar -xzf "${_ACME_TAR_FILE}" -C "/tmp/acme.sh-setup/" \
|
||||||
|
&& [ -f "${_ACME_SETUP_FILE}" ] \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "Missing setup file '${_ACME_SETUP_FILE}' after trying to extract '${_ACME_TAR_FILE}'"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
local _ACME_SETUP_FILE
|
||||||
|
_ACME_SETUP_FILE="${ACME_SETUP_FILE:?"setup(): Missing global parameter ACME_SETUP_FILE"}"
|
||||||
|
readonly _ACME_SETUP_FILE
|
||||||
|
|
||||||
|
isInstalled \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
! [ $(id -u) == 0 ] \
|
||||||
|
&& echo "Setup requires execution as user 'root'." \
|
||||||
|
&& exit 1
|
||||||
|
|
||||||
|
! [ "$(echo $HOME)" == "/root" ] \
|
||||||
|
&& echo "The setup is executed with 'root' privileges but not in the 'root' user environment." \
|
||||||
|
&& exit 1
|
||||||
|
|
||||||
|
! extractTarArchive \
|
||||||
|
&& exit 1
|
||||||
|
|
||||||
|
echo "Starting install of acme.sh:"
|
||||||
|
echo "----------------------------"
|
||||||
|
pushd "${_ACME_SETUP_FILE%/*}" > /dev/null 2>&1 #Removes shortest matching pattern '/*' from the end
|
||||||
|
./acme.sh --install --no-cron --no-profile 2>&1
|
||||||
|
popd > /dev/null 2>&1
|
||||||
|
isInstalled \
|
||||||
|
&& echo \
|
||||||
|
&& echo 'Now this script can be added into cron-tab (crontab -e), like this e.g.:' \
|
||||||
|
&& echo \
|
||||||
|
&& echo '# Each day at 6:00am renew certificates:' \
|
||||||
|
&& echo '0 6 * * * /renewCerts.sh --http --own > /var/log/renewCerts.sh.log 2>&1' \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "Something went wrong during setup."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function usage() {
|
||||||
|
echo
|
||||||
|
echo 'Commands:'
|
||||||
|
echo ' --prepare DOMAIN --usingAlias ALIAS-DOMAIN : Prepares a domain to issue certificate using an alias domain in DNS mode.'
|
||||||
|
echo ' See: https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode'
|
||||||
|
echo ' --dns --single DOMAIN [--force] : Issues a certificate for the given domain using DNS mode.'
|
||||||
|
echo ' --http --single DOMAIN [--force] : Issues a certificate for the given domain using HTTP mode.'
|
||||||
|
echo
|
||||||
|
echo ' (--dns|--http) --own [--force] : Iterates all domains found in RESULT_CERTS.'
|
||||||
|
echo
|
||||||
|
echo 'Current environment:'
|
||||||
|
echo " Full name of this script: OWN_FULLNAME='${OWN_FULLNAME}'"
|
||||||
|
echo " Configuration:"
|
||||||
|
echo " Version of 'acme.sh' that will be installed: ACME_VERSION='${ACME_VERSION}'"
|
||||||
|
echo " Tar file containing the setup of 'acme.sh': ACME_TAR_FILE='${ACME_TAR_FILE}'"
|
||||||
|
echo " Setup file of 'acme.sh' after extraction: ACME_SETUP_FILE='${ACME_SETUP_FILE}'"
|
||||||
|
echo " Full name of the installed script 'acme.sh': ACME_FILE='${ACME_FILE}'"
|
||||||
|
echo " Output:"
|
||||||
|
echo " Path were the issued certificate are saved: RESULT_CERTS='${RESULT_CERTS}'"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "/autoACME.env" ] \
|
||||||
|
&& source "/autoACME.env" \
|
||||||
|
&& echo "[$(date)] Environment '/autoACME.env' loaded."
|
||||||
|
|
||||||
|
local ACME_FILE ACME_VERSION OWN_FULLNAME
|
||||||
|
OWN_FULLNAME="$(readlink -e ${0})"
|
||||||
|
ACME_FILE="/root/.acme.sh/acme.sh"
|
||||||
|
ACME_VERSION="acme.sh-3.1.1"
|
||||||
|
readonly ACME_FILE ACME_VERSION OWN_FULLNAME
|
||||||
|
|
||||||
|
local ACME_SETUP_FILE ACME_TAR_FILE RESULT_CERTS
|
||||||
|
ACME_SETUP_FILE="/tmp/acme.sh-setup/${ACME_VERSION}/acme.sh"
|
||||||
|
ACME_TAR_FILE="${OWN_FULLNAME%/*}/${ACME_VERSION}.tar.gz"
|
||||||
|
RESULT_CERTS="${AUTOACME_RESULT_CERTS%/}" #Removes shortest matching pattern '/' from the end
|
||||||
|
RESULT_CERTS="${RESULT_CERTS:-"/etc/nginx/ssl"}/"
|
||||||
|
readonly ACME_SETUP_FILE ACME_TAR_FILE RESULT_CERTS
|
||||||
|
|
||||||
|
local REPOSITORY_URL
|
||||||
|
isGitRepository "${RESULT_CERTS}" \
|
||||||
|
&& REPOSITORY_URL="$(git -C ${RESULT_CERTS} config --get remote.origin.url)"
|
||||||
|
readonly REPOSITORY_URL
|
||||||
|
|
||||||
|
case "${1}" in
|
||||||
|
--dns)
|
||||||
|
case "${2}" in
|
||||||
|
--single)
|
||||||
|
echo "[$(date)] Issue single certificate '${3}' via DNS:" \
|
||||||
|
&& prepareFullDomainFolder "${3}" \
|
||||||
|
&& single "dns" "${3}" "${4}" \
|
||||||
|
&& return 0
|
||||||
|
;;
|
||||||
|
--own)
|
||||||
|
echo "[$(date)] Renewing own certificates via DNS:"
|
||||||
|
own "dns" "${3}" \
|
||||||
|
&& echo "Finished successfully." \
|
||||||
|
&& return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
--http)
|
||||||
|
case "${2}" in
|
||||||
|
--single)
|
||||||
|
echo "[$(date)] Issue single certificate '${3}' via HTTP:" \
|
||||||
|
&& prepareFullDomainFolder "${3}" \
|
||||||
|
&& single "http" "${3}" "${4}" \
|
||||||
|
&& echo \
|
||||||
|
&& echo "Checking configuration of nginx and restart the webserver:" \
|
||||||
|
&& echo "==========================================================" \
|
||||||
|
&& nginx -t && systemctl reload nginx \
|
||||||
|
&& return 0
|
||||||
|
;;
|
||||||
|
--own)
|
||||||
|
echo "[$(date)] Renewing own certificates via HTTP:" \
|
||||||
|
&& own "http" "${3}" \
|
||||||
|
&& echo \
|
||||||
|
&& echo "Checking configuration of nginx and restart the webserver:" \
|
||||||
|
&& echo "==========================================================" \
|
||||||
|
&& nginx -t && systemctl reload nginx \
|
||||||
|
&& return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
--prepare)
|
||||||
|
case "${3}" in
|
||||||
|
--usingAlias)
|
||||||
|
echo "[$(date)] Prepare domain '${2}' using the alias-domain '${4}' via DNS:" \
|
||||||
|
&& prepareFullDomainFolder "${2}" \
|
||||||
|
&& prepareAndCheckAliasDomain "${2}" "${4}" \
|
||||||
|
&& return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command '${1}' '${2}' '${3}' '${4}'"
|
||||||
|
usage
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
--setup)
|
||||||
|
setup \
|
||||||
|
&& return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command '${1}' '${2}'"
|
||||||
|
usage
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@" && exit 0 || exit 1
|
||||||
161
script/ssl/start.sh
Executable file
161
script/ssl/start.sh
Executable file
@@ -0,0 +1,161 @@
|
|||||||
|
#/bin/bash
|
||||||
|
|
||||||
|
function createEnvironmentFile() {
|
||||||
|
local _ENVIRONMENT_FILE _REPOSITORY_FOLDER
|
||||||
|
_ENVIRONMENT_FILE="${ENVIRONMENT_FILE:?"createEnvironmentFile(): Missing global parameter ENVIRONMENT_FILE"}"
|
||||||
|
_REPOSITORY_FOLDER="${AUTOACME_REPOSITORY_FOLDER:?"createEnvironmentFile(): Missing global parameter AUTOACME_REPOSITORY_FOLDER"}"
|
||||||
|
readonly _ENVIRONMENT_FILE _REPOSITORY_FOLDER
|
||||||
|
|
||||||
|
# Save environment for cronjob
|
||||||
|
export -p | grep -v -E "(HOME|OLDPWD|PWD|SHLVL)" > "${_ENVIRONMENT_FILE}" \
|
||||||
|
&& echo "SUCCESS: there values were exported into file: '${_ENVIRONMENT_FILE}'" \
|
||||||
|
&& echo " - AUTOACME_CONTAINER_HOSTNAME: ${AUTOACME_CONTAINER_HOSTNAME}" \
|
||||||
|
&& echo " - AUTOACME_DNS_PROVIDER: ${AUTOACME_DNS_PROVIDER}" \
|
||||||
|
&& echo " - AUTOACME_GIT_REPOSITORY_VIA_SSH: ${AUTOACME_GIT_REPOSITORY_VIA_SSH}" \
|
||||||
|
&& echo " - AUTOACME_PATH_IN_GIT_REPOSITORY: ${AUTOACME_PATH_IN_GIT_REPOSITORY}"
|
||||||
|
|
||||||
|
[ "${AUTOACME_GIT_REPOSITORY_VIA_SSH}" == "" ] \
|
||||||
|
&& echo "declare -x AUTOACME_RESULT_CERTS=\"${AUTOACME_REPOSITORY_FOLDER#/}\"" >> "${_ENVIRONMENT_FILE}" \
|
||||||
|
&& echo "SUCCESS: added AUTOACME_RESULT_CERTS (without git) into file '${_ENVIRONMENT_FILE}'." \
|
||||||
|
&& echo " - AUTOACME_RESULT_CERTS: ${AUTOACME_REPOSITORY_FOLDER#/}" \
|
||||||
|
&& echo " (depends on if there is a git repo and the path for the certs in it)"
|
||||||
|
|
||||||
|
! [ "${AUTOACME_GIT_REPOSITORY_VIA_SSH}" == "" ] \
|
||||||
|
&& echo "declare -x AUTOACME_RESULT_CERTS=\"${AUTOACME_REPOSITORY_FOLDER}${AUTOACME_PATH_IN_GIT_REPOSITORY#/}\"" >> "${_ENVIRONMENT_FILE}" \
|
||||||
|
&& echo "SUCCESS: added AUTOACME_RESULT_CERTS (with git) into file '${_ENVIRONMENT_FILE}'." \
|
||||||
|
&& echo " - AUTOACME_RESULT_CERTS: ${AUTOACME_REPOSITORY_FOLDER}${AUTOACME_PATH_IN_GIT_REPOSITORY#/}" \
|
||||||
|
&& echo " (depends on if there is a git repo and the path for the certs in it)"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureThereAreSSHKeys() {
|
||||||
|
grep -F 'ssh' "/root/.ssh/id_ed25519.pub" &> /dev/null \
|
||||||
|
&& echo "SUCCESS: ssh-keys found, printing public key:" \
|
||||||
|
&& cat "/root/.ssh/id_ed25519.pub" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
# -t type of the key pair
|
||||||
|
# -f defines the filenames (we use the standard for the selected type here)
|
||||||
|
# -q quiet, no output or interaction
|
||||||
|
# -N "" means the private key will not be secured by a passphrase
|
||||||
|
# -C defines a comment
|
||||||
|
ssh-keygen \
|
||||||
|
-t ed25519 \
|
||||||
|
-f "/root/.ssh/id_ed25519" -q -N "" \
|
||||||
|
-C "$(date +%Y%m%d)-root@$(hostname -s)_onHost_${AUTOACME_CONTAINER_HOSTNAME%%.*}"
|
||||||
|
|
||||||
|
grep -F 'ssh' "/root/.ssh/id_ed25519.pub" &> /dev/null \
|
||||||
|
&& echo "SUCCESS: ssh-keys generated, printing public key:" \
|
||||||
|
&& cat "/root/.ssh/id_ed25519.pub" \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "FAILED: something went wrong during the generation of the ssh keys..."
|
||||||
|
echo " These keys are mandantory to access the git repository."
|
||||||
|
echo "You can try to restart this script."
|
||||||
|
echo
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureGitIsInstalled() {
|
||||||
|
git --version &> /dev/null \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo \
|
||||||
|
&& echo "Installing Git in 30s (ensure the SSH-Key is trusted and has write pemissions)... " \
|
||||||
|
&& sleep 30 \
|
||||||
|
&& DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get install git -y &> /dev/null \
|
||||||
|
&& echo "SUCCESS: $(git --version) is usable now." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "FAILED: something went wrong during the installation of Git..."
|
||||||
|
echo " Git is mandantory to push the keys into the specified repository."
|
||||||
|
echo "You can try to install git manually (apt install git)."
|
||||||
|
echo
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureRepositoryIsAvailableAndWritable() {
|
||||||
|
local _REPOSITORY_FOLDER
|
||||||
|
_REPOSITORY_FOLDER="${AUTOACME_REPOSITORY_FOLDER:?"ensureRepositoryIsAvailableAndWritable(): Missing global parameter AUTOACME_REPOSITORY_FOLDER"}"
|
||||||
|
readonly _REPOSITORY_FOLDER
|
||||||
|
|
||||||
|
[ -d "${_REPOSITORY_FOLDER}.git" ] \
|
||||||
|
&& echo \
|
||||||
|
&& git -C "${_REPOSITORY_FOLDER}" pull &> /dev/null \
|
||||||
|
&& git -C "${_REPOSITORY_FOLDER}" push --dry-run &> /dev/null \
|
||||||
|
&& echo "Writable repository found in folder '${_REPOSITORY_FOLDER}'." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
! [ -d "${_REPOSITORY_FOLDER}.git" ] \
|
||||||
|
&& echo \
|
||||||
|
&& echo "Cloning repository '${AUTOACME_GIT_REPOSITORY_VIA_SSH}'... " \
|
||||||
|
&& GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git clone "${AUTOACME_GIT_REPOSITORY_VIA_SSH}" "${_REPOSITORY_FOLDER}" &> /dev/null \
|
||||||
|
&& git -C "${_REPOSITORY_FOLDER}" config user.name "autoacme on ${AUTOACME_CONTAINER_HOSTNAME%%.*}" \
|
||||||
|
&& git -C "${_REPOSITORY_FOLDER}" config user.email "autoacme@${AUTOACME_CONTAINER_HOSTNAME%%.*}" \
|
||||||
|
&& git -C "${_REPOSITORY_FOLDER}" push --dry-run &> /dev/null \
|
||||||
|
&& echo "SUCCESS: repository cloned into folder '${_REPOSITORY_FOLDER}' and it is writable." \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "FAILED: something went wrong during cloning the repository to '${_REPOSITORY_FOLDER}' from:"
|
||||||
|
echo " - ${AUTOACME_GIT_REPOSITORY_VIA_SSH}"
|
||||||
|
echo
|
||||||
|
echo "1.) You can try to clone it manually into: git clone ${AUTOACME_GIT_REPOSITORY_VIA_SSH} '${_REPOSITORY_FOLDER}'"
|
||||||
|
echo "2.) Check if the repositoty is writable: git -C '${_REPOSITORY_FOLDER}' push --dry-run"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareThisRuntimeForUsingGitOrIgnore() {
|
||||||
|
createEnvironmentFile \
|
||||||
|
|| return 1
|
||||||
|
|
||||||
|
[ "${AUTOACME_GIT_REPOSITORY_VIA_SSH}" == "" ] \
|
||||||
|
&& echo "There is no git repository specified." \
|
||||||
|
&& echo "To distribute all keys and certificates via a git repository set environment variable:" \
|
||||||
|
&& echo " - AUTOACME_GIT_REPOSITORY_VIA_SSH" \
|
||||||
|
&& echo \
|
||||||
|
&& echo "FIRST AND ONLY WARNING: DO NOT USE ANY PUBLIC GIT SERVICE FOR THAT!" \
|
||||||
|
&& echo \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo \
|
||||||
|
&& ensureThereAreSSHKeys \
|
||||||
|
&& ensureGitIsInstalled \
|
||||||
|
&& ensureRepositoryIsAvailableAndWritable \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
echo "No job will run inside this container because there is an issue."
|
||||||
|
echo "The container keeps running for 10min, please check your setup..."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
AUTOACME_REPOSITORY_FOLDER="/root/acmeResults/"
|
||||||
|
ENVIRONMENT_FILE="/autoACME.env"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo '################################################################################'
|
||||||
|
echo "# Container started at $(date +%F_%T) on host ${AUTOACME_CONTAINER_HOSTNAME}"
|
||||||
|
echo '################################################################################'
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Log start and truncate file: /autoACME.log
|
||||||
|
echo > /autoACME.log
|
||||||
|
|
||||||
|
# Generate SSH keys and setup Git if a repository is specified, on failure keep the container running
|
||||||
|
prepareThisRuntimeForUsingGitOrIgnore \
|
||||||
|
|| timeout --preserve-status 10m tail -f /autoACME.log
|
||||||
|
|
||||||
|
# Ensure acme.sh ist installed
|
||||||
|
/renewCerts.sh --setup >> /autoACME.log \
|
||||||
|
&& echo >> /autoACME.log
|
||||||
|
|
||||||
|
echo "Register following entry to crontab:" >> /autoACME.log
|
||||||
|
echo "------------------------------------" >> /autoACME.log
|
||||||
|
_CRON_ENTRY="$((RANDOM % 59)) $((RANDOM % 5)) * * * /renewCerts.sh --dns --own >> /autoACME.log 2>&1"
|
||||||
|
echo "${_CRON_ENTRY}" | tee -a /autoACME.log | crontab -
|
||||||
|
|
||||||
|
cron && tail -n 100 -f /autoACME.log
|
||||||
Reference in New Issue
Block a user