$linuxjunkies
>

Use osquery for Linux Host Visibility

Install osquery on Linux, write SQL queries against processes, files, and sockets, configure FIM packs, and enroll hosts into a Fleet manager for full fleet visibility.

AdvancedUbuntuDebianFedoraArch12 min readUpdated June 7, 2026

Before you start

  • Root or sudo access on the target host
  • Outbound HTTPS access to pkg.osquery.io to add the repository
  • Familiarity with basic SQL SELECT syntax
  • For fleet enrollment: a running Fleet or osctrl server and a valid enrollment secret

osquery turns your Linux host into a queryable database. Instead of grepping through /proc, parsing log files, or writing custom scripts, you write SQL against tables that expose processes, open files, network sockets, users, kernel modules, cron jobs, and hundreds of other system objects. It is a foundational tool for detection engineering, incident response, and continuous compliance — and it runs on every major Linux distribution.

Install osquery

The osquery project publishes signed packages for all major distributions. Use the official repository rather than distro-packaged versions, which are often several releases behind.

Debian / Ubuntu

export OSQUERY_KEY=1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B
curl -L https://pkg.osquery.io/deb/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/osquery.gpg
echo "deb [signed-by=/usr/share/keyrings/osquery.gpg arch=amd64] https://pkg.osquery.io/deb deb main" \
  | sudo tee /etc/apt/sources.list.d/osquery.list
sudo apt update && sudo apt install -y osquery

Fedora / RHEL / Rocky

curl -L https://pkg.osquery.io/rpm/GPG | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-osquery
sudo tee /etc/yum.repos.d/osquery.repo <<'EOF'
[osquery]
name=osquery
baseurl=https://pkg.osquery.io/rpm
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-osquery
EOF
sudo dnf install -y osquery

Arch Linux

yay -S osquery   # or paru, or clone the osquery AUR package directly

Start the Daemon

osqueryd is the long-running daemon that logs scheduled query results and forwards them to a fleet manager. osqueryi is the interactive shell for ad-hoc queries. Both are installed by the package.

sudo systemctl enable --now osqueryd
systemctl status osqueryd

The daemon reads its configuration from /etc/osquery/osquery.conf. If that file does not exist, the daemon starts with defaults and logs to /var/log/osquery/. Create a minimal config to verify the daemon accepts it:

sudo tee /etc/osquery/osquery.conf <<'EOF'
{
  "options": {
    "logger_plugin": "filesystem",
    "logger_path": "/var/log/osquery",
    "disable_events": "false",
    "schedule_splay_percent": "10"
  },
  "schedule": {}
}
EOF
sudo systemctl restart osqueryd

Interactive Queries with osqueryi

Launch the interactive shell as root for full table access:

sudo osqueryi

The prompt looks like osquery>. Every statement is SQL against a virtual schema. Start with discovery:

# List all available tables
SELECT name FROM osquery_tables ORDER BY name;

# Schema for a specific table
.schema processes

Query Processes

-- Running processes with network connections (join processes + process_open_sockets)
SELECT p.pid, p.name, p.path, p.cmdline, s.remote_address, s.remote_port
FROM processes p
JOIN process_open_sockets s ON p.pid = s.pid
WHERE s.remote_port != 0
ORDER BY p.name;

Query Open Files and Sockets

-- Processes listening on TCP
SELECT p.name, p.pid, s.local_address, s.local_port, s.state
FROM listening_ports s
JOIN processes p ON s.pid = p.pid
WHERE s.protocol = 6
ORDER BY s.local_port;
-- Writable files in /tmp owned by root but world-writable
SELECT path, mode, uid, gid, size
FROM file
WHERE directory = '/tmp'
  AND (CAST(mode AS INTEGER) & 2) != 0;

Query Users and Cron

-- All cron entries system-wide
SELECT command, path, minute, hour, day_of_month, month, day_of_week
FROM crontab;
-- Users with UID 0 (should normally be only root)
SELECT username, uid, gid, shell, directory
FROM users
WHERE uid = 0;
-- Kernel modules currently loaded
SELECT name, size, status, address
FROM kernel_modules
ORDER BY name;

Scheduled Queries and Packs

Packs are JSON bundles of scheduled queries with their own intervals and platform filters. osquery ships with community packs in /usr/share/osquery/packs/ (exact path varies by distro). Notable packs include incident-response, it-compliance, and ossec-rootkit.

Enable packs by referencing them in osquery.conf:

sudo tee /etc/osquery/osquery.conf <<'EOF'
{
  "options": {
    "logger_plugin": "filesystem",
    "logger_path": "/var/log/osquery",
    "disable_events": "false",
    "schedule_splay_percent": "10",
    "events_expiry": "3600"
  },
  "schedule": {
    "system_info": {
      "query": "SELECT hostname, cpu_brand, physical_memory FROM system_info;",
      "interval": 3600
    },
    "listening_ports": {
      "query": "SELECT pid, port, protocol, family, address FROM listening_ports;",
      "interval": 300
    }
  },
  "packs": {
    "incident-response": "/usr/share/osquery/packs/incident-response.conf",
    "it-compliance": "/usr/share/osquery/packs/it-compliance.conf"
  }
}
EOF
sudo systemctl restart osqueryd

