#!/bin/bash _CONF_FILE="/etc/jailspaces/js.conf" check_config() { [ -f "$_PHP_FPM_CONF_TEMPLATE" ] || die "$_PHP_FPM_CONF_TEMPLATE missing" [ -f "$_NGINX_CONF_TEMPLATE" ] || die "$_NGINX_CONF_TEMPLATE missing" } get_user_list() { eval "$_USER_LIST_CMD" | while read user; do echo $user; done; } user_create() { local cmd="${_USER_CREATE_CMD//@USERNAME@/$1}" eval "$cmd" return $? } user_exists() { get_user_list | grep -x "$1" &> /dev/null return $? } group_exists() { getent group | grep -P "^$1:" &> /dev/null return $? } user_is_valid() { echo "$1" | grep -ivP "[^a-z0-9]" &> /dev/null && [ "`echo -n \"$1\" | wc -c`" -le 10 ] && [ "`echo -n \"$1\" | wc -c`" -ge 4 ] && return 0 return 1 } get_user_chroot() { echo "${_PHP_FPM_CHROOT//@USERNAME@/$1}" } get_user_binds() { local username="$1" echo $_PHP_FPM_CHROOT_BIND if [ -n "$username" ]; then local bind_local="${_PHP_FPM_CHROOT_BIND_LOCAL//@USERNAME@/$username}" [ -f "$bind_local" ] && cat "$bind_local" fi } die() { echo "ERROR: $1" && stop 1 } is_valid_fqdn() { echo "$1" | grep -P '^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$' &> /dev/null return $? } get_FQDNs_for_user() { local nginx_config="${_NGINX_CONF//@USERNAME@/$1}" [ ! -r "$nginx_config" ] && nginx_config="$nginx_config.disabled" [ -r "$nginx_config" ] || echo "" for domain in `grep -P '^\s*server_name\s+.+;$' "$nginx_config" | rev | cut -c 2- | rev`; do [ "$domain" = "server_name" ] && continue; is_valid_fqdn "$domain" && echo "$domain" done | sort -u; } file_has() { case "$1" in perm) [ -e "$2" -a "`printf '%04d' \`stat -c '%a' $2\``" = "$3" ] && return 0 || return 1;; owner) [ -e "$2" -a "`stat -c '%U:%G' $2`" = "$3" ] && return 0 || return 1;; type) [ "$3" = "f" -a -f "$2" ] && return 0; [ "$3" = "d" -a -d "$2" ] && return 0; return 1;; esac } color() { local n="\033[0m" local g="\033[32m" local y="\033[33m" local r="\033[31m" eval "echo -en \"\$$1\"" echo -e "$2$n" } status() { local msg=""; case "$1" in g) msg="$2";; y) msg="$3";; r) msg="$4";; esac [ -n "$msg" ] && echo -n "[`color $1 \"$msg\"`]" } check_file_permissions() { local uUSERNAME="$1" local uCHROOT="`get_user_chroot $uUSERNAME`" local violation=false local cfile="" local suffix="" local f=1 for permDef in $_PHP_FPM_CHROOT_DIRS; do f=1; for field in file perm owner type; do eval "f_$field=\"`echo $permDef | cut -d, -f$f`\""; f=$(($f+1)); done; f_file="${f_file//@USERNAME@/$uUSERNAME}" cfile=$uCHROOT$f_file suffix="$f_perm,${f_owner//@USERNAME@/$uUSERNAME},$f_type" echo -n "$f_file," [ ! -e "$cfile" ] && violation=true && echo "false,true,true,true,$suffix" && continue; ! file_has perm "$cfile" "$f_perm" && violation=true && echo -n "true,false," || echo -n "true,true," ! file_has owner "$cfile" "${f_owner//@USERNAME@/$uUSERNAME}" && violation=true && echo -n "false," || echo -n "true," ! file_has type "$cfile" "$f_type" && violation=true && echo -n "false," || echo -n "true," echo "$suffix" done; $violation && return 1 || return 0 } fix_or_check_file_permissions() { local uUSERNAME="$1" local uCHROOT="`get_user_chroot $uUSERNAME`" local fix=false local f=1 local returnValue=0 [ -n "$2" ] && fix=true check_file_permissions "$uUSERNAME" | while read check; do f=1; for field in file exists perm owner type iperm iowner itype; do eval "f_$field=\"`echo $check | cut -d, -f$f`\""; f=$(($f+1)); done; local fullPath="$uCHROOT$f_file" if ! $f_exists; then local msg="$f_file does not exist" if $fix; then local status="r" [ "$f_itype" = "f" ] && touch "$fullPath" &> /dev/null && [ -f "$fullPath" ] && status="g" [ "$f_itype" = "d" ] && status="r" && mkdir -p "$fullPath" &> /dev/null && [ -d "$fullPath" ] && status="g" [ "$status" = "g" ] && status="r" && chown "$f_iowner" "$fullPath" && chmod "$f_iperm" "$fullPath" && status="g" printf "$pf2" "$msg" "`status $status 'CREATED' '' 'FAILED'`" [ "$status" = "g" ] || returnValue=1 else printf "$pf1" "" "$msg" fi fi if ! $f_perm; then local msg="$f_file has wrong permissions (must $f_iperm)" if $fix; then local status='r' chmod "$f_iperm" "$fullPath" && status="g" printf "$pf2" "$msg" "`status $status 'FIXED' '' 'FAILED'`" [ "$status" = "g" ] || returnValue=1 else printf "$pf1" "" "$msg" fi fi if ! $f_owner; then local msg="$f_file has wrong ownership (must $f_iowner)" if $fix; then local status="r" chown "$f_iowner" "$fullPath" && status="g" printf "$pf2" "$msg" "`status $status 'FIXED' '' 'FAILED'`" [ "$status" = "g" ] || returnValue=1 else printf "$pf1" "" "$msg" fi fi if ! $f_type; then local msg="" [ -f "$fullPath" ] && msg="$f_file is not a directory" [ -d "$fullPath" ] && msg="$f_file is not a regular file" if $fix; then printf "$pf2" "$msg --> please fix manually" "`status y '' 'SKIPPED'`" else printf "$pf1" "" "$msg" fi fi done; return $returnValue } # template destination owner mode var1 value1 var2 value2 install_template() { local template="$1" local destination="$2" local owner="$3" local mode="$4" shift 4 [ ! -f "$template" ] && printf "$pf2" "Template \"$template\" does not exist" "`status r '' '' 'ERROR'`" && return 1 [ -f "$destination" -o -f "$destination.disabled" ] && printf "$pf2" "Template target \"$destination\" already in use" "`status r '' '' 'ERROR'`" && return 2 local sedCmd="sed" while [ $# -gt 0 ]; do sedCmd="$sedCmd -e \"s/@$1@/$2/g\"" shift 2 done sedCmd="$sedCmd \"$template\"" local returnValue=0 local status="r" eval "$sedCmd" > "$destination" && status="g" printf "$pf2" "Installing template to \"$destination\"" "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] || return 1 [ "$status" = "g" ] && status="r" && chown "$owner" "$destination" && status="g" printf "$pf2" "Setting ownership to $owner" "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] || returnValue=1 [ "$status" = "g" ] && status="r" && chmod "$mode" "$destination" && status="g" printf "$pf2" "Setting mode to $mode" "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] || returnValue=1 return $returnValue } is_bound() { mount | grep " on $1 type " > /dev/null && return 0 || return 1 } get_base_path() { local path="$1" local lastPath="" while [ "$path" != "/" ]; do lastPath=$path; path=`dirname $path`; done; echo "$lastPath" } is_any_unbound() { local username="$1" local chroot="`get_user_chroot \"$username\"`" for bind in `get_user_binds "$username"`; do is_bound "$chroot$bind" || return 0 done return 1 } is_any_bound() { local username="$1" local chroot="`get_user_chroot \"$username\"`" for bind in `get_user_binds "$username"`; do is_bound "$chroot$bind" && return 0 done return 1 } reload_services() { local status="r" local error=false local sudo="" [ -n "$2" -a "$2" = "sudo" ] && sudo="sudo " if [ -n "$_OPT_RELOAD" ] && $_OPT_RELOAD; then if [ -z "$1" -o "$1" = "nginx" -o "$1" = "ALL" ]; then eval "$sudo$_RELOAD_NGINX_CMD" && status="g" printf "$pf2" "Reloading NGINX" "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] || error=true fi if [ -z "$1" -o "$1" = "php-fpm" -o "$1" = "ALL" ]; then status="r" eval "$sudo$_RELOAD_PHP_FPM_CMD" && status="g" printf "$pf2" "Reloading PHP-FPM" "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] || error=true fi fi if $error; then return 1 else return 0 fi } reset_nscd() { nscd --invalidate passwd &> /dev/null nscd --invalidate group &> /dev/null } stop() { rm -f "$_LOCKFILE" exit $1 } le_cmd() { if $_LOW_PRIV_TLS_REFRESH; then eval "$1" else su -c "$1" "$_LETS_ENCRYPT_USER" fi return $? } cert_get_domains() { local commonName="`openssl x509 -noout -text -in \"$1\" | grep 'Subject: CN=' | cut -d= -f2`" [ -n "$commonName" ] && echo $commonName # Subject Alternative Names [ -z "`openssl x509 -noout -text -in \"$1\" | grep 'X509v3 Subject Alternative Name:'`" ] && return 0 for d in \ `openssl x509 -noout -text -in "$1" | \ grep -A1 'X509v3 Subject Alternative Name:' \ | tail -n1 | tr -d '[:space:]' | \ sed -e 's/DNS://g' -e 's/,/ /g'`; do [ "$d" != "$commonName" ] && echo $d; done; } cert_get_expiry() { local expiry="`openssl x509 -noout -text -in \"$1\" | grep 'Not After' | cut -d: -f2-4`"; date -d "$expiry" +%s } create_systemd_units() { [ ! -f "${_SYSTEMD_UNIT_DIR}/rebindreadonly@.service" ] && \ cat <<- END > "${_SYSTEMD_UNIT_DIR}/rebindreadonly@.service" && \ echo -e "Created ${_SYSTEMD_UNIT_DIR}/rebindreadonly@.service" # PHP-FPM-CHROOT-BIND [Unit] Description=Remount bind for PHP-FPM chroot readonly DefaultDependencies=no After=%i.mount Before=local-fs.target [Service] Type=oneshot ExecStart=/bin/mount -o remount,bind,ro /%I END local chroot="" local eChroot="" local bind="" local eBind="" local mountpoint="" [ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroots.target" ] && \ cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroots.target" && \ echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroots.target" # PHP-FPM-CHROOT-BIND [Install] WantedBy=php5-fpm.service [Unit] Description=Bind all binds for all PHP-FPM chroots Before=php5-fpm.service END get_user_list | while read user; do chroot="`get_user_chroot ${user}`" eChroot="`systemd-escape -p \"${chroot}\"`" [ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" ] && \ cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" && \ echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" # PHP-FPM-CHROOT-BIND [Unit] Description=Bind all binds for PHP-FPM chroot ${chroot} END for bind in `get_user_binds "$user"`; do eBind="`systemd-escape -p \"${bind}\"`" mountpoint="`systemd-escape -p \"${chroot}${bind}\"`" [ ! -f "${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" ] && \ cat <<- END > "${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" && \ echo -e "Created ${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" # PHP-FPM-CHROOT-BIND [Unit] Description=Bind ${bind} for PHP-FPM chroot ${chroot} Requires=rebindreadonly@${mountpoint}.service Requires=php-chroot-create-mountpoint-file-${eBind}@${eChroot}.service Requires=php-chroot-create-mountpoint-dir-${eBind}@${eChroot}.service BindsTo=php-chroot-${eChroot}.target [Mount] What=${bind} Where=${chroot}${bind} Type=none Options=bind END [ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" ] && \ cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" && \ echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" # PHP-FPM-CHROOT-BIND [Unit] Description=Create mountpoint (file) for ${bind} in PHP-FPM Chroot Before=%i-${eBind}.mount ConditionPathExists=!/%I${bind} ConditionPathExists=${bind} ConditionPathIsDirectory=!${bind} [Service] Type=oneshot ExecStart=/bin/mkdir -p "/%I${bind}" ; /bin/rm -r "/%I${bind}" ; /usr/bin/touch "/%I${bind}" END [ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" ] && \ cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" && \ echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" # PHP-FPM-CHROOT-BIND [Unit] Description=Create mountpoint (dir) for ${bind} in PHP-FPM Chroot Before=%i-${eBind}.mount ConditionPathExists=!/%I${bind} ConditionPathExists=${bind} ConditionPathIsDirectory=${bind} [Service] Type=oneshot ExecStart=/bin/mkdir -p "/%I${bind}" END echo "Requires=${mountpoint}.mount" >> "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" done echo "BindsTo=php-chroots.target" >> "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" echo "Wants=php-chroot-${eChroot}.target" >> "${_SYSTEMD_UNIT_DIR}/php-chroots.target" done return 0 } list_systemd_units() { local unit="" ls -1b "${_SYSTEMD_UNIT_DIR}/"* 2> /dev/null | while read unit; do [ -f "$unit" ] && head -n1 "${unit}" | \ grep -x "# PHP-FPM-CHROOT-BIND" > /dev/null && echo "${unit}" done return 0 } delete_systemd_units() { ls -1b "${_SYSTEMD_UNIT_DIR}/"* 2> /dev/null | while read unit; do [ -f "$unit" ] && head -n1 "${unit}" | \ grep -x "# PHP-FPM-CHROOT-BIND" > /dev/null && \ echo -n "${unit}" && if $_OPT_YES; then rm "${unit}" && echo " (deleted)" else echo " (not deleted, use -Y)" fi done return 0 } pf0="%-16s: %-50s %11s\n" pf1="%-18s%s\n" pf2="%-69s%11s\n" ! source "$_CONF_FILE" &> /dev/null && printf "$pf2" "$_CONF_FILE could not be read." "`status r '' '' 'ERROR'`" && stop 1 # Skip single instance check for internal calls _OPT_INTERNAL_CALL=false if [ "$1" = "_INTERNAL_" -a "$EUID" -eq 0 ]; then _OPT_INTERNAL_CALL=true shift fi case "$1" in list) _OPT_ACTION="list" ;; status|fixperm) _OPT_ACTION="$1" _OPT_USERNAME="$2" ;; enable|disable) _OPT_ACTION="$1" _OPT_USERNAME="$2" _OPT_RELOAD=true if [ -n "$3" ]; then [ "$3" != "-n" ] && _OPT_ACTION="help" _OPT_RELOAD=false fi ;; binds) _OPT_ACTION="binds" _OPT_USERNAME="$3" case "$2" in bind ) _OPT_ACTION_BIND="bind";; unbind) _OPT_ACTION_BIND="unbind";; clean ) _OPT_ACTION_BIND="clean" _OPT_YES=false [ -n "$4" -a "$4" = "-Y" ] && _OPT_YES=true ;; status) _OPT_ACTION_BIND="status";; list ) _OPT_ACTION_BIND="list";; systemd) _OPT_ACTION_BIND="systemd" case "$3" in list) _OPT_ACTION_BIND_SYSTEMD="list";; create) _OPT_ACTION_BIND_SYSTEMD="create";; clean) _OPT_ACTION_BIND_SYSTEMD="clean" _OPT_YES=false [ -n "$4" -a "$4" = "-Y" ] && _OPT_YES=true ;; update) _OPT_ACTION_BIND_SYSTEMD="update";; *)_OPT_ACTION="help";; esac;; *)_OPT_ACTION="help";; esac ;; create) _OPT_ACTION="create" _OPT_USERNAME="$2" _OPT_DOMAINS="" shift 2 while [ "$#" -gt 0 ]; do ! is_valid_fqdn "$1" && printf "$pf2" "$1 is not a valid FQDN" "`status r '' '' 'ERROR'`" && stop 1 _OPT_DOMAINS="$_OPT_DOMAINS $1" shift done ;; delete) _OPT_ACTION="delete" _OPT_USERNAME="$2" _OPT_YES=false [ -n "$3" -a "$3" = "-Y" ] && _OPT_YES=true ;; tls) _OPT_ACTION="tls" case "$2" in init) _OPT_ACTION_TLS="init";; refresh|forcerefresh) _OPT_ACTION_TLS="refresh" _OPT_ACTION_TLS_FORCEREFRESH=false [ "$2" = "forcerefresh" ] && _OPT_ACTION_TLS_FORCEREFRESH=true _OPT_USERNAME="$3" _OPT_RELOAD=true if [ -n "$4" ]; then [ "$4" != "-n" ] && _OPT_ACTION="help" _OPT_RELOAD=false fi ;; *) _OPT_ACTION="help";; esac ;; *) _OPT_ACTION="help" ;; esac # Check if this is the only instance if ! $_OPT_INTERNAL_CALL; then _LOCKFILE="/tmp/wss.lock" if [ -e "$_LOCKFILE" ] && kill -0 `cat $_LOCKFILE` &> /dev/null; then printf "$pf2" "Another instance of this script seems to be runnig" "`status r '' '' 'ERROR'`" exit 1 fi trap "rm -f $_LOCKFILE;" INT TERM EXIT echo $$ > $_LOCKFILE fi # Check if we run as letsencrypt user for certificate refresh _LOW_PRIV_TLS_REFRESH=false if [ "$USER" = "$_LETS_ENCRYPT_USER" -a "$_OPT_ACTION_TLS" = "refresh" ]; then _LOW_PRIV_TLS_REFRESH=true fi # Check if this is run as root if ! $_LOW_PRIV_TLS_REFRESH && [ "$EUID" -ne 0 ]; then printf "$pf2" "Not run as root" "`status r '' '' 'ERROR'`" stop 1 fi if ! echo "$_OPT_ACTION" | grep -P "list|help" &> /dev/null && [ "$_OPT_ACTION_TLS" != "init" ] && [ "$_OPT_ACTION_BIND" != "systemd" ]; then if ! user_is_valid "$_OPT_USERNAME" ]; then printf "$pf2" "Username \"$_OPT_USERNAME\" is not valid" "`status r '' '' 'ERROR'`" stop 1 fi fi if ! echo "$_OPT_ACTION" | grep -P "list|help|create" &> /dev/null && [ "$_OPT_ACTION_TLS" != "init" ] && [ "$_OPT_ACTION_BIND" != "systemd" ]; then if ! user_exists "$_OPT_USERNAME"; then printf "$pf2" "Username \"$_OPT_USERNAME\" does not exist" "`status r '' '' 'ERROR'`" stop 1 fi fi uUSERNAME="$_OPT_USERNAME" uCERT="$_LETS_ENCRYPT_CRT_DIR/$uUSERNAME.crt" uCHROOT="`get_user_chroot \"$uUSERNAME\"`" uPOOL="${_PHP_FPM_CONF//@USERNAME@/$uUSERNAME}" uNGINX="${_NGINX_CONF//@USERNAME@/$uUSERNAME}" id "$uUSERNAME" &> /dev/null && status_user_exists="g" || status_user_exists="r" [ -r "$uNGINX" ] && status_nginx_exists="g" || status_nginx_exists="r" && [ -r "$uNGINX.disabled" ] && status_nginx_exists="y" [ "$status_nginx_exists" != "r" ] && uFQDNS="`get_FQDNs_for_user \"$uUSERNAME\"`" status_crt_exists="g" status_crt_expiry="g" status_crt_fqdns="g" if $_LETS_ENCRYPT_ENABLE; then [ -e "$uCERT" ] && status_crt_exists="g" || status_crt_exists="r" if [ "$status_crt_exists" = "g" ]; then uCERTFQDNS="`cert_get_domains \"$uCERT\"`" timeToExpiry=$((`cert_get_expiry "$uCERT"`-`date +%s`)) [ "$timeToExpiry" -le "$_LETS_ENCRYPT_EXPIRY" ] && status_crt_expiry="y" [ "$timeToExpiry" -le 0 ] && status_crt_expiry="r" if [ -n "$uFQDNS" ]; then for d in $uFQDNS; do dinc=false for c in $uCERTFQDNS; do [ "$d" = "$c" ] && dinc=true && break done ! $dinc && status_crt_fqdns="r" && break done fi fi fi if ! $_LOW_PRIV_TLS_REFRESH; then [ -d "$uCHROOT" ] && status_chroot_exists="g" || status_chroot_exists="r" [ -r "$uPOOL" ] && status_pool_exists="g" || status_pool_exists="r" && [ -r "$uPOOL.disabled" ] && status_pool_exists="y" group_exists "$uUSERNAME" && status_usergroup_exists="g" || status_usergroup_exists="r" check_file_permissions "$uUSERNAME" &> /dev/null && status_fileperms="g" || status_fileperms="r" is_any_unbound "$uUSERNAME" && status_binds="r" || status_binds="g" check_config fi case "$_OPT_ACTION" in list) get_user_list ;; status) printf "$pf0" "USERNAME" "$uUSERNAME" "`status $status_user_exists 'OK' '' 'INVALID'`" [ "$status_usergroup_exists" = "g" ] && statusMsg="$uUSERNAME" || statusMsg="No group \"$uUSERNAME\"" printf "$pf0" "USERGROUP" "$statusMsg" "`status $status_usergroup_exists 'OK' '' 'MISSING'`" printf "$pf0" "PHP-FPM-CHROOT" "$uCHROOT" "`status $status_chroot_exists 'OK' '' 'MISSING'`" printf "$pf0" "PHP-FPM-POOL" "$uPOOL" "`status $status_pool_exists 'ENABLED' 'DISABLED' 'MISSING'`" printf "$pf0" "NGINX CONFIG" "$uNGINX" "`status $status_nginx_exists 'ENABLED' 'DISABLED' 'MISSING'`" if [ "$status_nginx_exists" != "r" ]; then printf "$pf0" "FQDNs" "`get_FQDNs_for_user \"$uUSERNAME\" | wc -l`" get_FQDNs_for_user "$uUSERNAME" | while read fqdn; do printf "$pf1" "" "$fqdn" done; else printf "$pf0" "FQDNs" "Unknown (NGINX config missing)" "`status y '' 'UNKNOWN'`" fi if $_LETS_ENCRYPT_ENABLE; then if [ "$status_crt_exists" != "g" ]; then printf "$pf0" "TLS CERTIFICATE" "Missing" "`status r '' '' 'MISSING'`" else case "$status_crt_expiry" in g) statusMsg="valid";; y) statusMsg="expiring";; r) statusMsg="expired";; esac status="$status_crt_expiry" [ "$status_crt_fqdns" = "r" ] && statusMsg="$statusMsg, domains missing" && status="r" printf "$pf0" "TLS CERTIFICATE" "Exists, $statusMsg" "`status $status 'OK' 'EXPIRING' 'ERROR'`" if [ "$status_crt_fqdns" = "r" ]; then allFqdnsInCert=true for fqdn in $uFQDNS; do fqdnInCert=false for certfqdn in $uCERTFQDNS; do [ "$fqdn" = "$certfqdn" ] && fqdnInCert=true && break done ! $fqdnInCert && printf "$pf1" "" "$fqdn not in certificate" && allFqdnsInCert=false done else [ "$status_nginx_exists" = "r" ] && printf "$pf0" "TLS CERTIFICATE" "Unknown (NGINX config missing)" "`status y '' 'UNKNOWN'`" fi fi fi if [ "$status_chroot_exists" != "r" ]; then printf "$pf0" "FILE PERMISSIONS" "`[ "$status_fileperms" = "g" ] && echo -n \"All correct\" || echo -n \"Incorrect\"`" "`status $status_fileperms 'OK' '' 'INCORRECT'`" fix_or_check_file_permissions "$uUSERNAME" else printf "$pf0" "FILE PERMISSIONS" "Unknown (PHP-FPM-CHROOT missing)" "`status y '' 'UNKNOWN'`" fi if [ "$status_chroot_exists" != "r" ] ; then printf "$pf0" "CHROOT BINDS" "`[ "$status_binds" = "g" ] && echo -n \"All bound\" || echo -n \"Binds missing\"`" "`status $status_binds 'OK' '' 'MISSING'`" if [ "$status_binds" != "g" ]; then for bind in `get_user_binds "$uUSERNAME"`; do ! is_bound "$uCHROOT$bind" && printf "$pf1" "" "$bind missing" done fi else printf "$pf0" "CHROOT BINDS" "Unknown (PHP-FPM-CHROOT missing)" "`status y '' 'UNKNOWN'`" fi # Return value checkList="status_user_exists status_chroot_exists status_pool_exists status_nginx_exists status_usergroup_exists status_fileperms status_binds status_crt_exists status_crt_expiry status_crt_fqdns" for check in $checkList; do [ "${!check}" = "r" ] && stop 1; done stop 0 ;; fixperm) if [ "$status_chroot_exists" == "r" ]; then printf "$pf2" "Chroot does not exist. Please create manually." "`status r '' '' 'ERROR'`" stop 1 else fix_or_check_file_permissions "$uUSERNAME" fix stop $? fi ;; binds) returnValue=0 if [ "$_OPT_ACTION_BIND" = "systemd" ]; then ! $_SYSTEMD_ENABLE && stop 0 # List systemd unit files [ "$_OPT_ACTION_BIND_SYSTEMD" = "list" ] && list_systemd_units && stop 0 # Set up systemd unit files [ "$_OPT_ACTION_BIND_SYSTEMD" = "create" ] && create_systemd_units && stop 0 # Clean up systemd unit files [ "$_OPT_ACTION_BIND_SYSTEMD" = "clean" ] && delete_systemd_units && stop 0 # Update systemd unit files [ "$_OPT_ACTION_BIND_SYSTEMD" = "update" ] && $0 _INTERNAL_ binds systemd clean -Y && $0 _INTERNAL_ binds systemd create && systemctl daemon-reload && stop 0 stop 1 fi if [ "$status_chroot_exists" != "g" ]; then printf "$pf2" "Chroot \"$uCHROOT\" does not exist." "`status r '' '' 'ERROR'`" stop 1 fi for bind in `get_user_binds "$uUSERNAME"`; do if [ "$_OPT_ACTION_BIND" = "list" ]; then echo "$bind" continue fi if [ "$_OPT_ACTION_BIND" = "status" ]; then status_bind="r" && is_bound "$uCHROOT$bind" && status_bind="g" printf "$pf2" "$bind" "`status $status_bind 'BOUND' '' 'UNBOUND'`" [ "$status_bind" = "r" ] && returnValue=1 continue fi # if [ "$status_nginx_exists" = "g" -o "$status_pool_exists" = "g" ]; then # printf "$pf2" "Please disable webspace first." "`status r '' '' 'ERROR'`" # stop 1 # fi if [ "$_OPT_ACTION_BIND" = "bind" ] && ! is_bound "$uCHROOT$bind"; then # Create mointpoints if [ ! -e "$uCHROOT$bind" ]; then if [ -d "$bind" ]; then status="r" mkdir -p "$uCHROOT$bind" && status="g" || returnValue=1 printf "$pf2" "Creating mountpoint $uCHROOT$bind (dir)" "`status $status 'DONE' '' 'FAILED'`" else dir="$uCHROOT`dirname $bind`" status="r" mkdir -p "$dir" && status="g" || returnValue=1 printf "$pf2" "Creating directory $dir" "`status $status 'DONE' '' 'FAILED'`" status="r" touch "$uCHROOT$bind" && status="g" || returnValue=1 printf "$pf2" "Creating mountpoint $uCHROOT$bind (file)" "`status $status 'DONE' '' 'FAILED'`" fi fi if [ $returnValue -eq 0 ]; then status="r" mount --bind "$bind" "$uCHROOT$bind" && status="g" || returnValue=1 printf "$pf2" "Mount $uCHROOT$bind" "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] && status="r" && mount -o "remount,ro,bind" "$bind" "$uCHROOT$bind" && status="g" || returnValue=1 printf "$pf2" "Remount $uCHROOT$bind readonly" "`status $status 'DONE' '' 'FAILED'`" else printf "$pf" "Mount $uCHROOT$bind" "`status y '' 'SKIPPED'`" fi fi if [ "$_OPT_ACTION_BIND" = "unbind" -o "$_OPT_ACTION_BIND" = "clean" ] && is_bound "$uCHROOT$bind"; then status="r" umount "$uCHROOT$bind" && status="g" || returnValue=1 printf "$pf2" "Umount $uCHROOT$bind" "`status $status 'DONE' '' 'FAILED'`" fi done; if [ "$_OPT_ACTION_BIND" = "clean" ]; then deletePathes=() allPathes=() for bind in `get_user_binds "$uUSERNAME"`; do deletePath="`get_base_path \"$bind\"`" inList=false for e in "${allPathes[@]}"; do [ "$e" = "$uCHROOT$deletePath" ] && inList=true done $inList || allPathes+=("$uCHROOT$deletePath") if ! $inList; then if [ ! -e "$uCHROOT$deletePath" ]; then printf "$pf2" "$uCHROOT$deletePath - does not exist" "`status y '' 'SKIPPED'`" continue fi if is_bound "$uCHROOT$bind"; then printf "$pf2" "$uCHROOT$deletePath - still mounted" "`status r '' '' 'ERROR'`" continue fi deletePathes+=("$uCHROOT$deletePath") fi done [ "${#deletePathes}" -eq 0 ] && stop $returnValue if ! $_OPT_YES; then echo -e "\nWill execute the following commands in order:\n" for i in `seq 0 $((${#deletePathes[@]}-1))`; do echo -e "\trm -rf \"${deletePathes[$i]}\"" done; echo fi while [ "$commandsOK" != "y" -a "$commandsOK" != "n" ]; do ! $_OPT_YES && read -p "Are you OK with that? [y/n]: " commandsOK $_OPT_YES && commandsOK="y" if [ "$commandsOK" = "y" ]; then ! $_OPT_YES && echo for i in `seq 0 $((${#deletePathes[@]}-1))`; do cmd_status="r" rm -rf "${deletePathes[$i]}" [ "$?" -eq 0 ] && cmd_status="g" printf "$pf2" "Delete ${deletePathes[$i]}" "`status "$cmd_status" 'DONE' '' 'FAILED'`" [ "$cmd_status" = "g" ] || returnValue=1 done; fi if [ "$commandsOK" = "n" ]; then printf "$pf2" "Aborted by user." "`status y '' 'SKIPPED'`" fi done fi stop $returnValue ;; enable|disable) status="r" [ "$status_pool_exists" = "r" ] && printf "$pf2" "\"$uPOOL\" missing." "`status r '' '' 'ERROR'`" && stop 1 [ "$status_nginx_exists" = "r" ] && printf "$pf2" "\"$uNGINX\" missing." "`status r '' '' 'ERROR'`" && stop 1 [ "$status_pool_exists" != "$status_nginx_exists" ] && printf "$pf2" "POOL and NGINX config not in same state." "`status r '' '' 'ERROR'`" && stop 1 if [ "$_OPT_ACTION" = "enable" ]; then [ "$status_pool_exists" = "g" ] && printf "$pf2" "Webspace already enabled." "`status y '' 'SKIPPED' ''`" && stop 0 ! $0 _INTERNAL_ status "$uUSERNAME" &> /dev/null && printf "$pf2" "Webspace can not be enabled. Run \"$0 status $uUSERNAME\" to see why." "`status r '' '' 'ERROR'`" && stop 1 mv "$uPOOL.disabled" "$uPOOL" && status="g" [ "$status" = "g" ] && status="r" && mv "$uNGINX.disabled" "$uNGINX" && status="g" printf "$pf2" "Webspace enabled" "`status $status 'ENABLED' '' 'FAILED'`" [ "$status" = "g" ] || stop 1 elif [ "$_OPT_ACTION" = "disable" ]; then [ "$status_pool_exists" = "y" ] && printf "$pf2" "Webspace already disabled." "`status y '' 'SKIPPED' ''`" && stop 0 mv "$uPOOL" "$uPOOL.disabled" && status="g" [ "$status" = "g" ] && status="r" && mv "$uNGINX" "$uNGINX.disabled" && status="g" printf "$pf2" "Webspace disabled" "`status $status 'DISABLED' '' 'FAILED'`" [ "$status" = "g" ] || stop 1 fi reload_services || stop 1 ;; create) returnValue=0 reset_nscd ! user_is_valid "$_OPT_USERNAME" && printf "$pf2" "Invalid username ([a-zA-Z0-9]{4,10})" "`status r '' '' 'ERROR'`" && stop 1 if user_create "$_OPT_USERNAME"; then printf "$pf2" "Run _USER_CREATE_CMD..." "`status g 'DONE'`" else printf "$pf2" "Run _USER_CREATE_CMD..." "`status r '' '' 'FAILED'`" stop 1 fi status="r" eval "${_NGINX_ADD_GROUP_CMD//@USERNAME@/$_OPT_USERNAME}" && status="g" printf "$pf2" "Run _NGINX_ADD_GROUP_CMD..." "`status $status 'DONE' '' 'FAILED'`" [ "$status" = "g" ] || returnValue=1 ! id "$_OPT_USERNAME" &> /dev/null && printf "$pf2" "User \"$_OPT_USERNAME\" not found in system." "`status r '' '' 'ERROR'`" && stop 1 ! group_exists "$_OPT_USERNAME" && printf "$pf2" "No group \"$_OPT_USERNAME\" found in system." "`status r '' '' 'ERROR'`" && stop 1 uCHROOT="`get_user_chroot \"$_OPT_USERNAME\"`" if [ ! -d "$uCHROOT" ]; then status="r" mkdir -p "$uCHROOT" && status="g" printf "$pf2" "Create chroot \"$uCHROOT\"" "`status $status 'DONE' '' 'FAILED'`" fi [ ! -d "$uCHROOT" ] && printf "$pf2" "Chroot \"$uCHROOT\" does not exist." "`status r '' '' 'ERROR'`" && stop 1 domains="$_OPT_DOMAINS" if [ -z "$domains" ]; then # Ask for domain list echo printf "$pf2" "Please specify at least one domain for the new webspace." printf "$pf2" "Finish list with empty input." domains="" while true; do read -p "FQDN: " fqdn fqdn="`echo -e \"$fqdn\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'`" [ -z "$fqdn" -a -n "$domains" ] && break if is_valid_fqdn "$fqdn"; then domains="$domains $fqdn" else printf "$pf2" "Not a valid domain." "`status r '' '' 'ERROR'`" fi done domains="`echo -e \"$domains\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'`" fi echo install_template "$_NGINX_CONF_TEMPLATE" "${_NGINX_CONF//@USERNAME@/$_OPT_USERNAME}.disabled" "$_NGINX_CONF_TEMPLATE_OWNER" "$_NGINX_CONF_TEMPLATE_MODE" "USERNAME" "$_OPT_USERNAME" "DOMAINS" "$domains" || returnValue=1 install_template "$_PHP_FPM_CONF_TEMPLATE" "${_PHP_FPM_CONF//@USERNAME@/$_OPT_USERNAME}.disabled" "$_PHP_FPM_CONF_TEMPLATE_OWNER" "$_PHP_FPM_CONF_TEMPLATE_MODE" "USERNAME" "$_OPT_USERNAME" || returnValue=1 echo $0 _INTERNAL_ fixperm "$_OPT_USERNAME" || returnValue=1 echo $0 _INTERNAL_ binds bind "$_OPT_USERNAME" || returnValue=1 status="r" $0 _INTERNAL_ binds systemd update > /dev/null && status="g" [ "$status" = "g" ] || returnValue=1 printf "$pf2" "Update systemd units for chroot binds..." "`status $status 'DONE' '' 'FAILED'`" if $_LETS_ENCRYPT_ENABLE; then echo $0 _INTERNAL_ tls refresh "$_OPT_USERNAME" fi if [ -n "$_POST_CREATE_CMD" ]; then echo status="r" eval "${_POST_CREATE_CMD//@USERNAME@/$_OPT_USERNAME}" && status="g" [ "$status" = "g" ] || returnValue=1 printf "$pf2" "Run _POST_CREATE_CMD..." "`status $status 'DONE' '' 'FAILED'`" fi stop $returnValue ;; delete) if [ "$status_nginx_exists" = "g" -o "$status_pool_exists" = "g" ]; then printf "$pf2" "Please disable webspace first." "`status r '' '' 'ERROR'`" stop 1 fi deleteCmd[0]="rm \"${_NGINX_CONF//@USERNAME@/$uUSERNAME}.disabled\"" deleteCmd[1]="rm \"${_PHP_FPM_CONF//@USERNAME@/$uUSERNAME}.disabled\"" deleteCmd[2]="rm -f \"$uCERT\"" deleteCmd[3]="rm -f \"$_LETS_ENCRYPT_CSR_DIR/$uUSERNAME.csr\"" deleteCmd[4]="rm -r \"${_PHP_FPM_CHROOT//@USERNAME@/$uUSERNAME}\"" deleteCmd[5]="${_USER_DELETE_CMD//@USERNAME@/$uUSERNAME}" if ! $_OPT_YES; then echo -e "Will execute the following commands in order:\n" for i in `seq 0 $((${#deleteCmd[@]}-1))`; do echo -e "\t${deleteCmd[$i]}" done; echo fi returnValue=0 while [ "$commandsOK" != "y" -a "$commandsOK" != "n" ]; do ! $_OPT_YES && read -p "Are you OK with that? [y/n]: " commandsOK $_OPT_YES && commandsOK="y" if [ "$commandsOK" = "y" ]; then ! $_OPT_YES && echo if is_any_bound "$uUSERNAME"; then $0 _INTERNAL_ binds unbind "$uUSERNAME" [ "$?" -ne 0 ] && printf "$pf2" "Unbind failed." "`status r '' '' 'ERROR'`" && stop 1 fi for i in `seq 0 $((${#deleteCmd[@]}-1))`; do cmd_status="r" eval "${deleteCmd[$i]}" [ "$?" -eq 0 ] && cmd_status="g" printf "$pf2" "${deleteCmd[$i]}" "`status "$cmd_status" 'DONE' '' 'FAILED'`" [ "$cmd_status" = "g" ] || returnValue=1 done; fi if [ "$commandsOK" = "n" ]; then printf "$pf2" "Aborted by user." "`status y '' 'SKIPPED'`" stop 1 fi done reset_nscd status="r" $0 _INTERNAL_ binds systemd update > /dev/null && status="g" [ "$status" = "g" ] || returnValue=1 printf "$pf2" "Update systemd units for chroot binds..." "`status $status 'DONE' '' 'FAILED'`" stop $returnValue ;; tls) ! $_LETS_ENCRYPT_ENABLE && printf "$pf2" "Let's Encrypt functionality is not enabled." "`status r '' '' 'ERROR'`" && stop 1 # Check if we can use _LETS_ENCRYPT_USER if ! le_cmd "true"; then printf "$pf2" "Could not run as \"$_LETS_ENCRYPT_USER\"" "`status r '' '' 'ERROR'`" stop 1 fi # Check/setup _LETS_ENCRYPT_CRT/CSR/CHALLENGE_DIR for d in CRT CSR CHALLENGE; do dir="`eval echo \\$_LETS_ENCRYPT_${d}_DIR`" eval "status_${d}_dir=\"y\"" le_cmd "[ -d \"$dir\" -a -w \"$dir\" ]" && eval "status_${d}_dir=\"g\"" [ "`eval echo \\$status_${d}_dir`" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && eval "status_${d}_dir=\"r\"" status="`eval echo \\$status_${d}_dir`" printf "$pf2" "_LETS_ENCRYPT_${d}_DIR exists and writable by $_LETS_ENCRYPT_USER" "`status $status 'YES' 'NO' 'NO'`" [ "$status" = "r" ] && stop 1 if [ "$status" = "y" ]; then create_owner="$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP" create_mode="0710" if [ "$d" = "CSR" ]; then create_owner="$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" create_mode="0700" fi status_create="r" mkdir -p "$dir" && status_create="g" printf "$pf2" "Create $dir" "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" = "g" ] && status_create="r" && chown "$create_owner" "$dir" && chmod "$create_mode" "$dir" && status_create="g" printf "$pf2" "Setting permissions to $create_owner mode $create_mode" "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" != "g" ] && stop 1 fi done # Check/setup Account and Server key for k in ACCOUNT SERVER; do keyPath="`eval echo \\$_LETS_ENCRYPT_${k}_KEY`" eval "status_${k}_key=\"y\"" le_cmd "[ -r \"$keyPath\" ]" && eval "status_${k}_key=\"g\"" [ "`eval echo \\$status_${k}_key`" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && eval "status_${k}_key=\"r\"" status="`eval echo \\$status_${k}_key`" printf "$pf2" "_LETS_ENCRYPT_${k}_KEY exists and readable by $_LETS_ENCRYPT_USER" "`status $status 'YES' 'NO' 'NO'`" [ "$status" = "r" ] && stop 1 if [ "$status" = "y" ]; then create_owner="$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP" create_mode="0440" if [ "$k" = "ACCOUNT" ]; then create_owner="$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" create_mode="0400" fi; status_create="r" openssl genrsa $_LETS_ENCRYPT_KEYLENGTH > "$keyPath" && status_create="g" printf "$pf2" "Generate _LETS_ENCRYPT_${k}_KEY" "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" = "g" ] && status_create="r" && chown "$create_owner" "$keyPath" && chmod "$create_mode" "$keyPath" && status_create="g" printf "$pf2" "Setting permissions to $create_owner mode $create_mode" "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" != "g" ] && stop 1 fi done # Check/setup dhparams status_dhparams_exists="y" le_cmd "[ -r \"$_LETS_ENCRYPT_DHPARAMS\" ]" && status_dhparams_exists="g" [ "$status_dhparams_exists" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && status_dhparams_exists="r" printf "$pf2" "_LETS_ENCRYPT_DHPARAMS exists and readable by $_LETS_ENCRYPT_USER" "`status $status_dhparams_exists 'YES' 'NO' 'NO'`" [ "$status_dhparams_exists" = "r" ] && stop 1 if [ "$status_dhparams_exists" = "y" ]; then status_create="r" openssl dhparam -out "$_LETS_ENCRYPT_DHPARAMS" $_LETS_ENCRYPT_DHPARAMS_LENGTH > "$_LETS_ENCRYPT_DHPARAMS" && status_create="g" printf "$pf2" "Generating _LETS_ENCRYPT_DHPARAMS..." "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" = "g" ] && status_create="r" && chown "$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP" "$_LETS_ENCRYPT_DHPARAMS" && chmod "440" "$_LETS_ENCRYPT_DHPARAMS" && status_create="g" printf "$pf2" "Setting permissions to $_LETS_ENCRYPT_USER:$_NGINX_USERGROUP mode 440" "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" != "g" ] && stop 1 fi # Check/setup intermediate certificate status_crt_intermediate_exists="y" le_cmd "[ -r \"$_LETS_ENCRYPT_INTERMEDIATE\" ]" && status_crt_intermediate_exists="g" [ "$status_crt_intermediate_exists" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && status_crt_intermediate_exists="r" printf "$pf2" "_LETS_ENCRYPT_INTERMEDIATE exists and readable by $_LETS_ENCRYPT_USER" "`status $status_crt_intermediate_exists 'YES' 'NO' 'NO'`" [ "$status_crt_intermediate_exists" = "r" ] && stop 1 if [ "$status_crt_intermediate_exists" = "y" ]; then status_create="r" wget -O- "$_LETS_ENCRYPT_INTERMEDIATE_URL" > "$_LETS_ENCRYPT_INTERMEDIATE" && status_create="g" printf "$pf2" "Downloading _LETS_ENCRYPT_INTERMEDIATE..." "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" = "g" ] && status_create="r" && chown "$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP" "$_LETS_ENCRYPT_INTERMEDIATE" && chmod "440" "$_LETS_ENCRYPT_INTERMEDIATE" && status_create="g" printf "$pf2" "Setting permissions to $_LETS_ENCRYPT_USER:$_NGINX_USERGROUP mode 440" "`status $status_create 'DONE' '' 'FAILED'`" [ "$status_create" != "g" ] && stop 1 fi if [ "$_OPT_ACTION_TLS" = "refresh" ]; then [ "$status_nginx_exists" = "r" ] && printf "$pf2" "NGINX config could not be read" "`status r '' '' 'ERROR'`" && stop 1 [ -z "$uFQDNS" ] && printf "$pf2" "No domains for $uUSERNAME" "`status r '' '' 'ERROR'`" && stop 1 proceed=false if ! $_OPT_ACTION_TLS_FORCEREFRESH; then status="$status_crt_exists" [ "$status" = "r" ] && status="y" printf "$pf2" "Checking existance..." "`status $status 'YES' 'NO' ''`" [ "$status" != "g" ] && proceed=true if ! $proceed; then status="$status_crt_expiry" [ "$status" != "r" ] && printf "$pf2" "Checking expiry..." "`status $status 'VALID' 'EXPIRING' ''`" [ "$status" = "r" ] && printf "$pf2" "Checking expiry..." "`status r '' 'EXPIRED' ''`" [ "$status" != "g" ] && proceed=true fi if ! $proceed; then status="$status_crt_fqdns" [ "$status" = "r" ] && status="y" printf "$pf2" "Checking all domains available in cert..." "`status $status 'OK' 'MISSING' ''`" [ "$status" != "g" ] && proceed=true fi else proceed=true fi ! $proceed && printf "$pf2" "No reason to refresh certificate for $uUSERNAME" "`status y '' 'SKIPPING' ''`" && stop 0 status="r" csr_path="$_LETS_ENCRYPT_CSR_DIR/$uUSERNAME.csr" if [ "`echo \"$uFQDNS\" | wc -w`" -eq 1 ]; then le_cmd "openssl req -new -sha256 -key \"$_LETS_ENCRYPT_SERVER_KEY\" -subj \"/CN=$uFQDNS\" > \"$csr_path\"" && status="g" else san="DNS:`echo $uFQDNS | sed -e 's/ /,DNS:/g'`" le_cmd "openssl req -new -sha256 -key \"$_LETS_ENCRYPT_SERVER_KEY\" -subj \"/\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"[SAN]\nsubjectAltName=$san\")) > \"$csr_path\"" && status="g" fi printf "$pf2" "Creating CSR for $uUSERNAME..." "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 status="r" && le_cmd "chown \"$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP\" \"$csr_path\"" && status="g" printf "$pf2" "Set owner to $_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 status="r" && le_cmd "chmod $_LETS_ENCRYPT_CSR_MODE \"$csr_path\"" && status="g" printf "$pf2" "Set mode to $_LETS_ENCRYPT_CSR_MODE" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 status="r" le_cmd "$_LETS_ENCRYPT_ACME_TINY --account-key \"$_LETS_ENCRYPT_ACCOUNT_KEY\" --csr \"$csr_path\" --acme-dir \"$_LETS_ENCRYPT_CHALLENGE_DIR\" > \"$uCERT.signed\"" && status="g" printf "$pf2" "Request certificate for $uUSERNAME" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && le_cmd "rm -f $uCERT.signed" && stop 1 status="r" && le_cmd "cat \"$uCERT.signed\" \"$_LETS_ENCRYPT_INTERMEDIATE\" > \"$uCERT.chained\"" && status="g" printf "$pf2" "Chaining certifiacte..." "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && le_cmd "rm -f $uCERT.chained" && stop 1 status="r" && le_cmd "mv \"$uCERT.chained\" \"$uCERT\"" && status="g" printf "$pf2" "Putting new cert in place" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 status="r" && le_cmd "rm \"$uCERT.signed\"" && status="g" printf "$pf2" "Removing unchained certificate" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 status="r" && le_cmd "chown "$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" \"$uCERT\"" && status="g" printf "$pf2" "Set owner to $_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 status="r" && le_cmd "chmod $_LETS_ENCRYPT_CRT_MODE \"$uCERT\"" && status="g" printf "$pf2" "Set mode to $_LETS_ENCRYPT_CRT_MODE" "`status $status 'OK' '' 'FAILED'`" [ "$status" = "r" ] && stop 1 reload_services "nginx" "sudo" || stop 1 fi ;; help) cat < []] [] [-n|-Y] can be one of... list: List all usernames associated with webspaces create [FQDN0 [FQDN1 [...]]]: Create a webspace associated with with domains FQDN0 - FQDNn. If the domains are not provided from the commandline, they need to be provided interactively. status : Show status of webspace associated with enable [-n]: Enable webspace associated with -n prevents reload of services disable [-n]: Disable webspace associated with -n prevents reload of services delete [-Y]: Delete webspace associated with . If -Y is provided, no questions will be asked and the account and all data of this webspace will be deleted. fixperm : Set permissions and ownerships in PHP-FPM chroot of as defined in _PHP_FPM_CHROOT_DIRS binds list|status|bind|unbind|clean [-Y] : list: List binds for status: Show mount status of binds for bind: Mount all binds for 's chroot. Mountpoints will be created if they do not exist. undbind: Unmount all binds for . clean [-Y]: Unmount all binds for and delete mountpoints for binds. Without -Y it will just list the paths that would be deleted and ask for confirmation interactively. binds systemd list|create|update|clean [-Y] These commands manage unit files for systemd to automatically create mountpoints for users on boot and mount binds for the user's chroots. list: List all systemd unit files managed by this script. create: Create systemd units for all users. update: Same as $0 binds systemd clean -Y && $0 binds systemd create This is idempotent and will bring the unitfiles in sync with the user's chroot binds. clean [-Y]: Delete all unit files managed by this script. Without -Y it will just list the paths that would be deleted and ask for confirmation interactively. tls []: _LETS_ENCRYPT_ENABLE must be set to "true" to use these commands can be one of... init: Check preconditions and setup environment (directories, keys) for requesting TLS certificates using the "refresh" subcommand. refresh [-n]: Request and apply certificate for webspace associated with if no certificate is available, or if the actual certificate is expired or about to expire. -n prevents reload of services forcerefresh [-n]: Same as "refresh" but always gets a new certificate -n prevents reload of services END stop 1 ;; esac