Centralized logging is one of those boring-sounding things that become incredibly valuable the first time you investigate a security incident.
In this tutorial, you will build a simple but robust syslog server on Debian 13 using rsyslog, and then forward SSH login attempts from another Linux server to it.
We will go step by step and I will explain each configuration line, so you not only copy-paste, but also understand why it works.
The examples use two machines:
- Syslog server: Debian 13, IP address
192.168.0.123 - Client server: Another Linux server (e.g. Debian/Ubuntu)
Feel free to replace IP addresses and hostnames with your own environment.
1. Installing rsyslog on the Debian 13 syslog server
Debian uses rsyslog by default, but it is a good idea to make sure it is installed and enabled.
sudo apt update
sudo apt install rsyslog rsyslog-gnutls -y
sudo systemctl enable --now rsyslog
sudo systemctl status rsyslog
The last command should show that rsyslog is active (running).
If it is not, fix that before continuing.
2. Preparing the directory for remote logs
We will store all remote logs under /var/log/remote. Each client will have its own subdirectory based on its IP, and we will rotate files daily by date.
sudo mkdir -p /var/log/remote
sudo chown root:adm /var/log/remote
sudo chmod 750 /var/log/remote
Line by line:
mkdir -p /var/log/remote– creates the base directory for remote logs (the-pflag ignores it if it already exists).chown root:adm /var/log/remote– makes the directory owned byrootand groupadm, which is the standard group for log files on Debian.chmod 750 /var/log/remote– allows full access for root, read/execute for theadmgroup, and no access for others.
3. Enabling remote logging in rsyslog on Debian 13
Now we will configure rsyslog on the syslog server to listen on UDP and TCP port 514 and store logs in a per-client, per-day structure.
Create a new configuration file:
sudo nano /etc/rsyslog.d/10-listen-remote.conf
Insert the following content:
#### Modules to receive remote logs over UDP and TCP
module(load="imudp")
module(load="imtcp")
# UDP port 514, use ruleset "remote"
input(type="imudp" port="514" ruleset="remote")
# TCP port 514, use ruleset "remote"
input(type="imtcp" port="514" ruleset="remote")
#### Template for remote log files
# Resulting path example:
# /var/log/remote/192.168.0.50/2025-11-13.log
template(name="RemoteLogsFormat" type="string"
string="/var/log/remote/%fromhost-ip%/%$YEAR%-%$MONTH%-%$DAY%.log")
#### Ruleset for remote messages
ruleset(name="remote") {
action(
type="omfile"
dynaFile="RemoteLogsFormat"
createDirs="on"
)
}
Explanation line by line:
module(load="imudp")– loads the imudp module, which allows rsyslog to receive syslog messages over UDP.module(load="imtcp")– loads the imtcp module, which allows rsyslog to receive messages over TCP.input(type="imudp" port="514" ruleset="remote")– tells rsyslog to listen on UDP port 514 and send all received messages to the ruleset calledremote.input(type="imtcp" port="514" ruleset="remote")– the same, but for TCP port 514.-
template(name="RemoteLogsFormat" ...)– defines how the output filename will look:%fromhost-ip%– is replaced by the IP address of the client sending the logs.%$YEAR%-%$MONTH%-%$DAY%– inserts the current date, so you get one file per day.- The final path looks like
/var/log/remote/192.168.0.50/2025-11-13.log.
-
ruleset(name="remote") { ... }– defines a ruleset that will handle all messages coming from theinput(... ruleset="remote")lines above. -
Inside the ruleset:
type="omfile"– output is a file.dynaFile="RemoteLogsFormat"– uses our template to dynamically build the file path for each message.createDirs="on"– automatically creates missing directories (for example/var/log/remote/192.168.0.50), which is critical for this setup.
Reload rsyslog to apply the changes:
sudo systemctl restart rsyslog
sudo systemctl status rsyslog
4. Opening the syslog ports in the firewall (optional)
If you use ufw on the syslog server, you must allow TCP and/or UDP port 514:
sudo ufw allow 514/tcp
sudo ufw allow 514/udp
sudo ufw reload
If you manage firewalling on a router or hardware firewall, open the same ports there instead.
5. Configuring the client server to send SSH logs to the syslog server
On the client server (mocco in this example), we will configure rsyslog to forward only SSH-related logs.
This is more efficient than sending everything.
5.1 Ensure rsyslog is installed and running on the client
sudo apt update
sudo apt install rsyslog -y
sudo systemctl enable --now rsyslog
sudo systemctl status rsyslog
5.2 Create an rsyslog rule to forward SSH logs
Create a new file on the client:
sudo nano /etc/rsyslog.d/30-ssh-to-remote.conf
Add the following configuration (replace the IP with your syslog server IP):
# Forward SSH logs from this client to the central syslog server
if ($programname == "sshd" or $programname == "sshd-session") then {
action(
type="omfwd"
target="192.168.0.123" # IP of your syslog server
port="514"
protocol="tcp"
)
# No 'stop' here, so messages still go to local /var/log/auth.log
}
Explanation:
if ($programname == "sshd" or $programname == "sshd-session")– matches only messages generated by the SSH daemon. On many modern systems, the program name appears assshd-session, so we check both.-
action(...)withtype="omfwd"– uses the omfwd output module to forward messages to a remote syslog server.target="192.168.0.123"– the IP address of your central syslog server.port="514"– the port on which the server listens (we configured this earlier).protocol="tcp"– uses TCP instead of UDP, which is more reliable for log forwarding.
-
We deliberately do not use
stopafter this action. That means the messages are also processed by the default rsyslog rules and still appear in/var/log/auth.logon the client, which is usually what you want.
Reload rsyslog on the client:
sudo systemctl restart rsyslog
6. Testing the syslog pipeline end-to-end
6.1 Basic connectivity test from the client
On the client, verify that the TCP port 514 on the syslog server is reachable:
nc -vz 192.168.0.123 514
You should see something like Connection to 192.168.0.123 514 port [tcp/shell] succeeded!.
If this fails, fix firewall or routing first.
6.2 Watch syslog traffic on the server
On the syslog server, open a terminal and run:
sudo tcpdump -ni any port 514
If everything is correct, you will see packets arriving from the client IP when you generate SSH activity.
6.3 Generate SSH attempts and check log files
From another machine (or even from the syslog server), try to SSH into the client using wrong credentials a few times, then a correct login:
ssh invaliduser@CLIENT_IP
ssh root@CLIENT_IP
Back on the syslog server, check the directory structure:
sudo find /var/log/remote -maxdepth 2 -type d
You should see a directory with the client IP, e.g.:
/var/log/remote
/var/log/remote/192.168.0.50
Then list log files:
sudo find /var/log/remote -type f
You should see something like:
/var/log/remote/192.168.0.50/2025-11-13.log
View the last lines of the file:
sudo tail -n 50 /var/log/remote/192.168.0.50/*.log
You should see SSH authentication attempts similar to:
Nov 13 09:45:30 mocco sshd-session[126589]: Failed password for invalid user janko from 217.75.67.22 port 52426 ssh2
Nov 13 09:45:51 mocco sshd-session[126603]: Accepted password for mocco from 217.75.67.22 port 52442 ssh2
At this point, your centralized SSH attack logging is working.
7. Optional: One combined file for all SSH attempts
Per-client log files are great for forensics, but sometimes you want a single file that aggregates all SSH login attempts from all servers.
You can easily add this on the syslog server.
Create a new config file:
sudo nano /etc/rsyslog.d/20-ssh-aggregate.conf
Insert:
# Aggregate all SSH logs from all clients into a single file
if ($programname == "sshd" or $programname == "sshd-session") then {
action(
type="omfile"
file="/var/log/remote/ssh_auth_all.log"
createDirs="on"
)
}
Explanation:
- The condition is the same as on the client: we match all SSH daemon messages.
file="/var/log/remote/ssh_auth_all.log"– writes all these messages into one central log file.createDirs="on"– makes sure the directory exists (in this case,/var/log/remotealready does, but it is safe to keep).
Reload rsyslog:
sudo systemctl restart rsyslog
Now you can watch all SSH attacks in one place:
sudo tail -f /var/log/remote/ssh_auth_all.log
8. Basic log rotation for remote logs
By default, Debian uses logrotate for many log files, but it does not automatically know about our new directory.
We can add a simple logrotate configuration for /var/log/remote.
Create a new logrotate rule:
sudo nano /etc/logrotate.d/remote-syslog
Example configuration:
/var/log/remote/*/*.log {
daily
rotate 90
compress
missingok
notifempty
create 640 root adm
sharedscripts
postrotate
systemctl reload rsyslog >/dev/null 2>&1 || true
endscript
}
Explanation:
daily– rotate logs every day.rotate 90– keep 90 old log files (90 days if you rotate daily).compress– compress old log files with gzip to save space.missingok– do not complain if files are missing.notifempty– do not rotate empty log files.create 640 root adm– newly created log files get ownerroot:admand permissions640.postrotate ... endscript– after rotating logs, reload rsyslog so it reopens files cleanly.
9. Troubleshooting tips
-
No files appear in /var/log/remote
Check that rsyslog is listening:sudo ss -lntup | grep 514You should see rsyslog bound to port 514 (TCP and/or UDP).
-
Client reaches the port, but no log files are created
Confirm that your filter matches the right program name. On many systems,
SSH messages come fromsshd-session, not onlysshd.
Use both in your condition:if ($programname == "sshd" or $programname == "sshd-session") then { ... } -
rsyslog errors
Look at the journal on the syslog server:sudo journalctl -u rsyslog -n 50 -
Connectivity issues
From the client:nc -vz 192.168.0.123 514If this fails, fix firewall or routing.
10. Conclusion
You now have a working centralized syslog server on Debian 13 that collects SSH login attempts from at least one client server.
You learned how to:
- Enable remote logging in rsyslog using modules, inputs, templates, and rulesets.
- Forward specific logs (SSH) from a client using the
omfwdaction. - Organize logs per client and per day, and aggregate them for quick security monitoring.
- Add basic log rotation to avoid filling the disk.
From here, you can extend this setup to include more servers, network devices (like routers and firewalls), and even feed these logs into a full SIEM stack.
But even this simple configuration already gives you a strong security and troubleshooting advantage.
One comment