#!/bin/bash do { #//////////////////////////////////// # 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 setvar INPUT = '0' if [[ $1 =~ ^-?[0-9]+$ ]] { setvar INPUT = "$1" } #Import DietPi-Globals --------------------------------------------------------------- source /DietPi/dietpi/func/dietpi-globals G_CHECK_ROOT_USER G_CHECK_ROOTFS_RW export G_PROGRAM_NAME='DietPi-Letsencrypt' #Import DietPi-Globals --------------------------------------------------------------- #///////////////////////////////////////////////////////////////////////////////////// #Globals #///////////////////////////////////////////////////////////////////////////////////// setvar DP_LOGFILE = ""/var/log/dietpi-letsencrypt.log"" setvar DP_MONTHLY_CRON = ""/etc/cron.monthly/dietpi-letsencrypt"" setvar DP_LETSENCRYPT_BINARY = ""/usr/bin/certbot"" if (( $G_DISTRO < 4 )) { setvar DP_LETSENCRYPT_BINARY = ""/etc/certbot_scripts/certbot-auto"" } setvar DP_WEBSERVER_INDEX = '0' #0=apache2 1=lighttpd 2=nginx 3=minio setvar LETSENCRYPT_INSTALLED = '0' if test -f $DP_LETSENCRYPT_BINARY { setvar LETSENCRYPT_INSTALLED = '1' } setvar LETSENCRYPT_DOMAIN = ""mydomain.com"" setvar LETSENCRYPT_EMAIL = ""myemail@email.com"" setvar LETSENCRYPT_REDIRECT = '0' setvar LETSENCRYPT_AUTORENEW = '0' setvar LETSENCRYPT_KEYSIZE = '4096' proc 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') )) { setvar DP_WEBSERVER_INDEX = '0' G_DIETPI-NOTIFY 0 "Apache2 webserver detected" if (( $G_DISTRO >= 4 )) { setvar DP_LETSENCRYPT_BINARY = ""$DP_LETSENCRYPT_BINARY --apache"" } } elif (( $(ps aux | grep -ci -m1 '[l]ighttpd') )) { setvar DP_WEBSERVER_INDEX = '1' G_DIETPI-NOTIFY 0 "Lighttpd webserver detected" } elif (( $(ps aux | grep -ci -m1 '[n]ginx') )) { setvar DP_WEBSERVER_INDEX = '2' G_DIETPI-NOTIFY 0 "Nginx webserver detected" if (( $G_DISTRO >= 4 )) { setvar DP_LETSENCRYPT_BINARY = ""$DP_LETSENCRYPT_BINARY --nginx"" } } elif (( $(ps aux | grep -ci -m1 '[m]inio') )) { setvar DP_WEBSERVER_INDEX = '3' G_DIETPI-NOTIFY 0 "Minio S3 server detected" } else { setvar run_conditions_met = '0' } #Failed. No compatible webserver is currently running if (( ! $run_conditions_met )) { echo -e "Error: No compatible and/or active webserver was found. Aborting." >> "$DP_LOGFILE" if (( $INPUT == 0 )) { whiptail --title "Error" --msgbox "Error: No compatible and/or active webserver was found. Aborting." --backtitle $PROGRAM_NAME 8 60 } #Cert up } else { #------------------------------------------------------------------------------------------------------ #apache2 if (( $DP_WEBSERVER_INDEX == 0 )) { 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') )) { sed -i "/ServerAdmin /a ServerName" $dp_defaultsite #log echo -e "ServerName entry not found in $dp_defaultsite. Adding it now." >> "$DP_LOGFILE" } #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 )) { setvar cli_redirect = ""--redirect"" } #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 )) { # - 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 <<< """ > /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" } """ > /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 )) { cat <<< """ > /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") } } """ > /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_ } /etc/init.d/lighttpd force-reload #------------------------------------------------------------------------------------------------------ # Nginx } elif (( $DP_WEBSERVER_INDEX == 2 )) { 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 )) { setvar cli_redirect = ""--redirect"" } #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 )) { # - 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 <<< """ >> /etc/default/minio # Use if you want to run Minio on a custom port. MINIO_OPTS="--address :443" """ >> /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 <<< """ > /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 """ > /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 } #------------------------------------------------------------------------------------------------------ #ALL | Create cron job if (( $LETSENCRYPT_AUTORENEW && $G_DISTRO < 4 )) { cat <<< """ > "$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 #---------------------------------------------------------------- } """ > "$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 } if (( $INPUT == 0 )) { echo -e "" read -p "Press any key to continue..." echo -e "" } #Restart services /DietPi/dietpi/dietpi-services restart } } #///////////////////////////////////////////////////////////////////////////////////// # Settings File #///////////////////////////////////////////////////////////////////////////////////// setvar DP_SETTINGS = ""/DietPi/dietpi/.dietpi-letsencrypt"" proc Read_Settings_File { local sed_index=1 setvar LETSENCRYPT_DOMAIN = $(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) setvar LETSENCRYPT_EMAIL = $(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) setvar LETSENCRYPT_REDIRECT = $(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) setvar LETSENCRYPT_AUTORENEW = $(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) setvar LETSENCRYPT_KEYSIZE = $(sed -n "$sed_index"p $DP_SETTINGS);((sed_index++)) } proc Write_Settings_File { cat <<< """ > "$DP_SETTINGS" $LETSENCRYPT_DOMAIN $LETSENCRYPT_EMAIL $LETSENCRYPT_REDIRECT $LETSENCRYPT_AUTORENEW $LETSENCRYPT_KEYSIZE """ > "$DP_SETTINGS" $LETSENCRYPT_DOMAIN $LETSENCRYPT_EMAIL $LETSENCRYPT_REDIRECT $LETSENCRYPT_AUTORENEW $LETSENCRYPT_KEYSIZE _EOF_ } #///////////////////////////////////////////////////////////////////////////////////// # MENUS #///////////////////////////////////////////////////////////////////////////////////// setvar PROGRAM_NAME = ""DietPi-LetsEncrypt"" setvar CHOICE = '0' setvar OPTION = '0' setvar TARGETMENUID = '0' setvar PREVIOUS_MENU_SELECTION = """" proc Menu_Exit { whiptail --title "Exit $PROGRAM_NAME?" --yesno "Exit $PROGRAM_NAME?" --backtitle $PROGRAM_NAME --yes-button "Ok" --no-button "Back" --defaultno 9 55 setvar CHOICE = ""$? if (( $CHOICE == 0 )) { #exit setvar TARGETMENUID = '-1' } else { #Return to Main Menu setvar TARGETMENUID = '0' } } #TARGETMENUID=0 proc Menu_Main { local auto_renew_text="Disabled | Manual renewal every 90 days" if (( $LETSENCRYPT_AUTORENEW )) { setvar auto_renew_text = ""Enabled | Automatic cron.monthly renewals"" } local redirect_text="Disabled | Allows http and https usage" if (( $LETSENCRYPT_REDIRECT )) { setvar redirect_text = ""Enabled | Forces http redirects to https"" } setvar 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) setvar CHOICE = ""$? if (( $CHOICE == 0 )) { setvar PREVIOUS_MENU_SELECTION = "$OPTION" case (OPTION) { Domain { setvar LETSENCRYPT_DOMAIN = "$(Input_Box $LETSENCRYPT_DOMAIN Website-Domain)" } Email { setvar LETSENCRYPT_EMAIL = "$(Input_Box $LETSENCRYPT_EMAIL Email-Address)" } "Key Size" { if (( $LETSENCRYPT_KEYSIZE == 2048 )) { setvar LETSENCRYPT_KEYSIZE = '4096' } else { setvar LETSENCRYPT_KEYSIZE = '2048' } } "Auto Renew" { ((LETSENCRYPT_AUTORENEW++)) if (( $LETSENCRYPT_AUTORENEW > 1 )) { setvar LETSENCRYPT_AUTORENEW = '0' } } Redirect { ((LETSENCRYPT_REDIRECT++)) if (( $LETSENCRYPT_REDIRECT > 1 )) { setvar LETSENCRYPT_REDIRECT = '0' } } 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 setvar CHOICE = ""$? if (( $CHOICE == 0 )) { Write_Settings_File Run_Lets_Encrypt } } } } else { #Exit Menu_Exit } } proc Input_Box { local input_value=$1 local input_desc=$2 setvar OPTION = $(whiptail --inputbox "Please enter your $input_desc" 9 50 "$input_value" --title "Input $input_desc" 3>&1 1>&2 2>&3) setvar CHOICE = ""$? if (( $CHOICE == 0 )) { setvar input_value = "$OPTION" # - Prevent null values if test -z $input_value { setvar input_value = ''NULL'' } } echo -e $input_value } #///////////////////////////////////////////////////////////////////////////////////// # Main Loop #///////////////////////////////////////////////////////////////////////////////////// #Load Settings file. Generate if required. if test ! -f $DP_SETTINGS { Write_Settings_File } else { Read_Settings_File } #----------------------------------------------------------------------------------- #Check installed if (( ! $LETSENCRYPT_INSTALLED )) { #Menu if (( $INPUT == 0 )) { 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" } #----------------------------------------------------------------------------------- #Menu } elif (( $INPUT == 0 )) { { #Clear Screen buffer clear if (( $TARGETMENUID == 0 )) { Menu_Main } } #----------------------------------------------------------------------------------- #Run } elif (( $INPUT == 1 )) { Run_Lets_Encrypt } #----------------------------------------------------------------------------------- exit #----------------------------------------------------------------------------------- }