ittavern.com/items/2023-01-05_long_ssh-run-script-or-command-at-login.md
2025-10-27 20:12:00 +01:00

99 lines
3.9 KiB
Markdown

# SSH - run script or command at login
There a multiple use cases to run a script on login. Configuration, starting services, logging, sending a notification, and so on. I want to show you different ways to do so.
#### Example script
The example script will notify me via push notification on my smartphone as soon as a new SSH connection is established. You can use a simple command or a script, and I will use a script for this blog post.
`/path/to/script/notify-at-login.sh`
```bash
#!/bin/bash
# 1 - Script without output!
# IMPORTANT: Script with output break non-interactive sessions (scp, rsync, etc)
curl -d "\"$SSH_CONNECTION\" - \"$USER\" logged in" ntfy.sh/reallyecurestringfornotifications >/dev/null 2>&1
# If you only want to run the script for an interactive SSH login and need the output displayed, place the script right after section 2 and remove the redirect.
# 2 - Check if session is non-interactive (remote command, rsync, scp, etc)
if [[ $SSH_ORIGINAL_COMMAND ]]; then
eval "$SSH_ORIGINAL_COMMAND"
exit
fi
# 3 - choose your favorite shell for the SSH session
/bin/bash
```
Remember to make it executable:
: `sudo chmod +x /path/to/script/notify-at-login.sh`
**Side note**: I am using [ntfy](https://github.com/binwiederhier/ntfy) to send push notifications to my smartphone. In this example, the push notification would look this:
`92.160.50.201 40248 195.21.0.14 22 - <user> logged in`
#### Output on non-interactive connections
Just a reminder that you have to avoid any output of your script or command on non-interactive connections like rsync. Either prevent output from being displayed for non-interactive connections or all connections. The example script shows you one way to do so.
## ForceCommand
I prefer this method, and had been working pretty well so far. The user will run the command and it can't really be avoided by the client.
Use the `ForceCommand` option in your `/etc/ssh/sshd_config` file to run the script:
: `ForceCommand /path/to/script/notify-at-login.sh`
ForceCommand ignores any command or script supplied by the client and ~/.ssh/rc by default.
## PAM_exec
Put the script into a new directory `/etc/pam_scripts`, set the directory's permission to `0755` and the owner and group must be `root`. The files permissions are `0700`, must be executable and the owner and group must be `root` as well.
Directory:
: `sudo mkdir /etc/pam_scripts`
: `sudo chmod 0755 /etc/pam_scripts`
: `sudo chown root:root /etc/pam_scripts`
Script:
: `sudo chmod 0700 /etc/pam_scripts/notify-at-login.sh`
: `sudo chown root:root /etc/pam_scripts/notify-at-login.sh`
Enable `UsePAM` in the `/etc/ssh/sshd_config`:
: `UsePAM yes`
Tell PAM to run the script at SSH login by adding the following line to `etc/pam.d/sshd`:
: `session required pam_exec.so /etc/pam_scripts/notify-at-login.sh`
All scripts added to the `/etc/pam_scripts/` directory will be run as `root` at login.
## Shell startup & sshrc file
You can run the script by your preferred startup file (`.profile` / `.bashrc`, etc) or use the SSH-specific profiles that run additionally before the user shell is loaded.
For all users:
: `/etc/ssh/sshrc` *# runs only if there is no user-specific configuration file `~/.ssh/rc`*
Per user configuration in home dir:
: `~/.ssh/rc`
```markdown
~/.ssh/rc
Commands in this file are executed by ssh when the user
logs in, just before the user's shell (or command) is
started. See the sshd(8) manual page for more information.
```
Run the script via the startup file by adding the following line to it:
: `. /path/to/script/notify-at-login.sh`
Both the shell startup and sshrc files will be run by the user.
**Side note**: if security is a concern - like a login notification - it is not recommended to use this method. Profile config files can be avoided by `ssh user@server bash --norc --noprofile` and `~/.ssh/rc` can be changed by the user after the first login.
---