# Nginx reload failure during Let's Encrypt renewal — race condition on /run/nginx.pid in ExecReload

**URL:** <https://forum.hestiacp.com/t/nginx-reload-failure-during-lets-encrypt-renewal-race-condition-on-run-nginx-pid-in-execreload/22158>\
**Category:** General Questions\
**Created:** [August 25, 2026, 11:56am UTC](https://forum.hestiacp.com/t/nginx-reload-failure-during-lets-encrypt-renewal-race-condition-on-run-nginx-pid-in-execreload/22158 "2026-08-25T11:56:25Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![joao.machado](https://forum.hestiacp.com/letter_avatar_proxy/v4/letter/j/b5ac83/32.png) [@joao.machado](https://forum.hestiacp.com/u/joao.machado)\
**Post date:** [August 25, 2026, 11:56am UTC](https://forum.hestiacp.com/t/nginx-reload-failure-during-lets-encrypt-renewal-race-condition-on-run-nginx-pid-in-execreload/22158/1 "2026-08-25T11:56:25Z")

</div>

**Environment:**

- HestiaCP on Ubuntu (systemd-based nginx service)
- Default `/usr/lib/systemd/system/nginx.service`:

```auto
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStart=/usr/sbin/nginx -c ${CONFFILE}
ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /run/nginx.pid)"
ExecStop=/bin/sh -c "/bin/kill -s TERM $(/bin/cat /run/nginx.pid)"

```

**Observed behavior:**

During a normal Let’s Encrypt renewal for a single domain, `v-add-letsencrypt-domain` triggers **multiple restart calls in quick succession** :

```auto
07:51:52 v-generate-ssl-cert 'espacotres.com.br'
07:51:56 v-add-letsencrypt-domain 'espacotr' 'espacotres.com.br'
07:52:12 v-restart-service 'apache2' 'ssl'
07:52:17 v-restart-service 'nginx' 'ssl'

```

Inside the script, the relevant lines are:

```auto
312: $BIN/v-restart-proxy
313: check_result $? "Proxy restart failed" > /dev/null
345: $BIN/v-restart-proxy
346: check_result $? "Proxy restart failed" > /dev/null
360: $BIN/v-restart-web
361: check_result $? "Web restart failed" > /dev/null

```

So a single-domain renewal calls `v-restart-proxy` **twice** , then `v-restart-web` once — three separate reload/restart triggers for one certificate.

**The failure:**

In one of these consecutive reload cycles, the journal shows:

```auto
systemd[1]: Reloading nginx.service...
systemd[1]: Reloaded nginx.service.
systemd[1]: Reloading nginx.service...
systemd[1]: Reloaded nginx.service.
systemd[1]: Reloading nginx.service...
sh[...]: /bin/cat: /run/nginx.pid: No such file or directory
sh[...]: Usage: kill [options] <pid> [...]
systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
systemd[1]: Reload failed for nginx.service.
systemd[1]: Stopping nginx.service...
systemd[1]: nginx.service: Deactivated successfully.
systemd[1]: Starting nginx.service...

```

**Root cause hypothesis:**

`ExecReload` reads `/run/nginx.pid` via `cat` and pipes it into `kill`. When multiple restart/reload calls fire back-to-back (as `v-add-letsencrypt-domain` does), one of them can hit a brief window where nginx is mid-restart and the pidfile has been removed/not yet rewritten. `cat` then returns nothing, `kill -s HUP` runs with no PID argument, exits 1, and systemd marks the reload as failed — even though the underlying nginx config was valid the whole time. Systemd then stops and restarts the whole service, which succeeds, so end users see no actual outage, but the panel logs a “Nginx Restart Failed” alert.

**Questions for the community / maintainers:**

1. Is the double `v-restart-proxy` call in `v-add-letsencrypt-domain` intentional, or a leftover/redundancy? Would consolidating to a single restart/reload call (or adding a short delay between the two) be an acceptable fix?
2. Would it make sense to harden the shipped `ExecReload` to use `nginx -s reload` instead of the manual `cat`+`kill` pattern, to make it robust against overlapping calls regardless of what triggers them?
3. As a local workaround, we applied a systemd drop-in override:

```auto
[Service]
ExecReload=
ExecReload=/usr/sbin/nginx -s reload

```

Does this have any known downsides in a HestiaCP context (e.g. interaction with `v-restart-proxy`/`v-restart-web`’s own status checks)?
