Directive Coverage
bext supports 68 of 70 commonly used nginx directives (97% coverage). This page documents every supported directive and how it maps to bext's internal configuration.
Server Block Directives
listen
Parsed with full support for all common options:
listen 80;
listen 443 ssl http2;
listen [::]:80;
listen 0.0.0.0:8080 default_server;
Extracts: port, address, SSL flag, HTTP/2 flag, and default_server designation.
server_name
All name patterns are supported:
server_name example.com; # Exact match
server_name *.example.com; # Wildcard prefix
server_name example.*; # Wildcard suffix
server_name ~^api\d+\.example\.com$; # Regex
server_name .example.com; # Exact + wildcard prefix
server_name _; # Catch-all
Matching priority (same as nginx): exact > longest wildcard prefix > wildcard suffix > first regex match > default server.
root and index
root /var/www/html;
index index.html index.htm index.php;
error_page
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
default_type
default_type application/octet-stream;
Location Blocks
All five nginx location match types are supported with correct priority:
location = /health { } # Exact match (highest priority)
location ^~ /static/ { } # Prefix priority (skips regex)
location ~ \.php$ { } # Regex (case-sensitive)
location ~* \.(jpg|png)$ { } # Regex (case-insensitive)
location /api/ { } # Plain prefix (lowest priority)
Nested locations are supported:
location /api/ {
location /api/v2/ {
proxy_pass http://backend-v2;
}
proxy_pass http://backend-v1;
}
Proxy Directives
proxy_pass
location /api/ {
proxy_pass http://backend;
proxy_pass http://127.0.0.1:3000;
proxy_pass http://upstream_name;
}
Automatically detects upstream references and resolves them. WebSocket upgrade headers are detected and handled.
proxy_set_header
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
All nginx variables are substituted with bext runtime placeholders.
proxy_redirect
proxy_redirect off;
proxy_redirect default;
proxy_redirect http://backend/ /;
Proxy Timeouts
proxy_read_timeout 60s;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
Proxy Cache
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
location / {
proxy_cache my_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_bypass $http_pragma;
proxy_no_cache $http_authorization;
proxy_cache_use_stale error timeout updating;
proxy_cache_background_update on;
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
}
Upstream Blocks
Full support for load balancing:
upstream backend {
least_conn; # or: ip_hash, hash $uri
server 127.0.0.1:3001 weight=3;
server 127.0.0.1:3002;
server 127.0.0.1:3003 backup;
server 127.0.0.1:3004 down;
keepalive 32;
}
Load balancing strategies: round-robin (default), least_conn, ip_hash, hash (with variables).
Rewrite and Redirect
rewrite
rewrite ^/old/(.*)$ /new/$1 permanent; # 301 redirect
rewrite ^/temp/(.*)$ /new/$1 redirect; # 302 redirect
rewrite ^/api/v1/(.*)$ /api/v2/$1 last; # internal rewrite
rewrite ^/legacy/(.*)$ /current/$1 break;
Capture groups ($1, $2, etc.) are preserved and substituted.
return
return 301 https://$host$request_uri; # HTTPS redirect
return 200 "OK"; # Fixed response
return 403; # Status-only
Conditional Blocks
if ($request_uri ~ ^/old/) {
return 301 /new/;
}
if (-f $request_filename) {
break;
}
if (-d $request_filename) {
rewrite ^(.*)$ $1/index.html break;
}
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
Supports file existence (-f), directory existence (-d), regex matching (~, ~*), equality (=, !=), and variable existence checks.
try_files
try_files $uri $uri/ =404; # Static site
try_files $uri $uri/ /index.html; # SPA fallback
try_files $uri $uri/ /index.php?$query_string; # PHP/Laravel
try_files $uri @backend; # Named location
Resolution order:
1. Check each pattern (variable-substituted, path-traversal-guarded) 2. If a file exists, serve it 3. If a directory exists, check for index files 4. Fall back to the last argument: status code, internal redirect, or named location
SSL/TLS
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_dhparam /etc/nginx/dhparam.pem;
All certificates are loaded into bext's SNI resolver for multi-cert support.
Compression
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_comp_level 6;
gzip_min_length 256;
gzip_vary on;
gzip_proxied any;
Rate Limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_conn addr 10;
}
Access Control
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff";
add_header Strict-Transport-Security "max-age=31536000" always;
Variables and Maps
map
map $http_accept_language $lang {
default en;
~^fr fr;
~^de de;
}
geo
geo $country {
default US;
192.168.0.0/16 INTERNAL;
10.0.0.0/8 INTERNAL;
}
set
set $backend "http://127.0.0.1:3000";
FastCGI (PHP)
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
}
Converted to bext's embedded PHP runtime or proxied to an external PHP-FPM process.
Other Directives
autoindex on; # Directory listing
stub_status; # Status page
sub_filter 'old-text' 'new-text'; # Response body substitution
sub_filter_once off;
expires 30d; # Cache expiration header
client_max_body_size 50m; # Request body limit
keepalive_timeout 65;
Variable Substitution
All nginx variables are mapped to bext runtime placeholders:
| nginx Variable | bext Placeholder |
|---|---|
$host |
{host} |
$uri, $document_uri |
{uri} |
$request_uri |
{request_uri} |
$args, $query_string |
{query_string} |
$is_args |
{is_args} |
$scheme |
{scheme} |
$request_method |
{method} |
$remote_addr |
{client_ip} |
$server_name |
{server_name} |
$server_port |
{server_port} |
$server_protocol |
{server_protocol} |
$document_root |
{document_root} |
$request_filename |
{request_filename} |
$http_* |
{header:*} |
$cookie_* |
{cookie:*} |
$arg_* |
{arg:*} |