Skip to content

Instantly share code, notes, and snippets.

@amitkhare
Last active June 24, 2026 11:53
Show Gist options
  • Select an option

  • Save amitkhare/662a985619a9ef2a2546a7762b0cf703 to your computer and use it in GitHub Desktop.

Select an option

Save amitkhare/662a985619a9ef2a2546a7762b0cf703 to your computer and use it in GitHub Desktop.
Set up daily scheduled reboot, hardware watchdog, and emergency hard‑reset on Raspberry Pi for maximum uptime and self‑recovery.
#!/bin/bash
# Raspberry Pi Resilience Toolkit
# Interactive installer for scheduled reboots, hardware watchdog, and emergency reset
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Ensure the script is run as root
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}ERROR: Please run this script as root (use sudo).${NC}"
exit 1
fi
# --------------------------------------------------------
# Utility Functions
# --------------------------------------------------------
print_header() {
echo ""
echo "=================================================="
echo " Raspberry Pi Resilience Toolkit"
echo "=================================================="
}
print_section() {
echo ""
echo -e "${BLUE}[$1]${NC} $2"
echo "-----------------------------------------------"
}
success_msg() {
echo -e "${GREEN}✓${NC} $1"
}
warn_msg() {
echo -e "${YELLOW}⚠${NC} $1"
}
error_msg() {
echo -e "${RED}✗${NC} $1"
}
check_raspberry_pi() {
if grep -q "Raspberry Pi" /proc/device-tree/model 2>/dev/null || \
grep -q "BCM" /proc/cpuinfo 2>/dev/null; then
return 0
else
warn_msg "This system doesn't appear to be a Raspberry Pi."
echo -n "Continue anyway? (y/N): "
read -r response
[[ "$response" =~ ^[Yy]$ ]] || exit 0
return 1
fi
}
remount_boot_rw() {
local boot_path="$1"
if [ -f "$boot_path" ] && ! touch "$boot_path" 2>/dev/null; then
echo "-> Boot partition is read-only, remounting..."
mount -o remount,rw "$(dirname "$boot_path")" || {
error_msg "Failed to remount boot partition as writable"
return 1
}
return 0
fi
}
# --------------------------------------------------------
# Component Functions - Cron Scheduled Reboot
# --------------------------------------------------------
install_cron_reboot() {
print_section "CRON" "Setting up daily scheduled reboot at midnight"
local CRON_JOB="0 0 * * * /sbin/shutdown -r now"
if crontab -l 2>/dev/null | grep -Fq "$CRON_JOB"; then
warn_msg "Cron job already exists. Skipping installation."
return 0
fi
if crontab -l 2>/dev/null | { cat; echo "$CRON_JOB"; } | crontab -; then
success_msg "Daily midnight reboot added to root crontab."
echo " Schedule: Every day at 00:00 (midnight)"
return 0
else
error_msg "Failed to add cron job."
return 1
fi
}
uninstall_cron_reboot() {
print_section "CRON" "Removing daily scheduled reboot"
if ! crontab -l 2>/dev/null | grep -Fq "shutdown -r now"; then
warn_msg "No scheduled reboot found in crontab."
return 0
fi
# Remove the specific line while keeping other cron jobs
crontab -l 2>/dev/null | grep -Fv "shutdown -r now" | crontab -
if [ $? -eq 0 ]; then
success_msg "Scheduled reboot removed from crontab."
return 0
else
error_msg "Failed to remove cron job."
return 1
fi
}
check_cron_reboot() {
if crontab -l 2>/dev/null | grep -Fq "shutdown -r now"; then
echo -e " Status: ${GREEN}Installed${NC}"
return 0
else
echo -e " Status: ${RED}Not installed${NC}"
return 1
fi
}
# --------------------------------------------------------
# Component Functions - Hardware Watchdog
# --------------------------------------------------------
install_watchdog() {
print_section "WATCHDOG" "Setting up hardware watchdog for system hang recovery"
# Find config.txt
local CONFIG_FILE=""
if [ -f "/boot/firmware/config.txt" ]; then
CONFIG_FILE="/boot/firmware/config.txt"
elif [ -f "/boot/config.txt" ]; then
CONFIG_FILE="/boot/config.txt"
else
error_msg "Could not find config.txt on the boot partition."
return 1
fi
echo "-> Using config file: $CONFIG_FILE"
# Remount boot if needed
remount_boot_rw "$CONFIG_FILE" || return 1
# Enable hardware watchdog in firmware config
if grep -q "^dtparam=watchdog=on" "$CONFIG_FILE"; then
success_msg "Watchdog already enabled in $CONFIG_FILE."
elif grep -q "#dtparam=watchdog=on" "$CONFIG_FILE"; then
sed -i 's|#dtparam=watchdog=on|dtparam=watchdog=on|g' "$CONFIG_FILE"
success_msg "Uncommented watchdog parameter in $CONFIG_FILE."
else
echo "dtparam=watchdog=on" >> "$CONFIG_FILE"
success_msg "Added watchdog overlay to $CONFIG_FILE."
fi
# Install watchdog package if not present
if ! command -v watchdog &>/dev/null; then
echo "-> Installing watchdog package..."
if apt update -qq && apt install -y watchdog; then
success_msg "Watchdog package installed."
else
error_msg "Failed to install watchdog package."
return 1
fi
else
success_msg "Watchdog package already installed."
fi
# Configure watchdog daemon
local WATCHDOG_CONF="/etc/watchdog.conf"
if [ -f "$WATCHDOG_CONF" ]; then
echo "-> Configuring $WATCHDOG_CONF..."
# Create backup only if one doesn't exist
if [ ! -f "${WATCHDOG_CONF}.backup" ]; then
cp "$WATCHDOG_CONF" "${WATCHDOG_CONF}.backup"
success_msg "Backup created at ${WATCHDOG_CONF}.backup"
fi
# Enable settings
if grep -q "^#watchdog-device" "$WATCHDOG_CONF"; then
sed -i 's|^#watchdog-device|watchdog-device|g' "$WATCHDOG_CONF"
success_msg "Enabled watchdog device."
fi
if grep -q "^#max-temperature" "$WATCHDOG_CONF"; then
sed -i 's|^#max-temperature|max-temperature|g' "$WATCHDOG_CONF"
success_msg "Enabled max temperature monitoring."
fi
# Set timeout
if ! grep -q "^watchdog-timeout" "$WATCHDOG_CONF"; then
echo "watchdog-timeout = 15" >> "$WATCHDOG_CONF"
success_msg "Set watchdog timeout to 15 seconds."
fi
else
warn_msg "$WATCHDOG_CONF not found. Creating minimal config..."
cat > "$WATCHDOG_CONF" << 'EOF'
watchdog-device = /dev/watchdog
watchdog-timeout = 15
max-temperature = 80
EOF
success_msg "Created default watchdog configuration."
fi
# Enable and start service
echo "-> Starting watchdog service..."
if systemctl enable watchdog && systemctl restart watchdog; then
if systemctl is-active --quiet watchdog; then
success_msg "Watchdog service is active and running."
else
warn_msg "Watchdog service enabled but not running. A reboot may be needed."
fi
return 0
else
error_msg "Failed to enable/start watchdog service."
return 1
fi
}
uninstall_watchdog() {
print_section "WATCHDOG" "Removing hardware watchdog"
local made_changes=false
# Stop and disable service
if systemctl is-active --quiet watchdog 2>/dev/null; then
echo "-> Stopping watchdog service..."
systemctl stop watchdog
success_msg "Watchdog service stopped."
made_changes=true
fi
if systemctl is-enabled --quiet watchdog 2>/dev/null; then
echo "-> Disabling watchdog service..."
systemctl disable watchdog
success_msg "Watchdog service disabled."
made_changes=true
fi
# Restore config backup if exists
local WATCHDOG_CONF="/etc/watchdog.conf"
if [ -f "${WATCHDOG_CONF}.backup" ]; then
echo "-> Restoring original configuration..."
cp "${WATCHDOG_CONF}.backup" "$WATCHDOG_CONF"
success_msg "Original watchdog configuration restored."
made_changes=true
fi
# Remove dtparam from config.txt
local CONFIG_FILE=""
if [ -f "/boot/firmware/config.txt" ]; then
CONFIG_FILE="/boot/firmware/config.txt"
elif [ -f "/boot/config.txt" ]; then
CONFIG_FILE="/boot/config.txt"
fi
if [ -n "$CONFIG_FILE" ] && grep -q "^dtparam=watchdog=on" "$CONFIG_FILE"; then
remount_boot_rw "$CONFIG_FILE" 2>/dev/null
echo "-> Removing watchdog overlay from $CONFIG_FILE..."
sed -i '/^dtparam=watchdog=on/d' "$CONFIG_FILE"
success_msg "Watchdog overlay removed from $CONFIG_FILE."
made_changes=true
fi
# Option to remove package
if dpkg -l | grep -q "^ii.*watchdog"; then
echo ""
echo -n "Remove watchdog package also? (y/N): "
read -r remove_pkg
if [[ "$remove_pkg" =~ ^[Yy]$ ]]; then
apt purge -y watchdog
success_msg "Watchdog package removed."
made_changes=true
else
warn_msg "Watchdog package kept. It can be removed later with: sudo apt purge watchdog"
fi
fi
if [ "$made_changes" = true ]; then
success_msg "Watchdog has been removed."
echo " Note: A reboot may be required to fully disable the hardware watchdog."
else
warn_msg "No watchdog configuration found to remove."
fi
}
check_watchdog() {
local installed=false
# Check for dtparam
if [ -f "/boot/firmware/config.txt" ] && grep -q "^dtparam=watchdog=on" "/boot/firmware/config.txt" 2>/dev/null; then
installed=true
elif [ -f "/boot/config.txt" ] && grep -q "^dtparam=watchdog=on" "/boot/config.txt" 2>/dev/null; then
installed=true
fi
# Check service is running
if systemctl is-active --quiet watchdog 2>/dev/null; then
installed=true
echo -e " Status: ${GREEN}Installed and active${NC}"
elif [ "$installed" = true ]; then
echo -e " Status: ${YELLOW}Partially installed (reboot needed)${NC}"
else
echo -e " Status: ${RED}Not installed${NC}"
fi
}
# --------------------------------------------------------
# Component Functions - Emergency Power Cycle
# --------------------------------------------------------
install_emergency_script() {
print_section "EMERGENCY RESET" "Setting up hard power cycle script"
local SCRIPT_PATH="/usr/local/bin/hard_power_cycle.sh"
if [ -f "$SCRIPT_PATH" ]; then
warn_msg "Emergency script already exists at $SCRIPT_PATH"
echo -n "Overwrite? (y/N): "
read -r reply
[[ "$reply" =~ ^[Yy]$ ]] || {
warn_msg "Keeping existing script."
return 0
}
fi
cat > "$SCRIPT_PATH" << 'SCRIPT_EOF'
#!/bin/bash
# Emergency Hard Power Cycle Script
# Forces an immediate hardware-level reboot, bypassing OS shutdown
# Usage: sudo hard_power_cycle.sh
echo "WARNING: Triggering immediate hardware power cycle!"
echo "All unsaved data will be lost!"
echo ""
echo "You have 5 seconds to cancel (Ctrl+C)..."
sleep 5
echo "Proceeding with emergency reset..."
sync
sync
# Method 1: For Raspberry Pi 4/5 - use PMIC (Power Management IC)
if command -v vcgencmd &>/dev/null; then
echo "Attempting Raspberry Pi PMIC reset..."
vcgencmd power_monitor 0 2>/dev/null
if [ $? -ne 0 ]; then
echo "PMIC command failed, falling back to kernel SysRq."
fi
fi
# Method 2: Universal kernel reboot via SysRq
echo "Issuing emergency reboot via SysRq..."
echo 1 > /proc/sys/kernel/sysrq 2>/dev/null
echo b > /proc/sysrq-trigger 2>/dev/null
# If we reach here, all methods failed
echo "CRITICAL: All reset methods failed!"
echo "System may require manual power cycle."
exit 1
SCRIPT_EOF
chmod 755 "$SCRIPT_PATH"
success_msg "Emergency power cycle script created at $SCRIPT_PATH"
echo " Usage: sudo hard_power_cycle.sh"
return 0
}
uninstall_emergency_script() {
print_section "EMERGENCY RESET" "Removing hard power cycle script"
local SCRIPT_PATH="/usr/local/bin/hard_power_cycle.sh"
if [ -f "$SCRIPT_PATH" ]; then
rm -f "$SCRIPT_PATH"
success_msg "Emergency script removed from $SCRIPT_PATH"
else
warn_msg "Emergency script not found. Nothing to remove."
fi
}
check_emergency_script() {
if [ -f "/usr/local/bin/hard_power_cycle.sh" ]; then
echo -e " Status: ${GREEN}Installed${NC}"
return 0
else
echo -e " Status: ${RED}Not installed${NC}"
return 1
fi
}
# --------------------------------------------------------
# Status / Overview Display
# --------------------------------------------------------
show_status() {
print_header
echo ""
echo -e "${BLUE}Current Component Status:${NC}"
echo ""
echo "1. Scheduled Reboot (Cron)"
check_cron_reboot
echo ""
echo "2. Hardware Watchdog"
check_watchdog
echo ""
echo "3. Emergency Power Cycle Script"
check_emergency_script
echo ""
}
# --------------------------------------------------------
# Interactive Menu
# --------------------------------------------------------
show_menu() {
print_header
echo ""
echo "What would you like to do?"
echo ""
echo " ${GREEN}1${NC}) Install/Enable components"
echo " ${RED}2${NC}) Uninstall/Disable components"
echo " ${BLUE}3${NC}) Show current status"
echo " ${YELLOW}4${NC}) Install ALL components"
echo " ${RED}5${NC}) Uninstall ALL components"
echo " ${NC}0${NC}) Exit"
echo ""
echo -n "Select option [0-5]: "
}
component_menu() {
local action="$1" # "install" or "uninstall"
local verb="$2" # "Install" or "Uninstall"
while true; do
echo ""
echo "=================================================="
echo " $verb Components"
echo "=================================================="
echo ""
echo " 1) Scheduled Reboot (Cron)"
echo " 2) Hardware Watchdog"
echo " 3) Emergency Power Cycle Script"
echo " 4) ALL components"
echo " 0) Back to main menu"
echo ""
echo -n "Select component [0-4]: "
read -r choice
case $choice in
1) $action"_cron_reboot"; break ;;
2) $action"_watchdog"; break ;;
3) $action"_emergency_script"; break ;;
4)
echo ""
echo -n "$verb ALL components? (y/N): "
read -r confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo ""
if [ "$action" = "install" ]; then
install_cron_reboot
echo ""
install_watchdog
echo ""
install_emergency_script
else
uninstall_cron_reboot
echo ""
uninstall_watchdog
echo ""
uninstall_emergency_script
fi
echo ""
echo "=================================================="
echo -e "${GREEN}All components ${verb}ed!${NC}"
echo "=================================================="
if [ "$action" = "install" ] && grep -q "^dtparam=watchdog=on" "/boot/firmware/config.txt" 2>/dev/null; then
echo ""
warn_msg "A reboot is recommended to activate hardware watchdog."
echo -n "Reboot now? (y/N): "
read -r reboot_now
[[ "$reboot_now" =~ ^[Yy]$ ]] && reboot
fi
fi
break
;;
0) return ;;
*) error_msg "Invalid option." ;;
esac
done
}
# --------------------------------------------------------
# Main Script Execution
# --------------------------------------------------------
main() {
# Initial check
if ! grep -q "Raspberry Pi" /proc/device-tree/model 2>/dev/null && \
! grep -q "BCM" /proc/cpuinfo 2>/dev/null; then
warn_msg "This system doesn't appear to be a Raspberry Pi."
echo "Some features may not work correctly on other hardware."
echo -n "Continue anyway? (y/N): "
read -r response
[[ "$response" =~ ^[Yy]$ ]] || exit 0
fi
while true; do
show_menu
read -r option
case $option in
1)
component_menu "install" "Install"
;;
2)
component_menu "uninstall" "Uninstall"
;;
3)
show_status
echo ""
echo -n "Press Enter to return to menu..."
read -r
;;
4)
echo ""
echo -n "Install ALL components? (y/N): "
read -r confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
install_cron_reboot
echo ""
install_watchdog
echo ""
install_emergency_script
echo ""
echo "=================================================="
success_msg "All components installed!"
echo "=================================================="
if grep -q "^dtparam=watchdog=on" "/boot/firmware/config.txt" 2>/dev/null || \
grep -q "^dtparam=watchdog=on" "/boot/config.txt" 2>/dev/null; then
echo ""
warn_msg "A reboot is recommended to activate hardware watchdog."
echo -n "Reboot now? (y/N): "
read -r reboot_now
[[ "$reboot_now" =~ ^[Yy]$ ]] && reboot
fi
fi
;;
5)
echo ""
echo -e "${RED}WARNING: This will remove all resilience components.${NC}"
echo -n "Uninstall ALL components? (y/N): "
read -r confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
uninstall_cron_reboot
echo ""
uninstall_watchdog
echo ""
uninstall_emergency_script
echo ""
echo "=================================================="
success_msg "All components uninstalled!"
echo "=================================================="
fi
;;
0)
echo ""
success_msg "Goodbye!"
exit 0
;;
*)
error_msg "Invalid option. Please select 0-5."
sleep 1
;;
esac
done
}
# Run main function
main
@amitkhare

Copy link
Copy Markdown
Author

Raspberry Pi Resilience Toolkit

A single script that hardens your Raspberry Pi against crashes and hangs by installing three layers of automatic recovery:

  • Nightly reboot – prevents memory leaks and slowdowns over time
  • Hardware watchdog – detects system freezes and reboots within 15 seconds
  • Emergency reset script – forces a hardware-level power cycle when all else fails
  • Interactive menu. Safe and reversible. Ideal for headless, remote, or unattended Pi deployments.

Run it: sudo ./resilience.sh

Let me know if you need it shorter, longer, or tailored for a specific audience (e.g., GitHub README, forum post, project documentation).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment