Configure NGINX features with F5 WAF
This document shows examples of how to modify your NGINX configuration to enable F5 WAF for NGINX features.
It is intended as a reference for small, self-contained examples of how F5 WAF for NGINX can be configured.
Important constraints when F5 WAF for NGINX is enabled:
- Subrequest-based modules (NGINX modules that create internal HTTP subrequests) are not inspected in any scope block where app_protect_enable on is set. F5 WAF for NGINX inspects only direct, client-facing HTTP requests.
- Modules that require the HTTP Range header are not supported in the same configuration scope as app_protect_enable on. Place Range-dependent configuration in a server or location block without F5 WAF for NGINX enabled.
For additional information on configuring NGINX, you should view the NGINX documentation.
F5 WAF for NGINX inspects direct client-facing requests, but does not inspect internal subrequests generated by subrequest-based modules.
Examples of subrequest-based modules:
- Slice
- Mirror
- Client authorization
- njs
load_module modules/ngx_http_app_protect_module.so;
http {
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
app_protect_enable on;
proxy_pass http://127.0.0.1:8081$request_uri;
}
}
server {
listen 127.0.0.1:8081;
server_name localhost;
location / {
proxy_pass http://1.2.3.4$request_uri;
slice 2;
proxy_set_header Range $slice_range;
}
}
}load_module modules/ngx_http_app_protect_module.so;
http {
log_format test $uri;
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
app_protect_enable on;
mirror /mirror;
}
location /mirror {
log_subrequest on;
access_log test$args.log test;
}
}
}load_module modules/ngx_http_app_protect_module.so;
http {
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
auth_request /scan;
proxy_pass http://localhost:8888;
}
location /scan {
proxy_pass http://localhost:8081$request_uri;
}
}
server {
listen 127.0.0.1:8081;
server_name localhost;
location /scan {
app_protect_enable on;
proxy_pass http://localhost:8888;
}
}
}load_module modules/ngx_http_app_protect_module.so;
load_module modules/ngx_http_js_module.so;
http {
js_include service.js
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
app_protect_enable on;
proxy_pass http://127.0.0.1:8081$request_uri;
}
}
server {
listen 127.0.0.1:8081;
server_name localhost;
location / {
js_content foo;
}
}
}This configuration example shows how to enable WAF on an njs module that relies on the subrequest mechanism.
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
load_module modules/ngx_http_app_protect_module.so;
load_module modules/ngx_http_js_module.so;
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
js_import main from example.js;
server {
listen 80;
server_name localhost;
proxy_http_version 1.1;
app_protect_enable on;
location / {
proxy_pass http://127.0.0.1:8080/foo/$request_uri;
}
}
server {
listen 127.0.0.1:8080;
server_name localhost;
proxy_http_version 1.1;
location /foo {
js_content main.fetch_subrequest;
}
location / {
internal;
return 200 "Hello! I got your URI request - $request_uri\n";
}
}
}async function fetch_subrequest(r) {
let reply = await r.subrequest('/<script>');
let response = {
uri: reply.uri,
code: reply.status,
body: reply.responseText,
};
r.return(200, JSON.stringify(response));
}
export default {join};If the njs handler triggers an internal subrequest to /<script>, it is not inspected by F5 WAF for NGINX and succeeds:
curl "localhost/" {"uri":"/<script>","code":200,"body":"Hello! I got your URI request - /foo//\n"}However, if a direct, client-facing request attempts to trigger the same URL, it is inspected by F5 WAF for NGINX and is blocked according to the security policy.
curl "localhost/<script>"<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.
Your support ID is: 123456789
<a href='javascript:history.back();'>[Go Back]</a></body></html>Features that add or depend on the HTTP Range header are unsupported in the same scope as app_protect_enable on. Place Range-dependent logic in a separate scope that does not enable F5 WAF for NGINX, and have the F5 WAF for NGINX enable frontend proxy to that backend.
Examples of Range-dependent features:
- Static location
- Range
load_module modules/ngx_http_app_protect_module.so;
http {
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
app_protect_enable on;
proxy_pass http://127.0.0.1:8080/proxy/$request_uri;
}
location /proxy {
default_type text/html;
return 200 "Hello! I got your URI request - $request_uri\n";
}
}
}load_module modules/ngx_http_app_protect_module.so;
http {
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
app_protect_enable on;
proxy_pass http://127.0.0.1:8081$request_uri;
}
}
server {
listen 127.0.0.1:8081;
server_name localhost;
location / {
proxy_pass http://1.2.3.4$request_uri;
proxy_force_ranges on;
}
}
}