Falco is an open-source runtime security tool from the CNCF that watches Linux system calls and raises an alert when a process does something suspicious, such as opening a shell inside a container, reading /etc/shadow or writing below /etc. Image scanners find known vulnerabilities before deployment; Falco catches what actually happens while containers run. In this tutorial you will install Falco on Ubuntu 24.04 with the modern eBPF driver, trigger and read its alerts from Docker containers, write your own rules, and forward alerts to Slack with Falcosidekick.
Prerequisites
To follow this tutorial you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with a non-root user that has
sudoprivileges. The default Ubuntu 24.04 kernel (6.8) supports the modern eBPF driver, so no kernel headers or module builds are needed. - Docker Engine installed, to run test containers.
- At least 1 GB of free RAM for Falco.
- Optionally, a Slack incoming webhook URL for Step 6.
Step 1 - Adding the Falco repository
The Falco project publishes signed packages. Download its signing key into /etc/apt/keyrings:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://falco.org/repo/falcosecurity-packages.asc | sudo gpg --dearmor -o /etc/apt/keyrings/falco-archive-keyring.gpg
Add the repository:
echo "deb [signed-by=/etc/apt/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" | sudo tee /etc/apt/sources.list.d/falcosecurity.list
sudo apt update
Step 2 - Installing Falco with the modern eBPF driver
Falco needs a driver to receive system calls from the kernel. The modern eBPF driver is built into the Falco binary and works on any kernel from 5.8, so it is the right choice on Ubuntu 24.04. The package normally asks which driver to use in an interactive dialog; the environment variables below answer that question in advance:
sudo FALCO_FRONTEND=noninteractive FALCO_DRIVER_CHOICE=modern_ebpf apt install -y falco
The package installs and starts the falco-modern-bpf service. It also enables falcoctl-artifact-follow, which keeps the default rule set up to date automatically. Check that Falco is running:
sudo systemctl status falco-modern-bpf --no-pager
● falco-modern-bpf.service - Falco: Container Native Runtime Security with modern ebpf
Loaded: loaded (/usr/lib/systemd/system/falco-modern-bpf.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-09-25 10:15:02 UTC; 20s ago
Look at the startup log to confirm which rule files were loaded:
sudo journalctl -u falco-modern-bpf -n 20 --no-pager
The log lists /etc/falco/falco_rules.yaml (the default rules), /etc/falco/falco_rules.local.yaml and /etc/falco/rules.d if present, and ends with a line saying Falco is opening the modern BPF event source.
Step 3 - Triggering and reading your first alerts
The default rules already cover common attacker behavior in containers. Start a long-running test container:
docker run -d --name falco-test alpine:3.22 sleep 3600
Open an interactive shell in it and read the password hash file, two actions an attacker typically performs after getting in:
docker exec -it falco-test sh -c 'cat /etc/shadow > /dev/null'
Now read the alerts. Falco writes them to syslog, so they appear in the journal of its service:
sudo journalctl -u falco-modern-bpf --since "5 minutes ago" --no-pager | grep -E 'Notice|Warning'
Sep 25 10:17:41 server falco[2210]: 10:17:41.338411276: Notice A shell was spawned in a container with an attached terminal | evt_type=execve user=root user_uid=0 process=sh command=sh -c cat /etc/shadow > /dev/null terminal=34816 container_id=5c1a9e0f3b2d container_name=falco-test ...
Sep 25 10:17:41 server falco[2210]: 10:17:41.340102519: Warning Sensitive file opened for reading by non-trusted program | file=/etc/shadow process=cat command=cat /etc/shadow user=root container_id=5c1a9e0f3b2d container_name=falco-test ...
Each alert starts with a priority (Notice, Warning, Critical...), a description taken from the rule, and the fields that explain who did what: command line, user, file and container. To follow alerts live while you test, run sudo journalctl -u falco-modern-bpf -f.
Step 4 - Writing a custom rule
Never edit /etc/falco/falco_rules.yaml: it is replaced on every package or rules update. Put your own rules and changes in /etc/falco/falco_rules.local.yaml, which is loaded after the default file and can use its macros and lists.
As an example, add a rule that detects a package manager running inside a running container. Containers should be immutable, so installing software in one usually means someone is working inside it by hand, or an attacker is adding tools:
sudo nano /etc/falco/falco_rules.local.yaml
- list: package_manager_binaries
items: [apt, apt-get, dpkg, apk, yum, dnf, pip, pip3, npm]
- rule: Package manager run in container
desc: A package manager was executed inside a running container
condition: >
spawned_process
and container
and proc.name in (package_manager_binaries)
output: >
Package manager run in container
(command=%proc.cmdline user=%user.name container_id=%container.id
container_name=%container.name image=%container.image.repository)
priority: WARNING
tags: [container, software_mgmt]
spawned_process and container are macros defined in the default rules: the first matches every new process, the second limits the rule to processes that are not on the host.
Validate the rules before relying on them. Pass the default file too, because your rule uses its macros:
sudo falco -V /etc/falco/falco_rules.yaml -V /etc/falco/falco_rules.local.yaml
The command should report that both files are valid. Falco watches its configuration and rule files (watch_config_files: true by default) and reloads itself when they change, so no restart is needed. Trigger the new rule:
docker exec falco-test apk --version
sudo journalctl -u falco-modern-bpf --since "1 minute ago" --no-pager | grep 'Package manager'
Sep 25 10:24:03 server falco[2210]: 10:24:03.912775120: Warning Package manager run in container (command=apk --version user=root container_id=5c1a9e0f3b2d container_name=falco-test image=alpine)
Step 5 - Tuning noisy default rules
Some default rules fire on legitimate activity in your environment. Rather than disabling a rule entirely, add an exception to its condition with override. For example, to stop the terminal shell rule from firing for a debug image you use on purpose, append this to /etc/falco/falco_rules.local.yaml:
- rule: Terminal shell in container
condition: and not container.image.repository = "registry.example.com/debug-tools"
override:
condition: append
override: condition: append adds your text to the end of the original rule's condition, so every other container is still covered. Validate the files again with the falco -V command from Step 4 after each change.
Step 6 - Sending alerts to Slack with Falcosidekick
Reading the journal does not scale. Falcosidekick is the Falco project's companion service that receives alerts over HTTP and forwards them to Slack, email, webhooks, Loki, Elasticsearch and many other outputs. Run it as a container that listens only on localhost, replacing the webhook placeholder with your Slack incoming webhook URL:
docker run -d --name falcosidekick --restart unless-stopped \
-p 127.0.0.1:2801:2801 \
-e SLACK_WEBHOOKURL="https://hooks.slack.com/services/your/webhook/url" \
-e SLACK_MINIMUMPRIORITY=warning \
falcosecurity/falcosidekick
SLACK_MINIMUMPRIORITY=warning sends only Warning and higher to Slack, so routine Notice events stay in the journal.
Now tell Falco to send each alert as JSON to Falcosidekick. Falco loads extra configuration files from /etc/falco/config.d/, which keeps your changes separate from the packaged falco.yaml:
sudo nano /etc/falco/config.d/falcosidekick.yaml
json_output: true
http_output:
enabled: true
url: "http://127.0.0.1:2801/"
Restart Falco to be sure the new output is active, then trigger the sensitive file rule again:
sudo systemctl restart falco-modern-bpf
docker exec falco-test cat /etc/shadow > /dev/null
Check that Falcosidekick received and forwarded the event:
docker logs --tail 5 falcosidekick
2026/09/25 10:31:12 [INFO] : Slack - POST OK (200)
The alert also appears in your Slack channel, with the rule name, priority and output fields.
Running Falco on Kubernetes
On Kubernetes, Falco runs as a DaemonSet so that every node is monitored. The official Helm chart deploys Falco and, optionally, Falcosidekick:
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
--namespace falco --create-namespace \
--set driver.kind=modern_ebpf \
--set falcosidekick.enabled=true \
--set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/your/webhook/url" \
--set falcosidekick.config.slack.minimumpriority=warning
Check that one Falco pod runs per node and that it loaded its rules:
kubectl -n falco get pods -o wide
kubectl -n falco logs -l app.kubernetes.io/name=falco -c falco --tail 20
Custom rules are passed through the chart's customRules value instead of editing files on the nodes.
Clean up the test container
Remove the container used for testing:
docker rm -f falco-test
Troubleshooting
The service fails to start and the log mentions the BPF probe or bpf permissions. Confirm the kernel version with uname -r; the modern eBPF driver needs 5.8 or later. On an older kernel, reinstall with FALCO_DRIVER_CHOICE=kmod, which builds a kernel module and needs the matching linux-headers-$(uname -r) package.
No alerts appear in the journal. Check that you are reading the right unit (falco-modern-bpf, not a stopped falco-kmod), and that syslog_output is still enabled. Make sure the action really happened inside a container: the same command on the host does not match container rules.
Falco does not start after editing a rule. A rule or YAML error stops Falco from loading. Run sudo falco -V /etc/falco/falco_rules.yaml -V /etc/falco/falco_rules.local.yaml to see the exact line.
A rule fires constantly. Identify it with sudo journalctl -u falco-modern-bpf --since "1 hour ago" | grep -oE '(Notice|Warning|Critical|Error) [^|(]+' | sort | uniq -c | sort -rn | head, then add a narrow exception with override as in Step 5.
Conclusion
Falco now watches every process on your server, alerts on shells in containers, sensitive file reads and your own package manager rule, and forwards important events to Slack through Falcosidekick. Treat the default rules as a baseline: tune them with narrow exceptions until the alerts you receive are worth reading. As next steps, send alerts to your log platform through another Falcosidekick output, deploy the Helm chart on your Kubernetes clusters, and combine Falco with image scanning in CI so you cover both build time and run time.
