# Nginx Reverse Proxy and Cloudflare

**URL:** <https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653>\
**Category:** Developer help\
**Created:** [June 6, 2022, 7:23pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653 "2022-06-06T19:23:59Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jake1](https://avatars.discourse-cdn.com/v4/letter/j/73ab20/32.png) [@jake1](https://forum.ghost.org/u/jake1)\
**Post date:** [June 6, 2022, 7:23pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/1 "2022-06-06T19:23:59Z")

</div>

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…

> [@Basic Setup Question - URL and Reverse Proxy](https://forum.ghost.org/t/basic-setup-question-url-and-reverse-proxy/18037):
>
> This should be really simply, but I’ve been messing with this for hours. Any help at all is appreciated Currently I run the Docker image of Ghost, and then traefik hanldes being the reverse proxy out to the internet. traefik connects to ghost directly inside the docker network using port 2368 I am looking to replicate this setup outside of Docker, using NGINX Proxy Manager as the reverse proxy in its own VM, and then Ghost installed natively inside Ubuntu NGINX Proxy Manager is all setup, con…

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](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](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;  
> }

---

<div class="post-metadata">

**Author:** ![mjw](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/mjw/32/30781_2.png) [@mjw](https://forum.ghost.org/u/mjw)\
**Post date:** [June 6, 2022, 7:50pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/2 "2022-06-06T19:50:41Z")

</div>

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.

> [@How to install Ghost CMS on my VPS](https://forum.ghost.org/t/how-to-install-ghost-cms-on-my-vps/30621/15):
>
> Okay, next steps are to create a database and database user for Ghost. Type sudo mysql and you’ll see a different prompt. This is because you are using MySQL and have left the BASH command-line. You’ll need to replace \<password\> with your password; create a new one for this. create database boringdigital\_com; create user 'user\_boringdigital\_com'@'localhost' identified by '\<password\>'; grant all privileges on boringdigital\_com.\* to 'user\_boringdigital\_com'@'localhost'; flush privileges; quit; P…

---

<div class="post-metadata">

**Author:** ![jake1](https://avatars.discourse-cdn.com/v4/letter/j/73ab20/32.png) [@jake1](https://forum.ghost.org/u/jake1)\
**Post date:** [June 6, 2022, 8:38pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/3 "2022-06-06T20:38:59Z")

</div>

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.

```auto
✔ 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`

```

```auto
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

```

```auto
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$

```

---

<div class="post-metadata">

**Author:** ![jake1](https://avatars.discourse-cdn.com/v4/letter/j/73ab20/32.png) [@jake1](https://forum.ghost.org/u/jake1)\
**Post date:** [June 6, 2022, 8:58pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/4 "2022-06-06T20:58:34Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![mjw](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/mjw/32/30781_2.png) [@mjw](https://forum.ghost.org/u/mjw)\
**Post date:** [June 7, 2022, 10:49am UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/5 "2022-06-07T10:49:52Z")

</div>

> [@jake1](#):
>
> 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.

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.

> [@jake1](#):
>
> 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.

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.

> [@jake1](#):
>
> 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?

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.

> [@jake1](#):
>
> UFW - not enabled…

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.

> [@jake1](#):
>
> Output from mariadb / mysql below

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

> [@jake1](#):
>
> 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.

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.

---

<div class="post-metadata">

**Author:** ![jake1](https://avatars.discourse-cdn.com/v4/letter/j/73ab20/32.png) [@jake1](https://forum.ghost.org/u/jake1)\
**Post date:** [June 11, 2022, 5:11pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/6 "2022-06-11T17:11:41Z")

</div>

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!

---

<div class="post-metadata">

**Author:** ![benitoanagua](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/benitoanagua/32/25276_2.png) [@benitoanagua](https://forum.ghost.org/u/benitoanagua)\
**Post date:** [July 15, 2023, 9:10pm UTC](https://forum.ghost.org/t/nginx-reverse-proxy-and-cloudflare/30653/8 "2023-07-15T21:10:36Z")

</div>

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

 ![2023-07-15_17-06](https://us1.discourse-cdn.com/flex015/uploads/ghost2/original/3X/6/1/61d8a77608255386105c1eef27ab12950dc72a1f.png)
