Nginx Forking Service Unit
Create a systemd unit file for Nginx as a forking daemon. Covers configuration testing with ExecStartPre, PIDFile tracking, graceful reload, and signal-based lifecycle management.
Detailed Explanation
Running Nginx with systemd
Nginx traditionally runs as a forking daemon: the master process forks worker processes and the master writes its PID to a file. This is a classic Type=forking use case.
[Unit]
Description=Nginx HTTP Server
After=network.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
Configuration Validation
ExecStartPre=/usr/sbin/nginx -t -q runs nginx -t (test configuration) before starting. The -q flag suppresses output unless there's an error. If the configuration is invalid, the service fails to start with a clear error instead of starting with a broken config.
Nginx Signal Handling
Nginx uses Unix signals for lifecycle management:
| Signal | Nginx Action | systemd Directive |
|---|---|---|
| HUP | Reload configuration | ExecReload |
| QUIT | Graceful shutdown | ExecStop |
| TERM | Fast shutdown | (systemd default) |
| USR1 | Reopen log files | Custom |
| USR2 | Binary upgrade | Custom |
Graceful Reload
systemctl reload nginx
This sends SIGHUP to the master process. Nginx:
- Tests the new configuration
- Starts new worker processes with the new config
- Gracefully shuts down old workers (finish current connections)
- No downtime — no connections dropped
File Descriptor Limits
Nginx worker processes need one file descriptor per connection, plus descriptors for log files and upstream connections. For a server handling 10,000 concurrent connections:
LimitNOFILE=65535
Also configure worker_rlimit_nofile in nginx.conf to match.
Graceful Stop with Timeout
ExecStop=/bin/kill -s QUIT $MAINPID sends SIGQUIT for graceful shutdown:
- Workers finish processing current requests
- No new connections accepted
TimeoutStopSec=30gives 30 seconds for requests to complete- After timeout, systemd sends SIGKILL
Binary Upgrade (Zero-Downtime)
For upgrading the Nginx binary without downtime, use the USR2 signal:
kill -USR2 $(cat /run/nginx.pid)
# New master starts → old workers finish → kill old master
kill -QUIT $(cat /run/nginx.pid.oldbin)
This is typically scripted rather than managed through systemd directives.
Use Case
Deploying Nginx as a production web server or reverse proxy with configuration validation, graceful reloads for zero-downtime config changes, and proper signal-based lifecycle management.