Ghost Web Root Issues

  • What’s your URL?
    https://in-spired.xyz

  • What version of Ghost are you using?
    v3.41.3

  • How was Ghost installed and configured?
    I am using Nginx and Docker. I’m not all there with web application stuff but I followed this guide:
    Run your blog with Ghost, Docker and LetsEncrypt

  • What Node version, database, OS & browser are you using?
    Linode Ubuntu 20.04
    Browser I use primarily is Chrome
    Node v12.19.1

  • What errors or information do you see in the console?
    Not specifically errors… I’m just struggling to identify my web root which is making it impossible to renew my letsencrypt certificate.

  • What steps could someone else take to reproduce the issue you’re having?
    I run my letsencrypt renewal command and it asks for my web root. No problem, I thought. It’s at /home/inspired/ghost/content which is linked to /var/lib/ghost/content on my docker. So the challenge is made to https://in-spired.xyz/.well-known/acme-challenge/{random_string} to check if the site is active. But it can’t find that file. So I’m trying to identify where the actual web root is to put that folder and file there so that the challenge will succeed. I’ve got myself in such a muddle, I’d rather not reinstall the whole thing but I can’t see a way around this now and I’m not that good at web sort of stuff. I just followed the instructions in that blog post to set it up originally and it worked fine until I tried to renew my certificate.

I thought maybe I could put a file in the /var/lib/ghost/content/themes/casper/{file_here} and then access it through my browser. So I put a test.txt in that folder, but it redirects me to /test.txt/ rather than accessing the file.

If anyone has any idea where my true web root is… or has any experience with using it via Nginx and Docker i’d be most appreciative… Been stuck trying to fix it for two days, hence the eventual forum post. Probably being really stupid.

Nginx Configuration

root@localhost:/etc/nginx/conf.d# cat default 
server {
        listen 80;
        server_name in-spired.xyz;
        location /.well-known/ {
                root /var/www/in-spired.xyz/.well-known/;
        }

        location / {
                return 301 https://$server_name$request_uri;
        }
}
server {
        server_name in-spired.xyz;
        listen 443 ssl;

        location / {
                proxy_pass      http://127.0.0.1:2368;
                proxy_set_header    X-Real-IP $remote_addr;
                proxy_set_header    Host      $http_host;
                proxy_set_header X-Forwarded-Proto https;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        }

        ssl_certificate     /etc/letsencrypt/live/in-spired.xyz/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/in-spired.xyz/privkey.pem;
        ssl on;

}
root@localhost:/home/inspired/ghost/content/themes# ls -la
total 8
drwxr-xr-x 2 ubuntu ubuntu 4096 Feb  2 14:26 .
drwxr-xr-x 8 ubuntu ubuntu 4096 Feb  2 08:23 ..
lrwxrwxrwx 1 ubuntu ubuntu   44 Jan 31 18:09 casper -> /var/lib/ghost/current/content/themes/casper                                                                                           
root@localhost:/home/inspired/ghost/content/themes# 

Inside the docker

root@75d1ecb29b92:/var/lib/ghost/content/themes/casper# ls -la
total 300
drwxr-xr-x 4 node node   4096 Feb  2 14:44 .
drwxr-xr-x 3 node node   4096 Feb  2 14:33 ..
-rw-r--r-- 1 node node   1065 Oct 26  1985 LICENSE
-rw-r--r-- 1 node node   2895 Oct 26  1985 README.md
drwxr-xr-x 5 node node   4096 Feb  2 14:33 assets
-rw-r--r-- 1 node node   2480 Oct 26  1985 author.hbs
-rw-r--r-- 1 node node   5934 Oct 26  1985 default.hbs
-rw-r--r-- 1 node node    968 Oct 26  1985 error-404.hbs
-rw-r--r-- 1 node node   2597 Oct 26  1985 error.hbs
-rw-r--r-- 1 node node   5244 Oct 26  1985 gulpfile.js
-rw-r--r-- 1 node node   3079 Oct 26  1985 index.hbs
-rw-r--r-- 1 node node   2495 Oct 26  1985 package.json
-rw-r--r-- 1 node node   2161 Oct 26  1985 page.hbs
drwxr-xr-x 3 node node   4096 Feb  2 14:33 partials
-rw-r--r-- 1 node node   8394 Oct 26  1985 post.hbs
-rw-r--r-- 1 node node   1117 Oct 26  1985 tag.hbs
-rw-r--r-- 1 node node      5 Feb  2 14:44 test.txt
-rw-r--r-- 1 node node 220823 Oct 26  1985 yarn.lock
root@75d1ecb29b92:/var/lib/ghost/content/themes/casper# 

