A container ignores docker stop when its main process never receives the SIGTERM signal. This usually happens with shell form CMD or ENTRYPOINT, where a shell runs as PID 1 and your app is only its child. Switch to exec form, or call exec in your start script.
What actually happens on docker stop
The Dockerfile reference says docker stop sends a signal to end the container, and the default is SIGTERM. You can change it with the STOPSIGNAL instruction or per container at run time. Whatever process runs as PID 1 inside the container is the one that gets it.
Now look at how you wrote the start command. Shell form looks like this:
CMD node server.js
Docker runs that under a shell. The reference states that in shell form your process is a child of the shell, so it is not PID 1 and does not receive signals such as SIGTERM from docker stop. The shell may not forward the signal, so the app keeps running until the engine gives up and forces it to end.
Exec form fixes it
Exec form is a JSON array and runs the program directly, with no shell in between.
CMD ["node", "server.js"]
Docker's best practices page says CMD should almost always be used in this form. The reference prefers it for ENTRYPOINT too, and for both when they work together. A side effect: because no shell runs, environment variable expansion in the command does not happen. If you need it, read the variables inside your program or use a small start script.
When you need a start script
Many images run a script to render config, then start the app. The best practices page recommends ending such a script with the exec builtin so the final application becomes PID 1 and receives Unix signals.
#!/bin/sh
set -e
render_config
exec node server.js
Without exec, the script stays PID 1 and the app is again a child.
Why this is a security topic
Slow or forced shutdowns look like an operations nuisance, but they matter for safety. Rolling out a patched image depends on old containers stopping promptly. Graceful shutdown also lets apps flush logs and close connections, which keeps audit trails complete. And a process that cannot be stopped cleanly tends to get stopped with force, which can drop in flight work.
Checklist
| Check | Good sign |
|---|---|
| CMD and ENTRYPOINT in JSON array form | Yes |
| Start scripts finish with exec | Yes |
| STOPSIGNAL matches what your app handles | Yes |
| App handles SIGTERM in code | Yes |
To test, run the container, call docker stop, and watch how long it takes. Then check your logs for a clean shutdown message.
Quick check
Is shell form CMD always wrong?
Not always, but it is a common cause of missed signals. Prefer exec form, or use the exec builtin in a script.
Does Ctrl+C use the STOPSIGNAL setting?
No. The reference says STOPSIGNAL does not affect Ctrl+C, which sends SIGINT directly to the process.
Safeguard
Safeguard does SBOM and dependency scanning, and its policies and gates can run in CI so a bad image does not reach production. You can try a free scan before deciding anything.
Sources
Last reviewed: 19 October 2026.