How to Implement Per-User SSH MOTD (Message of the Day) for Custom Welcome Banners


1 views

When managing multiple users on an SSH server, you might want to greet each user with a customized message upon login. The standard /etc/motd approach displays the same message for everyone, which doesn't work when you need user-specific messages like:

Welcome back, developer1!
Your last login was: 2023-11-15 14:30 from 192.168.1.100

versus

ALERT for admin1:
Scheduled maintenance tonight at 2AM UTC

SSH displays messages in this order during login:

  1. /etc/issue.net (pre-login banner)
  2. /etc/motd (post-login message)
  3. PAM modules (like pam_motd)

The traditional approach modifies /etc/motd, but we need to intercept the process before the final display.

This method provides the most flexibility. First, create a script:

#!/bin/bash
# /usr/local/bin/user_motd.sh

USER=$1
MOTD_DIR="/etc/ssh/motd.d"

if [ -f "${MOTD_DIR}/${USER}" ]; then
    cat "${MOTD_DIR}/${USER}"
elif [ -f "${MOTD_DIR}/default" ]; then
    cat "${MOTD_DIR}/default"
fi

Then configure PAM by editing /etc/pam.d/sshd:

session optional pam_exec.so /usr/local/bin/user_motd.sh

Create per-user MOTD files in /etc/ssh/motd.d/:

$ sudo mkdir -p /etc/ssh/motd.d
$ echo "Welcome back developer!" | sudo tee /etc/ssh/motd.d/developer1
$ echo "System alerts for admin:" | sudo tee /etc/ssh/motd.d/admin1

For simpler cases, modify the user's ~/.bash_profile:

#!/bin/bash
# ~/.bash_profile

if [ -f ~/.motd ]; then
    cat ~/.motd
fi

Then create user-specific ~/.motd files:

$ echo "Your personal workspace" > ~/.motd

Combine both approaches for dynamic messages:

#!/bin/bash
# /usr/local/bin/dynamic_motd.sh

USER=$1
LAST_LOGIN=$(last -n 1 "$USER" | head -n 1 | awk '{print $3" "$4" "$5" "$6" from "$2}')

cat << EOF
Welcome $USER!
Last login: $LAST_LOGIN
System load: $(uptime | awk -F'[a-z]:' '{print $2}')
EOF
  • Set proper permissions: chmod 755 /usr/local/bin/user_motd.sh
  • Make MOTD directory read-only: chmod -R 755 /etc/ssh/motd.d
  • Regularly audit custom scripts for vulnerabilities

If messages don't appear:

$ ssh -vvv user@host  # Check debug output
$ grep pam_exec /var/log/auth.log
$ ls -la /etc/ssh/motd.d/  # Verify file permissions

When administering multi-user Linux systems, you might want to display personalized welcome messages when users SSH into the server. While the default /etc/motd provides a global message, we need per-user customization.

We'll leverage the bash or zsh shell initialization files combined with SSH's ForceCommand capability to achieve per-user MOTD functionality.

1. Create MOTD Template Files

First, create a directory to store user-specific MOTD files:

sudo mkdir /etc/motd.d
sudo chmod 755 /etc/motd.d

Then create template files for each user:

sudo nano /etc/motd.d/john
# Content for John's MOTD
Welcome back, John!
Your last login was: $(last -n 1 $USER | head -n 1 | awk '{print $4,$5,$6,$7}')

2. Modify SSH Configuration

Edit /etc/ssh/sshd_config:

Match User *
    ForceCommand /usr/local/bin/custom_motd.sh

3. Create the MOTD Script

Create /usr/local/bin/custom_motd.sh:

#!/bin/bash

# Check if MOTD file exists for user
MOTD_FILE="/etc/motd.d/${USER}"

if [ -f "$MOTD_FILE" ]; then
    # Process with parameter expansion
    eval "echo \"$(cat "$MOTD_FILE")\""
    echo ""
fi

# Execute user's shell
exec "$SHELL" "$@"

Make it executable:

sudo chmod +x /usr/local/bin/custom_motd.sh

For dynamic content, you can add variables to your MOTD templates:

sudo nano /etc/motd.d/alice
Hello Alice!
System load: $(uptime | awk -F'load average: ' '{print $2}')
Disk space:
$(df -h | grep -v tmpfs)

1. Set proper permissions on /etc/motd.d to prevent users from modifying others' MOTD files
2. Audit your MOTD templates for potential command injection vulnerabilities
3. Consider SELinux/AppArmor policies if enabled on your system

For simpler setups, you can add this to individual user's ~/.bashrc:

if [ -n "$SSH_CONNECTION" ]; then
    echo "===================================="
    echo "Welcome back, $USER!"
    echo "Your home directory is using $(du -sh $HOME | awk '{print $1}')"
    echo "===================================="
fi
  • Check /var/log/auth.log for SSH session issues
  • Test with ssh -v for verbose connection output
  • Verify script permissions and SELinux contexts if commands fail