Graylog is a centralized log management platform: servers and applications send their logs to it, and you search, filter, graph and alert on them from one web interface. It stores configuration in MongoDB and log messages in OpenSearch, which Graylog 6 manages for you through the Graylog Data Node. In this tutorial you will install Graylog with MongoDB and Data Node on Ubuntu 24.04, receive syslog messages from another server, route and enrich them with streams and pipeline rules, and create an alert for repeated SSH login failures.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS with at least 4 vCPUs, 8 GB of RAM and 50 GB of free disk space, for example a CubePath VPS. OpenSearch and Graylog are both Java applications and need that memory.
  • A non-root user with sudo privileges.
  • UFW enabled, with SSH allowed.
  • Optional: a second Linux server to send logs from.

This guide installs the Graylog 6.3 series. Check the Graylog documentation for the current major version and replace 6.3 in the repository package name if a newer series is available.

Step 1 - Installing MongoDB

Graylog stores its configuration, users and dashboards in MongoDB. Install MongoDB 7.0 from the official MongoDB repository. First add its signing key:

sudo apt update
sudo apt install -y gnupg curl
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | sudo gpg --dearmor -o /etc/apt/keyrings/mongodb-server-7.0.gpg

Add the repository for Ubuntu 24.04 (noble) and install the server:

echo "deb [arch=amd64,arm64 signed-by=/etc/apt/keyrings/mongodb-server-7.0.gpg] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt update
sudo apt install -y mongodb-org

Hold the package so an unattended upgrade never moves MongoDB to a version your Graylog release does not support, then start it:

sudo apt-mark hold mongodb-org
sudo systemctl enable --now mongod

Verify that MongoDB is running and listening only on localhost:

sudo ss -tlnp | grep 27017
LISTEN 0      4096       127.0.0.1:27017      0.0.0.0:*    users:(("mongod",pid=2311,fd=15))

Step 2 - Installing Graylog Data Node

Graylog Data Node runs and manages OpenSearch for Graylog, including certificates and version upgrades, so you do not install OpenSearch separately. Add the Graylog repository by installing its repository package:

cd /tmp
curl -fsSLO https://packages.graylog2.org/repo/packages/graylog-6.3-repository_latest.deb
sudo dpkg -i graylog-6.3-repository_latest.deb
sudo apt update

Install Data Node:

sudo apt install -y graylog-datanode

OpenSearch needs a higher limit on memory-mapped areas than the Linux default. Set it permanently and apply it:

echo "vm.max_map_count = 262144" | sudo tee /etc/sysctl.d/99-graylog-datanode.conf
sudo sysctl --system
cat /proc/sys/vm/max_map_count
262144

Graylog server and Data Node must share the same secret, which is used to encrypt and sign data between them. Generate a 96-character value and keep it for this step and the next one:

openssl rand -hex 48

Open the Data Node configuration:

sudo nano /etc/graylog/datanode/datanode.conf

Set the secret and the OpenSearch heap size. On an 8 GB server, 2 GB of heap leaves room for Graylog server, MongoDB and the page cache; on larger servers use up to half of the RAM, never more than 31 GB:

password_secret = paste_the_generated_secret_here
opensearch_heap = 2g

The file also contains mongodb_uri = mongodb://localhost/graylog, which already points to the local MongoDB. Start Data Node:

sudo systemctl enable --now graylog-datanode
sudo systemctl status graylog-datanode --no-pager

Data Node waits for Graylog server to configure it, which happens in Step 4.

Step 3 - Installing Graylog server

Install the Graylog server package from the same repository:

sudo apt install -y graylog-server

Create the SHA-256 hash of the password you will use for the admin account. The command reads the password without echoing it or storing it in your shell history:

read -rs -p "Admin password: " PW; echo; echo -n "$PW" | sha256sum | cut -d' ' -f1; unset PW
Admin password:
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Edit the server configuration:

sudo nano /etc/graylog/server/server.conf

Set these three keys. Use the same password_secret as in datanode.conf, paste the hash into root_password_sha2, and make the web interface listen on all interfaces:

password_secret = paste_the_generated_secret_here
root_password_sha2 = paste_the_sha256_hash_here
http_bind_address = 0.0.0.0:9000

Leave the other settings at their defaults. Start Graylog server:

sudo systemctl enable --now graylog-server

Allow access to the web interface only from your own IP address, replacing your_ip:

sudo ufw allow from your_ip to any port 9000 proto tcp

Step 4 - Completing the preflight setup

On its first start, Graylog runs a preflight web interface to connect the Data Node. It prints a temporary login for it in the server log:

sudo grep -A2 "Initial configuration" /var/log/graylog-server/server.log
Initial configuration is accessible at 0.0.0.0:9000, with username 'admin' and password 'kRgAWqwTfX'.
Try clicking on http://admin:[email protected]:9000

If nothing is found, wait a few seconds and run the command again. Open http://your_server_ip:9000 in your browser and log in with those temporary credentials. Then:

  1. The Data Node you installed appears in the list. Choose to create a new certificate authority, which Graylog uses to secure the connection to Data Node.
  2. Provision the certificates for the Data Node and wait until its status is Connected.
  3. Click Resume startup.

