Problems with HTTPS / SSL with reverse proxy

If you’re looking for some help, it’s important to provide as much context as possible so that people are able to assist you. Try to always mention:

  • What’s your URL? https://joeslab.org

  • What version of Ghost are you using? Latest docker image

  • What configuration? Configured with docker, with a reverse proxy before the system running Ghost. WAN → Nginx Reverse Proxy on Server 1 → System running ghost.

  • What browser? All browsers

  • What errors or information do you see in the console? When configuring Nginx Proxy Manager to use HTTPs with a Let’s Encrypt provided SSL cert, I get 502 Bad Gateway errors. When using HTTP, it forwards to the server and can be accessed as expected, but it’s unsecure which isn’t ideal.

  • What steps could someone else take to reproduce the issue you’re having?
    Unsure, I have a pretty odd setup I guess.

Just to provide a bit more context, I have a couple different webservers with different domains, so I’m running Nginx Proxy manager in a docker container.
From there, all of my other servers seem to work fine with https or http, it’s only ghost i’ve had problems with.

I have attempted:

  1. Using the Ubuntu ghost-cli installation method
  2. Using the official docker image
  3. Using the Bitnami image / steps

I’m rocking the docker version now because it seems the easiest to spin up and tear down when needed (plus lets me avoid the double reverse proxy with nginx and instead just uses from my understanding a firewall forwarding rule), but am open to doing the ghost-cli method if that’s the best way.

version: "3.3"
services:
  ghost:
    image: ghost:latest
    restart: always
    ports:
      - "8080:2368"
    depends_on:
      - db
    environment:
      url: http://localhost:2368
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghost
      database__connection__password: ghostdbpass
      database__connection__database: ghostdb
    volumes:
      - /home/ghost/content:/var/lib/ghost/content

  db:
    image: mariadb:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: <hidden>
      MYSQL_USER: ghost
      MYSQL_PASSWORD: ghostdbpass
      MYSQL_DATABASE: ghostdb
    volumes:
      - /home/ghost/mysql:/var/lib/mysql

and Nginx configuration on the first reverse proxy:

# ------------------------------------------------------------
# joeslab.org
# ------------------------------------------------------------

server {
  set $forward_scheme https;
  set $server         "192.168.86.85";
  set $port           8080;

  listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443 ssl http2;

  server_name joeslab.org;

  # Let's Encrypt SSL
  include conf.d/include/letsencrypt-acme-challenge.conf;
  include conf.d/include/ssl-ciphers.conf;
  ssl_certificate /etc/letsencrypt/live/npm-13/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/npm-13/privkey.pem;

  access_log /data/logs/proxy-host-11_access.log proxy;
  error_log /data/logs/proxy-host-11_error.log warn;

  location / {
    # Proxy!
    include conf.d/include/proxy.conf;
  }
  # Custom
  include /data/nginx/custom/server_proxy[.]conf;
}

From the nginx access log:

[19/Jul/2024:17:32:08 +0000] - 502 502 - GET https joeslab.org "/.git/config" [Client 185.196.9.227] [Length 556] [Gzip -] [Sent-to 192.168.86.85] "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" "-"

matched with the corresponding error log:

2024/07/19 17:32:08 [error] 295#295: *456 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream, client: 185.196.9.227, server: joeslab.org, request: "GET /.git/config HTTP/1.1", upstream: "https://192.168.86.85:8080/.git/config", host: "joeslab.org"

After an embarrassing amount of time trying to troubleshoot the worst part of technology ever created (advanced network configs), I was able to get it with the below to I guess do SSL termination on the nginx side?

location / {
    proxy_pass $forward_scheme://$server:$port;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

If you need an easier and, in my opinion, better solution, try Cloudflare’s proxied origin certificates. They are free and reliable. There are many other benefits, and the only potential drawback is that you’re sending all your private data traffic to a private company. This is also true when relying on Let’s Encrypt (Microsoft, if I’m not mistaken).

Cheers! And congratulations on finding the solution yourself.

1 Like

just for clarification, Let’s Encrypt is an open Certificate Authority and is not operated by Microsoft. The only data shared with them is the data necessary to register your certificate.

2 Likes

Thanks for your correcton, I was mistaken :)

Hi @jgilbrook,

+1 to the solution recommended by @ngeorger
Cloudflare is great and safe option.

I just recently finished my article about it

This article is a part of the guide about self-hosted Ghost: The Ghost Blog: Complete Guide

Leaving it here with hope that it helps somebody and save a time

1 Like

Off topic, sorry!
Nice guide with Proxmox! If you are interested to mention my project to deploy Ghost on Kubernetes, please check SREDevOps.org · GitHub