Masquerade Mode

Masquerade mode makes bext a full drop-in replacement for nginx. External tools — certbot, logrotate, monitoring, deployment scripts — see nginx and interact with it normally, but bext handles all traffic.

How It Works

Masquerade mode has three components:

1. Shim binary — installed at /usr/sbin/nginx, intercepts all CLI invocations 2. systemd drop-in — overrides the nginx.service to run bext instead 3. PID file — written at /run/nginx.pid for signal-based management

Installation

sudo bext nginx masquerade install

This performs four steps:

1. Backs up the real nginx binary to /usr/sbin/nginx.real 2. Installs the bext-nginx-shim at /usr/sbin/nginx 3. Writes a systemd drop-in at /etc/systemd/system/nginx.service.d/bext-masquerade.conf 4. Runs systemctl daemon-reload

Custom Paths

sudo bext nginx masquerade install \
  --bext-bin /usr/local/bin/bext-server \
  --shim-bin /usr/sbin/nginx \
  --pid-file /run/nginx.pid

Uninstallation

sudo bext nginx masquerade uninstall

This restores the original nginx binary, removes the systemd drop-in, and runs daemon-reload.

The Shim Binary

The shim at /usr/sbin/nginx handles all standard nginx CLI flags:

Flag Behavior
-t, -T Tests config syntax via bext-server nginx check
-v, -V Prints nginx/1.28.2 (bext-masquerade)
-s reload Sends SIGHUP to bext (config + TLS reload)
-s stop Sends SIGTERM to bext (graceful shutdown)
-s quit Sends SIGQUIT to bext (immediate shutdown)
-s reopen Sends SIGUSR1 to bext (log file reopen)
-c /path Specifies config file path
-g, -p Accepted but ignored (compatibility)

Combined flags work too: nginx -tc /etc/nginx/nginx.conf

The shim reads the PID file (default /run/nginx.pid, override with BEXT_PID_FILE) to find the running bext process for signal delivery.

systemd Drop-In

The generated override file:

# /etc/systemd/system/nginx.service.d/bext-masquerade.conf
[Service]
Type=exec
PIDFile=/run/nginx.pid
ExecStartPre=
ExecStart=/usr/local/bin/bext-server --nginx-masquerade
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
ExecStopPost=/bin/rm -f /run/nginx.pid
Restart=on-failure
RestartSec=5
LimitNOFILE=65535

This means:

- systemctl start nginx starts bext

- systemctl stop nginx stops bext

- systemctl reload nginx sends SIGHUP (config + TLS reload)

- systemctl status nginx shows bext's status

- Automatic restart on failure with 5-second delay

Signal Handling

SIGHUP — Config Reload

When bext receives SIGHUP (via nginx -s reload or systemctl reload nginx):

1. Re-parses the nginx config file from disk 2. Logs any new conversion warnings 3. Rebuilds the complete routing state (vhosts, upstreams, rate limiters) 4. Reloads all TLS certificates from disk into the SNI resolver 5. Performs an atomic state swap using ArcSwap

In-flight requests continue with the old config. New requests immediately use the new config. If the config parse fails, the old config continues serving and the error is logged.

This is critical for certbot integration — after Let's Encrypt renews a certificate, nginx -s reload (or the certbot deploy hook) reloads the new cert without downtime.

SIGUSR1 — Log Reopen

When bext receives SIGUSR1 (via nginx -s reopen):

1. Reopens the access log file in append mode 2. Updates the internal file handle

This enables standard logrotate workflows:

# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    rotate 14
    compress
    postrotate
        /usr/sbin/nginx -s reopen
    endscript
}

SIGTERM — Graceful Shutdown

Finishes in-flight requests, then exits. The PID file is cleaned up by the ExecStopPost directive.

Listening Configuration

In masquerade mode, bext:

1. Extracts all unique ports from the nginx vhost listen directives 2. Binds HTTP on every detected port 3. Binds HTTPS on port 443 with SNI resolution using all nginx TLS certificates 4. Sets the first certificate as the default fallback 5. Writes the PID file before accepting connections

Certbot Integration

Certbot works unchanged after masquerade installation:

# Initial certificate issuance
sudo certbot --nginx -d example.com

# The certbot nginx plugin interacts with the shim
# Renewal hooks call nginx -s reload, which sends SIGHUP to bext

The SIGHUP handler reloads certificates from disk, so the standard certbot renewal flow works without modification.

Monitoring Compatibility

Tools that check nginx status continue to work:

- systemctl status nginx — shows bext process status

- PID file/run/nginx.pid contains bext's PID

- nginx -t — validates config syntax via bext

- nginx -V — reports version (bext-masquerade)

- Process name — visible in ps as bun run server.ts or bext-server