#!/bin/bash { #//////////////////////////////////// # DietPi Lets Encrypt # #//////////////////////////////////// # Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com # #//////////////////////////////////// # # Info: # - filename /DietPi/dietpi/dietpi-letsencrypt # - Menu Frontend for Letsencrypt with CLI options for use on DietPi systems. # # usage: # - /DietPi/dietpi/dietpi-letsencrypt = Menu # - /DietPi/dietpi/dietpi-letsencrypt 1 = Create/Renew/Apply cert #//////////////////////////////////// #Grab Input INPUT=0 if [[ $1 =~ ^-?[0-9]+$ ]]; then INPUT=$1 fi #Import DietPi-Globals --------------------------------------------------------------- . /DietPi/dietpi/func/dietpi-globals G_CHECK_ROOT_USER G_CHECK_ROOTFS_RW export G_PROGRAM_NAME='DietPi-Letsencrypt' #Import DietPi-Globals --------------------------------------------------------------- #///////////////////////////////////////////////////////////////////////////////////// #Globals #///////////////////////////////////////////////////////////////////////////////////// DP_LOGFILE="/var/log/dietpi-letsencrypt.log" DP_MONTHLY_CRON="/etc/cron.monthly/dietpi-letsencrypt" DP_LETSENCRYPT_BINARY="/usr/bin/certbot" if (( $G_DISTRO < 4 )); then DP_LETSENCRYPT_BINARY="/etc/certbot_scripts/certbot-auto" fi DP_WEBSERVER_INDEX=0 #0=apache2 1=lighttpd 2=nginx 3=minio LETSENCRYPT_INSTALLED=0 if [ -f "$DP_LETSENCRYPT_BINARY" ]; then LETSENCRYPT_INSTALLED=1 fi LETSENCRYPT_DOMAIN="mydomain.com" LETSENCRYPT_EMAIL="myemail@email.com" LETSENCRYPT_REDIRECT=0 LETSENCRYPT_AUTORENEW=0 LETSENCRYPT_KEYSIZE=4096 Run_Lets_Encrypt(){ G_DIETPI-NOTIFY 3 "$PROGRAM_NAME" "Running cert" #Conditions that must be met before allowing run local run_conditions_met=1 /DietPi/dietpi/dietpi-services start # - Obtain installed and running webserver index if (( $(ps aux | grep -ci -m1 '[a]pache') )); then DP_WEBSERVER_INDEX=0 G_DIETPI-NOTIFY 0 "Apache2 webserver detected" if (( $G_DISTRO >= 4 )); then DP_LETSENCRYPT_BINARY="$DP_LETSENCRYPT_BINARY --apache" fi elif (( $(ps aux | grep -ci -m1 '[l]ighttpd') )); then DP_WEBSERVER_INDEX=1 G_DIETPI-NOTIFY 0 "Lighttpd webserver detected" elif (( $(ps aux | grep -ci -m1 '[n]ginx') )); then DP_WEBSERVER_INDEX=2 G_DIETPI-NOTIFY 0 "Nginx webserver detected" if (( $G_DISTRO >= 4 )); then DP_LETSENCRYPT_BINARY="$DP_LETSENCRYPT_BINARY --nginx" fi elif (( $(ps aux | grep -ci -m1 '[m]inio') )); then DP_WEBSERVER_INDEX=3 G_DIETPI-NOTIFY 0 "Minio S3 server detected" else run_conditions_met=0 fi #Failed. No compatible webserver is currently running if (( ! $run_conditions_met )); then echo -e "Error: No compatible and/or active webserver was found. Aborting." >> "$DP_LOGFILE" if (( $INPUT == 0 )); then whiptail --title "Error" --msgbox "Error: No compatible and/or active webserver was found. Aborting." --backtitle "$PROGRAM_NAME" 8 60 fi #Cert up else #------------------------------------------------------------------------------------------------------ #apache2 if (( $DP_WEBSERVER_INDEX == 0 )); then local dp_defaultsite="/etc/apache2/sites-available/000-default.conf" #Add ServerName if it doesnt exist. This is required to prevent letsencrypt compaining about vhost with no domain. if (( ! $(cat "$dp_defaultsite" | grep -ci -m1 'ServerName') )); then sed -i "/ServerAdmin /a ServerName" "$dp_defaultsite" #log echo -e "ServerName entry not found in $dp_defaultsite. Adding it now." >> "$DP_LOGFILE" fi #Apply domain name sed -i "/ServerName/c\ ServerName $LETSENCRYPT_DOMAIN" "$dp_defaultsite" #Restart apache2 to apply ServerName changes. systemctl restart apache2 local cli_redirect="--no-redirect" if (( $LETSENCRYPT_REDIRECT )); then cli_redirect="--redirect" fi #Cert me up Apache2 $DP_LETSENCRYPT_BINARY --duplicate --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN #------------------------------------------------------------------------------------------------------ #Lighttpd elif (( $DP_WEBSERVER_INDEX == 1 )); then # - Cert me up /DietPi/dietpi/dietpi-services stop $DP_LETSENCRYPT_BINARY certonly --standalone --duplicate --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN # - Create combined key cd /etc/letsencrypt/live/"$LETSENCRYPT_DOMAIN" cat privkey.pem cert.pem > combined.pem cat << _EOF_ > /etc/lighttpd/conf-enabled/letsencrypt.conf \$SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/combined.pem" ssl.ca-file = "/etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem" #ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:HIGH:!MD5:!aNULL:!EDH:!AESGCM" ssl.cipher-list = "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS" ssl.honor-cipher-order = "enable" ssl.use-sslv2 = "disable" ssl.use-sslv3 = "disable" } _EOF_ #Redirect rm /etc/lighttpd/conf-enabled/redirect.conf if (( $LETSENCRYPT_REDIRECT )); then cat << _EOF_ > /etc/lighttpd/conf-enabled/redirect.conf \$HTTP["scheme"] == "http" { # capture vhost name with regex conditiona -> %0 in redirect pattern # must be the most inner block to the redirect rule \$HTTP["host"] =~ ".*" { url.redirect = (".*" => "https://%0\$0") } } _EOF_ fi /etc/init.d/lighttpd force-reload #------------------------------------------------------------------------------------------------------ # Nginx elif (( $DP_WEBSERVER_INDEX == 2 )); then local nginx_defaultsite="/etc/nginx/sites-available/default" # Apply domain name sed -i "/server_name/c\ server_name $LETSENCRYPT_DOMAIN;" "$nginx_defaultsite" #Restart nginx to apply ServerName changes. systemctl restart nginx local cli_redirect="--no-redirect" if (( $LETSENCRYPT_REDIRECT )); then cli_redirect="--redirect" fi #Cert me up Nginx $DP_LETSENCRYPT_BINARY --duplicate --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN #------------------------------------------------------------------------------------------------------ #Minio elif (( $DP_WEBSERVER_INDEX == 3 )); then # - Cert me up /DietPi/dietpi/dietpi-services stop $DP_LETSENCRYPT_BINARY certonly --standalone --preferred-challenges tls-sni --staple-ocsp --agree-tos $cli_redirect --rsa-key-size $LETSENCRYPT_KEYSIZE --email $LETSENCRYPT_EMAIL -d $LETSENCRYPT_DOMAIN # Locate them correctly (THIS didn't work as symlinks) cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem /home/minio-user/.minio/certs/public.crt cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/privkey.pem /home/minio-user/.minio/certs/private.key # Own those certs! chown minio-user:minio-user /home/minio-user/.minio/certs/public.crt chown minio-user:minio-user /home/minio-user/.minio/certs/private.key # Add SSL to config file grep -v "MINIO_OPTS" /etc/default/minio > /etc/default/minio.temp1 grep -v "port" /etc/default/minio.temp1 > /etc/default/minio.temp2 rm /etc/default/minio.temp1 mv /etc/default/minio.temp2 /etc/default/minio cat << _EOF_ >> /etc/default/minio # Use if you want to run Minio on a custom port. MINIO_OPTS="--address :443" _EOF_ # Allow SSL binding for non root user setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/minio # Create renewl script cat << _EOF_ > /home/minio-user/.minio/dietpi-cert-renewl.sh # Minio only works with copied and owned certs. Upon renewal the new certs needs to be copied and re-owned systemctl stop minio.service # Copy to correct Location cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/fullchain.pem /home/minio-user/.minio/certs/public.crt cp /etc/letsencrypt/live/$LETSENCRYPT_DOMAIN/privkey.pem /home/minio-user/.minio/certs/private.key # Re-Own those certs! chown minio-user:minio-user /home/minio-user/.minio/certs/public.crt chown minio-user:minio-user /home/minio-user/.minio/certs/private.key systemctl start minio.service _EOF_ # Change permissions on renewal script chmod +x /home/minio-user/.minio/dietpi-cert-renewl.sh fi #------------------------------------------------------------------------------------------------------ #ALL | Create cron job if (( $LETSENCRYPT_AUTORENEW && $G_DISTRO < 4 )); then cat << _EOF_ > "$DP_MONTHLY_CRON" #!/bin/bash { #//////////////////////////////////// # DietPi-LetsEncrypt Autorenew script # #//////////////////////////////////// # # Info: # - Location $DP_MONTHLY_CRON # #//////////////////////////////////// #---------------------------------------------------------------- # Main Loop #---------------------------------------------------------------- /DietPi/dietpi/dietpi-letsencrypt 1 &>> $DP_LOGFILE # Minio specific applications if (( $(ps aux | grep -ci -m1 '[m]inio') )); then /home/minio-user/.minio/dietpi-cert-renewl.sh fi #---------------------------------------------------------------- exit #---------------------------------------------------------------- } _EOF_ chmod +x "$DP_MONTHLY_CRON" fi if (( $INPUT == 0 )); then echo -e "" read -p "Press any key to continue..." echo -e "" fi #Restart services /DietPi/dietpi/dietpi-services restart fi } #///////////////////////////////////////////////////////////////////////////////////// # Settings File #///////////////////////////////////////////////////////////////////////////////////// DP_SETTINGS="/DietPi/dietpi/.dietpi-letsencrypt" Read_Settings_File(){ local sed_index=1 LETSENCRYPT_DOMAIN=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) LETSENCRYPT_EMAIL=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) LETSENCRYPT_REDIRECT=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) LETSENCRYPT_AUTORENEW=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) LETSENCRYPT_KEYSIZE=$(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) } Write_Settings_File(){ cat << _EOF_ > "$DP_SETTINGS" $LETSENCRYPT_DOMAIN $LETSENCRYPT_EMAIL $LETSENCRYPT_REDIRECT $LETSENCRYPT_AUTORENEW $LETSENCRYPT_KEYSIZE _EOF_ } #///////////////////////////////////////////////////////////////////////////////////// # MENUS #///////////////////////////////////////////////////////////////////////////////////// PROGRAM_NAME="DietPi-LetsEncrypt" CHOICE=0 OPTION=0 TARGETMENUID=0 PREVIOUS_MENU_SELECTION="" Menu_Exit(){ whiptail --title "Exit $PROGRAM_NAME?" --yesno "Exit $PROGRAM_NAME?" --backtitle "$PROGRAM_NAME" --yes-button "Ok" --no-button "Back" --defaultno 9 55 CHOICE=$? if (( $CHOICE == 0 )); then #exit TARGETMENUID=-1 else #Return to Main Menu TARGETMENUID=0 fi } #TARGETMENUID=0 Menu_Main(){ local auto_renew_text="Disabled | Manual renewal every 90 days" if (( $LETSENCRYPT_AUTORENEW )); then auto_renew_text="Enabled | Automatic cron.monthly renewals" fi local redirect_text="Disabled | Allows http and https usage" if (( $LETSENCRYPT_REDIRECT )); then redirect_text="Enabled | Forces http redirects to https" fi OPTION=$(whiptail --title "$PROGRAM_NAME" --menu "Please select a option." --cancel-button "Exit" --default-item "$PREVIOUS_MENU_SELECTION" --backtitle "$PROGRAM_NAME" 14 70 6 \ "Domain" ": $LETSENCRYPT_DOMAIN" \ "Email" ": $LETSENCRYPT_EMAIL" \ "Redirect" ": $redirect_text" \ "Auto Renew" ": $auto_renew_text" \ "Key Size" ": $LETSENCRYPT_KEYSIZE" \ "Apply" "Runs Lets Encrypt with your chosen options." 3>&1 1>&2 2>&3) CHOICE=$? if (( $CHOICE == 0 )); then PREVIOUS_MENU_SELECTION=$OPTION case "$OPTION" in Domain) LETSENCRYPT_DOMAIN="$(Input_Box $LETSENCRYPT_DOMAIN Website-Domain)" ;; Email) LETSENCRYPT_EMAIL="$(Input_Box $LETSENCRYPT_EMAIL Email-Address)" ;; "Key Size") if (( $LETSENCRYPT_KEYSIZE == 2048 )); then LETSENCRYPT_KEYSIZE=4096 else LETSENCRYPT_KEYSIZE=2048 fi ;; "Auto Renew") ((LETSENCRYPT_AUTORENEW++)) if (( $LETSENCRYPT_AUTORENEW > 1 )); then LETSENCRYPT_AUTORENEW=0 fi ;; Redirect) ((LETSENCRYPT_REDIRECT++)) if (( $LETSENCRYPT_REDIRECT > 1 )); then LETSENCRYPT_REDIRECT=0 fi ;; Apply) whiptail --title "Run Lets Encrypt?" --yesno "LetsEncrypt will now be run. This will:\n- Create your free SSL cert.\n- Automatically apply and enable your SSL cert\n- NB: This process can take a long time, please be patient.\n\nWould you like to continue?" --backtitle "$PROGRAM_NAME" --yes-button "Ok" --no-button "Back" --defaultno 13 65 CHOICE=$? if (( $CHOICE == 0 )); then Write_Settings_File Run_Lets_Encrypt fi ;; esac else #Exit Menu_Exit fi } Input_Box(){ local input_value=$1 local input_desc=$2 OPTION=$(whiptail --inputbox "Please enter your $input_desc" 9 50 "$input_value" --title "Input $input_desc" 3>&1 1>&2 2>&3) CHOICE=$? if (( $CHOICE == 0 )); then input_value=$OPTION # - Prevent null values if [ -z "$input_value" ]; then input_value='NULL' fi fi echo -e "$input_value" } #///////////////////////////////////////////////////////////////////////////////////// # Main Loop #///////////////////////////////////////////////////////////////////////////////////// #Load Settings file. Generate if required. if [ ! -f "$DP_SETTINGS" ]; then Write_Settings_File else Read_Settings_File fi #----------------------------------------------------------------------------------- #Check installed if (( ! $LETSENCRYPT_INSTALLED )); then #Menu if (( $INPUT == 0 )); then G_DIETPI-NOTIFY 1 "Certbot binary not found ( $DP_LETSENCRYPT_BINARY )" G_DIETPI-NOTIFY 2 "Please install Certbot with DietPi-Software before running this program." read -p "Press any key to continue....." else echo -e "Error: Letsencrypt binary not installed ( $DP_LETSENCRYPT_BINARY )." >> "$DP_LOGFILE" fi #----------------------------------------------------------------------------------- #Menu elif (( $INPUT == 0 )); then while (( $TARGETMENUID > -1 )); do #Clear Screen buffer clear if (( $TARGETMENUID == 0 )); then Menu_Main fi done #----------------------------------------------------------------------------------- #Run elif (( $INPUT == 1 )); then Run_Lets_Encrypt fi #----------------------------------------------------------------------------------- exit #----------------------------------------------------------------------------------- }