Skip to main content

NGINX

NGINX Pipelog Module: Send Access Logs to External Programs

by , , revisited on


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

📅 Updated: March 19, 2026 (Originally published: February 10, 2026)

The NGINX pipelog module allows you to send HTTP access logs to external programs via Unix pipes. This module enables workflows that standard NGINX logging cannot achieve: piping logs to custom scripts, real-time log processors, or any command-line tool.

When to Use Pipelog vs Native NGINX Logging

NGINX already supports several logging methods natively:

  • File logging: access_log /var/log/nginx/access.log;
  • Syslog: access_log syslog:server=127.0.0.1:514,tag=nginx;
  • Multiple destinations: You can specify multiple access_log directives

So when should you use the NGINX pipelog module instead?

Use pipelog when you need to:
– Pipe logs to custom scripts that process each entry in real-time
– Send real-time alerts (Slack, email) on specific access patterns
– Send logs to programs that don’t support syslog protocol
– Use shell commands or pipelines for log processing
– Have the module automatically restart crashed log consumers

Use native access_log when you need to:
– Write logs to files (native is simpler)
– Send to syslog servers (native syslog: prefix works well)
– Basic logging without external dependencies

How the NGINX Pipelog Module Works

When you configure the pipelog directive, NGINX spawns the specified command as a child process. It connects the command’s stdin to a Unix pipe. Every log entry goes to this pipe instead of a file. The external command reads from stdin and processes the log data.

This architecture offers several advantages:

  1. Pipe to any command: Send logs to scripts, log shippers, or custom processors.
  2. Real-time processing: The external command receives logs as requests complete.
  3. Automatic restart: If the pipe command crashes, the module restarts it automatically.
  4. Non-blocking option: Write operations can be non-blocking to prevent slowdowns.

Installation

RHEL, CentOS, AlmaLinux, Rocky Linux

Install the GetPageSpeed repository and the module:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-pipelog

Load the module in your NGINX configuration by adding to the top of /etc/nginx/nginx.conf:

load_module modules/ngx_http_pipelog_module.so;

Debian and Ubuntu

First, set up the GetPageSpeed APT repository, then install:

sudo apt-get update
sudo apt-get install nginx-module-pipelog

On Debian/Ubuntu, the package handles module loading automatically. No load_module directive is needed.

For more details, see the module pages:
– RPM packages: nginx-extras.getpagespeed.com/modules/pipelog
– APT packages: apt-nginx-extras.getpagespeed.com/modules/pipelog

Configuration Directives

The NGINX pipelog module provides two directives. Use pipelog_format for defining log formats. Use pipelog for enabling pipe-based logging.

pipelog_format

Defines a named log format for use with the pipelog directive.

Syntax:

pipelog_format name [escape=default|json|none] string ...;

Context: http, server, location

Parameters:
name: A unique identifier for this format
escape: How to escape special characters (default: default)
default: Escape characters as \xXX
json: JSON-compatible escaping for structured logging
none: No escaping (use with caution)
string: The format string using NGINX variables

Example:

pipelog_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';

pipelog_format json escape=json '{"time": "$time_iso8601", '
                                '"remote_addr": "$remote_addr", '
                                '"request": "$request", '
                                '"status": $status, '
                                '"body_bytes_sent": $body_bytes_sent}';

pipelog

Enables pipe-based logging to an external command.

Syntax:

pipelog command [format [nonblocking] [if=condition]];
pipelog off;

Context: http, server, location, if in location, limit_except

Default: off

Parameters:
command: The shell command to pipe logs to (no | prefix needed)
format: Name of a pipelog_format (defaults to combined format)
nonblocking: Enable non-blocking writes to prevent slow commands from blocking NGINX
if=condition: Conditional logging based on a variable

Practical Use Cases

Real-time Slack Alerts for Sensitive Endpoints

This is where the NGINX pipelog module truly shines. Send instant Slack notifications when someone accesses admin panels, API keys, or other sensitive endpoints:

http {
    pipelog_format alert escape=json
        '{"uri":"$uri","client":"$remote_addr","time":"$time_iso8601"}';

    server {
        listen 80;

        # Alert on sensitive endpoint access
        location /admin {
            pipelog "/usr/local/bin/slack-alert.sh" alert;
            proxy_pass http://backend;
        }

        location /wp-login.php {
            pipelog "/usr/local/bin/slack-alert.sh" alert;
            proxy_pass http://backend;
        }

        location /.env {
            pipelog "/usr/local/bin/slack-alert.sh" alert;
            return 404;
        }
    }
}

Create the alert script at /usr/local/bin/slack-alert.sh:

#!/bin/bash
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"

while read -r line; do
    curl -s -X POST "$WEBHOOK_URL" \
        -H "Content-Type: application/json" \
        -d "{\"text\": \"⚠️ Sensitive endpoint accessed: $line\"}" &
done

Make it executable: chmod +x /usr/local/bin/slack-alert.sh

Now every access to /admin, /wp-login.php, or /.env triggers an instant Slack notification. This is impossible with native NGINX logging alone.

Custom Log Processing Script

Send logs to a script that filters, transforms, or forwards them:

