How to redirect from root to www for Ghost in NGINX

Environment information

If you’re looking for help, please provide information about your environment. If you delete this template and don’t provide any information, your topic will be automatically closed.

If you aren’t running the latest version of Ghost, the first thing we’ll ask you to do is update to the latest version of Ghost.

And

  • How was Ghost installed and configured? Digital Ocean 1-click
  • What Node version, database, OS & browser are you using? Node 16.17.0, MySQL, Mac OS Monterey, Safari
  • What errors or information do you see in the console? None in console, but browser displays 403 Forbidden nginx/1.18.0 (Ubuntu) or an invalid SSL certificate notice
  • What steps could someone else take to reproduce the issue you’re having? See below

Context

I have the domain traceyle.id.au. I’m trying to host my Ghost site on www.traceyle.id.au and redirect traceyle.id.au to that.

  • I set up an A record for www.traceyle.id.au to the IP of my DigitalOcean droplet where I installed Ghost
  • I set up an A record for traceyle.id.au to the same IP
  • I set up Ghost with the URL www.traceyle.id.au
  • https://www.traceyle.id.au works, but I’m having trouble with figuring out how to get traceyle.id.au to redirect to https://www.traceyle.id.au

What I’ve tried

I was trying to read up on how this could be done in general (non-specific to Ghost) and I saw solutions suggesting redirects using NGINX. If there’s an easier way, let me know.

Some references include these:

So I tried sudo nano /etc/nginx/sites-available/default and added this above the default server configuration:

server {
       listen 80;
       server_name traceyle.id.au;
       return 302 $scheme://www.traceyle.id.au$request_uri;
}

(Would change it to 301 for permanent redirect if it works)

And I tried adjusting the default server configuration as follows

server {
        server_name www.traceyle.id.au;
        listen 80; 
        listen [::]:80;

       # Commented out the following line
       # server_name _;

I did make sure to run sudo systemctl restart nginx after making changes.

What I want to happen

All URLs on traceyle.id.au redirect to https://www.traceyle.id.au

What actually happened

The results are the same as before I tried those changes.

Reverting back

I ended up commenting out my changes and trying to revert back to the Ghost default NGINX config for that file. (I don’t think I changed anything but I might have accidentally)

The default server configuration for reference:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }
}

(removed the commented lines to keep it condensed)

Alternatives

I’m unfamiliar with NGINX so let me know if there’s anything I’ve missed.

Maybe I should edit /etc/nginx/sites-enabled/null.conf instead. I’ll try that next.

Update

Ok editing /etc/nginx/sites-enabled/null.conf worked for redirecting from http://traceyle.id.au to https://www.traceyle.id.au. So I was editing the wrong place for one thing.

I added this:

server {
    listen *:80;
    listen [::]:80;
    server_name traceyle.id.au;
    return 302 https://www.traceyle.id.au$request_uri;
}

will update to 301 when totally confirming that it works.

However I still get an invalid certificate error when I visit https://traceyle.id.au – I want that to redirect to https://www.traceyle.id.au

This is the rest of that file for reference:

server {
    listen 80;
    listen [::]:80;

    server_name www.traceyle.id.au;
    root /var/www/ghost/system/nginx-root; # Used for acme.sh SSL verification (https://acme.sh)

    location ^~ www.traceyle.id.au {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:2368;
        proxy_redirect off;
    }

    location ~ /.well-known {
        allow all;
    }

    client_max_body_size 50m;
}

You shouldn’t have or edit files in /etc/nginx/sites-enabled. This folder only includes symbolic links to /etc/nginx/sites-available.

Before attempting to redirect non-WWW to the bare domain, you need to setup SSL correctly.

Did you chose SSL (Let’s Encrypt) when setting up Ghost? And, specified https://www.traceyle.id.au as the site URL?

1 Like

Hi t1-tracey,

I have kind of the opposite use case running (forwarding from www.whatever.xyz to ghost hosted on whatever.xyz). Maybe I can help with the configuration. There probably is a simpler way, but for now it works for me.

Three things upfront:

  1. As initally said, I am using the opposite redirect. I have written the examples with your use case i.e. forwarding to www. in mind
  2. I am using certbot to obtain the SSL-certificates from Let’s Encrypt for the non-ghost administrated parts, while ghost uses the acme.sh script for certificate management. Up to now it looks like the two processes come along quite well, but I only have it running for a few days and I have not tried to renew anything.
  3. Make a backup before testing (especially of /etc/nginx/sites-available as certbot will edit those files and things can get broken)

OS: Ubuntu 22.04

Let’s get started:

Part 1 - configuring nginx:

Make a new configuration file in /etc/nginx/sites-available.
Obviously do not use a name that was used by the ghost installation routine.

sudo nano /etc/nginx/sites-available/mylittletestingsite.net.conf
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name mylittletestingsite.net;
    return 301 https://www.mylittletestingsite.net$request_uri;
}

In case you do not have ipv6 running, you can leave out the two listen [::]: statements

The idea of this file is to collect everything (http and https) that comes in from mylittletestingsite.net and permanently (301) redirect it to https://www.mylittletestingsite.net
However, to allow secure connections to https://mylittletestingsite.net without warning, we need a certificate for that domain. We will obtain this certificate with certbot, but before that we have to create a link to the file we just have created in /etc/nginx/sites-enabled to make it active:

sudo ln -s /etc/nginx/sites-available/mylittletestingsite.net.conf /etc/nginx/sites-enabled/

after testing for syntax problems with nginx -t we can restart nginx (reload probably would also work).

sudo systemctl restart nginx

Part 2 - certbot & getting certificate:
This is largely based on the following post (for reference):
https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-22-04

Update snap:

sudo snap install core; sudo snap refresh core

Install certbot with snap (alternative to apt)

sudo snap install --classic certbot

Link certbot from install dir to /usr/bin (sometimes necessary to use it from the CLI)

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Now it is time to fetch the required certificates.
It is important to specify the domain that has NOT been used in the ghost installation routine! Certbort will look in the files in /etc/sites-available for the server block with the given name and edit that block.

sudo certbot --nginx -d mylittletestingsite.net

The interactive script will ask for an email address and then obtain and install the certificates. It will also edit the file in /etc/nginx/sites-available that we created in Step 1 and set up a system.d timer for regular renewal (alternative to crontab)

After restarting nginx, the redirects from https://mylittletestingsite.net to https://www.mylittletestingsite.net should work.

sudo systemctl restart nginx

Hope that helps.
Alex

1 Like

Yep I did choose SSL Let’s Encrypt when setting up ghost – and specified https://www.traceyle.id.au

Thank you for letting me know – I will revert those changes.

1 Like

Many thanks lxb for writing this up, and converting from your experience for my case. This worked for me :partying_face:

For future reference, these are the steps that I didn’t do the first time, but did do this time, and helped to make it work for me.

  • Part 1: Creating the new configuration file and setting up the link.

  • Part 2: I did try certbot at one point but couldn’t seem to generate the certificate for https://traceyle.id.au without having to confirm in some way. I had run sudo certbox --certonly -d newdomain.net

    But this worked for me after creating the configuration file:

    sudo certbot --nginx -d mylittletestingsite.net

After these steps, I was able to get the root site (HTTP and HTTPS) to redirect successfully to the www site.

I had to do a bit extra to get the www domain on HTTP to redirect to HTTPS but I used your example in the conf file to do it. And that works now also.

Thanks so much again – this had been a huge headache for me previously, and now I understand it better. Danke!!

1 Like