Redirect HTTP to HTTPS in Nginx

When a website is available over HTTPS, requests that still arrive over plain HTTP should be redirected before Nginx serves the page. The usual setup is a dedicated server block on port 80 that returns a permanent redirect to the HTTPS URL, which uses port 443 by default.
This guide explains how to configure the redirect for one site or several sites on the same server.
Quick Reference
| Configuration | Description |
|---|---|
return 301 https://example.com$request_uri; | Permanently redirect a website to HTTPS |
return 308 https://example.com$request_uri; | Permanently redirect while preserving the request method and body |
return 301 https://$host$request_uri; | Preserve the matched domain in a shared redirect block |
listen 80 default_server; | Make a block the fallback for unmatched HTTP hostnames |
server_name _; | Use an invalid placeholder name; this does not create a catch-all |
sudo nginx -t | Test the configuration syntax |
sudo systemctl reload nginx | Apply a valid configuration |
A dedicated HTTP server block is clearer than testing the request scheme with the if directive
. The main if caveats apply when it is used inside a location block with directives from other modules. A return or rewrite ... last inside if is safe, but no condition is needed when the server block listens only on port 80.
Redirect HTTP to HTTPS per Site
After an SSL certificate is installed for a domain, you will typically have two server blocks : one for HTTP on port 80 and another for HTTPS on port 443.
To redirect a single website to HTTPS, open the domain configuration file and make the following changes:
server {
listen 80;
server_name linuxize.com www.linuxize.com;
return 301 https://linuxize.com$request_uri;
}Here is what each line does:
listen 80- The server block will listen for incoming connections on port 80 for the specified domain.server_name linuxize.com www.linuxize.com- Specifies the server block’s domain names. Make sure you replace it with your domain name.return 301 https://linuxize.com$request_uri- Redirect the traffic to the HTTPS version of the site. The$request_urivariable is the full original request URI, including the arguments.
Usually, you will also want to redirect the HTTPS www version of the site to the non-www or vice versa. The recommended way to do the redirect is to create a separate server block for both www and non-www versions.
For example, to redirect the HTTPS www requests to non-www, you would use the following configuration:
server {
listen 80;
server_name linuxize.com www.linuxize.com;
return 301 https://linuxize.com$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name www.linuxize.com;
# . . . other code
return 301 https://linuxize.com$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name linuxize.com;
# . . . other code
}The http2 on; directive replaces the older listen 443 ssl http2; syntax, which is deprecated since Nginx 1.25.1. If you run an older Nginx version, keep the http2 parameter on the listen line instead.
Before reloading Nginx, test the updated configuration:
sudo nginx -tIf the test reports that the syntax is valid, reload the Nginx service to apply the changes:
sudo systemctl reload nginxRedirect All Sites to HTTPS
If several websites on the server use HTTPS, you can redirect their known domain names from one shared HTTP server block. Keep a separate default block that rejects unknown hostnames instead of copying an arbitrary hostname into the redirect URL.
The following configuration rejects unmatched hostnames and redirects the listed websites:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com example.net www.example.net;
return 301 https://$host$request_uri;
}Here is what each directive does:
listen 80 default_server- Makes the first block the fallback for HTTP requests with an unmatched hostname.server_name _- Uses an invalid placeholder name. Thedefault_serverparameter, not this value, creates the fallback.return 444- Closes requests for unknown hostnames without sending a redirect.server_name example.com ...- Lists every hostname that the shared redirect block accepts.return 301 https://$host$request_uri- Redirects a matched hostname to the same request URI over HTTPS.
For example, if a visitor opens http://example.com/page2, Nginx redirects the request to https://example.com/page2. Replace the example names with every domain and alias that has a working HTTPS server block and certificate.
Use separate per-domain blocks when different sites need different canonical hostnames or redirect rules.
Troubleshooting
Redirect loops after enabling HTTPS
For direct traffic, verify that the HTTP server block listens only on port 80 and the HTTPS block listens only on port 443. If a load balancer, CDN, or reverse proxy terminates TLS and forwards requests to Nginx over HTTP, configure the redirect at that proxy. Otherwise, Nginx may redirect every forwarded HTTPS request back to the same URL. Only use a forwarded scheme header when it comes from a trusted proxy.
301 redirect not taking effect after reload
Browsers cache 301 redirects aggressively. Clear the browser cache or test with curl -I http://yourdomain.com to confirm the redirect is in place at the server level.
nginx: configuration file test failed after editing
Run sudo nginx -t before reloading to validate the configuration syntax. Check for missing semicolons, unclosed braces, or typos in directive names.
HTTPS page not loading after redirect
Confirm that an SSL certificate is installed and the HTTPS server block is listening on port 443 with the ssl parameter. Check that the certificate paths in ssl_certificate and ssl_certificate_key are correct.
The plain HTTP request was sent to HTTPS port error
Nginx returns this error when an unencrypted HTTP request reaches a port where the ssl parameter is enabled. Check that the redirect URL starts with https:// and does not append a port, and that no application or proxy behind Nginx sends plain HTTP traffic to port 443.
FAQ
Should I use return 301 or rewrite for the redirect?
Use return 301 for a permanent website redirect. It is simpler than a rewrite rule because it does not require a regular expression and stops request processing immediately. If an API or another endpoint must preserve a POST or other non-GET method and its body, use return 308 instead.
What is the difference between $host and $server_name in the redirect URL?
Nginx sets $host from the hostname in the request line, the Host header, or the matching server name, in that order. $server_name contains the name of the server block handling the request. Use $host only in a block with explicit accepted domain names. Use a hardcoded domain in a per-site block when every request should go to one canonical hostname.
Does a 301 redirect affect SEO?
A 301 (Moved Permanently) redirect passes link equity to the destination URL and is the correct choice for permanent HTTP-to-HTTPS migrations. Search engines update their index to the HTTPS version after crawling the redirect.
Why should I avoid using if for redirects in Nginx?
The if directive belongs to the rewrite module and does not behave like a general-purpose conditional. Problems mainly occur when it is combined with directives from other modules inside a location block. A return or rewrite ... last inside if is safe, but a dedicated port 80 server block does not need a condition and is easier to read.
How do I force browsers to always use HTTPS?
After the redirect and certificate are working reliably, add the HSTS header to the HTTPS server block. Start with a short policy such as add_header Strict-Transport-Security "max-age=300" always;. Verify that every page works over HTTPS, then increase max-age to 31536000. Browsers accept HSTS only over HTTPS and will not allow users to bypass certificate errors until the policy expires, so do not start with a long duration.
Conclusion
Test every configuration change with sudo nginx -t before reloading Nginx. If you also run Apache, see how to redirect HTTP to HTTPS in Apache
.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page