Reverse Proxy Config Errors With URL


  • How was Ghost installed and configured? ghost-cli
  • What Node version, database, OS & browser are you using? nodejs 12.19.0-deb-1nodesource1, mariadb-server 1:10.5.6+maria~focal, Ubuntu 20.04.1 LTS, Firefox 82
  • What errors or information do you see in the console? No console errors - the browser reports either 502 Bad Gateway, or “The page isn’t redirecting properly” depending on the particular configuration I’m testing. “ghost log” reports entries like these: [2020-10-29 15:45:08] INFO "GET /" 301 0ms
  • What steps could someone else take to reproduce the issue you’re having?

I’m trying to set up Ghost behind a reverse proxy. The proxy server is doing the SSL termination and then it passes the request to the Ghost server via port 80 http. When Ghost is configured to use https in the URL, it throws the message shown above in the ghost log along with the browser reporting an issue with redirecting. If Ghost is configured to use http, then the site will load, but it will sometimes show broken encryption because some assets are showing up with http URLs instead of https. Does anything look incorrect here?

Reverse proxy configuration:

upstream tdd {

server {

    location / {
            proxy_pass http://tdd;
            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 $scheme;

    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/tdd.crt;
    ssl_certificate_key /etc/nginx/ssl/tdd.key;


Ghost configuration:

  "url": "",
  "server": {
    "port": 2370,
    "host": ""
  "database": {
    "client": "mysql",
    "connection": {
      "host": "localhost",
      "user": "ghost-254",
      "password": "",
      "database": "html_prod"
  "mail": {
    "transport": "Direct"
  "logging": {
    "transports": [
  "process": "systemd",
  "paths": {
    "contentPath": "/var/www/"

Nginx configuration on Ghost server:

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

    root /var/www/; # Used for 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;


    location ~ /.well-known {
        allow all;

    client_max_body_size 50m;

I also noticed that when I changed the Ghost configuration from http to https, it changed the port, but did not update the nginx configuration to reflect this, so I had to manually edit the nginx configuration file after finding the errors in the nginx log.

1 Like

URL looks good - if you’re using https, it has to be https

Does nginx use the x-forwarded-proto header in determining the protocol? Maybe try hardcoding the header in your Ghost conf file to https and see if that fixes it? proxy_set_header X-Forwarded-Proto https

1 Like

If I change the proxy_pass statement to then it throws SSL handshake errors when trying to hand the request to the backend:

[error] 418172#418172: *2260 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream, client:, server:, request: "GET / HTTP/1.0", upstream: "", host: ""

It looks like Ghost isn’t serving a certificate (which makes sense because I did not choose to configure SSL during setup) but if the URL is set to something with https then it refuses to reply properly. I’m not sure what the best solution is here.

As of now, it’s impossible for the Ghost process to serve requests on an https-server, so that makes sense. What I meant by the URL looks good is in your Ghost config - if you’re planning on serving your website using https, the URL has to be configured so, and SSL termination has to take place before the request hits the Ghost process.

What happens when you apply the change to nginx I suggested?

Ok, now it looks to be working. The default setup had proxy_set_header X-Forwarded-Proto $scheme which I assume was resolving to plain http since the reverse proxy sitting in front of the Ghost server is using http to communicate.

Will modifying the nginx config manually in this way cause any problems when upgrading Ghost versions later? The install generated this script automatically so I might need to be on the lookout in case it gets overwritten in the future.


Sounds like nginx doesn’t process the header coming from upstream :upside_down_face:

Nothing to worry about on the Ghost nginx config side, you don’t have a standard install so the standard template doesn’t work

Odd behavior but looks to be an nginx problem. That header is set the same way on the reverse proxy so I’m not sure why it doesn’t make it through:

proxy_set_header X-Forwarded-Proto $scheme

That server does serve a certificate and listens on 443.