syslog-ng is a high-performance, flexible syslog daemon that can act as a centralised log server, receiving log messages from dozens of remote hosts, filtering them, and writing them to organised file hierarchies or forwarding them to external storage systems. Unlike the default rsyslog that ships with RHEL 9, syslog-ng offers a powerful pattern-based configuration language with explicit source, destination, filter, and log blocks that make complex routing logic easy to read and maintain. This guide walks through installing syslog-ng on RHEL 9, configuring it as a central log server listening on TCP and UDP port 514, routing logs by facility and severity, encrypting log transport with TLS, and configuring a client host to forward its logs to the server.

Prerequisites

  • Two RHEL 9 hosts: one designated as the central log server, one as a client
  • EPEL repository enabled on both hosts for the syslog-ng package
  • Root or sudo access on both hosts
  • DNS resolution or /etc/hosts entries so the client can resolve the server hostname
  • Firewall access to open port 514 (TCP and UDP) on the server

Step 1 — Install syslog-ng on Both Hosts

syslog-ng is available from the EPEL repository. Install it on both the central server and the client host. The installation also installs the default configuration file at /etc/syslog-ng/syslog-ng.conf, which you will replace in the following steps.

# Enable EPEL if not already present (run on both server and client)
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

# Install syslog-ng (run on both server and client)
sudo dnf install -y syslog-ng

# Verify the installed version
syslog-ng --version | head -3

# Stop and disable rsyslog to avoid conflicts (run on both hosts)
sudo systemctl stop rsyslog
sudo systemctl disable rsyslog

Step 2 — Configure the Central syslog-ng Server

The server configuration defines a network() source that listens for incoming syslog messages on both UDP and TCP port 514, and multiple file() destinations that organise logs into per-host directories. The log blocks wire sources, filters, and destinations together. Replace the default /etc/syslog-ng/syslog-ng.conf on the server host with the configuration below.

sudo tee /etc/syslog-ng/syslog-ng.conf > /dev/null <<'EOF'
@version: 4.7
@include "scl.conf"

options {
    flush_lines(0);
    time_reopen(10);
    log_fifo_size(10000);
    chain_hostnames(no);
    use_dns(yes);
    use_fqdn(no);
    create_dirs(yes);
    keep_hostname(yes);
};

# Local system logs
source s_local {
    system();
    internal();
};

# Remote clients — accept on both UDP and TCP 514
source s_network {
    network(
        transport("udp")
        ip("0.0.0.0")
        port(514)
    );
    network(
        transport("tcp")
        ip("0.0.0.0")
        port(514)
    );
};

# Destinations — per-host log files
destination d_host_logs {
    file("/var/log/remote/${HOST}/${YEAR}-${MONTH}-${DAY}.log"
         owner("root") group("root") perm(0640)
    );
};

# Local system destination
destination d_local_messages { file("/var/log/messages"); };
destination d_local_secure   { file("/var/log/secure"); };
destination d_local_cron     { file("/var/log/cron"); };

# Filters by facility
filter f_kern     { facility(kern); };
filter f_authpriv { facility(authpriv); };
filter f_cron     { facility(cron); };

# Log routing
log { source(s_local);   filter(f_authpriv); destination(d_local_secure);   };
log { source(s_local);   filter(f_cron);     destination(d_local_cron);      };
log { source(s_local);                       destination(d_local_messages);  };
log { source(s_network);                     destination(d_host_logs);       };
EOF

Step 3 — Open the Firewall and Start syslog-ng on the Server

Validate the configuration with syslog-ng --syntax-only before starting the daemon to catch any YAML or syntax errors. Open UDP and TCP port 514 in firewalld, then enable and start the syslog-ng service.

# Validate the configuration (run on the server)
sudo syslog-ng --syntax-only

# Open port 514 for both UDP and TCP
sudo firewall-cmd --permanent --add-port=514/tcp
sudo firewall-cmd --permanent --add-port=514/udp
sudo firewall-cmd --reload

# Enable and start syslog-ng
sudo systemctl enable --now syslog-ng

# Confirm the service is running and listening
sudo systemctl status syslog-ng
sudo ss -ulnp | grep 514
sudo ss -tlnp | grep 514

Step 4 — Configure the Client to Forward Logs to the Server

On the client host, configure syslog-ng to collect local system logs and forward all of them to the central server over TCP. Using TCP rather than UDP prevents log message loss if the network is briefly congested. Replace logserver.example.com with the actual hostname or IP address of your central server.

sudo tee /etc/syslog-ng/syslog-ng.conf > /dev/null <<'EOF'
@version: 4.7
@include "scl.conf"

options {
    flush_lines(0);
    use_dns(yes);
    use_fqdn(no);
    keep_hostname(yes);
};

# Collect all local system logs and internal syslog-ng messages
source s_local {
    system();
    internal();
};

# Forward everything to the central syslog server over TCP
destination d_remote {
    network(
        "logserver.example.com"
        transport("tcp")
        port(514)
    );
};

log {
    source(s_local);
    destination(d_remote);
};
EOF

sudo syslog-ng --syntax-only
sudo systemctl enable --now syslog-ng

Step 5 — Enable TLS Encryption for Log Transport

Transmitting syslog over plain TCP sends log messages in cleartext. For any environment handling sensitive data, enable TLS on the server’s network source and configure the client to present or verify a certificate. The example below assumes you have a CA certificate, server certificate, and server key already in place — adjust the file paths to match your PKI infrastructure.

# --- On the SERVER: replace the network() source block with a TLS version ---
# In /etc/syslog-ng/syslog-ng.conf, update the s_network source:

# source s_network {
#     network(
#         transport("tls")
#         ip("0.0.0.0")
#         port(6514)
#         tls(
#             key-file("/etc/syslog-ng/tls/server.key")
#             cert-file("/etc/syslog-ng/tls/server.crt")
#             ca-dir("/etc/syslog-ng/tls/ca.d")
#             peer-verify(optional-trusted)
#         )
#     );
# };

# --- On the CLIENT: update d_remote to use TLS on port 6514 ---
# destination d_remote {
#     network(
#         "logserver.example.com"
#         transport("tls")
#         port(6514)
#         tls(
#             key-file("/etc/syslog-ng/tls/client.key")
#             cert-file("/etc/syslog-ng/tls/client.crt")
#             ca-file("/etc/syslog-ng/tls/ca.crt")
#             peer-verify(required-trusted)
#         )
#     );
# };

# Open port 6514 on the server firewall for TLS syslog
sudo firewall-cmd --permanent --add-port=6514/tcp
sudo firewall-cmd --reload

# Reload syslog-ng after configuration changes
sudo systemctl reload syslog-ng

Conclusion

You have installed syslog-ng on RHEL 9, configured a central server to accept logs from remote hosts over TCP and UDP, organised incoming messages into per-host log files, and set up a client to forward all its system logs to the server. The modular source / filter / destination / log configuration model makes it straightforward to add routing rules — for example, sending all authpriv messages to a dedicated security audit file or forwarding critical alerts to an external SIEM. Enabling TLS on port 6514 ensures that log data in transit is encrypted and the identity of syslog sources is verified, protecting against log injection attacks on the network.

Next steps: How to Install and Configure Nagios Core on RHEL 9, How to Set Up OpenTelemetry Collector on RHEL 9, and How to Install Jaeger for Distributed Tracing on RHEL 9.