#!/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 setglobal INPUT = '0' if [[ $1 =~ ^-?[0-9]+$ ]] { setglobal 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 #///////////////////////////////////////////////////////////////////////////////////// setglobal DP_LOGFILE = '"/var/log/dietpi-letsencrypt.log'" setglobal DP_MONTHLY_CRON = '"/etc/cron.monthly/dietpi-letsencrypt'" setglobal DP_LETSENCRYPT_BINARY = '"/usr/bin/certbot'" if sh-expr ' $G_DISTRO < 4 ' { setglobal DP_LETSENCRYPT_BINARY = '"/etc/certbot_scripts/certbot-auto'" } setglobal DP_WEBSERVER_INDEX = '0' #0=apache2 1=lighttpd 2=nginx 3=minio setglobal LETSENCRYPT_INSTALLED = '0' if test -f $DP_LETSENCRYPT_BINARY { setglobal LETSENCRYPT_INSTALLED = '1' } setglobal LETSENCRYPT_DOMAIN = '"mydomain.com'" setglobal LETSENCRYPT_EMAIL = '"myemail@email.com'" setglobal LETSENCRYPT_REDIRECT = '0' setglobal LETSENCRYPT_AUTORENEW = '0' setglobal 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 sh-expr ' $(ps aux | grep -ci -m1 '[a]pache') ' { setglobal DP_WEBSERVER_INDEX = '0' G_DIETPI-NOTIFY 0 "Apache2 webserver detected" if sh-expr ' $G_DISTRO >= 4 ' { setglobal DP_LETSENCRYPT_BINARY = ""$DP_LETSENCRYPT_BINARY --apache"" } } elif sh-expr ' $(ps aux | grep -ci -m1 '[l]ighttpd') ' { setglobal DP_WEBSERVER_INDEX = '1' G_DIETPI-NOTIFY 0 "Lighttpd webserver detected" } elif sh-expr ' $(ps aux | grep -ci -m1 '[n]ginx') ' { setglobal DP_WEBSERVER_INDEX = '2' G_DIETPI-NOTIFY 0 "Nginx webserver detected" if sh-expr ' $G_DISTRO >= 4 ' { setglobal DP_LETSENCRYPT_BINARY = ""$DP_LETSENCRYPT_BINARY --nginx"" } } elif sh-expr ' $(ps aux | grep -ci -m1 '[m]inio') ' { setglobal DP_WEBSERVER_INDEX = '3' G_DIETPI-NOTIFY 0 "Minio S3 server detected" } else { setglobal run_conditions_met = '0' } #Failed. No compatible webserver is currently running if sh-expr ' ! $run_conditions_met ' { echo -e "Error: No compatible and/or active webserver was found. Aborting." >> $DP_LOGFILE if sh-expr ' $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 sh-expr ' $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 sh-expr ' ! $(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 sh-expr ' $LETSENCRYPT_REDIRECT ' { setglobal 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 sh-expr ' $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 sh-expr ' $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 sh-expr ' $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 sh-expr ' $LETSENCRYPT_REDIRECT ' { setglobal 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 sh-expr ' $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 sh-expr ' $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 sh-expr ' $INPUT == 0 ' { echo -e "" read -p "Press any key to continue..." echo -e "" } #Restart services /DietPi/dietpi/dietpi-services restart } } #///////////////////////////////////////////////////////////////////////////////////// # Settings File #///////////////////////////////////////////////////////////////////////////////////// setglobal DP_SETTINGS = '"/DietPi/dietpi/.dietpi-letsencrypt'" proc Read_Settings_File{ local sed_index=1 setglobal LETSENCRYPT_DOMAIN = $[sed -n "$sed_index"p $DP_SETTINGS];sh-expr 'sed_index++' setglobal LETSENCRYPT_EMAIL = $[sed -n "$sed_index"p $DP_SETTINGS];sh-expr 'sed_index++' setglobal LETSENCRYPT_REDIRECT = $[sed -n "$sed_index"p $DP_SETTINGS];sh-expr 'sed_index++' setglobal LETSENCRYPT_AUTORENEW = $[sed -n "$sed_index"p $DP_SETTINGS];sh-expr 'sed_index++' setglobal LETSENCRYPT_KEYSIZE = $[sed -n "$sed_index"p $DP_SETTINGS];sh-expr '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 #///////////////////////////////////////////////////////////////////////////////////// setglobal PROGRAM_NAME = '"DietPi-LetsEncrypt'" setglobal CHOICE = '0' setglobal OPTION = '0' setglobal TARGETMENUID = '0' setglobal 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 setglobal CHOICE = $Status if sh-expr ' $CHOICE == 0 ' { #exit setglobal TARGETMENUID = '-1' } else { #Return to Main Menu setglobal TARGETMENUID = '0' } } #TARGETMENUID=0 proc Menu_Main{ local auto_renew_text="Disabled | Manual renewal every 90 days" if sh-expr ' $LETSENCRYPT_AUTORENEW ' { setglobal auto_renew_text = '"Enabled | Automatic cron.monthly renewals'" } local redirect_text="Disabled | Allows http and https usage" if sh-expr ' $LETSENCRYPT_REDIRECT ' { setglobal redirect_text = '"Enabled | Forces http redirects to https'" } setglobal 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] setglobal CHOICE = $Status if sh-expr ' $CHOICE == 0 ' { setglobal PREVIOUS_MENU_SELECTION = $OPTION match $OPTION { with Domain setglobal LETSENCRYPT_DOMAIN = $[Input_Box $LETSENCRYPT_DOMAIN Website-Domain] with Email setglobal LETSENCRYPT_EMAIL = $[Input_Box $LETSENCRYPT_EMAIL Email-Address] with "Key Size" if sh-expr ' $LETSENCRYPT_KEYSIZE == 2048 ' { setglobal LETSENCRYPT_KEYSIZE = '4096' } else { setglobal LETSENCRYPT_KEYSIZE = '2048' } with "Auto Renew" sh-expr 'LETSENCRYPT_AUTORENEW++' if sh-expr ' $LETSENCRYPT_AUTORENEW > 1 ' { setglobal LETSENCRYPT_AUTORENEW = '0' } with Redirect sh-expr 'LETSENCRYPT_REDIRECT++' if sh-expr ' $LETSENCRYPT_REDIRECT > 1 ' { setglobal LETSENCRYPT_REDIRECT = '0' } with 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 setglobal CHOICE = $Status if sh-expr ' $CHOICE == 0 ' { Write_Settings_File Run_Lets_Encrypt } } } else { #Exit Menu_Exit } } proc Input_Box{ local input_value=$1 local input_desc=$2 setglobal OPTION = $[whiptail --inputbox "Please enter your $input_desc" 9 50 $input_value --title "Input $input_desc" !3 > !1 !1 > !2 !2 > !3] setglobal CHOICE = $Status if sh-expr ' $CHOICE == 0 ' { setglobal input_value = $OPTION # - Prevent null values if test -z $input_value { setglobal 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 sh-expr ' ! $LETSENCRYPT_INSTALLED ' { #Menu if sh-expr ' $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 sh-expr ' $INPUT == 0 ' { while sh-expr ' $TARGETMENUID > -1 ' { #Clear Screen buffer clear if sh-expr ' $TARGETMENUID == 0 ' { Menu_Main } } #----------------------------------------------------------------------------------- #Run } elif sh-expr ' $INPUT == 1 ' { Run_Lets_Encrypt } #----------------------------------------------------------------------------------- exit #----------------------------------------------------------------------------------- }