Nginx Reverse Proxy and Cloudflare

Hi all, hope someone can help as I’m struggling to get this working over HTTPS!
I have searched through this forum and tried all the different combinations over ports / HTTP / HTTPS I can think of but no success. This post is very similar to my situation…

Ghost-CLI version: 1.21.0
Ghost version: 5.2.2
Ghost server OS: Ubuntu server 20.04.4
Node: v16.15.1
Database: MySQL
DNS: Cloudflare
Cloudflare SSL: Tried full and full (strict)
Ghost server local IP: 10.0.40.5
Nginx Proxy Manager server IP which I’m using for my reverse proxy: 10.0.40.90
Followed this guide for install: https ://ghost. org/docs/install/ubuntu/

Hope I can get this figured out as I like what I have seen in Ghost so far! I have had Wordpress working on this same server (clean rebuild before I installed Ghost) so I know the DNS records etc point to the right place and the Cloudflare cert can work with the NPM reverse proxy etc.

Details below but let me know if I’ve missed anything!
Thanks!


I have successfully got this working by setting my config.production.json to http://ghost.mydomain.co.uk however I then get errors in the browser console complaining about some images trying to load over HTTP and it also says Stripe won’t work as I don’t have HTTPS enabled (I’m not planning to use Stripe anyway), however it also stops the membership sign up button from working.

As soon as I change my ghost config to https://ghost.mydomain.co.uk and then restart it I then can’t get to Ghost.

I am using Cloudflare as my DNS host and have the records proxied.

In Nginx Proxy Manager (NPM) I have tried various combinations of the following:
Proxy host scheme set to http or https.
Forward hostname / IP: 10.0.40.5
Forward port: 80 or 443 or 2368. If I set it to 2368 I cannot access Ghost at all (on http or https). From what I understand I should be able to use my reverse proxy to get to this port as that’s all the reverse proxy installed with Ghost does?

NPM: Custom locations - nothing configured in here.
NPM SSL - I have tried a LetsEncrypt cert (created by NPM) and also a Cloudflare Origin cert. Force SSL and HTTP/2 support enabled.
NPM advanced: below config.

location / {
proxy_pass http:// 10.0.40.5:2368; (# I matched this to the host forward port each time so 80 / 443. Space in this line just for this post)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $https;
proxy_set_header Host $http_host;
proxy_intercept_errors on;
}

In the ghost.mydomain.conf I have the following but I also tried changing the listening port to 443. I’m not sure if I need to touch this file if I’m using my own reverse proxy on a different server?

