Dynamic MOTD (Message of the Day) for Linux distributions with distribution-specific color coding and cloud provider support.
- Distribution-specific colors based on official logo colors (auto-disabled on non-TTY output and when
NO_COLORis set) - Cloud provider detection: AWS, Azure, GCP, OpenStack — detected at login, not install time
- OS-specific modules: RHEL, Rocky Linux, Raspberry Pi, WSL
- Virtualization detection: KVM, VMware, Xen, Docker, LXC, Kubernetes, etc. (via
systemd-detect-virt) - Disk usage for all real mountpoints
- Last login per user
- Sysadmin notices: broadcast messages with
dynmotd-notify - User exclusion: Hide MOTD for specific users
- Multi-shell login hooks: bash, zsh, fish
- Extensible: Add custom scripts in
/etc/dynmotd.d/ - Fortune integration: Random quotes (optional)
| Distribution | Color |
|---|---|
| Ubuntu | Orange (#E95420) |
| Debian | Wine Red (#A80030) |
| RHEL/CentOS | Red (#EE0000) |
| Rocky Linux | Green (#10B981) |
| AlmaLinux | Dark Blue (#0F4266) |
| Oracle Linux | Red (#F80000) |
| Fedora | Blue (#3C6EB4) |
| SUSE | Green (#73BA25) |
| Arch Linux | Blue (#1793D1) |
| Manjaro | Green (#35BF5C) |
| Alpine Linux | Blue (#0D597F) |
| Raspbian | Raspberry (#C51A4A) |
Standard tools (available on most Linux distributions):
curlawkxargsbasenamegreplsb-release(for Debian-based)fortune(optional)
sudo ./install.shThis will:
- Install
dynmotd,dynmotd-notify,dynmotd-excludeto/usr/local/bin/ - Create symlink
dmfor quick access - Wire up login hooks for every shell detected on the system:
- bash →
/etc/profile.d/dynmotd.sh - zsh → block appended to
/etc/zsh/zprofile(or/etc/zprofile) - fish →
/etc/fish/conf.d/dynmotd.fish(login-only guard)
- bash →
- Create
/etc/dynmotd.conffor user exclusion - Create
/etc/dynmotd.d/for custom scripts - Install all cloud modules (detection happens at runtime, not install time)
- Auto-detect OS-specific modules (Raspberry Pi, RHEL/Rocky tuned-adm)
# 1. Disable default MOTD (optional)
sudo vi /etc/ssh/sshd_config
# Set: PrintMotd no
# 2. Disable PAM MOTD (if applicable)
sudo vi /etc/pam.d/login
# Comment: # session optional pam_motd.so
# 3. Install dynmotd
sudo cp dynmotd /usr/local/bin/
sudo chmod 755 /usr/local/bin/dynmotd
# 4. Set up auto-display on login
echo "/usr/local/bin/dynmotd" | sudo tee /etc/profile.d/dynmotd.sh
sudo chmod 644 /etc/profile.d/dynmotd.sh
# 5. Create custom scripts directory
sudo mkdir -p /etc/dynmotd.dsudo ./uninstall.shTwo mechanisms exist — admin-wide and per-user.
Admin exclusion (requires root) — manages /etc/dynmotd.conf:
sudo dynmotd-exclude add jenkins
sudo dynmotd-exclude add serviceaccount
sudo dynmotd-exclude list
sudo dynmotd-exclude remove jenkinsOr edit /etc/dynmotd.conf directly (one username per line, # for comments).
Self opt-out (any user) — toggles ~/.dynmotd-disable:
dynmotd-exclude mute # disable MOTD for yourself
dynmotd-exclude unmute # re-enable
dynmotd-exclude status # check current stateEither mechanism suppresses the MOTD for the matching user.
Use dynmotd-notify (installed alongside dynmotd) to show sysadmin messages to every user at login:
sudo dynmotd-notify add "maintenance tonight at 20:00"
sudo dynmotd-notify add --expires 2026-05-01 "freeze until May 1"
sudo dynmotd-notify list
sudo dynmotd-notify remove 20260418-093512-42
sudo dynmotd-notify clearNotices are stored as plain-text files in /var/lib/dynmotd/notices/ and auto-hidden past their optional expiration date.
Place custom scripts in /etc/dynmotd.d/ with .sh extension. Scripts are executed in alphabetical order.
Naming convention:
00_*.sh- OS-specific info01_*.sh- Cloud provider info99_*.sh- Miscellaneous (fortune, etc.)
Available variables (exported by dynmotd):
COLOR_COLUMN # Bold formatting
COLOR_VALUE # Distribution color
RESET_COLORS # Reset to default
DISTRO_COLOR # Raw distribution color codeExample custom script (/etc/dynmotd.d/50_docker.sh):
if command -v docker > /dev/null; then
DOCKER_STATUS=$(systemctl is-active docker 2>/dev/null || echo "not installed")
echo -e "===== DOCKER ==================================================================
${COLOR_COLUMN}${COLOR_VALUE}- Status${RESET_COLORS}.............: ${DOCKER_STATUS}"
fi| Provider | Detection Method | Info Displayed |
|---|---|---|
| AWS | IMDSv2 token | External IP, Instance ID/Type, Zone |
| Azure | Metadata API | External IP, Resource Group, VM ID/Size, Location |
| GCP | Metadata header | External IP, Project, Machine Type, Image, VPC, Zone, Scopes |
| OpenStack | /openstack/ endpoint |
External IP, Instance ID/Type, Hostname, Project, Zone |
Detection runs at login time, not at install — snapshotted/migrated VMs automatically pick up the new provider. A non-cloud host pays only ~1s (single reachability probe) at login. All cloud metadata requests have a 2-second timeout.
dynmotd/
├── dynmotd # Main script
├── dynmotd-notify # CLI for broadcast notices
├── dynmotd-exclude # CLI for per-user MOTD opt-out / admin exclusion
├── install.sh # Installation script
├── uninstall.sh # Uninstallation script
├── 00_cloud_detect.sh # Runtime cloud-provider detection (shared)
├── 00_notices.sh # Displays sysadmin notices at login
├── 00_raspberry_pi.sh # Raspberry Pi module
├── 00_rhel.sh # RHEL/Oracle Linux module
├── 00_rocky.sh # Rocky Linux module
├── 00_wsl.sh # Windows Subsystem for Linux module
├── 01_aws.sh # AWS EC2 metadata (self-gated)
├── 01_azure.sh # Azure VM metadata (self-gated)
├── 01_gcp.sh # GCP Compute Engine metadata (self-gated)
├── 01_openstack.sh # OpenStack metadata (self-gated)
├── 99_fortune.sh # Fortune quotes
└── example/ # Example configurations
===============================================================================
- Hostname...........: myserver (192.168.1.100)
- OS version.........: Rocky Linux 9.2 (Blue Onyx)
- Kernel release.....: 5.14.0-284.11.1.el9_2.x86_64
- Users..............: Currently 2 user(s) logged on
===============================================================================
- CPUs...............: 4 x GenuineIntel/Intel(R) Xeon(R) CPU @ 2.80GHz
- Load average.......: 0.15 - 0.10 - 0.05 (1-5-15 min)
- Memory.............: 16Gi - 4.2Gi - 10Gi (total-used-free)
- Swap...............: 2Gi - 0B - 2Gi (total-used-free)
- Processes..........: 156 running - 2 background - 0 zombies
- System uptime......: 45 days 12 hours 30 minutes 15 seconds
===== ROCKY LINUX INFO ========================================================
- Tuned profile......: virtual-guest
===== GCP INSTANCE METADATA ===================================================
- External IP........: 34.56.78.90
- Project ID.........: my-project-123
- Machine Type.......: e2-medium
- Image..............: rocky-linux-9-v20230615
- Preemptible........: FALSE
- VPC................: default
- Zone...............: us-central1-a
- Additional Scopes..: [compute.readonly]
===== FORTUNE =================================================================
The best way to predict the future is to invent it.
-- Alan Kay
===============================================================================
This project is a fork of Neutrollized/dynmotd.
Original author: Neutrollized - Thanks for the original work!
Maintained by: StackOps
- Distribution-specific color coding based on official logo colors
- OpenStack cloud provider support
- Rocky Linux and Alpine Linux support
- Runtime cloud detection (works on snapshotted/migrated VMs)
- Multi-shell login hooks (bash, zsh, fish)
- Broadcast notices system (
dynmotd-notify) - Per-user and admin MOTD exclusion (
dynmotd-exclude) - Virtualization, disk, last-login rows
NO_COLOR/ non-TTY color suppression- Exported color variables for custom scripts
- Timeout on all cloud metadata requests
- Improved error handling and code consistency