Bump

:wave:

I believe the letsencrypt advice is to use location ^~ /.well-known/acme-challenge/ for your location matcher to tell nginx to stop considering other paths.

The file location in your configuration is /var/www/in-spired.xyz/.well-known/. If you want to troubleshoot by using a file like test.txt you would want to put it at that location on the host with nginx running.

You probably want to check your nginx logs to see if there’s an error for this path.

Right now any request to in-spired.xyz is being caught by this location block:

location / {
                return 301 https://$server_name$request_uri;
        }

Thanks for your reply.

I’ve attempted to tell letsencrypt that my web root is there only to be met with these messages:

Challenge failed for domain in-spired.xyz
Challenge failed for domain www.in-spired.xyz
http-01 challenge for in-spired.xyz
http-01 challenge for www.in-spired.xyz
Cleaning up challenges
Failed to renew certificate in-spired.xyz with error: Some challenges have failed.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/in-spired.xyz/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: in-spired.xyz
   Type:   unauthorized
   Detail: Invalid response from
   https://in-spired.xyz/.well-known/acme-challenge/ldoptcpsrfb_wqxddlzqdtwu0ygus-_k7zppt-zk1ry/
   [139.162.201.166]: "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\n
   <meta charset=\"utf-8\" />\n    <meta
   http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" /"

   Domain: www.in-spired.xyz
   Type:   unauthorized
   Detail: Invalid response from
   https://www.in-spired.xyz/.well-known/acme-challenge/alnkq-msfod1qkeaaoh3n1asmaqc6gery-4awvjxzxo/
   [139.162.201.166]: "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\n
   <meta charset=\"utf-8\" />\n    <meta
   http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" /"

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address.

Interestingly, if I put a file at /var/lib/ghost/versions/3.41.3/content/themes/casper/test.txt I can access it on my site now. I don’t really understand why, as my root (Like you’ve mentioned) points to /var/www/in-spired.xyz/.well-known/.

Not really sure how to set my webroot to /var/lib/ghost/versions/3.41.3/content/themes/casper as this is inside my docker so it says it doesn’t exist on my host.

Thanks for your help.

This was the docker command I originally used to set it up, which might be the issue?

#!/bin/sh
docker rm -f ghost

docker run --name ghost \
 -p 127.0.0.1:2368:2368 \
 -e url=https://in-spired.xyz \
 -v /home/inspired/ghost/content:/var/lib/ghost/content \
 --restart=always \
  -d ghost:1.21.1-alpine

As the -v is pointing to a folder that now doesn’t exist after updating ghost, which now exists inside the docker as /var/lib/ghost/versions/3.41.3/content/themes/casper.

Were you able to check the nginx logs on the host? It still appears that all requests are being forwarded to HTTPS (you can see the https prefix in the letsencrypt errors). Something is not working correctly with this rule:

       location /.well-known/ {
                root /var/www/in-spired.xyz/.well-known/;
        }

I believe letsencrypt recommends location ^~ /.well-known/acme-challenge/

Hi mate,

Yes I did, they are currently being forwarded to HTTPS as my cert is active at the moment, It’s a renewal that’s causing the issues, not sure why it originally worked and won’t now.

They shouldn’t be forwarded to https.

server {
        listen 80;
        server_name in-spired.xyz;
        location /.well-known/ {
                root /var/www/in-spired.xyz/.well-known/;
        }

        location / {
                return 301 https://$server_name$request_uri;
        }
}

This block in nginx translates to “If someone asks me for /.well-known on port 80 (with no HTTPS) then it should go to /var/www/in-spired.xyz/.well-known/ otherwise every other request should be forwarded to HTTPS”

If you curl against your URL you get something like this:

curl http://in-spired.xyz/.well-known/
<html>
<head><title>301 Moved Permanently</title></head>

