Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/v3/configuration/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Options:
--text-charset [<TEXT_CHARSET>]
Set a default `charset=utf-8` parameter on limited set of `text` responses that don't already have one [env: SERVER_TEXT_CHARSET=] [default: true] [possible values: true, false]
--health [<HEALTH>]
Add a /health endpoint that doesn't generate any log entry and returns a 200 status code. This is especially useful with Kubernetes liveness and readiness probes [env: SERVER_HEALTH=] [default: false] [possible values: true, false]
Add the `/livez` (liveness) and `/readyz` (readiness) endpoints for Kubernetes-style probes. They answer `GET` and `HEAD` with `200 OK` and log requests at `debug` level only [env: SERVER_HEALTH=] [default: false] [possible values: true, false]
--metrics [<METRICS>]
Enable the /metrics endpoint that exposes Prometheus metrics for HTTP requests, connections, and latency [env: SERVER_METRICS=] [default: false] [possible values: true, false]
--maintenance-mode [<MAINTENANCE_MODE>]
Expand Down
2 changes: 1 addition & 1 deletion src/v3/configuration/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ Set a default `charset=utf-8` parameter on limited set of `text` responses that

## SERVER_HEALTH

Add a `/health` endpoint that doesn't generate any log entry and returns a `200` status code. This is especially useful with Kubernetes liveness and readiness probes. Default `false` (disabled).
Add the `/livez` (liveness) and `/readyz` (readiness) endpoints for Kubernetes-style probes. They answer `GET` and `HEAD` with `200 OK` and log requests at `debug` level only. See [Health endpoint](../features/health-endpoint.md) for details. Default `false` (disabled).

## SERVER_METRICS

Expand Down
2 changes: 1 addition & 1 deletion src/v3/configuration/file.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ use-relative-root = false
#### Check for existing pre-compressed files
compression-static = true

#### Health-check endpoint (GET or HEAD `/health`)
#### Health-check endpoints (GET or HEAD `/livez` and `/readyz`)
health = false

#### Markdown content negotiation
Expand Down
2 changes: 1 addition & 1 deletion src/v3/defaults.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ The types considered compressible include all `text/*` MIME types, plus `applica

| Setting | Default | Rationale |
| ---------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------ |
| Health endpoint | disabled | Opt-in via `--health`. Returns `200 OK` at `/health` with no log noise. Designed for Kubernetes probes. |
| Health endpoints | disabled | Opt-in via `--health`. Returns `200 OK` at `/livez` and `/readyz` with no log noise. For Kubernetes probes. |
| Metrics endpoint | disabled | Opt-in via `--metrics`. Exposes Prometheus metrics at `/metrics`. |
| Markdown content negotiation | disabled | Opt-in. When enabled, serves `.md` files for `Accept: text/markdown` requests. |
| Maintenance mode | disabled | Opt-in for planned downtime. Returns `503` with a custom page. |
Expand Down
2 changes: 1 addition & 1 deletion src/v3/features/custom-http-headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ SWS validates the codes at startup and fails to start on an empty array or a cod
An optional string that selects which responses the entry applies to:

- `files` (default): responses of the static file handler only, including error responses such as `404 Not Found` and plain [URL rewrites](url-rewrites.md), which are served as files.
- `all`: also the responses SWS returns before serving a file: [URL redirects](url-redirects.md), [URL rewrites](url-rewrites.md) with `redirect`, the [health endpoint](health-endpoint.md), the [metrics endpoint](metrics.md), CORS requests rejected with `403 Forbidden`, [Basic Authentication](basic-authentication.md) challenges, [maintenance mode](maintenance-mode.md) and `405 Method Not Allowed`.
- `all`: also the responses SWS returns before serving a file: [URL redirects](url-redirects.md), [URL rewrites](url-rewrites.md) with `redirect`, the [health endpoints](health-endpoint.md), the [metrics endpoint](metrics.md), CORS requests rejected with `403 Forbidden`, [Basic Authentication](basic-authentication.md) challenges, [maintenance mode](maintenance-mode.md) and `405 Method Not Allowed`.

These early responses serve no file, so `source` is matched against the request path as is. `scope` can be combined with `status`.

Expand Down
7 changes: 6 additions & 1 deletion src/v3/features/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,14 @@ spec:
- --health
ports:
- containerPort: 8787
name: http
livenessProbe:
httpGet:
path: /health
path: /livez
port: http
readinessProbe:
httpGet:
path: /readyz
port: http
```