server {
listen 80;
listen [::]:80;
server_name ghost.mydomain. co. uk; (Space in here just for this post)
root /var/www/mydomain/system/nginx-root; # Used for acme.sh SSL verification
location / {
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; (space in here just for this post)
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}

I can help, but not today. I suggest you remove the Ghost instance (ghost uninstall) and the Nginx config, and start over. Take a look at this thread.

Thanks for getting back to me Martin. I feel like I’m quite close but I’m just not 100% sure what values I should be using on Cloudflare / Nginx Proxy Manger / the site.conf file under sites-enabled folder.
Happy to start over if it’s helpful but not sure what I will have done differently as I have been using nginx from the start as opposed to Apache like the other post. I have it in a VM so can easily snapshot.
If I start over, when Ghosts asks me if I want to install nginx is there any benefit to installing this if I’m using a separate reverse proxy?

  • Cloudflare - SSL currently set to full (strict) with the DNS record proxied.
  • Nginx proxy manager - should scheme be set to HTTPS?
  • NPM - should forward port be set to 2368 or 443?
  • NPM - what should be under advanced nginx config?
  • site.conf file - Do I need to do anything with this file if I’m using a separate NPM server?

Few extra bits of info I missed from my original post.

  • UFW - not enabled but my server is behind NAT so not directly exposed.
  • I’m trying to use this on a subdomain but not sure if this changes anything anyway.
  • Output from ghost doctor below.
  • Output from mariadb / mysql below.
  • Output showing sites-available / enabled directories.
✔ Checking system Node.js version - found v16.15.1
✔ Checking logged in user
✔ Ensuring user is not logged in as ghost user
✔ Checking if logged in user is directory owner
✔ Checking current folder permissions
✔ Checking system compatibility
✔ Checking for a MySQL installation
+ sudo systemctl is-active ghost_ghost-jakereed-co-uk
? Sudo Password [hidden]
Instance is currently running
ℹ Validating config [skipped]
✔ Checking folder permissions
✔ Checking file permissions
✔ Checking content folder ownership
✔ Checking memory availability
✔ Checking binary dependencies
✔ Checking free space
✔ Checking systemd unit file
✔ Checking systemd node version - found v16.15.1`Preformatted text`
jake@hz-ubuntu-wordpresse:/etc/nginx/sites-available$ sudo dpkg -l | grep -i mariadb
jake@hz-ubuntu-wordpresse:/etc/nginx/sites-available$ sudo dpkg -l | grep -i mysql
ii  mysql-client-8.0                      8.0.29-0ubuntu0.20.04.3            amd64        MySQL database client binaries
ii  mysql-client-core-8.0                 8.0.29-0ubuntu0.20.04.3            amd64        MySQL database core client binaries
ii  mysql-common                          5.8+1.0.5ubuntu2                   all          MySQL database common files, e.g. /etc/mysql/my.cnf
ii  mysql-server                          8.0.29-0ubuntu0.20.04.3            all          MySQL database server (metapackage depending on the latest version)
ii  mysql-server-8.0                      8.0.29-0ubuntu0.20.04.3            amd64        MySQL database server binaries and system database setup
ii  mysql-server-core-8.0                 8.0.29-0ubuntu0.20.04.3            amd64        MySQL database server binariespe or paste code here
jake@hz-ubuntu-wordpresse:/etc/nginx/sites-available$ ls -Flai /etc/nginx/sites-enabled
total 12
660107 drwxr-xr-x 2 root root 4096 Jun  6 21:07 ./
659600 drwxr-xr-x 8 root root 4096 Jun  5 13:21 ../
660316 lrwxrwxrwx 1 root root   34 Jun  5 13:21 default -> /etc/nginx/sites-available/default
683054 -rw-r--r-- 1 root root  559 Jun  6 19:47 ghost.jakereed.co.uk.conf
jake@hz-ubuntu-wordpresse:/etc/nginx/sites-available$ ls -Flai /etc/nginx/sites-available
total 16
659931 drwxr-xr-x 2 root root 4096 Jun  5 13:35 ./
659600 drwxr-xr-x 8 root root 4096 Jun  5 13:21 ../
660089 -rw-r--r-- 1 root root 2416 Mar 26  2020 default
296600 -rw-rw-r-- 1 jake jake  511 Jun  5 14:11 ghost.jakereed.co.uk.conf
jake@hz-ubuntu-wordpresse:/etc/nginx/sites-available$

If I set NPM scheme to https, forward port to 443 and proxy pass to port 80 under NPM advanced nginx config then I get a message to say there are too many redirects. I realise I probably don’t want to pass port 80 but like I said i’ve been trying just about every different combination I can think of!

The rest of the time I normally get a 502 bad gateway Cloudflare page to say there’s a problem on my server end.

Using ghost install correctly will set this up for you out-of-the-box. However, you seem to be doing something different to the guide, e.g., using Nginx Proxy Manager, which isn’t needed.

If you read the thread (from the post I referenced) you will understand that the first part of the thread was rolling back, so a clean installation could take place.

Ghost doesn’t install Nginx–it is a prerequisite–but it does configure the site an SSL for the given domain. Moreover, Nginx is a reverse proxy.

Ghost runs on the local host, e.g. 127.0.0.1:<some port> and Nginx is used to proxy this to http or https (recommended.) http is port 80 whereas http is on port 443; these ports are exposed to the Internet whereas the Ghost port is not.

You need to harden any server that is accessible to the Internet, more so with an application such as Ghost that can be set up as a bulk mailer. However, it looks like you are using a VM on your home network, so this should already be behind a firewall in your router; just make sure 80 and 443 are open and forwarded to the VM.

You are using MySQL, not MariaDB. This is an important distinction since Ghost only supports MySQL 8.0.

This is to be expected since you have a broken Nginx configuration.

If you haven’t already used Ghost, I think the best option is to start over. The thread I posted covers this for Ubuntu 20.04. The only difference is the OP wanted Ghost V4 whereas you can install V5 by omitting the 4.48.1,

To tidy up Nginx, remove the symbolic links to the Ghost site in /etc/nginx/sites-enabled and delete the borked configuration file in /etc/nginx/sites-available. Ignore or uninstall Nginx Proxy Manager since it is unnecessary.

You’ll almost certainly need to clear cookies in your web browser to prevent the unwanted redirects reoccurring.

Edit: I note your root domain is resolving fine. If you want to use Cloudflare instead of ACME (Let’s Encrypt etc.) then you’ll need to set up Cloudflare Origin Server certificates including a certificate request (CSR), and manually configure Nginx. If you’ve set up your root domain certificate with a wildcard, you may use this. Please reach out to me, and I can give you the Nginx configuration, since this is how I handle SSL.

1 Like

I ended up using the Ghost Docker image and I got it working quite easily using my same Nginx Proxy Manager on a different server.
Everything is being served over HTTPS and everything is working.

I’m sure it is possible to get it working the way I was initially trying but I’m quite happy running it in Docker anyway so will stick with this!

2 Likes

I had a similar problem, setting the SSL/TLS encryption mode to Full (strict) solved the problem.