Redirects keep your visitors and your search ranking when a page moves, when you switch domain or when you force HTTPS. This guide shows how to write clean Nginx redirects on your VPS Linux Infrawire, and how to test them before they reach production.
📋 Prerequisites
- A Linux VPS (Ubuntu 24.04 / Debian 12 or AlmaLinux 9 / Rocky 9) with root SSH access. You find the IP and the root password in your customer area.
- Nginx installed and serving at least one site (
sudo apt install nginxorsudo dnf install nginx). - A domain name (
example.com) whose DNS A/AAAA records point toVPS_IP.
🧭 301 or 302: which one to pick
- 301 (Moved Permanently): the move is final. Browsers and search engines cache it and transfer the ranking to the new URL.
- 302 (Found): the move is temporary (maintenance, A/B test). The old URL stays the reference.
If in doubt, use 302 first: a wrong 301 can stay cached in browsers for a long time.
⚙️ return or rewrite
Prefer return: it is faster and easier to read, because Nginx stops processing immediately.
Nginxlocation = /old-page { return 301 /new-page; }
Use rewrite only when you must capture part of the URL with a regular expression:
Nginxrewrite ^/blog/(\d+)/(.*)$ /articles/$2 permanent;
The flag permanent sends a 301, redirect sends a 302.
🌐 Redirect www to non-www
Create a dedicated server block that only redirects. Edit /etc/nginx/sites-available/example.com (Debian/Ubuntu) or /etc/nginx/conf.d/example.com.conf (AlmaLinux/Rocky):
Nginx1server { 2 listen 80; 3 listen [::]:80; 4 server_name www.example.com; 5 return 301 $scheme://example.com$request_uri; 6}
For the opposite direction, swap the two host names. $request_uri keeps the path and the query string.
🔒 Redirect HTTP to HTTPS
Once a certificate is installed, send all clear-text traffic to HTTPS:
Nginx1server { 2 listen 80; 3 listen [::]:80; 4 server_name example.com www.example.com; 5 return 301 https://example.com$request_uri; 6} 7 8server { 9 listen 443 ssl; 10 listen [::]:443 ssl; 11 http2 on; 12 server_name www.example.com; 13 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; 14 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; 15 return 301 https://example.com$request_uri; 16}
The real site then lives in a third block listening on 443 with server_name example.com;. Note that http2 on; requires Nginx 1.25.1 or newer, which is the case on Ubuntu 24.04.
🔗 Old URL to new URL
For a few pages, use exact matches (=), which are the fastest:
Nginxlocation = /about-us.html { return 301 /about; } location = /promo { return 302 /offers/current; }
For a whole folder that moved while keeping the sub-paths:
Nginxlocation /docs/ { rewrite ^/docs/(.*)$ /help/$1 permanent; }
🏠 Redirect a whole domain
When you abandon old-example.com for example.com, keep every path:
Nginx1server { 2 listen 80; 3 listen [::]:80; 4 server_name old-example.com www.old-example.com; 5 return 301 https://example.com$request_uri; 6}
If the old domain also has HTTPS, add a matching listen 443 ssl; block with its own certificate, otherwise browsers show a certificate error before the redirect.
✅ Test and reload cleanly
Always validate the syntax before reloading. A reload keeps current connections alive, a restart does not.
Bashsudo nginx -t sudo systemctl reload nginx
Then check the headers without following the redirect:
Bashcurl -I http://www.example.com/old-page
Expected output (shortened):
HTTP/1.1 301 Moved Permanently
Server: nginx
Location: https://example.com/old-page
To follow the whole chain and see every hop, use curl -IL http://www.example.com/old-page. Ideally there is a single hop: avoid chains such as HTTP, then www, then HTTPS.
🛠️ Troubleshooting
Too many redirects (loop). A rule matches its own destination, often because a proxy or CDN already terminates HTTPS. Check the Location header with curl -I and make sure the target block does not redirect again.
The change has no effect. You edited a file that is not enabled. On Debian/Ubuntu, check the link in /etc/nginx/sites-enabled/, then run sudo nginx -t and sudo systemctl reload nginx. Browsers also cache 301: test with curl or a private window.
Query string lost. With rewrite ... ? or a fixed target, parameters vanish. Use $request_uri in return, or keep $args explicitly.
Wrong block answers. Nginx picks the block by server_name. List them with sudo nginx -T | grep server_name and look for duplicates.
🎉 Your redirects are live: permanent where it is final, temporary where it is not, and tested with curl before your visitors notice anything.