Nginx rule to redirect non-www to www

My web server is Nginx 1.22.1, run on Debian 12 virtual server, accessed over ssh.

I have the below listed configuration file for all server blocks.

It was created by Certbot, except I added www. to the line return 301 https://www.$host$request_uri; in order to redirect non-www requests to www. (Sorry, I cannot highlight this piece withing the code block.)

The certificates work just fine. The question is, have I amended the config with the www. correctly? Somehow requests are not being redirected to www. I've tried several browsers on two devices.

server {
    if ($host = www.example.ru) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = example.ru) {
        return 301 https://www.$host$request_uri;
    } # managed by Certbot

   listen 80;
   server_name example.ru www.example.ru;
    return 404; # managed by Certbot
}

I can login to a root shell on my machine (yes or no, or I don't know): yes

I'm using a control panel to manage my site (no, or provide the name and version of the control panel): Ptyxis terminal (Fedora Gnome default)

The version of my client is (e.g. output of certbot --version or certbot-auto --version if you're using Certbot): 2.1.0

Hello @thumos, welcome to the Let's Encrypt community. :slightly_smiling_face:

For general nginx information you might find nginx documentation and https://forum.nginx.org/ helpful.

2 Likes

This is only the relevant fragment of the config files, of course.

Are you sure it is the HTTP requests that are not redirecting? Because those look fine.

I wonder if what you are seeing is that HTTPS://example.com requests are not redirecting to HTTPS://www.example.com ? Many browsers use "https first" strategies and prefer those results.

That would need something in your server block for port 443.

You should test redirects with curl or similar tool and not browsers. Or, use the browsers Developer Tools to see what requests it is actually making.

3 Likes

Here are a couple of tools to assist in checking redirection

  1. https://www.redirect-checker.org/
  2. Rex Swain's HTTP Viewer
4 Likes

Thanks. Yes, I implied https requests.

Thanks, will try them out.

Redirect Checker shows that http request redirect to www, while https ones do not

http with no www:

>>> http://example.ru

> --------------------------------------------
> 301 Moved Permanently
> --------------------------------------------

|**Status:**|301 Moved Permanently|
| --- | --- |
|**Code:**|301|
|**Server:**|nginx/1.22.1|
|**Date:**|Tue, 18 Mar 2025 22:13:56 GMT|
|**Content-Type:**|text/html|
|**Content-Length:**|169|
|**Connection:**|close|
|**Location:**|https://www.example.ru/|

https with no www:

>>> https://example.ru

> --------------------------------------------
> 200 OK
> --------------------------------------------

|**Status:**|200 OK|
| --- | --- |
|**Code:**|200|
|**Server:**|nginx/1.22.1|
|**Date:**|Tue, 18 Mar 2025 22:17:24 GMT|
|**Content-Type:**|text/html|
|**Content-Length:**|12590|
|**Last-Modified:**|Tue, 18 Mar 2025 18:17:29 GMT|
|**Connection:**|close|
|**ETag:**|"67d9b8b9-312e"|
|**X-Frame-Options:**|DENY|
|**X-Content-Type-Options:**|nosniff|
|**Accept-Ranges:**|bytes|

So now you know what you have to fix :slight_smile:

That is what you might have meant. But, you only showed the HTTP server block (port 80).

4 Likes

You are right. It's the first time I'm doing this, I got confused by return 301 https://... mentioned within the server listen 80 rule.

Below is a complete config file for one website, before I amended it with "www". What would be an easy way to redirect both http and https to www?

server {
   server_name example.ru www.example.ru;

    ##
    # Include general vhost configuration snippet
    ##
    include /etc/nginx/snippets/general-vhost.conf;
    include /etc/nginx/snippets/general-security.conf;

    ##
    # Logging
    ##
    access_log  /var/www/example.ru/logs/access.log;
    error_log   /var/www/example.ru/logs/error.log info;

   root /var/www/example.ru/html;
   index index.html;


    #
    #   Default configuration.
    #
    location / {

        #
        #   Since we deliver files with no extension, we need to tell
        #   Nginx what those files are.
        #
        default_type text/html;

        #
        #   First attempt to serve request as file, then
        #   as directory, then fall back to displaying a 404.
        #
        try_files $uri $uri.html $uri/ =404;

    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}

server {
    if ($host = www.example.ru) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.ru) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


   listen 80;
   server_name example.ru www.example.ru;
    return 404; # managed by Certbot

}

Also, general-vhost.conf snippet used in the file above:

# favicon.ico
location = /favicon.ico {
    log_not_found off;
    access_log off;
}

# robots.txt
location = /robots.txt {
    log_not_found off;
    access_log off;
}

And general-security.conf snippet:

# Basic Security Headers
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

# . files
location ~ /\.(?!well-known) {
    deny all;
}

You could add the above into the server block for port 443. No other changes are needed.

4 Likes

Isn't the same rule necessary for port 80?

No. Certbot's redirects handle the HTTP request and redirect them to HTTPS.

That new redirect in port 443 block will ensure any HTTPS request for your apex gets redirected to www. Doesn't matter if it came from HTTP redirect or someone typed https://example.com directly.

You could modify the port 80 server block to send apex to www directly but it has little benefit. Many browsers actually try both HTTP and HTTPS at the same time (initially) and just use HTTPS result straight away. They'll even remember that (for a bit) even without HSTS .

This is all general server admin advice. It is not specific to Let's Encrypt. Just thought I'd help clarify the benefits of what Certbot does and how to achieve your goal. Your other option is to use certbot certonly and configure all the server blocks yourself. If you plan to continuously adjust what Certbot does you might want to use this option instead.

3 Likes

Many thanks, Mike. The return 301 does the job.

Both http://example.ru and https://example.ru are being redirected to https://www.example.ru

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.