syslog-ng is a high-performance, feature-rich syslog daemon that far exceeds the capabilities of the standard rsyslog — it supports complex log routing with conditional filters, structured parsing, TLS-encrypted transport, and native output plugins for Elasticsearch, Kafka, and cloud logging services. On RHEL 8 the package is available from EPEL, making installation straightforward without manual source compilation. This tutorial covers installing syslog-ng, configuring it as both a local collector and a centralised log server, enabling TLS-encrypted forwarding between a client and server node, and finally shipping logs to Elasticsearch.

Prerequisites

  • One or two RHEL 8 servers (or AlmaLinux 8 / Rocky Linux 8) — one acting as the log client, one as the centralised log server
  • EPEL 8 repository enabled on both hosts: dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
  • Port 514 TCP/UDP (plain syslog) or 6514 TCP (TLS syslog) open between client and server in firewalld
  • OpenSSL installed for TLS certificate generation
  • Root or sudo access on both hosts

Step 1 — Install syslog-ng from EPEL

Stop and disable rsyslog first to avoid both daemons competing for the same log sockets, then install syslog-ng from EPEL on both the client and server nodes.

sudo systemctl stop rsyslog
sudo systemctl disable rsyslog

sudo dnf install -y epel-release
sudo dnf install -y syslog-ng

syslog-ng --version | head -3

sudo systemctl enable --now syslog-ng
sudo systemctl status syslog-ng

Step 2 — Configure a Local Log Source and Remote Destination

Edit /etc/syslog-ng/syslog-ng.conf on the client host to define a local source from the systemd journal and kernel, a network destination pointing at the central server, and a log path wiring them together. Back up the original file first.

sudo cp /etc/syslog-ng/syslog-ng.conf /etc/syslog-ng/syslog-ng.conf.bak

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(1000);
    long_hostnames(off);
    use_dns(no);
    use_fqdn(no);
    create_dirs(yes);
    keep_hostname(yes);
};

source s_local {
    system();
    internal();
};

destination d_local {
    file("/var/log/messages"
        template("${ISODATE} ${HOST} ${PROGRAM}[${PID}]: ${MSG}n")
    );
};

destination d_remote {
    network(
        "LOG_SERVER_IP"
        port(514)
        transport("tcp")
    );
};

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

Replace LOG_SERVER_IP with the IP address of your central syslog-ng server. Reload the daemon after saving.

sudo syslog-ng --syntax-only
sudo systemctl reload syslog-ng

Step 3 — Configure syslog-ng as a Central Collector

On the server host, configure syslog-ng to listen on TCP port 514 and write incoming messages to per-host log files under /var/log/hosts/.

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

options {
    flush_lines(0);
    time_reopen(10);
    create_dirs(yes);
    keep_hostname(yes);
    use_dns(no);
};

source s_local { system(); internal(); };

source s_network {
    network(
        ip("0.0.0.0")
        port(514)
        transport("tcp")
    );
};

destination d_hosts {
    file("/var/log/hosts/${HOST}/${YEAR}-${MONTH}-${DAY}.log"
        create_dirs(yes)
        template("${ISODATE} ${HOST} ${PROGRAM}[${PID}]: ${MSG}n")
    );
};

log { source(s_local); destination(d_hosts); };
log { source(s_network); destination(d_hosts); };
EOF

sudo firewall-cmd --permanent --add-port=514/tcp
sudo firewall-cmd --reload
sudo systemctl reload syslog-ng

Step 4 — Enable TLS-Encrypted Transport

Plain TCP syslog transmits log data unencrypted. Generate a self-signed CA and server certificate, then update both the client and server configurations to use TLS on port 6514.

# On the SERVER — generate CA and server certificate
sudo mkdir -p /etc/syslog-ng/tls/{ca,server}

# CA key and certificate
openssl genrsa -out /etc/syslog-ng/tls/ca/ca-key.pem 4096
openssl req -new -x509 -days 3650 
  -key /etc/syslog-ng/tls/ca/ca-key.pem 
  -out /etc/syslog-ng/tls/ca/ca-cert.pem 
  -subj "/CN=syslog-ng CA"

# Server key and certificate signed by the CA
openssl genrsa -out /etc/syslog-ng/tls/server/server-key.pem 4096
openssl req -new 
  -key /etc/syslog-ng/tls/server/server-key.pem 
  -out /tmp/server.csr 
  -subj "/CN=log-server"
openssl x509 -req -days 3650 
  -in /tmp/server.csr 
  -CA /etc/syslog-ng/tls/ca/ca-cert.pem 
  -CAkey /etc/syslog-ng/tls/ca/ca-key.pem 
  -CAcreateserial 
  -out /etc/syslog-ng/tls/server/server-cert.pem

# Copy ca-cert.pem to the CLIENT at /etc/syslog-ng/tls/ca/ca-cert.pem

Update the server network source to add a tls() block, and update the client destination similarly. Example server source snippet:

# Server — replace the s_network source with the TLS version
source s_network {
    network(
        ip("0.0.0.0")
        port(6514)
        transport("tls")
        tls(
            key-file("/etc/syslog-ng/tls/server/server-key.pem")
            cert-file("/etc/syslog-ng/tls/server/server-cert.pem")
            ca-dir("/etc/syslog-ng/tls/ca")
            peer-verify(optional-untrusted)
        )
    );
};

# Client — replace the d_remote destination with the TLS version
destination d_remote {
    network(
        "LOG_SERVER_IP"
        port(6514)
        transport("tls")
        tls(
            ca-dir("/etc/syslog-ng/tls/ca")
        )
    );
};

# Reload both nodes
sudo systemctl reload syslog-ng

Step 5 — Forward Logs to Elasticsearch

syslog-ng ships with a native Elasticsearch destination in its syslog-ng-mod-elasticsearch-http package (available from EPEL or the syslog-ng premium repo). Add it to the server’s configuration to index every received log line into Elasticsearch.

sudo dnf install -y syslog-ng-devel syslog-ng-http

# Add this destination block to /etc/syslog-ng/syslog-ng.conf on the server
destination d_elasticsearch {
    elasticsearch-http(
        url("http://localhost:9200/_bulk")
        index("syslog-ng-${YEAR}.${MONTH}.${DAY}")
        type("")
        template("$(format-json --pair ISODATE=${ISODATE} --pair HOST=${HOST}
            --pair PROGRAM=${PROGRAM} --pair PID=${PID} --pair MSG=${MSG})")
        flush-lines(100)
        flush-timeout(10)
    );
};

# Add d_elasticsearch to both log paths
# log { source(s_network); destination(d_hosts); destination(d_elasticsearch); };

sudo syslog-ng --syntax-only
sudo systemctl reload syslog-ng

# Verify logs are arriving in Elasticsearch
curl -s "http://localhost:9200/syslog-ng-*/_count" | python3 -m json.tool

Conclusion

You have installed syslog-ng from EPEL on RHEL 8, configured it as a local log collector and a centralised TCP server writing per-host log files, secured the transport with TLS certificates, and added an Elasticsearch output destination for log analytics. syslog-ng’s flexible configuration language lets you add filters, rewrite rules, and branching log paths without restarting the daemon — making it well suited to environments where log routing requirements evolve frequently. For high-throughput deployments, consider enabling the multi-line-mode() option for multi-line application logs and tuning the log_fifo_size and flush_lines options to balance latency against throughput.

Next steps: Parsing Structured Application Logs with syslog-ng PatternDB, Setting Up a Redundant syslog-ng Relay Network, and Shipping syslog-ng Output to an OpenSearch Cluster.