Graylog finishes starting and the normal login page appears. Log in as admin with the password you hashed in Step 3.

Confirm from the shell that the server reports itself as healthy:

curl -s http://127.0.0.1:9000/api/system/lbstatus
ALIVE

Step 5 - Receiving syslog messages

Graylog receives logs through inputs. Create a syslog input:

  1. Go to System > Inputs.
  2. Select Syslog UDP and click Launch new input.
  3. Enable Global, set the title to Syslog UDP, the bind address to 0.0.0.0 and the port to 1514.
  4. Save. The input shows as Running.

Port 1514 is used instead of the standard 514 because Graylog does not run as root and cannot bind ports below 1024. Allow it from the servers that will send logs, replacing client_ip:

sudo ufw allow from client_ip to any port 1514 proto udp

On each client server, configure rsyslog (installed by default on Ubuntu) to forward all messages. Create a new file:

sudo nano /etc/rsyslog.d/60-graylog.conf

Add this line, replacing your_server_ip with the Graylog server address. A single @ means UDP and the template sends RFC 5424 messages, which Graylog parses cleanly:

*.* @your_server_ip:1514;RSYSLOG_SyslogProtocol23Format

Restart rsyslog and send a test message:

sudo systemctl restart rsyslog
logger "Hello from $(hostname) to Graylog"

In the Graylog web interface, open Search and look for Hello from. The message appears within a few seconds with the client hostname in the source field. On the System > Inputs page, the input's throughput counter also increases.

UDP syslog is simple but unencrypted and can drop messages. For application logs, Graylog's GELF inputs (TCP or UDP) accept structured JSON with custom fields, and most logging libraries and Docker's gelf log driver can send it.

Step 6 - Routing messages with streams

A stream is a category of messages defined by rules, used to separate logs for searching, permissions, retention and alerts. Create one for authentication logs:

  1. Go to Streams and click Create stream.
  2. Name it Authentication, keep the default index set, and enable Remove matches from 'Default Stream' if you want these messages stored only here.
  3. Open the stream's rule editor and add a rule: field application_name, type match exactly, value sshd. (Check a message in Search to confirm the exact field name your input produces.)
  4. Start the stream.

Run logger -t sshd "stream test" on a client and confirm that the message appears when you search inside the Authentication stream.

Step 7 - Enriching messages with pipeline rules

Pipelines transform messages as they arrive: extract fields, rename them, drop noise or tag events. This rule marks failed SSH logins and extracts the source IP. Go to System > Pipelines, open Manage rules, create a rule and paste:

rule "tag failed ssh logins"
when
  has_field("message") && contains(to_string($message.message), "Failed password")
then
  let m = regex("from (\\d{1,3}(?:\\.\\d{1,3}){3})", to_string($message.message));
  set_field("event_type", "ssh_failed_login");
  set_field("src_ip", m["0"]);
end

The when block selects messages and the then block modifies them. regex returns a map whose key "0" is the first capture group.

Rules only run inside a pipeline connected to a stream. Create a pipeline named Auth enrichment, add the rule to stage 0, and connect the pipeline to the Authentication stream.

To test it, try to log in to a client over SSH with a wrong password, then search for event_type:ssh_failed_login. The matching messages now carry event_type and src_ip fields you can filter and group by.

Step 8 - Creating an alert

Alerts in Graylog are event definitions that run a search on a schedule. Create one that fires on a burst of failed SSH logins:

  1. Go to Alerts > Event Definitions and click Create event definition.
  2. Name it SSH brute force and choose the condition type Filter & Aggregation.
  3. Set the search query to event_type:ssh_failed_login, search within the last 5 minutes and execute every 1 minute.
  4. Add an aggregation: group by src_ip, condition count() >= 10.
  5. Add a notification. An HTTP Notification can call a webhook such as a chat integration. Email notifications also work once you configure the transport_email_* settings in server.conf.

Triggered events appear under Alerts and include the offending src_ip.

Troubleshooting

The preflight page never shows the Data Node: check that password_secret is identical in datanode.conf and server.conf, and read sudo journalctl -u graylog-datanode -n 50. A max_map_count error means Step 2's sysctl setting was not applied.

Graylog server stops shortly after starting: read sudo tail -n 100 /var/log/graylog-server/server.log. Messages about MongoDB mean mongod is not running; memory errors mean the server needs more RAM or a smaller opensearch_heap.

Syslog messages do not arrive: confirm the input is running, that UFW allows UDP 1514 from the client, and watch for incoming packets on the Graylog server with sudo tcpdump -ni any udp port 1514 while you run logger test on the client. Also check sudo systemctl status rsyslog on the client for syntax errors in the forwarding file.

Messages arrive with the wrong timestamp: set the time zone of the admin user under the user's profile, and make sure clients run an NTP client (timedatectl shows System clock synchronized: yes).

Conclusion

Graylog is now collecting syslog from your servers, storing it in OpenSearch through Data Node, routing authentication logs into their own stream, enriching failed SSH logins with a pipeline rule and alerting on bursts of them. As next steps, place the web interface behind an HTTPS reverse proxy, configure index set retention to match your disk size, and add GELF inputs for your application logs.