TrulyInsane1

Proxmox - Disable laptop lid and sleep

Jan 4th, 2026
1,715
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 7.35 KB | None | 0 0
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3.  
  4. # -----------------------------------------------------------------------------
  5. # disable-lid-sleep-proxmox.sh
  6. #
  7. # Purpose:
  8. #   Configure a Proxmox/Debian host (especially laptops) to ignore the lid switch
  9. #   and prevent any suspend/hibernate when the lid is closed.
  10. #
  11. # What it does:
  12. #   1) Configures systemd-logind to ignore lid close events
  13. #   2) Masks sleep/suspend/hibernate targets (hard stop)
  14. #   3) Disables console blanking via GRUB (consoleblank=0)
  15. #   4) Installs a systemd oneshot service to disable setterm blanking/powersave
  16. #
  17. # Safe features:
  18. #   - Makes backups before editing files
  19. #   - Idempotent: re-running won't duplicate config
  20. #   - Verifies systemd + grub tools exist
  21. #
  22. # Usage:
  23. #   sudo ./disable-lid-sleep-proxmox.sh
  24. #
  25. # Optional:
  26. #   sudo ./disable-lid-sleep-proxmox.sh --undo
  27. # -----------------------------------------------------------------------------
  28.  
  29. SCRIPT_NAME="$(basename "$0")"
  30. STAMP="$(date +%Y%m%d-%H%M%S)"
  31.  
  32. require_root() {
  33.   if [[ "${EUID}" -ne 0 ]]; then
  34.     echo "ERROR: Must be run as root. Use: sudo ./${SCRIPT_NAME}"
  35.     exit 1
  36.   fi
  37. }
  38.  
  39. has_cmd() { command -v "$1" >/dev/null 2>&1; }
  40.  
  41. backup_file() {
  42.   local f="$1"
  43.   if [[ -f "$f" ]]; then
  44.     cp -a "$f" "${f}.bak.${STAMP}"
  45.     echo "Backup created: ${f}.bak.${STAMP}"
  46.   fi
  47. }
  48.  
  49. ensure_line_in_file() {
  50.   local file="$1"
  51.   local line="$2"
  52.  
  53.   mkdir -p "$(dirname "$file")"
  54.   touch "$file"
  55.  
  56.   if ! grep -Fxq "$line" "$file"; then
  57.     echo "$line" >> "$file"
  58.     echo "Added to $file: $line"
  59.   else
  60.     echo "Already present in $file: $line"
  61.   fi
  62. }
  63.  
  64. set_or_replace_keyvalue() {
  65.   # Sets key=value in a config file (logind.conf style), uncommenting if needed.
  66.   local file="$1"
  67.   local key="$2"
  68.   local value="$3"
  69.  
  70.   mkdir -p "$(dirname "$file")"
  71.   touch "$file"
  72.  
  73.   if grep -Eq "^[#[:space:]]*${key}=" "$file"; then
  74.     sed -i -E "s|^[#[:space:]]*(${key}=).*|\1${value}|" "$file"
  75.     echo "Set $key=$value in $file"
  76.   else
  77.     echo "${key}=${value}" >> "$file"
  78.     echo "Appended $key=$value to $file"
  79.   fi
  80. }
  81.  
  82. mask_sleep_targets() {
  83.   local targets=(
  84.     sleep.target
  85.     suspend.target
  86.     hibernate.target
  87.     hybrid-sleep.target
  88.   )
  89.  
  90.   for t in "${targets[@]}"; do
  91.     systemctl mask "$t" >/dev/null 2>&1 || true
  92.     echo "Masked: $t"
  93.   done
  94. }
  95.  
  96. unmask_sleep_targets() {
  97.   local targets=(
  98.     sleep.target
  99.     suspend.target
  100.     hibernate.target
  101.     hybrid-sleep.target
  102.   )
  103.  
  104.   for t in "${targets[@]}"; do
  105.     systemctl unmask "$t" >/dev/null 2>&1 || true
  106.     echo "Unmasked: $t"
  107.   done
  108. }
  109.  
  110. install_dpms_service() {
  111.   local svc="/etc/systemd/system/disable-dpms.service"
  112.  
  113.   backup_file "$svc"
  114.  
  115.   cat > "$svc" <<'EOF'
  116. [Unit]
  117. Description=Disable monitor sleep / console blanking on boot
  118.  
  119. [Service]
  120. Type=oneshot
  121. ExecStart=/usr/bin/setterm -blank 0 -powersave off -powerdown 0
  122.  
  123. [Install]
  124. WantedBy=multi-user.target
  125. EOF
  126.  
  127.   systemctl daemon-reload
  128.   systemctl enable --now disable-dpms.service
  129.   echo "Installed & enabled: disable-dpms.service"
  130. }
  131.  
  132. remove_dpms_service() {
  133.   local svc="/etc/systemd/system/disable-dpms.service"
  134.   if [[ -f "$svc" ]]; then
  135.     systemctl disable --now disable-dpms.service >/dev/null 2>&1 || true
  136.     rm -f "$svc"
  137.     systemctl daemon-reload
  138.     echo "Removed: disable-dpms.service"
  139.   else
  140.     echo "disable-dpms.service not found; skipping."
  141.   fi
  142. }
  143.  
  144. configure_logind() {
  145.   local f="/etc/systemd/logind.conf"
  146.   backup_file "$f"
  147.  
  148.   set_or_replace_keyvalue "$f" "HandleLidSwitch" "ignore"
  149.   set_or_replace_keyvalue "$f" "HandleLidSwitchExternalPower" "ignore"
  150.   set_or_replace_keyvalue "$f" "HandleLidSwitchDocked" "ignore"
  151.   set_or_replace_keyvalue "$f" "LidSwitchIgnoreInhibited" "no"
  152.  
  153.   systemctl restart systemd-logind
  154.   echo "Restarted: systemd-logind"
  155. }
  156.  
  157. undo_logind() {
  158.   # We don't "restore defaults" perfectly (depends on distro), but we do remove
  159.   # the explicit settings by commenting them out if present.
  160.   local f="/etc/systemd/logind.conf"
  161.   if [[ -f "$f" ]]; then
  162.     backup_file "$f"
  163.     sed -i -E \
  164.       -e 's|^(HandleLidSwitch=)|#\1|' \
  165.       -e 's|^(HandleLidSwitchExternalPower=)|#\1|' \
  166.       -e 's|^(HandleLidSwitchDocked=)|#\1|' \
  167.       -e 's|^(LidSwitchIgnoreInhibited=)|#\1|' \
  168.       "$f"
  169.     systemctl restart systemd-logind
  170.     echo "Commented out lid settings in $f and restarted logind."
  171.   else
  172.     echo "$f not found; skipping."
  173.   fi
  174. }
  175.  
  176. configure_grub_consoleblank() {
  177.   if ! has_cmd update-grub && ! has_cmd grub-mkconfig; then
  178.     echo "WARNING: Neither update-grub nor grub-mkconfig found; skipping GRUB step."
  179.     return 0
  180.   fi
  181.  
  182.   local f="/etc/default/grub.d/nolidsleep.cfg"
  183.   mkdir -p /etc/default/grub.d
  184.   backup_file "$f"
  185.  
  186.   # Ensure the commandline includes consoleblank=0 without duplicating.
  187.   if [[ -f "$f" ]] && grep -q 'consoleblank=0' "$f"; then
  188.     echo "GRUB consoleblank already configured in $f"
  189.   else
  190.     cat > "$f" <<'EOF'
  191. # Keep the local console from blanking (useful on laptop Proxmox installs)
  192. GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT consoleblank=0"
  193. EOF
  194.     echo "Wrote GRUB config snippet: $f"
  195.   fi
  196.  
  197.   if has_cmd update-grub; then
  198.     update-grub
  199.     echo "Ran: update-grub"
  200.   else
  201.     # Fallback (uncommon on Debian/Proxmox, but harmless)
  202.     grub-mkconfig -o /boot/grub/grub.cfg
  203.     echo "Ran: grub-mkconfig -o /boot/grub/grub.cfg"
  204.   fi
  205. }
  206.  
  207. undo_grub_consoleblank() {
  208.   local f="/etc/default/grub.d/nolidsleep.cfg"
  209.   if [[ -f "$f" ]]; then
  210.     backup_file "$f"
  211.     rm -f "$f"
  212.     echo "Removed: $f"
  213.  
  214.     if has_cmd update-grub; then
  215.       update-grub
  216.       echo "Ran: update-grub"
  217.     elif has_cmd grub-mkconfig; then
  218.       grub-mkconfig -o /boot/grub/grub.cfg
  219.       echo "Ran: grub-mkconfig -o /boot/grub/grub.cfg"
  220.     else
  221.       echo "WARNING: No grub update tool found; GRUB not regenerated."
  222.     fi
  223.   else
  224.     echo "$f not found; skipping."
  225.   fi
  226. }
  227.  
  228. show_status() {
  229.   echo
  230.   echo "---- STATUS CHECKS ----"
  231.   echo "logind.conf lid settings:"
  232.   grep -E '^(#\s*)?(HandleLidSwitch|HandleLidSwitchExternalPower|HandleLidSwitchDocked|LidSwitchIgnoreInhibited)=' \
  233.     /etc/systemd/logind.conf 2>/dev/null || echo "(no matching lines found)"
  234.  
  235.   echo
  236.   echo "Masked sleep targets:"
  237.   for t in sleep.target suspend.target hibernate.target hybrid-sleep.target; do
  238.     systemctl is-enabled "$t" 2>/dev/null || true
  239.   done
  240.  
  241.   echo
  242.   echo "DPMS service:"
  243.   systemctl status disable-dpms.service --no-pager -l 2>/dev/null || echo "(service not installed)"
  244.  
  245.   echo
  246.   echo "GRUB snippet:"
  247.   if [[ -f /etc/default/grub.d/nolidsleep.cfg ]]; then
  248.     cat /etc/default/grub.d/nolidsleep.cfg
  249.   else
  250.     echo "(not present)"
  251.   fi
  252.   echo "-----------------------"
  253.   echo
  254. }
  255.  
  256. main() {
  257.   require_root
  258.  
  259.   local mode="apply"
  260.   if [[ "${1:-}" == "--undo" ]]; then
  261.     mode="undo"
  262.   fi
  263.  
  264.   if [[ "$mode" == "apply" ]]; then
  265.     echo "Applying lid-close ignore + anti-sleep configuration..."
  266.     configure_logind
  267.     mask_sleep_targets
  268.     configure_grub_consoleblank
  269.     install_dpms_service
  270.     show_status
  271.     echo "DONE. Reboot recommended to ensure GRUB consoleblank=0 takes effect:"
  272.     echo "  reboot"
  273.   else
  274.     echo "Undoing configuration..."
  275.     undo_logind
  276.     unmask_sleep_targets
  277.     undo_grub_consoleblank
  278.     remove_dpms_service
  279.     show_status
  280.     echo "DONE. Reboot recommended:"
  281.     echo "  reboot"
  282.   fi
  283. }
  284.  
  285. main "$@"
  286.  
Advertisement