Scheduled results accumulate in /var/log/osquery/osqueryd.results.log as newline-delimited JSON. Each record includes the query name, a diff of added/removed rows, and the epoch timestamp — directly ingestible by most SIEM and log aggregation tools.

sudo tail -f /var/log/osquery/osqueryd.results.log | python3 -m json.tool

File Integrity Monitoring with FIM

osquery's file_events table provides inotify-backed FIM. Define paths to watch in osquery.conf under the file_paths key, then query file_events in a schedule:

sudo tee /etc/osquery/osquery.conf <<'EOF'
{
  "options": {
    "disable_events": "false"
  },
  "file_paths": {
    "etc": ["/etc/%%"],
    "ssh": ["/home/%/.ssh/%%", "/root/.ssh/%%"],
    "binaries": ["/usr/bin/%%", "/usr/sbin/%%"]
  },
  "schedule": {
    "file_events": {
      "query": "SELECT target_path, action, md5, sha256, time FROM file_events;",
      "interval": 60,
      "removed": false
    }
  }
}
EOF
sudo systemctl restart osqueryd

Note: %% is osquery's recursive glob; % is a single directory wildcard. Monitoring very large directory trees will increase CPU and inotify watch usage. Check your inotify limit with cat /proc/sys/fs/inotify/max_user_watches and increase it in /etc/sysctl.d/ if needed.

Fleet Management

Running osquery on a single host is useful; running it across a fleet is transformative. The two most common open-source fleet managers are Fleet (formerly Kolide Fleet, now fleetdm.com) and osctrl. Both implement the osquery TLS remote API.

Enroll a Host with Fleet

After deploying the Fleet server (a separate task covered in the Fleet documentation), generate an enrollment secret from the Fleet UI or CLI, then configure osquery to use the TLS plugin:

sudo tee /etc/osquery/osquery.flags <<'EOF'
--tls_hostname=fleet.example.com
--host_identifier=hostname
--enroll_secret_path=/etc/osquery/enroll_secret
--tls_server_certs=/etc/osquery/fleet.crt
--config_plugin=tls
--config_tls_endpoint=/api/v1/osquery/config
--logger_plugin=tls
--logger_tls_endpoint=/api/v1/osquery/log
--enroll_tls_endpoint=/api/v1/osquery/enroll
EOF
# Write your enrollment secret (obtained from the Fleet server)
echo -n 'YOUR_ENROLL_SECRET' | sudo tee /etc/osquery/enroll_secret
sudo chmod 600 /etc/osquery/enroll_secret
sudo systemctl restart osqueryd

Once enrolled, Fleet distributes pack configurations centrally and lets you run live queries against any or all enrolled hosts from a single interface — no SSH required.

Verify Everything is Working

# Confirm the daemon is active
systemctl is-active osqueryd

# Check for startup errors
journalctl -u osqueryd -n 50 --no-pager

# Confirm results are being written
sudo ls -lh /var/log/osquery/

# Quick ad-hoc check from the interactive shell
sudo osqueryi --line "SELECT * FROM os_version;"

Troubleshooting

  • osqueryd won't start after config change: Validate JSON syntax with python3 -m json.tool /etc/osquery/osquery.conf before restarting. A single trailing comma breaks the parser.
  • file_events table is empty: Confirm --disable_events=false is set (it defaults to false, but an explicit flag in an older osquery.flags file may override the config). Also verify inotify watches are not exhausted.
  • High CPU on a busy host: Increase schedule_splay_percent and raise query intervals. The process_events table in particular can generate high volume on active servers — filter aggressively in the query's WHERE clause.
  • TLS enrollment fails: Check that the clock on the host is within a few seconds of the Fleet server (NTP drift causes TLS failures). Also verify the CA certificate path in --tls_server_certs.
  • Permission errors in osqueryi: Most tables that read /proc or /etc/shadow require root. Run sudo osqueryi for full visibility.
tested on:Ubuntu 24.04Debian 12Fedora 40Rocky 9

Frequently asked questions

Does osquery work on Wayland desktops or does it require X11?
osquery is a daemon and CLI tool with no display dependency. It works identically on headless servers, Wayland desktops, and X11 systems. Desktop session information is exposed through the logged_in_users table regardless of display server.
How does osquery differ from auditd for monitoring file and process events?
auditd writes raw audit records to a flat log and requires aureport or ausearch to make sense of them. osquery uses the same kernel event sources but exposes results as structured SQL tables with JOIN support, making correlation across process, file, and network data far easier to express and automate.
Will running osquery noticeably impact production server performance?
At default intervals (300–3600 seconds for most scheduled queries) the overhead is negligible on modern hardware. Tables like process_events or dns_lookup_events that fire on every kernel event can be expensive; always add specific WHERE filters and keep their intervals short to limit log volume, not query frequency.
Can osquery detect rootkits or kernel-level tampering?
osquery can detect many rootkit indicators using the ossec-rootkit pack: SUID files, unexpected kernel modules, processes hidden from /proc, and setuid binaries in unusual locations. It cannot detect sophisticated bootkit or hypervisor-level tampering that manipulates the kernel before osquery runs.
What is the difference between osquery packs and scheduled queries defined directly in osquery.conf?
Functionally identical — packs are simply a way to bundle related queries into separate JSON files for easier versioning and sharing. The Fleet manager also lets you target packs to specific host labels, so separating queries into packs enables fine-grained fleet-wide targeting.

Related guides