Graceful Shutdown
Edit on GitHubGhostunnel supports graceful shutdown: when a shutdown is triggered, it stops accepting new connections and waits for existing connections to drain before exiting. If connections do not drain within the configured timeout, the process force-exits.
Shutdown Triggers #
A graceful shutdown can be initiated with a signal or via an HTTP endpoint:
Signals (Unix) #
On Unix (Linux, macOS), sending SIGTERM or SIGINT to the Ghostunnel
process triggers a graceful shutdown:
# Graceful shutdown via signal
kill -TERM <pid>
kill -INT <pid> # also sent by Ctrl+CNote:
SIGHUPandSIGUSR1do not shut down the process. They trigger a reload of certificates and OPA policies instead.
Signals (Windows) #
On Windows, the Interrupt signal (Ctrl+C) triggers shutdown. When running
as a Windows service, a service stop
request from the Service Control Manager triggers the same graceful shutdown.
There are no reload signals on Windows, but --timed-reload can be used to
periodically reload certificates and OPA policies on a fixed interval.
HTTP endpoint (/_shutdown) #
Available since v1.8.1.
If --enable-shutdown is set (requires --status), you can trigger a
shutdown via HTTP POST:
curl -X POST --cacert test-keys/cacert.pem https://localhost:6060/_shutdownAny HTTP method other than POST returns 405 Method Not Allowed.
Shutdown Sequence #
When a shutdown is triggered, the following happens in order:
- Status transitions to “stopping”: the
/_statusendpoint reflects that the process is shutting down. - Status HTTP server begins shutting down: best-effort graceful shutdown of the internal status listener.
- Force-exit timer starts: a timer begins counting down from the
--shutdown-timeoutvalue (default: 5 minutes). - Listener closes: Ghostunnel stops accepting new connections.
- In-flight connections continue: established connections are not interrupted. Data continues to flow until both sides close normally. Connections that are still mid-handshake (or mid-dial to the backend) when shutdown starts are canceled rather than drained.
- Process exits when either:
- All in-flight connections have drained (exit code 0), or
- The shutdown timeout fires (exit code 1).
Flags #
| Flag | Default | Description |
|---|---|---|
--shutdown-timeout | 5m | Maximum time to wait for in-flight connections to drain. If connections are still open after this duration, the process force-exits with code 1. |
--enable-shutdown | false | Enable the /_shutdown HTTP endpoint on the status port. Requires --status. |
--status | (none) | [http(s)://]HOST:PORT, unix:PATH, systemd:NAME, or launchd:NAME for the status listener. Required for /_shutdown. |
See Command-Line Flags for the full flag reference.
Choosing a Shutdown Timeout #
The default timeout of 5 minutes is generous. Tune it based on your workload:
- Short-lived requests (e.g. REST APIs): a lower timeout like
30sor1mis usually sufficient. - Long-lived connections (e.g. streaming, WebSocket-like traffic): you may need to increase the timeout or accept that some connections will be force-closed.
- Zero-downtime deployments: coordinate the shutdown timeout with your
orchestrator’s termination grace period (e.g. Kubernetes
terminationGracePeriodSeconds) to avoid the orchestrator killing the process before Ghostunnel’s own timeout fires.
Other flags like --connect-timeout and --max-conn-lifetime also influence
connection behavior and may be relevant when tuning shutdown. See
Command-Line Flags for the full list.
Integration with systemd #
Available since v1.8.0.
When running as a systemd service with Type=notify-reload, Ghostunnel
notifies systemd of its state transitions (ready, reloading, stopping). The
graceful shutdown sequence integrates with systemd’s service
lifecycle. See Systemd for unit file examples and
configuration details.