http {
    pipelog_format json escape=json
        '{"timestamp":"$time_iso8601",'
        '"client":"$remote_addr",'
        '"method":"$request_method",'
        '"uri":"$uri",'
        '"status":$status,'
        '"size":$body_bytes_sent,'
        '"request_time":$request_time}';

    server {
        listen 80;
        server_name example.com;

        pipelog "/usr/local/bin/log-processor.py" json;

        location / {
            root /var/www/html;
        }
    }
}

Your log-processor.py could send alerts on errors, update real-time metrics, filter sensitive data, or forward logs to multiple destinations.

Real-time Log Shipping

Send logs directly to a log shipper or aggregation tool that reads from stdin:

pipelog "/usr/bin/vector --config /etc/vector/nginx.toml" json;

Or pipe to nc for simple TCP forwarding to a log server:

pipelog "/usr/bin/nc logserver.example.com 5140" main;

Using logger for Syslog (Simple Demo)

While NGINX has native syslog support, using logger via pipelog demonstrates the module’s flexibility. This approach works well with journalctl for LEMP stack troubleshooting:

pipelog "/usr/bin/logger -t nginx -p local0.info" main;

Note: For simple syslog needs, native access_log syslog:server=... is simpler. Use pipelog with logger when you need additional shell processing or when combining with other commands in a pipeline.

Conditional Logging

Skip logging for specific requests using the if parameter. This technique is similar to disabling logging for Varnish backend probes:

http {
    map $uri $loggable {
        ~^/health  0;
        ~^/metrics 0;
        default    1;
    }

    pipelog_format main '$remote_addr - [$time_local] "$request" $status';

    server {
        pipelog "/usr/local/bin/log-processor.sh" main if=$loggable;

        location / {
            root /var/www/html;
        }
    }
}

This skips logging for /health and /metrics endpoints. For Magento sites, you might also want to disable logging of security probes.

Non-blocking Mode for High Traffic

On high-traffic sites, a slow log consumer could cause NGINX worker processes to block:

pipelog "/usr/local/bin/slow-processor.sh" main nonblocking;

With nonblocking enabled, log entries may be dropped if the pipe buffer fills up. Use this when log delivery is less critical than request handling performance.

Performance Considerations

The NGINX pipelog module adds minimal overhead compared to file-based logging:

  1. Pipe writes vs file writes: Writing to a pipe is typically faster than writing to disk.
  2. Memory buffering: The kernel buffers pipe data, reducing syscall overhead.
  3. External process overhead: The spawned command runs independently from NGINX workers.

However, consider these factors:

  • Pipe buffer size: The kernel pipe buffer (typically 64KB on Linux) limits queued data.
  • Consumer speed: Your external command must process logs fast enough to keep up with traffic.
  • Non-blocking tradeoffs: Using nonblocking prevents blocking but may lose logs under heavy load.

Best Practices

Follow these recommendations for reliable pipelog deployments:

  1. Always use absolute paths: Specify /usr/bin/logger instead of just logger. This prevents PATH manipulation issues.

  2. Test consumer throughput: Before production deployment, verify your log processor can handle peak traffic.

  3. Use nonblocking sparingly: Only enable nonblocking if you’ve observed actual blocking issues.

  4. Monitor the error log: The module logs pipe failures to NGINX error log. Set up monitoring for these messages.

  5. Background slow operations: In alert scripts, use & to background curl calls so they don’t block log processing.

Troubleshooting

Logs Not Appearing

  1. Check if module is loaded:

    nginx -V 2>&1 | grep -o pipelog
    
  2. Verify configuration syntax:
    nginx -t
    
  3. Check if the pipe command is running:
    ps aux | grep -E "log-processor|slack-alert"
    
  4. Test the command manually:
    echo '{"test":"data"}' | /usr/local/bin/slack-alert.sh
    

Command Crashes or Restarts

The NGINX pipelog module automatically restarts crashed commands. Check your error log:

tail -f /var/log/nginx/error.log | grep -i pipe

Security Considerations

When using the NGINX pipelog module:

  • Validate command paths: Use absolute paths for commands to prevent PATH manipulation.
  • Limit permissions: Run log processing commands with minimal privileges.
  • Sanitize log data: If your command executes log content, ensure proper escaping.
  • Protect webhook URLs: Store Slack webhook URLs in environment variables, not in scripts.

Comparison with Native access_log

Feature access_log (file) access_log (syslog:) pipelog
Writes to files Yes No No
Syslog support No Yes (native) Via logger command
Pipe to any command No No Yes
Real-time Slack/alerts No No Yes
Auto-restart consumer N/A N/A Yes
Non-blocking mode No No Yes
Conditional logging Yes (if=) Yes (if=) Yes (if=)

Bottom line: Use native access_log for files or syslog. Use the NGINX pipelog module when you need real-time alerts, custom scripts, or tools that read from stdin. For structured distributed tracing across microservices, consider the NGINX OpenTelemetry module which exports spans in OpenTelemetry format to collectors like Jaeger or Zipkin.

Conclusion

The NGINX pipelog module fills a specific gap: piping access logs to arbitrary commands in real-time. The Slack alerting example shows its true power – instant notifications when sensitive endpoints are accessed.

For sysadmins who need real-time log processing or security alerting, the pipelog module offers automatic command restart and non-blocking mode. These features make it reliable for production environments.

Install the module from the GetPageSpeed repository and explore the source code on GitHub to learn more.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.