---
title: NGINX
description: Validate, start, reload and stop an NGINX process from Bun with bun:nginx.
---

`bun:nginx` controls an installed NGINX executable from JavaScript. Bun manages the NGINX master process; NGINX itself handles HTTP, TLS, proxying, caching and its configured modules. `bun:Nginixx` resolves to the same module.

```ts
import Nginx from "bun:nginx";
import { homedir } from "node:os";
import { join } from "node:path";

const provider = await Nginx.probe({ binary: "/usr/sbin/nginx" });
if (!provider.available) throw new Error(provider.message);

await using nginx = await Nginx.create({
  binary: "/usr/sbin/nginx",
  prefix: join(homedir(), "apps", "my-nginx"),
  configFile: "nginx.conf",
  timeoutMs: 10_000,
});
await nginx.validate();
const started = await nginx.start();
console.log(started.pid);
await nginx.reload();
```

Bun does not download NGINX. `binary` defaults to `nginx` on `PATH`.

## Prefix and configuration

The prefix directory must already exist and `configFile` must resolve inside it. Omit the `daemon` and `pid` directives: Bun runs NGINX in the foreground and writes the master PID to `<prefix>/bun-nginx.pid`. Create NGINX's log and temporary directories inside the prefix, or set their paths in the configuration.

Only one controller can own a prefix at a time; ownership is recorded in an exclusive `.bun-nginx-owner` file. `start()` refuses a prefix that already contains a PID file, and `reload()` and `quit()` check that the PID belongs to the master Bun started. The controller never adopts, reloads or stops an NGINX process it did not start. On Unix the master runs in its own process group; on Windows it runs in a job object that terminates it when the controller closes.

`validate()` runs `nginx -t` with a separate temporary PID file, so it never touches the PID file of a running master.

## API

| Method                  | Description                                                                         |
| ----------------------- | ----------------------------------------------------------------------------------- |
| `Nginx.probe(options?)` | Runs `nginx -V` and reports version, configure arguments and compiled capabilities. |
| `Nginx.create(options)` | Claims the prefix and returns a controller.                                         |
| `nginx.probe(options?)` | Same as `Nginx.probe` for this controller's executable.                             |
| `nginx.validate()`      | Tests the configuration.                                                            |
| `nginx.start()`         | Starts the master and resolves with its status once the PID is written.             |
| `nginx.reload()`        | Reloads the configuration in the same master.                                       |
| `nginx.quit()`          | Stops the master gracefully. The controller can be started again.                   |
| `nginx.status()`        | Returns `{ running, pid, prefix, configFile, pidFile, closed, lastExitCode }`.      |
| `nginx.close()`         | Quits, releases the prefix and resolves with `{ closed: true, forced }`.            |

All methods return promises. `create()` and `probe()` accept:

| Option            | Description                                                           |
| ----------------- | --------------------------------------------------------------------- |
| `binary`          | Executable path or name on `PATH`. Default `nginx`.                   |
| `binaryArguments` | Launcher arguments placed before NGINX flags (at most 16).            |
| `maxOutputBytes`  | Limit for each of stdout and stderr, 1–1048576 bytes. Default 262144. |
| `timeoutMs`       | Deadline in milliseconds, integer 1–30000.                            |
| `signal`          | `AbortSignal` that cancels the operation.                             |
| `prefix`          | (`create` only) Existing directory owned by this controller.          |
| `configFile`      | (`create` only) Configuration file inside `prefix`.                   |

Every operation also accepts its own `timeoutMs` and `signal`. Running two operations on the same controller at once rejects with `ERR_NGINX_BUSY`.

## Lifetime

A running master keeps Bun's event loop alive. When the master exits, Bun stops its remaining workers. A failed or aborted `start()` terminates the child. `close()` attempts a graceful quit and terminates the process if that exceeds the deadline (`forced: true`); calling it again succeeds. If the controller is garbage-collected or the process exits, Bun terminates the NGINX processes it started. Use `await using` or a `finally` block to close the controller deterministically.

## Errors

`probe()` resolves with `available: false` and code `ERR_NGINX_PROVIDER_UNAVAILABLE` when the executable cannot be run. Other failures reject with one of these codes:

| Code                             | Meaning                                               |
| -------------------------------- | ----------------------------------------------------- |
| `ERR_NGINX_PROVIDER_UNAVAILABLE` | The NGINX executable cannot be run.                   |
| `ERR_NGINX_CONFIG`               | NGINX rejected the configuration.                     |
| `ERR_NGINX_OWNER`                | The prefix or PID file belongs to another controller. |
| `ERR_NGINX_BUSY`                 | Another operation is in progress on this controller.  |
| `ERR_NGINX_TIMEOUT`              | The operation exceeded `timeoutMs`.                   |
| `ERR_NGINX_OUTPUT_LIMIT`         | NGINX output exceeded `maxOutputBytes`.               |
| `ERR_NGINX_NATIVE`               | A process or system call failed.                      |
| `ABORT_ERR`                      | The operation was cancelled with its `AbortSignal`.   |

Invalid options, such as a `configFile` that resolves outside `prefix`, reject with `ERR_INVALID_ARG_VALUE`.

The capabilities reported by `probe()` (`http`, `httpTLS`, `http2`, `http3`, `stream`, `mail`, `udp`, `threads`, ...) come from the build flags printed by `nginx -V`. `platform` and `arch` describe the host running Bun, not the executable.

## Windows

The official NGINX for Windows is a beta release: it uses a single effective worker process (`effectiveWorkersMaximum: 1`) and does not support UDP or QUIC. See [NGINX for Windows](https://nginx.org/en/docs/windows.html).

The repository script `packages/bun-nginx/scripts/prepare-provider.ts` downloads the official NGINX 1.31.6 Windows ZIP, verifies its signature with the official NGINX signing keys in an isolated keyring, and extracts it into a directory you choose:

```powershell
bun packages/bun-nginx/scripts/prepare-provider.ts C:\path\to\nginx-sdk "C:\Program Files\Git\usr\bin\gpg.exe"
```

## Rust HTTP module

[`packages/bun-nginx/native`](https://github.com/aphrody-labs/bun/tree/main/packages/bun-nginx/native) contains an NGINX HTTP module written in Rust with [ngx-rust](https://github.com/nginx/ngx-rust). It is compiled into an NGINX executable built from source with `--add-module` (see `packages/bun-nginx/scripts/build-provider.ts`); a stock NGINX binary does not include it. It adds two location directives:

- `bun_nginx;` returns a small JSON metadata response.
- `bun_nginx_delay <ms>;` (1–1000) returns that response after an asynchronous NGINX timer.

```nginx
events { worker_connections 32; }
http {
    server {
        listen 127.0.0.1:8080;
        location = /info { bun_nginx; }
        location = /delay { bun_nginx_delay 500; }
    }
}
```

The optional `@aphrody/bun-nginx` package re-exports `bun:nginx` and adds `readModuleInfo(nginx, url, options?)`, which reads that response over loopback HTTP and checks that it comes from the master owned by the controller:

```ts
import { readModuleInfo } from "@aphrody/bun-nginx";

const info = await readModuleInfo(nginx, "http://127.0.0.1:8080/info");
console.log(info.nginxVersion, info.masterPID, info.pendingTimers);
```

`options` accepts `timeoutMs` (default 2000), `signal` and `expectedConfigurationSha256`.

## References

- [NGINX command-line switches](https://nginx.org/en/docs/switches.html)
- [NGINX development guide](https://nginx.org/en/docs/dev/development_guide.html)
- [Building NGINX from sources](https://nginx.org/en/docs/configure.html)
