Filebeat is Elastic's lightweight log shipper: it tails log files, keeps track of how far it has read, and sends each line to Elasticsearch (or Logstash) with little CPU and memory. Its modules include ready-made parsers and Kibana dashboards for common software such as Nginx and the system logs. In this tutorial you will install Filebeat 9 on Ubuntu 24.04, connect it to an existing Elasticsearch cluster over TLS, enable the system and nginx modules, add a custom input for JSON application logs and switch to a least-privilege API key.
Prerequisites
To follow this tutorial you need:
- A server running Ubuntu 24.04 LTS whose logs you want to ship, for example a CubePath VPS, with a non-root
sudouser. - A running Elasticsearch 9.x cluster and Kibana 9.x reachable from that server on ports
9200and5601. We refer to them asyour_es_hostandyour_kibana_host. - The password of the
elasticsuperuser (only needed for the initial setup) and the cluster's HTTP CA certificate. On a self-managed Elasticsearch installed from packages, it is/etc/elasticsearch/certs/http_ca.crt. - Nginx installed on the Filebeat server if you want to follow the Nginx module part.
ImportantFilebeat's major version must match your Elasticsearch cluster. This guide uses the
9.xrepository. If your cluster runs 8.x, use8.xin the repository URL in Step 1 and install the same minor version as the cluster.
Step 1 - Installing Filebeat from the Elastic repository
Elastic publishes signed APT packages. Download the signing key into its own keyring so it only applies to the Elastic repository:
sudo install -m 0755 -d /etc/apt/keyrings
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /etc/apt/keyrings/elasticsearch.gpg
Add the repository and install Filebeat:
echo "deb [signed-by=/etc/apt/keyrings/elasticsearch.gpg] https://artifacts.elastic.co/packages/9.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-9.x.list
sudo apt update
sudo apt install filebeat
Check the installed version:
filebeat version
filebeat version 9.1.4 (amd64), libbeat 9.1.4 [...]
Do not start the service yet: it has no valid output configured.
Step 2 - Connecting Filebeat to Elasticsearch
Copy the cluster's HTTP CA certificate to the Filebeat server, for example with scp, and place it in /etc/filebeat/certs/:
sudo mkdir -p /etc/filebeat/certs
sudo cp http_ca.crt /etc/filebeat/certs/http_ca.crt
Instead of writing the password into the configuration file, store it in the Filebeat keystore, which is readable only by root:
sudo filebeat keystore create
sudo filebeat keystore add ES_PWD
Type the elastic password when prompted. You can now reference it as ${ES_PWD}.
Open the main configuration file:
sudo nano /etc/filebeat/filebeat.yml
The packaged file contains many commented examples. Replace its content with the following minimal configuration:
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
filebeat.inputs: []
setup.kibana:
host: "http://your_kibana_host:5601"
output.elasticsearch:
hosts: ["https://your_es_host:9200"]
username: "elastic"
password: "${ES_PWD}"
ssl.certificate_authorities: ["/etc/filebeat/certs/http_ca.crt"]
processors:
- add_host_metadata: ~
If Kibana is served over HTTPS, use https:// in setup.kibana.host. When no Kibana credentials are set, Filebeat uses the Elasticsearch output credentials for Kibana.
Validate the file and test the connection:
sudo filebeat test config
sudo filebeat test output
Config OK
elasticsearch: https://your_es_host:9200...
parse url... OK
connection...
parse host... OK
dns lookup... OK
addresses: 10.0.0.20
dial up... OK
TLS...
security: server's certificate chain verification is enabled
handshake... OK
TLS version: TLSv1.3
dial up... OK
talk to server... OK
version: 9.1.4
Never "fix" a TLS error by setting ssl.verification_mode: none. If the handshake fails, the CA file or the hostname in hosts is wrong.
Step 3 - Enabling the system and Nginx modules
Modules bundle an input definition, an Elasticsearch ingest pipeline that parses the lines, and Kibana dashboards. List them and enable the two you need:
sudo filebeat modules enable system nginx
sudo filebeat modules list | head -n 5
Enabled:
nginx
system
Disabled:
Enabling a module only renames its file in /etc/filebeat/modules.d/. The filesets inside are still disabled by default, so edit each file. Start with the system module:
sudo nano /etc/filebeat/modules.d/system.yml
- module: system
syslog:
enabled: true
auth:
enabled: true
Then the Nginx module:
sudo nano /etc/filebeat/modules.d/nginx.yml
- module: nginx
access:
enabled: true
error:
enabled: true
The modules use the default Ubuntu paths (/var/log/syslog, /var/log/auth.log, /var/log/nginx/access.log*, /var/log/nginx/error.log*). If your logs live elsewhere, add var.paths: ["/path/to/file.log*"] under the fileset.
Step 4 - Loading index templates, pipelines and dashboards
filebeat setup creates the index template, the ILM policy, the ingest pipelines of the enabled modules and the Kibana dashboards. It needs elevated privileges, which is why it runs now with the elastic user, before you switch to a restricted API key. The --pipelines option needs the modules listed explicitly:
sudo filebeat setup -e --pipelines --modules system,nginx
The command takes a minute and ends with lines similar to:
Index setup finished.
Loading dashboards (Kibana must be running and reachable)
Loaded dashboards
Loaded Ingest pipelines
Start Filebeat and enable it at boot:
sudo systemctl enable --now filebeat
systemctl status filebeat --no-pager
Write a test line to syslog and search for it a few seconds later:
logger "filebeat test message from $(hostname)"
curl -s -u elastic --cacert /etc/filebeat/certs/http_ca.crt \
"https://your_es_host:9200/filebeat-*/_search?q=message:%22filebeat%20test%20message%22&size=1&filter_path=hits.hits._source.message"
After typing the password you should see your message:
{"hits":{"hits":[{"_source":{"message":"filebeat test message from web-01"}}]}}
In Kibana, open Discover and select the filebeat-* data view, or open Dashboards and search for [Filebeat Nginx] or [Filebeat System].
Step 5 - Adding a custom input for JSON application logs
Applications that write one JSON object per line (see structured logging) do not need grok or dissect parsing. A filestream input with the ndjson parser decodes each line into fields. Every filestream input needs a unique id, which Filebeat uses to track read offsets.
Edit /etc/filebeat/filebeat.yml and replace filebeat.inputs: [] with:
filebeat.inputs:
- type: filestream
id: orders-api-json
paths:
- /var/log/orders-api/*.log
parsers:
- ndjson:
target: "app"
add_error_key: true
fields:
service: orders-api
fields_under_root: true
target: "app" places the decoded keys under app.*, which avoids clashes with Filebeat's own ECS fields such as message or log.level. add_error_key: true adds an error.message field instead of dropping lines that are not valid JSON.
For plain-text logs with multi-line stack traces, such as Java applications, use the multiline parser. In filestream it is configured under parsers, not at the input level. This example starts a new event on every line that begins with a date and appends all other lines to the previous event:
- type: filestream
id: billing-java
paths:
- /var/log/billing/app.log
parsers:
- multiline:
type: pattern
pattern: '^\d{4}-\d{2}-\d{2}'
negate: true
match: after
Validate and restart:
sudo filebeat test config
sudo systemctl restart filebeat
Step 6 - Switching to a least-privilege API key
The elastic superuser should not stay in a configuration file on every server. Create an API key that can only write Filebeat data. Run this from any machine that can reach Elasticsearch, and enter the elastic password when prompted:
curl -s -u elastic --cacert /etc/filebeat/certs/http_ca.crt \
-X POST "https://your_es_host:9200/_security/api_key" \
-H "Content-Type: application/json" -d '
{
"name": "filebeat-web-01",
"role_descriptors": {
"filebeat_writer": {
"cluster": ["monitor", "read_ilm", "read_pipeline"],
"index": [
{
"names": ["filebeat-*"],
"privileges": ["view_index_metadata", "create_doc", "auto_configure"]
}
]
}
}
}'
{"id":"VuaCfGcBCdbkQm-e5aOx","name":"filebeat-web-01","api_key":"ui2lp2axTNmsyakw9tvNnw","encoded":"..."}
Store id:api_key in the keystore:
sudo filebeat keystore add ES_API_KEY
Enter the value as VuaCfGcBCdbkQm-e5aOx:ui2lp2axTNmsyakw9tvNnw (your own id and api_key). Then edit the output in /etc/filebeat/filebeat.yml, replacing username and password:
output.elasticsearch:
hosts: ["https://your_es_host:9200"]
api_key: "${ES_API_KEY}"
ssl.certificate_authorities: ["/etc/filebeat/certs/http_ca.crt"]
Remove the stored password, test and restart:
sudo filebeat keystore remove ES_PWD
sudo filebeat test output
sudo systemctl restart filebeat
When you need to run filebeat setup again (for example after enabling another module or upgrading), temporarily add superuser credentials or run it from an admin machine.
Troubleshooting
No events arrive. Read Filebeat's own log first: sudo journalctl -u filebeat -n 50 --no-pager. Errors such as 403 Forbidden point to API key privileges, x509: certificate signed by unknown authority to the CA file.
Events arrive but are not parsed. The ingest pipelines are missing. Rerun filebeat setup --pipelines --modules system,nginx with superuser credentials.
Exiting: no modules or inputs enabled. You enabled a module but left all its filesets at enabled: false, and there is no custom input. Enable at least one fileset.
A file is not picked up. Check the glob in paths with ls, and remember that each filestream input needs a unique id. Changing an id makes Filebeat treat the files as new and re-read them from the start.
Conclusion
Filebeat now ships system, Nginx and JSON application logs from Ubuntu 24.04 to Elasticsearch over verified TLS, authenticated with an API key that can only write Filebeat data. Next, adjust the filebeat ILM policy in Kibana so retention matches your disk budget, add processors such as drop_event to discard noisy health-check lines, and roll the same configuration out to your other servers with a configuration management tool.