Expand Down
2 changes: 2 additions & 0 deletions src/v3/features/graceful-shutdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ Here is an example of delaying the graceful shutdown process by `10` seconds aft
```sh
static-web-server -p 8787 -d ./public/ -g trace --grace-period 10
```

With the [health endpoints](./health-endpoint.md) enabled, `/readyz` returns `503 Service Unavailable` during the grace period.
82 changes: 74 additions & 8 deletions src/v3/features/health-endpoint.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,61 @@
# Health endpoint

SWS provides an optional `/health` endpoint that can be used to check if it is running properly.
When the `/health` is requested, SWS will generate a log only at the `debug` level instead of the usual `info` level for a regular file.
SWS provides optional health endpoints for the Kubernetes-style [liveness and readiness probes](https://kubernetes.io/docs/reference/using-api/health-checks/):

The HTTP methods supported are `GET` and `HEAD`.
| Path | Probe |
| --------- | --------- |
| `/livez` | Liveness |
| `/readyz` | Readiness |

This feature is disabled by default and can be controlled by the boolean `--health` option or the equivalent [SERVER_HEALTH](../configuration/env.md#server_health) env.
This feature is disabled by default and can be controlled by the boolean `--health` option, the equivalent [SERVER_HEALTH](../configuration/env.md#server_health) env, or the `health` key in the [config file](../configuration/file.md).

## Usage with Kubernetes liveness probe
```sh
static-web-server --root ./public --health
SERVER_HEALTH=true static-web-server --root ./public
```

```toml
[general]
health = true
```

> [!WARNING] `/health` was removed in v3
> SWS v2 served a single `/health` endpoint. SWS v3 serves `/livez` and `/readyz` instead, and requests to `/health` go to the static file handler like any other path. See the [migration guide](../migration-guide.md#_10-health-endpoint-replaced-by-livez-and-readyz).

## Behavior

When the feature is enabled, SWS answers `GET` and `HEAD` requests to `/livez` and `/readyz` with `200 OK`:

- `GET` returns the body `OK` with `Content-Type: text/plain; charset=utf-8`.
- `HEAD` returns the same headers with an empty body.
- The query string is ignored, so `/livez?verbose` and `/readyz?verbose` also return `200 OK`.
- Only the exact paths match: `/livez/`, `/readyz/` or `/LIVEZ` go to the static file handler.
- Other methods are not handled by the health endpoints: `OPTIONS` goes on to the rest of the request pipeline (e.g. [CORS](./cors.md)), and methods SWS does not support, such as `POST`, return `405 Method Not Allowed`.
- Requests are logged at `debug` level instead of the usual `info` level, to avoid noise from frequent probes. See [Logging](./logging.md#per-request-logging).

Once shutdown starts (`SIGTERM`, `SIGINT`, `SIGQUIT` or <kbd>CTRL + C</kbd> on Windows), `/readyz` returns `503 Service Unavailable` with the body `shutting down`, while `/livez` keeps returning `200 OK`. With a [grace period](./graceful-shutdown.md), SWS keeps serving requests during that time, so load balancers stop routing new traffic before connections close.

```sh
curl -i http://localhost:8787/livez
```

```text
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
content-length: 2

OK
```

The health endpoint is well suited for the Kubernetes liveness probe:
When the feature is disabled, `/livez` and `/readyz` are regular paths served from the root directory.

## Interaction with other features

The health endpoints run before [CORS](./cors.md), [Basic Authentication](./basic-authentication.md), [maintenance mode](./maintenance-mode.md), [URL redirects](./url-redirects.md) and [URL rewrites](./url-rewrites.md), so probes succeed without credentials and while maintenance mode is on.

[Custom HTTP headers](./custom-http-headers.md) apply to the health endpoints only with `scope = "all"`.

## Usage with Kubernetes probes

```yaml
apiVersion: v1
Expand All @@ -26,10 +72,30 @@ spec:
- --log-level=info
- --health
ports:
- containerPort: 80
- containerPort: 8787
name: http
livenessProbe:
httpGet:
path: /health
path: /livez
port: http
readinessProbe:
httpGet:
path: /readyz
port: http
```

Add `--grace-period` (e.g. `--grace-period=10`) so `/readyz` fails while SWS still serves in-flight and new requests during a rollout. Keep it below the pod's `terminationGracePeriodSeconds` (default `30`).

### With TLS

With [`--tls`](./tls.md), point the probes at the TLS port and set `scheme: HTTPS`. The kubelet skips certificate verification for HTTPS probes.

```yaml
readinessProbe:
httpGet:
path: /readyz
port: https
scheme: HTTPS
```

Do not probe the [`--https-redirect`](./http-https-redirect.md) port: it accepts only `Host` values listed in `--https-redirect-from-hosts` (default `localhost`), and the kubelet sends the pod IP, so probes get `400 Bad Request`.
2 changes: 1 addition & 1 deletion src/v3/features/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static-web-server -p 8788 -d ./public/ -g trace --log-format pretty --log-with-a

## Per-request logging

When the level is `info` or lower, SWS logs each request with the `incoming request` message. Requests to the health endpoint are logged at `debug` level instead, to avoid noise from frequent probes.
When the level is `info` or lower, SWS logs each request with the `incoming request` message. Requests to the [health endpoints](./health-endpoint.md) (`/livez` and `/readyz`) are logged at `debug` level instead, to avoid noise from frequent probes.

```json
{
Expand Down
2 changes: 1 addition & 1 deletion src/v3/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ SWS is designed to be **simple by default, powerful when needed**. You can point
| [**Trailing Slash Redirect**](./features/trailing-slash-redirect) | Enforce or remove trailing slashes on directory URLs. |
| [**Error Pages**](./features/error-pages) | Replace the default 404/5xx pages with your own HTML files. |
| [**Logging**](./features/logging) | Structured JSON or human-readable text combined logs to stdout or a file. |
| [**Health Endpoint**](./features/health-endpoint) | A dedicated `/health` route for load balancer and orchestrator checks. |
| [**Health Endpoint**](./features/health-endpoint) | The `/livez` and `/readyz` routes for load balancer and orchestrator checks. |
| [**Metrics**](./features/metrics) | Prometheus-compatible metrics endpoint for monitoring and alerting. |
| [**Virtual Hosting**](./features/virtual-hosting) | Serve multiple domains from a single SWS instance by host header routing. |
| [**Multiple Index Files**](./features/multiple-index-files) | Fallback chain of index documents (`index.html`, `index.htm`, etc.). |
Expand Down
15 changes: 15 additions & 0 deletions src/v3/migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ The v2 supports running SWS as a WASM/WASI binary (via Wasmer). However, v3 stil

**Action:** For now, if you run SWS on WASM/WASI, stay on v2 or migrate to a native binary (Linux, macOS, Windows).

### 10. Health endpoint replaced by `/livez` and `/readyz`

| | v2 | v3 |
| --------------- | ---------- | ---------------------- |
| Liveness probe | `/health` | `/livez` |
| Readiness probe | `/health` | `/readyz` |
| Enable | `--health` | `--health` (unchanged) |

v3 no longer serves `/health`. With `--health` enabled, requests to `/health` go to the static file handler like any other path, which usually returns `404 Not Found`. The `--health` flag, the `SERVER_HEALTH` env var and the `health` TOML key are unchanged.

**Action:** Point liveness probes at `/livez` and readiness probes at `/readyz`. Update any load balancer or monitoring check that requests `/health`.

See the [Health endpoint](./features/health-endpoint.md) page for more details.

## Quick migration checklist

1. **Port:** Add `--port 80` if you were relying on the default.
Expand All @@ -127,3 +141,4 @@ The v2 supports running SWS as a WASM/WASI binary (via Wasmer). However, v3 stil
7. **Logging:** Add `--log-format pretty` if you prefer old-style human-readable logs.
8. **TOML `text-charset`:** Change `"utf-8"` string to `true` boolean.
9. **WebAssembly:** Migrate to a native binary — Wasm is no longer supported.
10. **Health endpoint:** Replace `/health` with `/livez` (liveness) and `/readyz` (readiness) in probes and checks.