The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Use one Nginx server block on port 80 to issue a permanent redirect, and a separate TLS-enabled block on port 443 to serve the site. In the HTTPS block, make try_files end with =404 and map errors with error_page 404 /404.html;. That combination preserves the requested path and query string, serves a custom not-found page internally, and leaves the client with an actual HTTP 404 instead of a second redirect or a misleading 200 response.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
The canonical two-server-block configuration
Keep insecure traffic and secure content handling separate. The port-80 block should do nothing except redirect to HTTPS:
As an Amazon Associate I earn from qualifying purchases.
Recommended Free Tools
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
$request_uri contains the original path and query string, so a request for http://example.com/assets/missing.css?v=4 is sent to https://example.com/assets/missing.css?v=4. The 301 status tells clients and caches that the move is permanent.
The destination needs its own TLS listener, certificate, key, content root, and not-found handling:
#1 Best Overall
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ $uri.html =404;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
}
A redirect does not create TLS configuration. Until the 443 block has a valid certificate and private key, the browser cannot complete the HTTPS connection that the 301 advertises.
What happens to a missing URL
- The client requests an HTTP URL on port 80.
- Nginx returns
301with aLocationpointing to the HTTPS version of the same request URI. - The client makes a new request to port 443.
- The TLS server block checks the requested path with
try_files. - If no listed file or directory exists, the final
=404parameter generates a not-found response. error_page 404 /404.html;internally selects the custom document while retaining the error response semantics.
The browser therefore receives the content of /404.html with status 404. It does not receive a second 301, and it does not receive a successful 200 merely because a friendly error document was rendered.
Configure the redirect safely
Use a dedicated port-80 block
Put the redirect in the server block that listens on port 80. Do not place it in the HTTPS content location. A redirect embedded in the secure location can interfere with normal routing and, in a misconfigured setup, send requests around in a loop.
List every hostname that should answer on port 80 in server_name. If one hostname is canonical, use a fixed destination instead of reflecting the request host:
Rank #2
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
The fixed-host form is appropriate when both names must converge on example.com. The $host form keeps the requested, configured hostname in the redirect and is useful when both names are intentionally valid public hosts. Choose deliberately; the redirect target determines your canonical-host policy.
Preserve the complete request URI
Use $request_uri, not only a literal slash. It carries the path and query string that the visitor requested. Omitting it sends every URL to the home page and can break deep links, asset requests, search results, and application parameters.
Choose a status that matches the move
| Status | Typical use | Method behavior | Operational note |
|---|---|---|---|
| 301 | Permanent HTTP-to-HTTPS migration | Clients may change a non-GET request to GET | Can be cached aggressively; the pattern in this guide uses it. |
| 302 | Temporary redirect | Historically may change method to GET | Use only when the move is temporary. |
| 307 | Temporary redirect while preserving method | Preserves the original method | Useful for temporary changes involving POST or other non-GET requests. |
| 308 | Permanent redirect while preserving method | Preserves the original method | Use when a permanent move must retain method semantics and your clients support it. |
A permanent 301 is the clearest general-purpose choice for a site-wide HTTP-to-HTTPS migration. If an API must preserve POST, PUT, or another method across the redirect, evaluate 307 or 308 instead of assuming every client will retain the method after a 301.
Make static routing return a real 404
How try_files evaluates paths
In try_files $uri $uri/ $uri.html =404;, Nginx checks the requested URI as a file, then as a directory, then with an .html suffix. The last parameter is the result when none of those candidates exists. Because that final parameter is =404, Nginx emits status 404 rather than passing the request to a success page.
This form suits a static site that supports extensionless links and optional directory indexes. If your site does not use extensionless HTML, you can simplify the list, but retain an explicit final 404 outcome for absent resources.
Place the custom document under the configured root
Create the file at /var/www/html/404.html when the server’s root is /var/www/html. The document can contain normal HTML, styles, and images that are available at paths that themselves resolve successfully. Keep the page useful without depending on a JavaScript application or a missing API endpoint; an error page should still render when the original route is broken.
Restrict direct access to the handler URI
The exact location block uses internal;:
location = /404.html {
internal;
}
Nginx can enter this location through its internal error processing, but an external request for /404.html is not allowed to use it as a normal public endpoint. The exact-match location also prevents a broader location from accidentally applying different handling to the error document.
Preserve the 404 status during error rendering
The plain directive is the important distinction:
error_page 404 /404.html;
This performs an internal redirect to the specified URI while retaining the not-found result sent to the client. Nginx documents that this kind of internal redirect changes the client request method to GET for methods other than GET and HEAD; that behavior affects how the error document is fetched internally, not whether the original response is a 404.
Rank #4
Do not substitute an external redirect when the requirement is a genuine not-found response:
error_page 404 =301 https://example.com/404.html;
The =301 form intentionally changes the client-visible result to a redirect. A crawler, browser, or monitoring system then sees 301 and may follow it to a page that returns 200. That is a different design from serving a custom representation of a 404.
Application and proxy routing require a different check
Static files can be checked directly by Nginx. An application server or reverse proxy may instead receive every unknown path and generate a generic page with status 200. That is a “soft 404”: it looks like an error to a person but reports success to clients, search engines, caches, and monitoring tools.
For an application-backed location, make the upstream framework return 404 when the route or resource does not exist. If Nginx uses a fallback to an application entry point, verify that the application distinguishes an unknown route from its normal home page. Do not add a blanket success fallback merely to make navigation appear complete.
You can still use an Nginx error_page for the final 404, but the upstream must first emit the correct status. Test both an unknown route and a known route whose underlying record is absent; they may take different application paths but should each report the status your API or site contract specifies.
When TLS terminates before Nginx
Some deployments terminate TLS at a load balancer, reverse proxy, or edge service and forward traffic to Nginx over an internal connection. In that architecture, Nginx may see an ordinary HTTP connection even though the visitor used HTTPS.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallConfigure the edge to pass a trusted indication of the original protocol and configure Nginx to use that signal. The exact header name, rewrite rule, and trust boundary depend on the proxy product and network design; they are not interchangeable. Never treat an arbitrary client-supplied forwarding header as proof that a request was secure. The edge should overwrite or authenticate the signal, and Nginx should redirect only requests that the trusted architecture identifies as originally HTTP.
If Nginx redirects every internal HTTP hop without checking the trusted protocol signal, an already-secure visitor can be redirected repeatedly. Keep the port-80 redirect for direct HTTP traffic, and adapt it to the documented forwarded-protocol mechanism when TLS is terminated upstream.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Validate the configuration before reloading
Check syntax and certificates
- Confirm that the certificate and private-key paths in the 443 block exist and are readable by the Nginx worker process.
- Run
nginx -tto test configuration syntax and referenced files. - Only after a successful test, reload Nginx using your operating system’s service procedure or the Nginx reload signal. A reload applies the new configuration without needlessly stopping existing workers.
A syntax test does not prove that a certificate is trusted by every client or that an upstream application returns the intended status. Those require request-level checks.
Check the redirect and query string
curl -i "http://example.com/missing-page?source=test"
For the port-80 request, verify a 301 status and a Location whose HTTPS URL still contains /missing-page?source=test. If the path or query string disappears, inspect the return directive for a missing $request_uri.
Free tools Windows power users keep installed
One-click scans. No signup required.
Check the final response without hiding redirects
curl -i "https://example.com/missing-page?source=test"
curl -iL "http://example.com/missing-page?source=test"
The direct HTTPS request should end with status 404 and the body of your custom page. The -L request should show the initial 301 followed by the final 404. A final 200 indicates an application fallback, an incorrect error_page target, or a custom page being served by a separate success location.
Quick Recap
Troubleshooting common failure modes
The redirect loops
- Check whether TLS is terminated at a proxy. Nginx may be redirecting an internal HTTP hop that originated as HTTPS.
- Confirm that the port-80 redirect is not duplicated inside the 443 content location.
- Inspect every proxy’s forwarded-protocol handling and trust configuration.
The browser reports a certificate error after the redirect
- Verify that the 443 server block has
listen 443 ssl;. - Check that the certificate covers the hostname in the redirect.
- Check the configured certificate and private-key files and their permissions.
An unknown URL returns 200
- Inspect
try_filesand ensure its final parameter is=404, not an application entry point that always succeeds. - For proxied applications, inspect the upstream response status for the unknown route.
- Look for a broad fallback location that replaces an upstream 404 with a generated page.
The custom page redirects instead of returning 404
- Search the configuration for
error_page 404 =301,=302, or another explicit response code. - Use the internal form
error_page 404 /404.html;when the client must receive 404. - Make sure
/404.htmlis an actual file beneath the configured root and that its exact location is not being overridden.
The custom page itself is inaccessible
- Confirm the file exists at the path produced by the server’s
root. - Check read permissions for the Nginx worker.
- Remember that
internal;blocks direct browser access by design; test it through a missing resource rather than requesting/404.htmldirectly.
Configuration decisions at a glance
| Decision | Recommended pattern | When to choose another option |
|---|---|---|
| HTTP redirect location | Dedicated listen 80 server block with return 301 |
Use a temporary status only for a genuinely temporary migration. |
| Redirect destination | https://$host$request_uri when both listed hosts remain valid |
Use a fixed hostname when enforcing one canonical host. |
| Static missing-file handling | try_files ... =404 |
Application routes need an upstream status-aware design. |
| Custom error document | error_page 404 /404.html; plus an exact internal location |
Use an external redirect only when a redirect is explicitly desired. |
| TLS termination | Certificate and key directly in the 443 Nginx block | When a trusted edge terminates TLS, adapt to its forwarded-protocol signal. |
Final implementation checklist
- The port-80 block lists the intended hostnames and contains only the HTTP-to-HTTPS redirect.
- The redirect preserves the original path and query string with
$request_uri. - The 443 block has a TLS listener, certificate, private key, root, and normal content locations.
- Static routing ends with
=404when no file, directory, or intended HTML variant exists. - The custom document exists under the configured root.
- The error handler uses the internal form rather than
=301or another external status. - Unknown application routes return 404 from the upstream instead of a generated 200 page.
- Proxy deployments use a trusted original-protocol signal and do not redirect already-secure requests.
- Both direct HTTPS requests and followed HTTP redirects have been tested with headers visible.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

