Temporal Server: Self-hosting a Production-Ready Instance
Temporal is an open-source workflow orchestration engine designed to manage, execute, and monitor complex workflows and activities. In plain terms, …
Read ArticlePluggable Authentication Modules ( PAM) provide a flexible mechanism for authenticating users on Linux systems. By integrating PAM with Gotify, you can receive real-time notifications for SSH login attempts, enhancing your system’s security and awareness.
I’ve been using this approach for over 5 years across many systems — it’s lightweight, reliable, and highly effective. Let’s walk through how to set it up.
Before you begin, make sure you have the following:
sudo
privileges.curl
installed.Gotify is a simple self-hosted server for sending notifications. You can also use a hosted instance if desired.
Install Gotify or use an existing instance.
Create an application in Gotify and note down the application token.
Test that your setup works by sending a test message:
curl -X POST "http://<gotify-server>/message" \
-H "X-Gotify-Key: <application-token>" \
-F "title=Test Notification" \
-F "message=This is a test message"
We’ll configure PAM to trigger this script every time someone logs in via SSH.
Create the script:
sudo vim /usr/local/bin/pam-ssh-notify.sh
Paste the following:
#!/usr/bin/env bash
GOTIFY_URL="http://<gotify-server>/message"
GOTIFY_TOKEN="<gotify-token>"
/usr/bin/curl -s -X POST "$GOTIFY_URL" \
-H "X-Gotify-Key: $GOTIFY_TOKEN" \
-F "title=SSH Login Alert" \
-F "message=User \"$PAM_USER\" logged in from \"$PAM_RHOST\""
Make it executable:
sudo chmod +x /usr/local/bin/pam-ssh-notify.sh
Edit the PAM configuration for SSH:
sudo vim /etc/pam.d/sshd
Add this line at the end of the file:
session optional pam_exec.so /usr/local/bin/pam-ssh-notify.sh
Why optional?
If Gotify is unreachable and this script fails, PAM will ignore the failure.
If you use required
, login failures could result from simple network errors — not ideal for a monitoring hook.
Ensure the UsePAM
setting is set to ‘yes’ inside of /etc/ssh/sshd_config
(or wherever your configuration is).
Restart SSH:
sudo systemctl restart sshd
Log in from another machine and confirm that your Gotify app receives a notification.
When PAM executes your custom script, it passes in useful environment variables that can be used to enhance logic, filtering, and alerting.
Variable | Description | Example Use Case |
---|---|---|
PAM_USER | User being authenticated | Notify only on root logins |
PAM_RHOST | Remote IP or hostname | GeoIP filter or blacklist |
PAM_SERVICE | Service name (e.g. sshd , sudo ) | Alert only on sshd logins |
PAM_TTY | Terminal device (e.g. pts/0 ) | Log which TTY was used |
PAM_TYPE | Event type (auth , session , etc.) | Differentiate login vs session start |
PAM_RUSER | Originating user (e.g. for sudo ) | Log who used sudo |
While this PAM-to-Gotify setup is simple and effective, it’s best suited for single-node systems like personal VPS setups or small self-hosted boxes, systems you’re willing to give your full attention to. It is not scalable for large fleets or production environments with dozens or hundreds of machines. For those cases, you’d want something more robust and asynchronous — like a logging agent with webhook triggers or a centralized security event bus. For a midrange use case with an audit trail, I’ve also swapped out Gotify for a custom Slack App, using the channel webhooks in the past.
Also, a critical caution: setting your PAM module to required
instead of optional
can be dangerous.
If Gotify (or DNS) is down, a required
script failure will prevent user logins entirely.
This is not hypothetical — in 2021 Facebook famously
locked themselves out of their own data center because DNS broke, and they couldn’t log in to fix the DNS server.
By marking this hook as optional
, you avoid cascading failures. Learn from their mistakes.
PAM is capable of much more–adding 2-factor authentication, YubiKey support, LDAP auth, encrypted filesystem mounting, etc. If you want to learn more, the ArchLinux Wiki is a great source, even if you’re not running Arch yourself.
With just a few lines of shell and PAM configuration, you can build powerful real-time login alerts and security automation using Gotify.
The $PAM_*
variables give you rich context for decision-making and logging, and the system is lightweight and reliable.
Feel free to extend this setup to logins via sudo
, su
, or even failed login attempts — and adapt it to your environment as needed.
Stay secure!
Temporal is an open-source workflow orchestration engine designed to manage, execute, and monitor complex workflows and activities. In plain terms, …
Read ArticleBackground In a recent blog post, I discussed a few of the reasons why in 2021, I began working on a new Fleet Configuration Management tool to …
Read Article