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
sudoprivileges. - 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:
- 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.
- Provision the certificates for the Data Node and wait until its status is Connected.
- 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
NoteThe web interface uses plain HTTP on port 9000. Before exposing it beyond your own IP, put it behind a reverse proxy such as Nginx or Caddy with a TLS certificate and set
http_external_uriinserver.confto the public HTTPS URL.
Step 5 - Receiving syslog messages
Graylog receives logs through inputs. Create a syslog input:
- Go to System > Inputs.
- Select Syslog UDP and click Launch new input.
- Enable Global, set the title to
Syslog UDP, the bind address to0.0.0.0and the port to1514. - 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:
- Go to Streams and click Create stream.
- Name it
Authentication, keep the default index set, and enable Remove matches from 'Default Stream' if you want these messages stored only here. - Open the stream's rule editor and add a rule: field
application_name, type match exactly, valuesshd. (Check a message in Search to confirm the exact field name your input produces.) - 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:
- Go to Alerts > Event Definitions and click Create event definition.
- Name it
SSH brute forceand choose the condition type Filter & Aggregation. - Set the search query to
event_type:ssh_failed_login, search within the last 5 minutes and execute every 1 minute. - Add an aggregation: group by
src_ip, conditioncount()>=10. - 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 inserver.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.
