One config for the four common setups
Reverse proxy sends requests to an app on a local port - Node.js, Next.js, Python, .NET - and passes on the real client IP and protocol in X-Forwarded headers. Static site serves files from a folder. SPA does the same but sends unknown paths to index.html so React, Vue or Angular routing works on refresh. PHP-FPM hands .php files to PHP and routes everything else through index.php, the way Laravel and WordPress expect.
HTTPS and redirects done in one place
With HTTPS on, port 80 answers only with a 301 to the HTTPS address, and the non-canonical name (www or bare domain - you choose) redirects to the canonical one, so every page has a single address. That matters for SEO as much as for security. Certificate paths follow Let’s Encrypt’s layout; run certbot first if you do not have a certificate yet.
Two nginx traps this avoids
First: an add_header inside a location block silently drops every add_header inherited from the server block - including your security headers. The static-asset cache rule therefore uses expires, which does not have that effect. Second: from nginx 1.25.1, HTTP/2 is switched on with http2 on; and the old listen 443 ssl http2 form logs a deprecation warning. Untick the version switch for older servers.
After deploying, run the security headers checker and the website speed test against the site to confirm the headers, HTTP/2 and compression are really live.

