Introduction
Rsyslog is the default syslog daemon on most Linux distributions — processing millions of messages per second with filtering, templating, and forwarding to files, databases, or remote servers. Ansible automates the full centralized logging stack: rsyslog server for log collection, client agents for forwarding, TLS encryption, custom templates, and log rotation.
Deploy Rsyslog Server
---
- name: Deploy Rsyslog central server
hosts: log_servers
become: true
vars:
rsyslog_listen_port: 514
rsyslog_tls_port: 6514
rsyslog_log_base: /var/log/remote
tasks:
- name: Install Rsyslog with extras
ansible.builtin.package:
name:
- rsyslog
- rsyslog-gnutls
- rsyslog-relp
state: present
- name: Create remote log directory
ansible.builtin.file:
path: "{{ rsyslog_log_base }}"
state: directory
owner: syslog
group: adm
mode: '0755'
- name: Deploy server config
ansible.builtin.template:
src: rsyslog-server.conf.j2
dest: /etc/rsyslog.d/10-remote.conf
mode: '0644'
notify: restart rsyslog
- name: Allow syslog through firewall
ansible.posix.firewalld:
port: "{{ item }}"
permanent: true
state: enabled
immediate: true
loop:
- "{{ rsyslog_listen_port }}/tcp"
- "{{ rsyslog_listen_port }}/udp"
- "{{ rsyslog_tls_port }}/tcp"
- name: Start Rsyslog
ansible.builtin.service:
name: rsyslog
state: started
enabled: true
handlers:
- name: restart rsyslog
ansible.builtin.service:
name: rsyslog
state: restarted
Server Config Template
# templates/rsyslog-server.conf.j2
# Managed by Ansible — Central syslog server
# UDP reception
module(load="imudp")
input(type="imudp" port="{{ rsyslog_listen_port }}")
# TCP reception
module(load="imtcp")
input(type="imtcp" port="{{ rsyslog_listen_port }}")
{% if rsyslog_tls_enabled | default(false) %}
# TLS reception
module(load="imtcp"
StreamDriver.Name="gtls"
StreamDriver.Mode="1"
StreamDriver.AuthMode="x509/fingerprint")
global(
DefaultNetstreamDriver="gtls"
DefaultNetstreamDriverCAFile="/etc/rsyslog.d/ssl/ca.crt"
DefaultNetstreamDriverCertFile="/etc/rsyslog.d/ssl/server.crt"
DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/ssl/server.key"
)
input(type="imtcp" port="{{ rsyslog_tls_port }}"
StreamDriver.Name="gtls"
StreamDriver.Mode="1"
StreamDriver.AuthMode="anon")
{% endif %}
# Store logs per host/program
template(name="RemoteLog" type="string"
string="{{ rsyslog_log_base }}/%HOSTNAME%/%PROGRAMNAME%.log")
template(name="RemoteLogDate" type="string"
string="{{ rsyslog_log_base }}/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%/%PROGRAMNAME%.log")
# JSON template for structured logging
template(name="JsonLog" type="list") {
constant(value="{")
constant(value="\"timestamp\":\"") property(name="timereported" dateFormat="rfc3339")
constant(value="\",\"host\":\"") property(name="hostname")
constant(value="\",\"severity\":\"") property(name="syslogseverity-text")
constant(value="\",\"facility\":\"") property(name="syslogfacility-text")
constant(value="\",\"program\":\"") property(name="programname")
constant(value="\",\"message\":\"") property(name="msg" format="json")
constant(value="\"}\n")
}
# Route remote logs
if $fromhost-ip != '127.0.0.1' then {
action(type="omfile" dynaFile="RemoteLog"
FileOwner="syslog" FileGroup="adm" FileCreateMode="0640"
DirCreateMode="0755" DirOwner="syslog" DirGroup="adm")
stop
}
Configure Clients
---
- name: Configure Rsyslog clients
hosts: all:!log_servers
become: true
vars:
rsyslog_server: "{{ groups['log_servers'][0] }}"
rsyslog_server_port: 514
rsyslog_protocol: tcp
tasks:
- name: Install Rsyslog
ansible.builtin.package:
name: rsyslog
state: present
- name: Deploy forwarding config
ansible.builtin.template:
src: rsyslog-client.conf.j2
dest: /etc/rsyslog.d/50-forward.conf
mode: '0644'
notify: restart rsyslog
- name: Start Rsyslog
ansible.builtin.service:
name: rsyslog
state: started
enabled: true
handlers:
- name: restart rsyslog
ansible.builtin.service:
name: rsyslog
state: restarted
# templates/rsyslog-client.conf.j2
# Forward all logs to central server
# Queue for reliability
$ActionQueueType LinkedList
$ActionQueueFileName fwdRule1
$ActionResumeRetryCount -1
$ActionQueueSaveOnShutdown on
$ActionQueueMaxDiskSpace 1g
{% if rsyslog_protocol == 'tcp' %}
# TCP forwarding
*.* @@{{ rsyslog_server }}:{{ rsyslog_server_port }}
{% else %}
# UDP forwarding
*.* @{{ rsyslog_server }}:{{ rsyslog_server_port }}
{% endif %}
Custom Filtering Rules
- name: Deploy custom filter rules
ansible.builtin.copy:
dest: /etc/rsyslog.d/20-filters.conf
content: |
# Drop noisy messages
:msg, contains, "CRON" stop
# Route auth logs separately
auth,authpriv.* /var/log/auth.log
# Emergency messages to all terminals
*.emerg :omusrmsg:*
# High-severity to separate file
*.err;*.crit;*.alert;*.emerg /var/log/critical.log
# Application-specific routing
if $programname == 'myapp' then {
action(type="omfile" file="/var/log/myapp/app.log")
stop
}
mode: '0644'
notify: restart rsyslog
Logrotate Integration
- name: Configure logrotate for remote logs
ansible.builtin.copy:
dest: /etc/logrotate.d/remote-syslog
content: |
{{ rsyslog_log_base }}/*/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
mode: '0644'
Performance Tuning
- name: Deploy high-volume config
ansible.builtin.copy:
dest: /etc/rsyslog.d/01-performance.conf
content: |
# High-volume tuning
global(
workDirectory="/var/spool/rsyslog"
maxMessageSize="32k"
)
main_queue(
queue.type="LinkedList"
queue.size="500000"
queue.dequeueBatchSize="1000"
queue.workerThreads="4"
queue.workerThreadMinimumMessages="10000"
queue.maxDiskSpace="2g"
queue.saveOnShutdown="on"
)
mode: '0644'
notify: restart rsyslog
Health Check
- name: Check Rsyslog status
ansible.builtin.command: rsyslogd -v
register: rsyslog_version
changed_when: false
- name: Test log forwarding
ansible.builtin.command: logger -t ansible-test "Test message from {{ inventory_hostname }}"
changed_when: true
- name: Verify log arrived on server
ansible.builtin.command: "grep 'ansible-test' {{ rsyslog_log_base }}/{{ inventory_hostname }}/ansible-test.log"
delegate_to: "{{ groups['log_servers'][0] }}"
register: log_check
changed_when: false
ignore_errors: true
Troubleshooting
Check Config Syntax
- name: Validate rsyslog config
ansible.builtin.command: rsyslogd -N1
register: config_check
changed_when: false
Related Articles
Conclusion
Rsyslog is the workhorse of Linux logging — Ansible automates the central server (TCP/UDP/TLS listeners, per-host directory structure, JSON templates) and client forwarding (reliable queues, protocol selection). Use filtering rules for noise reduction, logrotate for disk management, and performance tuning for high-volume environments. Centralized logging as code means every server forwards logs consistently from day one.