HEX
Server: Apache/2
System: Linux nexus-01 4.18.0-553.146.1.el8_10.x86_64 #1 SMP Tue Jul 21 03:06:01 EDT 2026 x86_64
User: aglcoke (1118)
PHP: 8.2.32
Disabled: mail,exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: //usr/local/directadmin/scripts/letsencrypt.sh
#!/bin/bash

export EXEC_PROPAGATION_TIMEOUT=300
export EXEC_POLLING_INTERVAL=30

if [ "$(id -u)" != "0" ]; then
	echo "this script can only run as root";
	exit 1
fi

if [ ! -x /usr/local/bin/lego ]; then
	echo "missing 'lego' command, it can be installed using CustomBuild with command:"
	echo "	da build lego"
	exit 1
fi

update_conf_file() {
	local file=$1    # .../data/users/jonas/domains/example.com.conf
	local key=$2     # acme_enabled
	local val=$3     # yes

	if [ ! -f "${file}" ]; then
		echo "no such file: ${file}" 1>&2
		exit 1
	fi

	local key_escaped val_escaped
	key_escaped=$(sed 's/[.[\*^\/&$]/\\&/g' <<< "${key}")
	val_escaped=$(sed 's/[.[\*^\/&$]/\\&/g' <<< "${val}")

	if grep -q "^${key_escaped}=" "${file}"; then
		sed -i -e "s/^${key_escaped}=.*$/${key_escaped}=${val_escaped}/" "${file}"
	else
		echo "${key}=${val}" >> "${file}"
	fi
}

lego_key_type() {
	local key_type=$1

	case "${key_type}" in
		# Identity mappings
		ec256|ec384|rsa2048|rsa4096|rsa8192) echo "${key_type}";;
		# Old DA key-types
		prime256v1) echo "ec256";;
		secp384r1)  echo "ec384";;
		2048)       echo "rsa2048";;
		4096)       echo "rsa4096";;
		8192)       echo "rsa8192";;
		# Default
		*) echo "ec256" ;;
	esac
}

command_server_cert() {
	local domain_csv=$1
	local key_type=$2

	da config-set acme_server_cert_enabled "1"
	if [ -n "${domain_csv}" ]; then
		ADDITIONAL_DOMAINS="$(tr , '\n' <<< "${domain_csv}" | grep -Fvx "$(da config-get servername)" | paste -sd,)"
		da config-set acme_server_cert_additional_domains "${ADDITIONAL_DOMAINS}"
	fi
	if [ -n "${key_type}" ]; then 
		da config-set acme_server_cert_key_type "$(lego_key_type "${key_type}")"
	fi
	if [ -s "/usr/local/directadmin/conf/ca.dnsprovider" ]; then
		da config-set acme_server_cert_dns_provider_env_file "/usr/local/directadmin/conf/ca.dnsprovider"
	fi

	if ! da taskq --run 'action=ssl&value=server_acme&force=true'; then
		echo "Failed to issue new certificate"
		exit 1
	fi

	echo "Server certificate with domains ${domain_csv} has been created successfully"
	
	da config-set ssl 1

	if systemctl --quiet is-active directadmin.service; then
		systemctl restart directadmin.service
	fi
}

