mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-08-28 11:40:04 +00:00
Work on acme.sh hander
and dns providers
This commit is contained in:
@@ -1768,7 +1768,7 @@ _inithttp() {
|
|||||||
if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then
|
if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then
|
||||||
_ACME_CURL="$_ACME_CURL -L "
|
_ACME_CURL="$_ACME_CURL -L "
|
||||||
fi
|
fi
|
||||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
if [ "$DEBUG" ] && [ "$DEBUG" -ge 2 ]; then
|
||||||
_CURL_DUMP="$(_mktemp)"
|
_CURL_DUMP="$(_mktemp)"
|
||||||
_ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
|
_ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
|
||||||
fi
|
fi
|
||||||
@@ -1808,6 +1808,8 @@ _inithttp() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_HTTP_MAX_RETRY=8
|
||||||
|
|
||||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
||||||
_post() {
|
_post() {
|
||||||
body="$1"
|
body="$1"
|
||||||
@@ -1815,6 +1817,33 @@ _post() {
|
|||||||
needbase64="$3"
|
needbase64="$3"
|
||||||
httpmethod="$4"
|
httpmethod="$4"
|
||||||
_postContentType="$5"
|
_postContentType="$5"
|
||||||
|
_sleep_retry_sec=1
|
||||||
|
_http_retry_times=0
|
||||||
|
_hcode=0
|
||||||
|
while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
|
||||||
|
[ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
|
||||||
|
_lastHCode="$?"
|
||||||
|
_debug "Retrying post"
|
||||||
|
_post_impl "$body" "$_post_url" "$needbase64" "$httpmethod" "$_postContentType" "$_lastHCode"
|
||||||
|
_hcode="$?"
|
||||||
|
_debug _hcode "$_hcode"
|
||||||
|
if [ "$_hcode" = "0" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
_http_retry_times=$(_math $_http_retry_times + 1)
|
||||||
|
_sleep $_sleep_retry_sec
|
||||||
|
done
|
||||||
|
return $_hcode
|
||||||
|
}
|
||||||
|
|
||||||
|
# body url [needbase64] [POST|PUT|DELETE] [ContentType] [displayError]
|
||||||
|
_post_impl() {
|
||||||
|
body="$1"
|
||||||
|
_post_url="$2"
|
||||||
|
needbase64="$3"
|
||||||
|
httpmethod="$4"
|
||||||
|
_postContentType="$5"
|
||||||
|
displayError="$6"
|
||||||
|
|
||||||
if [ -z "$httpmethod" ]; then
|
if [ -z "$httpmethod" ]; then
|
||||||
httpmethod="POST"
|
httpmethod="POST"
|
||||||
@@ -1866,7 +1895,9 @@ _post() {
|
|||||||
fi
|
fi
|
||||||
_ret="$?"
|
_ret="$?"
|
||||||
if [ "$_ret" != "0" ]; then
|
if [ "$_ret" != "0" ]; then
|
||||||
|
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||||
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
|
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
|
||||||
|
fi
|
||||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||||
_err "Here is the curl dump log:"
|
_err "Here is the curl dump log:"
|
||||||
_err "$(cat "$_CURL_DUMP")"
|
_err "$(cat "$_CURL_DUMP")"
|
||||||
@@ -1922,8 +1953,10 @@ _post() {
|
|||||||
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
|
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
|
||||||
fi
|
fi
|
||||||
if [ "$_ret" != "0" ]; then
|
if [ "$_ret" != "0" ]; then
|
||||||
|
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||||
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
|
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
_sed_i "s/^ *//g" "$HTTP_HEADER"
|
_sed_i "s/^ *//g" "$HTTP_HEADER"
|
||||||
else
|
else
|
||||||
_ret="$?"
|
_ret="$?"
|
||||||
@@ -1936,13 +1969,38 @@ _post() {
|
|||||||
|
|
||||||
# url getheader timeout
|
# url getheader timeout
|
||||||
_get() {
|
_get() {
|
||||||
|
url="$1"
|
||||||
|
onlyheader="$2"
|
||||||
|
t="$3"
|
||||||
|
_sleep_retry_sec=1
|
||||||
|
_http_retry_times=0
|
||||||
|
_hcode=0
|
||||||
|
while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
|
||||||
|
[ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
|
||||||
|
_lastHCode="$?"
|
||||||
|
_debug "Retrying GET"
|
||||||
|
_get_impl "$url" "$onlyheader" "$t" "$_lastHCode"
|
||||||
|
_hcode="$?"
|
||||||
|
_debug _hcode "$_hcode"
|
||||||
|
if [ "$_hcode" = "0" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
_http_retry_times=$(_math $_http_retry_times + 1)
|
||||||
|
_sleep $_sleep_retry_sec
|
||||||
|
done
|
||||||
|
return $_hcode
|
||||||
|
}
|
||||||
|
|
||||||
|
# url getheader timeout displayError
|
||||||
|
_get_impl() {
|
||||||
_debug GET
|
_debug GET
|
||||||
url="$1"
|
url="$1"
|
||||||
onlyheader="$2"
|
onlyheader="$2"
|
||||||
t="$3"
|
t="$3"
|
||||||
|
displayError="$4"
|
||||||
_debug url "$url"
|
_debug url "$url"
|
||||||
_debug "timeout=$t"
|
_debug "timeout=$t"
|
||||||
|
_debug "displayError" "$displayError"
|
||||||
_inithttp
|
_inithttp
|
||||||
|
|
||||||
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
|
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
|
||||||
@@ -1961,7 +2019,9 @@ _get() {
|
|||||||
fi
|
fi
|
||||||
ret=$?
|
ret=$?
|
||||||
if [ "$ret" != "0" ]; then
|
if [ "$ret" != "0" ]; then
|
||||||
|
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||||
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
|
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
|
||||||
|
fi
|
||||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||||
_err "Here is the curl dump log:"
|
_err "Here is the curl dump log:"
|
||||||
_err "$(cat "$_CURL_DUMP")"
|
_err "$(cat "$_CURL_DUMP")"
|
||||||
@@ -1987,8 +2047,10 @@ _get() {
|
|||||||
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
|
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
|
||||||
fi
|
fi
|
||||||
if [ "$ret" != "0" ]; then
|
if [ "$ret" != "0" ]; then
|
||||||
|
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||||
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
|
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
ret=$?
|
ret=$?
|
||||||
_err "Neither curl nor wget is found, can not do GET."
|
_err "Neither curl nor wget is found, can not do GET."
|
||||||
@@ -3925,7 +3987,7 @@ _ns_lookup_ali() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ns_is_available_dp() {
|
_ns_is_available_dp() {
|
||||||
if _get "https://dns.alidns.com" "" 1 >/dev/null 2>&1; then
|
if _get "https://doh.pub" "" 1 >/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
@@ -4145,6 +4207,10 @@ issue() {
|
|||||||
if [ -z "$_ACME_IS_RENEW" ]; then
|
if [ -z "$_ACME_IS_RENEW" ]; then
|
||||||
_initpath "$_main_domain" "$_key_length"
|
_initpath "$_main_domain" "$_key_length"
|
||||||
mkdir -p "$DOMAIN_PATH"
|
mkdir -p "$DOMAIN_PATH"
|
||||||
|
else
|
||||||
|
Le_OrderFinalize=""
|
||||||
|
Le_LinkOrder=""
|
||||||
|
Le_LinkCert=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
|
if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
|
||||||
@@ -4712,26 +4778,13 @@ $_authorizations_map"
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug "sleep 2 secs to verify"
|
|
||||||
sleep 2
|
|
||||||
_debug "checking"
|
|
||||||
|
|
||||||
_send_signed_request "$uri"
|
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "$d:Verify error:$response"
|
|
||||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
|
||||||
_clearup
|
|
||||||
_on_issue_err "$_post_hook" "$vlist"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 original "$response"
|
_debug2 original "$response"
|
||||||
|
|
||||||
response="$(echo "$response" | _normalizeJson)"
|
response="$(echo "$response" | _normalizeJson)"
|
||||||
_debug2 response "$response"
|
_debug2 response "$response"
|
||||||
|
|
||||||
status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
|
status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
|
||||||
|
_debug2 status "$status"
|
||||||
if _contains "$status" "invalid"; then
|
if _contains "$status" "invalid"; then
|
||||||
error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')"
|
error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')"
|
||||||
_debug2 error "$error"
|
_debug2 error "$error"
|
||||||
@@ -4763,9 +4816,9 @@ $_authorizations_map"
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$status" = "pending" ]; then
|
if [ "$status" = "pending" ]; then
|
||||||
_info "Pending"
|
_info "Pending, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
|
||||||
elif [ "$status" = "processing" ]; then
|
elif [ "$status" = "processing" ]; then
|
||||||
_info "Processing"
|
_info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
|
||||||
else
|
else
|
||||||
_err "$d:Verify error:$response"
|
_err "$d:Verify error:$response"
|
||||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||||
@@ -4773,7 +4826,19 @@ $_authorizations_map"
|
|||||||
_on_issue_err "$_post_hook" "$vlist"
|
_on_issue_err "$_post_hook" "$vlist"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
_debug "sleep 2 secs to verify again"
|
||||||
|
sleep 2
|
||||||
|
_debug "checking"
|
||||||
|
|
||||||
|
_send_signed_request "$uri"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "$d:Verify error:$response"
|
||||||
|
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||||
|
_clearup
|
||||||
|
_on_issue_err "$_post_hook" "$vlist"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
done
|
done
|
||||||
|
@@ -7,8 +7,8 @@
|
|||||||
"created_on",
|
"created_on",
|
||||||
"modified_on",
|
"modified_on",
|
||||||
"user_id",
|
"user_id",
|
||||||
"provider_key",
|
|
||||||
"name",
|
"name",
|
||||||
|
"acme_sh_name",
|
||||||
"meta"
|
"meta"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -28,16 +28,16 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 1
|
"minimum": 1
|
||||||
},
|
},
|
||||||
"provider_key": {
|
|
||||||
"type": "string",
|
|
||||||
"minLength": 1,
|
|
||||||
"maxLength": 100
|
|
||||||
},
|
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"maxLength": 100
|
"maxLength": 100
|
||||||
},
|
},
|
||||||
|
"acme_sh_name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 4,
|
||||||
|
"maxLength": 50
|
||||||
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
|
@@ -67,12 +67,11 @@
|
|||||||
"created_on": 1602593653,
|
"created_on": 1602593653,
|
||||||
"modified_on": 1602593653,
|
"modified_on": 1602593653,
|
||||||
"user_id": 1,
|
"user_id": 1,
|
||||||
"provider_key": "route53",
|
|
||||||
"name": "Route53",
|
"name": "Route53",
|
||||||
|
"acme_sh_name": "dns_aws",
|
||||||
"meta": {
|
"meta": {
|
||||||
"access_key": "abc123",
|
"AWS_ACCESS_KEY_ID": "abc123",
|
||||||
"access_secret": "def098",
|
"AWS_SECRET_ACCESS_KEY": "def098"
|
||||||
"zone_id": "ABC123"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@@ -36,12 +36,11 @@
|
|||||||
"created_on": 1602593653,
|
"created_on": 1602593653,
|
||||||
"modified_on": 1602593653,
|
"modified_on": 1602593653,
|
||||||
"user_id": 1,
|
"user_id": 1,
|
||||||
"provider_key": "route53",
|
|
||||||
"name": "Route53",
|
"name": "Route53",
|
||||||
|
"acme_sh_name": "dns_aws",
|
||||||
"meta": {
|
"meta": {
|
||||||
"access_key": "abc123",
|
"AWS_ACCESS_KEY_ID": "abc123",
|
||||||
"access_secret": "def098",
|
"AWS_SECRET_ACCESS_KEY": "def098"
|
||||||
"zone_id": "ABC123"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,12 +40,11 @@
|
|||||||
"created_on": 1602593653,
|
"created_on": 1602593653,
|
||||||
"modified_on": 1602593653,
|
"modified_on": 1602593653,
|
||||||
"user_id": 1,
|
"user_id": 1,
|
||||||
"provider_key": "route53",
|
|
||||||
"name": "Route53",
|
"name": "Route53",
|
||||||
|
"acme_sh_name": "dns_aws",
|
||||||
"meta": {
|
"meta": {
|
||||||
"access_key": "abc123",
|
"AWS_ACCESS_KEY_ID": "abc123",
|
||||||
"access_secret": "def098",
|
"AWS_SECRET_ACCESS_KEY": "def098"
|
||||||
"zone_id": "ABC123"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,12 +50,11 @@
|
|||||||
"created_on": 1602593653,
|
"created_on": 1602593653,
|
||||||
"modified_on": 1602593653,
|
"modified_on": 1602593653,
|
||||||
"user_id": 1,
|
"user_id": 1,
|
||||||
"provider_key": "route53",
|
|
||||||
"name": "Route53",
|
"name": "Route53",
|
||||||
|
"acme_sh_name": "dns_aws",
|
||||||
"meta": {
|
"meta": {
|
||||||
"access_key": "abc123",
|
"AWS_ACCESS_KEY_ID": "abc123",
|
||||||
"access_secret": "def098",
|
"AWS_SECRET_ACCESS_KEY": "def098"
|
||||||
"zone_id": "ABC123"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -70,8 +70,8 @@ CREATE TABLE IF NOT EXISTS `dns_provider`
|
|||||||
created_on INTEGER NOT NULL DEFAULT 0,
|
created_on INTEGER NOT NULL DEFAULT 0,
|
||||||
modified_on INTEGER NOT NULL DEFAULT 0,
|
modified_on INTEGER NOT NULL DEFAULT 0,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
provider_key TEXT NOT NULL,
|
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
acme_sh_name TEXT NOT NULL,
|
||||||
meta TEXT NOT NULL,
|
meta TEXT NOT NULL,
|
||||||
is_deleted INTEGER NOT NULL DEFAULT 0,
|
is_deleted INTEGER NOT NULL DEFAULT 0,
|
||||||
FOREIGN KEY (user_id) REFERENCES user (id)
|
FOREIGN KEY (user_id) REFERENCES user (id)
|
||||||
@@ -92,6 +92,7 @@ CREATE TABLE IF NOT EXISTS `certificate`
|
|||||||
status TEXT NOT NULL, -- ready,requesting,failed,provided
|
status TEXT NOT NULL, -- ready,requesting,failed,provided
|
||||||
error_message text NOT NULL DEFAULT "",
|
error_message text NOT NULL DEFAULT "",
|
||||||
meta TEXT NOT NULL,
|
meta TEXT NOT NULL,
|
||||||
|
is_ecc INTEGER NOT NULL DEFAULT 0,
|
||||||
is_deleted INTEGER NOT NULL DEFAULT 0,
|
is_deleted INTEGER NOT NULL DEFAULT 0,
|
||||||
FOREIGN KEY (user_id) REFERENCES user (id),
|
FOREIGN KEY (user_id) REFERENCES user (id),
|
||||||
FOREIGN KEY (certificate_authority_id) REFERENCES certificate_authority (id),
|
FOREIGN KEY (certificate_authority_id) REFERENCES certificate_authority (id),
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
package acme
|
package acme
|
||||||
|
|
||||||
|
// Some light reading:
|
||||||
|
// https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -10,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"npm/embed"
|
"npm/embed"
|
||||||
"npm/internal/config"
|
"npm/internal/config"
|
||||||
|
"npm/internal/entity/dnsprovider"
|
||||||
"npm/internal/logger"
|
"npm/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,7 +21,7 @@ var acmeShFile string
|
|||||||
|
|
||||||
// GetAcmeShVersion will return the acme.sh script version
|
// GetAcmeShVersion will return the acme.sh script version
|
||||||
func GetAcmeShVersion() string {
|
func GetAcmeShVersion() string {
|
||||||
if r, err := shExec("--version"); err == nil {
|
if r, err := shExec([]string{"--version"}, nil); err == nil {
|
||||||
// modify the output
|
// modify the output
|
||||||
r = strings.Trim(r, "\n")
|
r = strings.Trim(r, "\n")
|
||||||
v := strings.Split(r, "\n")
|
v := strings.Split(r, "\n")
|
||||||
@@ -27,7 +31,7 @@ func GetAcmeShVersion() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// shExec executes the acme.sh with arguments
|
// shExec executes the acme.sh with arguments
|
||||||
func shExec(args ...string) (string, error) {
|
func shExec(args []string, envs []string) (string, error) {
|
||||||
if _, err := os.Stat(acmeShFile); os.IsNotExist(err) {
|
if _, err := os.Stat(acmeShFile); os.IsNotExist(err) {
|
||||||
e := fmt.Errorf("%s does not exist", acmeShFile)
|
e := fmt.Errorf("%s does not exist", acmeShFile)
|
||||||
logger.Error("AcmeShError", e)
|
logger.Error("AcmeShError", e)
|
||||||
@@ -37,6 +41,8 @@ func shExec(args ...string) (string, error) {
|
|||||||
logger.Debug("CMD: %s %v", acmeShFile, args)
|
logger.Debug("CMD: %s %v", acmeShFile, args)
|
||||||
// nolint: gosec
|
// nolint: gosec
|
||||||
c := exec.Command(acmeShFile, args...)
|
c := exec.Command(acmeShFile, args...)
|
||||||
|
c.Env = envs
|
||||||
|
|
||||||
b, e := c.Output()
|
b, e := c.Output()
|
||||||
|
|
||||||
if e != nil {
|
if e != nil {
|
||||||
@@ -65,26 +71,22 @@ func WriteAcmeSh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequestCert does all the heavy lifting
|
// RequestCert does all the heavy lifting
|
||||||
func RequestCert(domains []string, method string) error {
|
func RequestCert(domains []string, method, caBundle, outputFullchainFile, outputKeyFile string, dnsProvider *dnsprovider.Model) error {
|
||||||
args := []string{"--issue"}
|
// TODO log file location configurable
|
||||||
|
args, err := buildCertRequestArgs(domains, method, caBundle, outputFullchainFile, outputKeyFile, dnsProvider)
|
||||||
webroot := "/home/wwwroot/example.com"
|
if err != nil {
|
||||||
|
return err
|
||||||
// Add domains to args
|
|
||||||
for _, domain := range domains {
|
|
||||||
args = append(args, "-d", domain)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch method {
|
envs := make([]string, 0)
|
||||||
// case "dns":
|
if dnsProvider != nil {
|
||||||
case "http":
|
envs, err = dnsProvider.GetAcmeShEnvVars()
|
||||||
args = append(args, "-w", webroot)
|
if err != nil {
|
||||||
|
return err
|
||||||
default:
|
}
|
||||||
return fmt.Errorf("RequestCert method not supported: %s", method)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := shExec(args...)
|
ret, err := shExec(args, envs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -93,3 +95,56 @@ func RequestCert(domains []string, method string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is split out into it's own function so it's testable
|
||||||
|
func buildCertRequestArgs(domains []string, method, caBundle, outputFullchainFile, outputKeyFile string, dnsProvider *dnsprovider.Model) ([]string, error) {
|
||||||
|
// TODO log file location configurable
|
||||||
|
args := []string{"--issue", "--log", "/data/logs/acme.sh.log"}
|
||||||
|
|
||||||
|
if caBundle != "" {
|
||||||
|
args = append(args, "--ca-bundle", caBundle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if outputFullchainFile != "" {
|
||||||
|
args = append(args, "--fullchain-file", outputFullchainFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if outputKeyFile != "" {
|
||||||
|
args = append(args, "--key-file", outputKeyFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO webroot location configurable
|
||||||
|
webroot := "/data/acme/wellknown"
|
||||||
|
|
||||||
|
methodArgs := make([]string, 0)
|
||||||
|
switch method {
|
||||||
|
case "dns":
|
||||||
|
if dnsProvider == nil {
|
||||||
|
return nil, ErrDNSNeedsDNSProvider
|
||||||
|
}
|
||||||
|
methodArgs = append(methodArgs, "--dns", dnsProvider.AcmeShName)
|
||||||
|
|
||||||
|
case "http":
|
||||||
|
if dnsProvider != nil {
|
||||||
|
return nil, ErrHTTPHasDNSProvider
|
||||||
|
}
|
||||||
|
methodArgs = append(methodArgs, "-w", webroot)
|
||||||
|
default:
|
||||||
|
return nil, ErrMethodNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
hasMethod := false
|
||||||
|
|
||||||
|
// Add domains to args
|
||||||
|
for _, domain := range domains {
|
||||||
|
args = append(args, "-d", domain)
|
||||||
|
// Method has to appear after first domain, but does not need to be repeated
|
||||||
|
// for other domains.
|
||||||
|
if !hasMethod {
|
||||||
|
args = append(args, methodArgs...)
|
||||||
|
hasMethod = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
190
backend/internal/acme/acmesh_test.go
Normal file
190
backend/internal/acme/acmesh_test.go
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
package acme
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"npm/internal/entity/dnsprovider"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tear up/down
|
||||||
|
/*
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
config.Init(&version, &commit, &sentryDSN)
|
||||||
|
code := m.Run()
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO configurable
|
||||||
|
const acmeLogFile = "/data/logs/acme.sh.log"
|
||||||
|
const acmeWebroot = "/data/acme/wellknown"
|
||||||
|
|
||||||
|
func TestBuildCertRequestArgs(t *testing.T) {
|
||||||
|
type want struct {
|
||||||
|
args []string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
domains []string
|
||||||
|
method string
|
||||||
|
caBundle string
|
||||||
|
outputFullchainFile string
|
||||||
|
outputKeyFile string
|
||||||
|
dnsProvider *dnsprovider.Model
|
||||||
|
want want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "http single domain",
|
||||||
|
domains: []string{"example.com"},
|
||||||
|
method: "http",
|
||||||
|
caBundle: "",
|
||||||
|
outputFullchainFile: "/data/acme/certs/a.crt",
|
||||||
|
outputKeyFile: "/data/acme/certs/example.com.key",
|
||||||
|
dnsProvider: nil,
|
||||||
|
want: want{
|
||||||
|
args: []string{
|
||||||
|
"--issue",
|
||||||
|
"--log",
|
||||||
|
acmeLogFile,
|
||||||
|
"--fullchain-file",
|
||||||
|
"/data/acme/certs/a.crt",
|
||||||
|
"--key-file",
|
||||||
|
"/data/acme/certs/example.com.key",
|
||||||
|
"-d",
|
||||||
|
"example.com",
|
||||||
|
"-w",
|
||||||
|
acmeWebroot,
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "http multiple domains",
|
||||||
|
domains: []string{"example.com", "example-two.com", "example-three.com"},
|
||||||
|
method: "http",
|
||||||
|
caBundle: "",
|
||||||
|
outputFullchainFile: "/data/acme/certs/a.crt",
|
||||||
|
outputKeyFile: "/data/acme/certs/example.com.key",
|
||||||
|
dnsProvider: nil,
|
||||||
|
want: want{
|
||||||
|
args: []string{
|
||||||
|
"--issue",
|
||||||
|
"--log",
|
||||||
|
acmeLogFile,
|
||||||
|
"--fullchain-file",
|
||||||
|
"/data/acme/certs/a.crt",
|
||||||
|
"--key-file",
|
||||||
|
"/data/acme/certs/example.com.key",
|
||||||
|
"-d",
|
||||||
|
"example.com",
|
||||||
|
"-w",
|
||||||
|
acmeWebroot,
|
||||||
|
"-d",
|
||||||
|
"example-two.com",
|
||||||
|
"-d",
|
||||||
|
"example-three.com",
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "http single domain with dns provider",
|
||||||
|
domains: []string{"example.com"},
|
||||||
|
method: "http",
|
||||||
|
caBundle: "",
|
||||||
|
outputFullchainFile: "/data/acme/certs/a.crt",
|
||||||
|
outputKeyFile: "/data/acme/certs/example.com.key",
|
||||||
|
dnsProvider: &dnsprovider.Model{
|
||||||
|
AcmeShName: "dns_cf",
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
args: nil,
|
||||||
|
err: ErrHTTPHasDNSProvider,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dns single domain",
|
||||||
|
domains: []string{"example.com"},
|
||||||
|
method: "dns",
|
||||||
|
caBundle: "",
|
||||||
|
outputFullchainFile: "/data/acme/certs/a.crt",
|
||||||
|
outputKeyFile: "/data/acme/certs/example.com.key",
|
||||||
|
dnsProvider: &dnsprovider.Model{
|
||||||
|
AcmeShName: "dns_cf",
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
args: []string{
|
||||||
|
"--issue",
|
||||||
|
"--log",
|
||||||
|
acmeLogFile,
|
||||||
|
"--fullchain-file",
|
||||||
|
"/data/acme/certs/a.crt",
|
||||||
|
"--key-file",
|
||||||
|
"/data/acme/certs/example.com.key",
|
||||||
|
"-d",
|
||||||
|
"example.com",
|
||||||
|
"--dns",
|
||||||
|
"dns_cf",
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dns multiple domains",
|
||||||
|
domains: []string{"example.com", "example-two.com", "example-three.com"},
|
||||||
|
method: "dns",
|
||||||
|
caBundle: "",
|
||||||
|
outputFullchainFile: "/data/acme/certs/a.crt",
|
||||||
|
outputKeyFile: "/data/acme/certs/example.com.key",
|
||||||
|
dnsProvider: &dnsprovider.Model{
|
||||||
|
AcmeShName: "dns_cf",
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
args: []string{
|
||||||
|
"--issue",
|
||||||
|
"--log",
|
||||||
|
acmeLogFile,
|
||||||
|
"--fullchain-file",
|
||||||
|
"/data/acme/certs/a.crt",
|
||||||
|
"--key-file",
|
||||||
|
"/data/acme/certs/example.com.key",
|
||||||
|
"-d",
|
||||||
|
"example.com",
|
||||||
|
"--dns",
|
||||||
|
"dns_cf",
|
||||||
|
"-d",
|
||||||
|
"example-two.com",
|
||||||
|
"-d",
|
||||||
|
"example-three.com",
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dns single domain no provider",
|
||||||
|
domains: []string{"example.com"},
|
||||||
|
method: "dns",
|
||||||
|
caBundle: "",
|
||||||
|
outputFullchainFile: "/data/acme/certs/a.crt",
|
||||||
|
outputKeyFile: "/data/acme/certs/example.com.key",
|
||||||
|
dnsProvider: nil,
|
||||||
|
want: want{
|
||||||
|
args: nil,
|
||||||
|
err: ErrDNSNeedsDNSProvider,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
args, err := buildCertRequestArgs(tt.domains, tt.method, tt.caBundle, tt.outputFullchainFile, tt.outputKeyFile, tt.dnsProvider)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want.args, args)
|
||||||
|
assert.Equal(t, tt.want.err, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
10
backend/internal/acme/errors.go
Normal file
10
backend/internal/acme/errors.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package acme
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// All errors relating to Acme.sh use
|
||||||
|
var (
|
||||||
|
ErrDNSNeedsDNSProvider = errors.New("RequestCert dns method requires a dns provider")
|
||||||
|
ErrHTTPHasDNSProvider = errors.New("RequestCert http method does not need a dns provider")
|
||||||
|
ErrMethodNotSupported = errors.New("RequestCert method not supported")
|
||||||
|
)
|
@@ -9,17 +9,17 @@ func CreateDNSProvider() string {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"provider_key",
|
|
||||||
"name",
|
"name",
|
||||||
|
"acme_sh_name",
|
||||||
"meta"
|
"meta"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"provider_key": %s,
|
|
||||||
"name": %s,
|
"name": %s,
|
||||||
|
"acme_sh_name": %s,
|
||||||
"meta": {
|
"meta": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, stringMinMax(2, 100), stringMinMax(1, 100))
|
`, stringMinMax(1, 100), stringMinMax(4, 50))
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,7 @@ func Create(certificate *Model) (int, error) {
|
|||||||
expires_on,
|
expires_on,
|
||||||
status,
|
status,
|
||||||
meta,
|
meta,
|
||||||
|
is_ecc,
|
||||||
is_deleted
|
is_deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:created_on,
|
:created_on,
|
||||||
@@ -54,6 +55,7 @@ func Create(certificate *Model) (int, error) {
|
|||||||
:expires_on,
|
:expires_on,
|
||||||
:status,
|
:status,
|
||||||
:meta,
|
:meta,
|
||||||
|
:is_ecc,
|
||||||
:is_deleted
|
:is_deleted
|
||||||
)`, certificate)
|
)`, certificate)
|
||||||
|
|
||||||
@@ -91,6 +93,7 @@ func Update(certificate *Model) error {
|
|||||||
expires_on = :expires_on,
|
expires_on = :expires_on,
|
||||||
status = :status,
|
status = :status,
|
||||||
meta = :meta,
|
meta = :meta,
|
||||||
|
is_ecc = :is_ecc,
|
||||||
is_deleted = :is_deleted
|
is_deleted = :is_deleted
|
||||||
WHERE id = :id`, certificate)
|
WHERE id = :id`, certificate)
|
||||||
|
|
||||||
|
@@ -50,6 +50,7 @@ type Model struct {
|
|||||||
Status string `json:"status" db:"status" filter:"status,string"`
|
Status string `json:"status" db:"status" filter:"status,string"`
|
||||||
ErrorMessage string `json:"error_message,omitempty" db:"error_message" filter:"error_message,string"`
|
ErrorMessage string `json:"error_message,omitempty" db:"error_message" filter:"error_message,string"`
|
||||||
Meta types.JSONB `json:"-" db:"meta"`
|
Meta types.JSONB `json:"-" db:"meta"`
|
||||||
|
IsECC int `json:"is_ecc" db:"is_ecc" filter:"is_ecc,integer"`
|
||||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||||
// Expansions:
|
// Expansions:
|
||||||
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"`
|
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"`
|
||||||
@@ -201,7 +202,8 @@ func (m *Model) Request() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = acme.RequestCert(domains, m.Type)
|
// TODO: fill in blank params
|
||||||
|
err = acme.RequestCert(domains, m.Type, "", "", "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Status = StatusFailed
|
m.Status = StatusFailed
|
||||||
m.ErrorMessage = err.Error()
|
m.ErrorMessage = err.Error()
|
||||||
|
@@ -33,16 +33,16 @@ func Create(provider *Model) (int, error) {
|
|||||||
created_on,
|
created_on,
|
||||||
modified_on,
|
modified_on,
|
||||||
user_id,
|
user_id,
|
||||||
provider_key,
|
|
||||||
name,
|
name,
|
||||||
|
acme_sh_name,
|
||||||
meta,
|
meta,
|
||||||
is_deleted
|
is_deleted
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:created_on,
|
:created_on,
|
||||||
:modified_on,
|
:modified_on,
|
||||||
:user_id,
|
:user_id,
|
||||||
:provider_key,
|
|
||||||
:name,
|
:name,
|
||||||
|
:acme_sh_name,
|
||||||
:meta,
|
:meta,
|
||||||
:is_deleted
|
:is_deleted
|
||||||
)`, provider)
|
)`, provider)
|
||||||
@@ -73,8 +73,8 @@ func Update(provider *Model) error {
|
|||||||
created_on = :created_on,
|
created_on = :created_on,
|
||||||
modified_on = :modified_on,
|
modified_on = :modified_on,
|
||||||
user_id = :user_id,
|
user_id = :user_id,
|
||||||
provider_key = :provider_key,
|
|
||||||
name = :name,
|
name = :name,
|
||||||
|
acme_sh_name = :acme_sh_name,
|
||||||
meta = :meta,
|
meta = :meta,
|
||||||
is_deleted = :is_deleted
|
is_deleted = :is_deleted
|
||||||
WHERE id = :id`, provider)
|
WHERE id = :id`, provider)
|
||||||
|
@@ -18,8 +18,8 @@ type Model struct {
|
|||||||
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
CreatedOn types.DBDate `json:"created_on" db:"created_on" filter:"created_on,integer"`
|
||||||
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
ModifiedOn types.DBDate `json:"modified_on" db:"modified_on" filter:"modified_on,integer"`
|
||||||
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
UserID int `json:"user_id" db:"user_id" filter:"user_id,integer"`
|
||||||
ProviderKey string `json:"provider_key" db:"provider_key" filter:"provider_key,string"`
|
|
||||||
Name string `json:"name" db:"name" filter:"name,string"`
|
Name string `json:"name" db:"name" filter:"name,string"`
|
||||||
|
AcmeShName string `json:"acme_sh_name" db:"acme_sh_name" filter:"acme_sh_name,string"`
|
||||||
Meta types.JSONB `json:"meta" db:"meta"`
|
Meta types.JSONB `json:"meta" db:"meta"`
|
||||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||||
}
|
}
|
||||||
@@ -71,3 +71,41 @@ func (m *Model) Delete() bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAcmeShEnvVars returns the env vars required for acme.sh dns cert requests
|
||||||
|
func (m *Model) GetAcmeShEnvVars() ([]string, error) {
|
||||||
|
envs := make([]string, 0)
|
||||||
|
switch m.AcmeShName {
|
||||||
|
|
||||||
|
// AWS
|
||||||
|
case "dns_aws":
|
||||||
|
envs = []string{
|
||||||
|
"AWS_ACCESS_KEY_ID=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"",
|
||||||
|
"AWS_SECRET_ACCESS_KEY=\"xxxxxxx\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cloudflare
|
||||||
|
case "dns_cf":
|
||||||
|
envs = []string{
|
||||||
|
"CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"",
|
||||||
|
"CF_Email=\"xxxx@sss.com\"",
|
||||||
|
"CF_Token=\"xxxx\"",
|
||||||
|
"CF_Account_ID=\"xxxx\"",
|
||||||
|
"CF_Zone_ID=\"xxxx\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
// DuckDNS
|
||||||
|
case "dns_duckdns":
|
||||||
|
envs = []string{
|
||||||
|
"DuckDNS_Token=\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Njalla
|
||||||
|
case "dns_njalla":
|
||||||
|
envs = []string{
|
||||||
|
"NJALLA_Token=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return envs, nil
|
||||||
|
}
|
||||||
|
70
backend/internal/entity/dnsprovider/model_test.go
Normal file
70
backend/internal/entity/dnsprovider/model_test.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package dnsprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModelGetAcmeShEnvVars(t *testing.T) {
|
||||||
|
type want struct {
|
||||||
|
envs []string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
dnsProvider Model
|
||||||
|
want want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "dns_aws",
|
||||||
|
dnsProvider: Model{
|
||||||
|
AcmeShName: "dns_aws",
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
envs: []string{
|
||||||
|
"AWS_ACCESS_KEY_ID=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"",
|
||||||
|
"AWS_SECRET_ACCESS_KEY=\"xxxxxxx\"",
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dns_cf",
|
||||||
|
dnsProvider: Model{
|
||||||
|
AcmeShName: "dns_cf",
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
envs: []string{
|
||||||
|
"CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"",
|
||||||
|
"CF_Email=\"xxxx@sss.com\"",
|
||||||
|
"CF_Token=\"xxxx\"",
|
||||||
|
"CF_Account_ID=\"xxxx\"",
|
||||||
|
"CF_Zone_ID=\"xxxx\"",
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dns_duckdns",
|
||||||
|
dnsProvider: Model{
|
||||||
|
AcmeShName: "dns_duckdns",
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
envs: []string{
|
||||||
|
"DuckDNS_Token=\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\"",
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
envs, err := tt.dnsProvider.GetAcmeShEnvVars()
|
||||||
|
assert.Equal(t, tt.want.envs, envs)
|
||||||
|
assert.Equal(t, tt.want.err, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -11,7 +11,8 @@ ENV GOPROXY=$GOPROXY \
|
|||||||
GOPRIVATE=$GOPRIVATE \
|
GOPRIVATE=$GOPRIVATE \
|
||||||
S6_LOGGING=0 \
|
S6_LOGGING=0 \
|
||||||
SUPPRESS_NO_CONFIG_WARNING=1 \
|
SUPPRESS_NO_CONFIG_WARNING=1 \
|
||||||
S6_FIX_ATTRS_HIDDEN=1
|
S6_FIX_ATTRS_HIDDEN=1 \
|
||||||
|
CERT_HOME=/data/acme/
|
||||||
|
|
||||||
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
|
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
|
||||||
|
|
||||||
|
@@ -23,6 +23,12 @@ services:
|
|||||||
- ./rootfs/var/www/html:/var/www/html
|
- ./rootfs/var/www/html:/var/www/html
|
||||||
- ../data:/data
|
- ../data:/data
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
aliases:
|
||||||
|
- website1.internal
|
||||||
|
- website2.internal
|
||||||
|
- website3.internal
|
||||||
|
|
||||||
stepca:
|
stepca:
|
||||||
image: nginxproxymanager/testca
|
image: nginxproxymanager/testca
|
||||||
|
@@ -18,7 +18,7 @@ mkdir -p /tmp/nginx/body \
|
|||||||
/var/lib/nginx/cache/public \
|
/var/lib/nginx/cache/public \
|
||||||
/var/lib/nginx/cache/private \
|
/var/lib/nginx/cache/private \
|
||||||
/var/cache/nginx/proxy_temp \
|
/var/cache/nginx/proxy_temp \
|
||||||
/data/acme
|
/data/acme/wellknown
|
||||||
|
|
||||||
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
|
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user