So the first part of the block above is not working. Can you check the nginx logs? Does that directory exist? Does it have appropriate permissions?

Here is the log from when I try to update the cert:

34.211.6.84 - - [11/Feb/2021:21:36:57 +0000] "GET /.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q HTTP/1.1" 301 178 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
64.78.149.164 - - [11/Feb/2021:21:36:57 +0000] "GET /.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q/ HTTP/1.1" 301 106 "https://www.in-spired.xyz/.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
64.78.149.164 - - [11/Feb/2021:21:36:57 +0000] "GET /.well-known/acme-challenge/osgrkgzpcgcr7-wlqdctrygceuugyh0l4tkfuddpn8y/ HTTP/1.1" 404 2726 "https://in-spired.xyz/.well-known/acme-challenge/OSGrkgZPcGcr7-wlQdCtrYgCEuUgYH0L4TKfuDDpN8Y/" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
3.128.26.105 - - [11/Feb/2021:21:36:57 +0000] "GET /.well-known/acme-challenge/uipe894k-8wpgzmruxrdasqn4ygelfp08ecoe9owd2q/ HTTP/1.1" 404 2726 "https://www.in-spired.xyz/.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q/" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
64.78.149.164 - - [11/Feb/2021:21:36:57 +0000] "GET /.well-known/acme-challenge/uipe894k-8wpgzmruxrdasqn4ygelfp08ecoe9owd2q/ HTTP/1.1" 404 2726 "https://www.in-spired.xyz/.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q/" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
34.211.6.84 - - [11/Feb/2021:21:36:57 +0000] "GET /.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q HTTP/1.1" 301 5 "http://www.in-spired.xyz/.well-known/acme-challenge/UIPe894k-8WpGzmrUxrdaSqn4yGElfp08eCoE9oWd2Q" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"

And here is the directory and the permissions:

root@localhost:/opt# ls -la /var/www/
total 12
drwxr-xr-x  3 inspired inspired 4096 Feb 11 21:26 .
drwxr-xr-x 14 root     root     4096 Jan 31 18:06 ..
drwxr-xr-x  3 inspired inspired 4096 Feb  1 16:32 in-spired.xyz
root@localhost:/opt# ls -la /var/www/in-spired.xyz/
total 12
drwxr-xr-x 3 inspired inspired 4096 Feb  1 16:32 .
drwxr-xr-x 3 inspired inspired 4096 Feb 11 21:26 ..
drwxr-xr-x 2 inspired inspired 4096 Feb 11 21:37 .well-known

Again, thank you for your time :slight_smile: Sorry I can’t be more helpful… I’m perfectly fine usually with web roots but messing about with docker will be my nemesis

Bump. Still searching for a method to fix this if anyone got any ideas :slight_smile: TLS Cert runs out over the next couple days, if not I’ll probably just rebuild the site but that’s not preferable :stuck_out_tongue:

It seems to still not be processed correctly by nginx for some reason. Here are some steps you can try to debug yourself:

curl -s http://in-spired.xyz/.well-known/acme-challenge/ldoptcpsrfb_wqxddlzqdtwu0ygus-_k7zppt-zk1ry -v

The output of that will show you this:

Location: https://in-spired.xyz/.well-known/acme-challenge/ldoptcpsrfb_wqxddlzqdtwu0ygus-_k7zppt-zk1ry

That means nginx is catching it and forwarding it to HTTPS.

This part of your nginx configuration is not working:

location /.well-known/ {
    root /var/www/in-spired.xyz/.well-known/;
}

The configuration you used from the blogpost is set up to have the letsencrypt files be outside of the container (outside of ghost) and this is ideal. You don’t really want Ghost serving these files.

You can perform the same test.txt files by putting that file in the path to your .well-known (that path is /var/www/in-spired.xyz/.well-known/). You might also want to verify that there are files in that path on your host - if they’re missing you can’t renew the certificate regardless. You’d have to start over with a new one.

@elijahsgh Thanks for all your help. I managed to actually fix it with just a simple change to the command used to renew.

certbot renew -a nginx rather than just certbot renew.

I really appreciate all your time though, so thank you :smiley:

1 Like