AUTOMATION - Gracefully Shutdown VM's & ESXi Host via SSH

Hi All,

Here is a simple guide on how to automatically execute commands within Home Assistant to your ESXi Host.

List of guide and links that I use to make it happen. Credit to them!

  1. Guide: Start up and shut down remote linux PC using Home Assistant

  2. ESXi keeps prompting for password after adding ssh public key to authorized_keys

  3. Home Assistant Shell Integration: Local & SSH Linux Control

For starters, below is the list of my environment setup information:

  1. ESXi Host - Intel NUC11PAHi7

  2. NAS Storage - Synology DS420+

  3. ESXi Version - ESXi-8.0.0-20513097-standard (VMware, Inc.)

  4. Home Assistant Version - Home Assistant 2023.1.7

  5. Supervisor Version - Supervisor 2023.01.1

  6. Operating System Version - Operating System 9.4

  7. Frontend Version - Frontend 20230110.0 - latest

Prerequisite:

*** Disclaimer *** 
Always make a full backup for all the related devices and system which involve in the activities.
You have been warned

ESXi Host

1. Enable SSH on ESXi

  • Select the TSM-SSH entry on the list
  • Click Actions - > Policy
  • Choose Start and stop with host, and the SSH service will activate after every host restart

2. Enable Autostart on ESXi

  • Select System
  • Click Edit Setting - > Enable (choose Yes)

Home Assistant Instance

1. Install official ‘SSH & Web Terminal’ Add-on

  • Untick the 'Protection mode’
  • Start the Add-on after installation
  • Open the Web UI

2. Creating SSH key pair

mkdir /config/ssh_keys
ssh-keygen -t rsa -b 4096 -f /config/ssh_keys/id_rsa_homeassistant
  • When a password is queried, leave it empty. If fulfilled with password the SSH connection will require both key and password and can’t be used for remote commands by home assistant
  • In above lines we first create a directory for our ssh keys, because Home Assistant is run in a docker container and does not have visibility to default /root/.ssh folder at all
  • Second line starts the key generation. The ssh key is generated with by default 2048 bits, but should be 4096 bits

3. Next we are going to copy the public key to our remote ESXi Host

cat /config/ssh_keys/id_rsa_homeassistant.pub | ssh username@remote_esxi_host_ip 'cat >>/etc/ssh/keys-root/authorized_keys'
  • Please change the ‘username’ according to user created for SSH
  • Please change the ‘remote_esxi_host_ip’ according to your ESXi Host IP’s

4. Verify that it’s working by SSH’ing into ESXi Host from Home Assistant shell

ssh -i /config/ssh_keys/id_rsa_homeassistant username@remote_esxi_host_ip
  • If everything is working as expected, no password will be queried

5. We going to create a shell commands which is done through configuration.yaml

shell_command:
  turn_off_esxi: ssh -i /config/ssh_keys/id_rsa_homeassistant -o StrictHostKeyChecking=no username@remote_esxi_host_ip "/sbin/shutdown.sh && /sbin/poweroff"
  • Save it, Check and Restart

6. We going to create a scripts which is done through scripts.yaml

alias: General - Turn Off ESXi
sequence:
  - repeat:
      count: "3"
      sequence:
        - delay:
            hours: 0
            minutes: 0
            seconds: 7
            milliseconds: 0
        - service: notify.all_device
          data:
            title: ٱلسَّلَامُ عَلَيْكُمْ وَرَحْمَةُ ٱللَّٰهِ وَبَرَكَاتُهُ
            message: Power outage !!! at {{states('sensor.time')}}
  - delay:
      hours: 0
      minutes: 1
      seconds: 0
      milliseconds: 0
  - service: button.press
    data: {}
    target:
      entity_id: button.kenanga_shutdown
  - delay:
      hours: 0
      minutes: 1
      seconds: 0
      milliseconds: 0
  - service: shell_command.turn_off_esxi
    data: {}
mode: single
icon: mdi:laptop-account
  • FYI - ‘button.kenanga_shutdown’ is my NAS Storage

7. We going to create an automation which is done through automations.yaml

