Ubuntu 24.04 Dynamic MOTD (Console + SSH) — Working Recipe + Lessons Learned
Goal: A single dynamic banner (MOTD) that appears once on SSH and console, updates correctly, and survives reboot on Ubuntu Server 24.04.
This document is written from a real-world troubleshooting session and captures the known-good setup and the gotchas that caused the “works on console but not on SSH” loop.
What you end up with
- A custom MOTD generator script at:
/etc/update-motd.d/50-ops - A dynamic MOTD file at:
/run/motd.dynamic(tmpfs; wiped on reboot) - A symlink so SSH reliably displays it:
/etc/motd -> /run/motd.dynamic - PAM configured to display/update MOTD for SSH and display once on console
- Optional boot-time generation so
/run/motd.dynamicexists immediately after reboot
Step-by-step (known-good)
1) Create your MOTD script
Create /etc/update-motd.d/50-ops and make it executable:
sudo nano /etc/update-motd.d/50-ops
sudo chmod 755 /etc/update-motd.d/50-ops
sudo chown root:root /etc/update-motd.d/50-ops
Your script should print the banner to stdout. Don’t try to write
/run/motd.dynamicinside the script unless you have a reason.
Test it prints output:
sudo run-parts /etc/update-motd.d
2) Generate /run/motd.dynamic at boot (recommended)
Because /run is tmpfs, it is empty after every reboot. Create a oneshot service to generate the file at boot so it always exists before any login.
Create /etc/systemd/system/build-motd.service:
sudo tee /etc/systemd/system/build-motd.service >/dev/null <<'EOF'
[Unit]
Description=Generate /run/motd.dynamic from /etc/update-motd.d
After=local-fs.target
ConditionPathExists=/etc/update-motd.d
[Service]
Type=oneshot
ExecStart=/usr/bin/env bash -lc 'run-parts /etc/update-motd.d > /run/motd.dynamic'
ExecStartPost=/bin/chmod 0644 /run/motd.dynamic
[Install]
WantedBy=multi-user.target
EOF
Enable it:
sudo systemctl daemon-reload
sudo systemctl enable --now build-motd.service
Verify after reboot (or immediately):
ls -l /run/motd.dynamic
head -n 5 /run/motd.dynamic
3) The critical Ubuntu 24.04 fix: align /etc/motd
Ubuntu 24.04 SSH display behavior strongly assumes /etc/motd is the display endpoint.
Create the symlink:
sudo ln -sf /run/motd.dynamic /etc/motd
Verify:
ls -l /etc/motd
You should see:
/etc/motd -> /run/motd.dynamic
4) SSH daemon settings
Edit /etc/ssh/sshd_config and ensure:
UsePAM yes
PrintMotd no
PrintLastLog yes
Reload ssh (no reboot required):
sudo systemctl reload ssh
5) PAM: SSH MOTD must run before common-session (Ubuntu 24.04)
Edit /etc/pam.d/sshd.
Add (or ensure) exactly one MOTD pair BEFORE @include common-session:
# MOTD must run BEFORE common-session on 24.04
session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
@include common-session
Do not leave additional
pam_motdduplicates elsewhere in the file.
6) PAM: console login should display once
Console uses /etc/pam.d/login.
To avoid the “double banner on console” issue, use one display-only line:
session optional pam_motd.so motd=/run/motd.dynamic noupdate
(If you have two lines like motd=... and then noupdate on the next line, console can print twice.)
No service restart needed; just log out/in on console.
Validation checklist
After reboot
ls -l /run/motd.dynamic || echo "missing"
SSH
Open a fresh session:
ssh sysops@your-host
Expected:
- The dynamic banner prints once
- Then Last login: ...
- Then prompt
![[Pasted image 20260210153707.png]]
Console
Log out and log back in. Expected: - The banner prints once, not twice
Troubleshooting (fast, practical)
A) SSH shows only “Last login”, no banner
Check:
1) Is /run/motd.dynamic present and non-empty?
ls -l /run/motd.dynamic
head -n 3 /run/motd.dynamic
2) Is /etc/motd aligned?
ls -l /etc/motd
3) Is SSH using PAM?
sudo sshd -T | egrep -i "usepam|printmotd"
4) Does SSH open a PAM session?
sudo journalctl -b -t sshd --no-pager | tail -n 50
You should see:
- pam_unix(sshd:session): session opened ...
B) Console shows MOTD twice
Fix /etc/pam.d/login to have only one effective pam_motd display line (use noupdate on the same line).
C) “It worked until reboot”
That’s /run being wiped. Enable the boot oneshot generator and/or ensure PAM updates the file.
Lessons learned (what caused the 3‑day loop)
1) /run is tmpfs: /run/motd.dynamic disappears every reboot.
2) Console ≠ SSH: different PAM stacks (login vs sshd).
3) Ubuntu 24.04 ordering matters: pam_motd needs to run before common-session in sshd.
4) pam_motd is quiet: when skipped, you often get no obvious error—just no banner.
5) SSH display path expects /etc/motd: the symlink /etc/motd -> /run/motd.dynamic is the stabilizer that made SSH consistently display the banner.
6) Avoid “clever” fixes when tired: freeze state, test one change, confirm with a reboot.
“Shareable” quick fix summary
If someone says: “Console banner works, SSH shows nothing on Ubuntu 24.04”:
1) Ensure:
UsePAM yes
PrintMotd no
2) Ensure /etc/pam.d/sshd has pam_motd before common-session.
3) Ensure:
sudo ln -sf /run/motd.dynamic /etc/motd
4) Ensure /run/motd.dynamic exists after reboot (boot oneshot service).
End of document.