command_domain_cert() {
	local dns_name=$1
	local key_size=$2

	local domain
	if ! domain=$(find_domain "${dns_name}"); then
		echo "unable to find '${dns_name}' domain owner" 1>&2
		echo "make sure this DNS name is owned by some user" 1>&2
		exit 1
	fi

	local username
	username=$(sed -n -e 's/^'"${domain//./\\.}"':\s*\(.*\)/\1/p' /etc/virtual/domainowners)
	if [ -z "${username}" ]; then
		echo "unable to find '${domain}' owner" 1>&2
		exit 1
	fi

	# Enable ACME for the domain
	local domain_conf="/usr/local/directadmin/data/users/${username}/domains/${domain}.conf"

	# convert alias/pointer domain to main domain
	if [ ! -f "${domain_conf}" ]; then
		local f
		for f in "/usr/local/directadmin/data/users/${username}/domains/"*.pointers; do
			if [ -f "${f}" ] && grep -q "^${domain//./\\.}=" "${f}"; then
				domain_conf="${f%%.pointers}.conf"
				f="${f//*\/}"
				domain="${f%%.pointers}"
				break
			fi
		done
	fi

	update_conf_file "${domain_conf}" acme_enabled yes || exit 1

	if [ -n "${key_size}" ]; then
		update_conf_file "${domain_conf}" acme_key_type "$(lego_key_type "${key_size}")" || exit 1
	fi

	if ! da taskq --debug=1 --run "action=rewrite&value=letsencrypt&domain=${domain}"; then
		echo "failed issuing certificates" 1>&2
		exit 1
	fi
}

find_domain() {
	local record=$1        # long.name.example.com

	if [ -z "${record}" ]; then
		return 1
	fi

	local domains
	readarray -t domains < <(cut -d : -f 1 /etc/virtual/domainowners)

	while true; do
		local d
		for d in "${domains[@]}"; do
			if [ "${d}" = "${record}" ]; then
				echo "${record}"
				return
			fi
		done
		# remove single component and try again
		if [ "${record#*.}" = "${record}" ]; then
			return 1
		fi
		record=${record#*.}
	done
}

command_add_dns_challenge_record() {
	local key=${1%%.}                     # Strip '.' suffix
	local value=$2

	local domain
	if ! domain=$(find_domain "${key}"); then
		echo "refusing to create DNS challenge record '${key}', unable to find matching domain" 1>&2
		exit 1
	fi

	if [ "${domain}" = "${key}" ]; then
		# top level entries uses full domain with leading .
		key="${domain}."
	else
		# remove domain suffix
		key="${key%%".${domain}"}"
	fi

	da taskq --run "action=dns&do=add&domain=${domain}&type=TXT&name=${key}&value=\"${value}\"&ttl=120&named_reload=yes"
	exit 0
}

command_remove_dns_challenge_record() {
	local key=${1%%.}                     # Strip '.' suffix
	local value=$2

	local domain
	if ! domain=$(find_domain "${key}"); then
		echo "refusing to create DNS challenge record '${key}', unable to find matching domain" 1>&2
		exit 1
	fi

	if [ "${domain}" = "${key}" ]; then
		# top level entries uses full domain with leading .
		key="${domain}."
	else
		# remove domain suffix
		key="${key%%".${domain}"}"
	fi

	da taskq --run "action=dns&do=delete&domain=${domain}&type=TXT&name=${key}&value=\"${value}\"&named_reload=yes"
	exit 0
}

command_help() {
	echo "Usage:"
	echo "    $0 request|renew <domain> [<key-type>]"
	echo "    $0 server_cert [<domain>] [<key-type>]"
	echo ""
	echo "Got $# args:"
	echo "    $0 $1 $2 $3"
	echo ""
	echo "Multiple comma separated domains, owned by the same user, can be used for a certificate request"
	exit 0
}

case "$1" in
	server_cert)
		command_server_cert "${2}" "${3}"
		;;
	request|request_single|request_full|renew)
		IFS=',' read -r -a dns_names <<< "${2}"
		for name in "${dns_names[@]}"; do
			command_domain_cert "${name}" "${3}"
		done
		;;
	present)
		# lego callback for DNS challenge
		# ./letsencrypt.sh "present" "_acme-challenge.foo.example.com." "MsijOYZxqyjGnFGwhjrhfg-Xgbl5r68WPda0J9EgqqI"
		command_add_dns_challenge_record "${2}" "${3}"
		;;
	cleanup)
		# lego callback for DNS challenge
		command_remove_dns_challenge_record "${2}" "${3}"
		;;
	*)
		command_help "$@" ;;
esac