alias: General - Automate Power
description: ""
trigger:
  - platform: state
    entity_id:
      - switch.group_tasmota
    to: unavailable
    for:
      hours: 0
      minutes: 3
      seconds: 0
    id: main_power_off
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: main_power_off
        sequence:
          - service: script.turn_on
            data: {}
            target:
              entity_id: script.general_turn_off_esxi
mode: single
  • FYI - ‘switch.group_tasmota’ is the group of Sonoff POW R2 powered my appliance and stuff
  • FYI - My System Infrastructure was covered by UPS in-case of sudden power outage

Conclusion

The shell command and command line integrations are without a doubt some of the most powerful integrations available in Home Assistant. They open up a whole world of possibilities!

You should now be able to integrate remote bash scripts into Home Assistant, allowing almost unlimited control of any Linux-based remote device!

Congratulations if you made it to the end!

2 Likes

Hello @devilization ,

Thank you for these very useful guidelines !

Having recently added a UPS to my network configuration I wanted to enable Home Assistant to turn-off the ESXi host it’s currently running on (in case the UPS goes offline and the battery level goes below a certain threshold).

Most of the steps you describe work fine until when I try to connect from Home Assistant terminal to the ESXi host through ssh.

My connection gets refused with the following message :

Unable to negotiate with IPADDRESS port 22: no matching MAC found. Their offer: hmac-sha2-256,hmac-sha2-512

Having searched the web for such errors, I only came across (sort of) complicated answers.

From what I understand this seems to be a misunderstanding between the ESXi host serving ssh services and HA’s add-on client.

FWIW, I’m running :

  • ESXi-8.0.0-20513097-standard
  • Home Assistant as a virtual machine on the ESXi host
    – Home Assistant 2023.5.4
    – Supervisor 2023.04.1
    – Operating System 10.2

I used to be able to connect to the ESXi host with the official SSH add-on through its terminal but for whatever reason I couldn’t automate any commands through HA.

I hope it’s clear.

Maybe it rings a bell to someone reading this.

Yours,

Jérôme

I found the solution to my (own) problem here.

From what I could find/understand on my own, the MAC (“message authentication code”) here seems to be related to some kind of pre-authentication from the client on the target daemon.

The only thing that had to be done was to explicitely specify a MAC that both ssh players (daemon on ESXi and client on Home Assistant) could agree on. In my case :

hmac-sha2-512

Which results in the following full connection command from Home Assistant :

ssh -i /config/ssh_keys/id_rsa_homeassistant -m hmac-sha2-512 root@ESXi'sIPAddress

If you want to check which MACs your client can use, type the following command on the client machine (Home Assistant VM in my case) :

$ ssh -Q mac

It unsurprisingly turns out that @frenck 's Advanced SSH & Web Terminal can deal with quite a lot of MACs whereas my ESXi ssh damon is only configured with :

hmac-sha2-256 & hmac-sha2-512

Next step here would be to find a way not to connect as root user on the ESXi host which would obviously enhance security.

Thanks @devilization & @frenck

Apologies for the late reply, thanks @JeromeT for the tip, after updating my ESXi version to ESXi-8.0b-21203435-standard (VMware, Inc.), my shell command suddenly stop working.

By changing the command as below, it start working again:

shell_command:
  turn_off_maya: ssh -m hmac-sha2-512 -A -i /config/ssh_keys/id_rsa -o StrictHostKeyChecking=no username@remote_esxi_host_ip "/sbin/shutdown.sh && /sbin/poweroff"

In addition, i have added other services as well, basically it use the same method but a little bit different in creating the SSH key pair as below:

  1. For piCorePlayer
    Setup passwordless ssh | piCorePlayer documentation
shell_command:
  turn_off_picoreruangtamu: ssh -i /config/ssh_keys/id_rsa -o StrictHostKeyChecking=no username@remote_picore_player_ip "pcp sd"
  1. For Mikrotik Devices
    SSH - RouterOS - MikroTik Documentation
shell_command:
  turn_off_mikrotik: ssh -i /config/ssh_keys/id_rsa -o StrictHostKeyChecking=no username@remote_mikrotik_device_ip "system/shutdown"