Hi everyone. I am trying to get Ghost working in my self-hosted environment. However, all the images (uploaded via the Ghost Editor) do not show. Everything else, eg the text, shows correctly.
I have found that the images are not loading due to them having “img src” of (1) absolute URL, (2) using http transport.
My current setup looks like this:
[Internet] — [Reverse Proxy] — [Ghost]
Ghost is set up to serve via plain http, i.e. no SSL.
Reverse Proxy serves via https, i.e. it adds https with an SSL certificate for incoming Internet requests, terminates/proxies requests to non-encrypted http Ghost at the backend.
So, while all the usual HTML text are rendered correctly, all “img src” generated by Ghost to use “http://FQDN/content/images/…” do not. Modern browsers detect these as “mixed content, i.e. http within https), and block them, and render them as “broken-link images”.
Perhaps one solution is for Ghost to not generate using absolute URLs, and use relative URLs like “/content/images/…”.
Another way is to set up Ghost backend to also serve https, but I am trying to avoid unnecessary encryption/decryption logic at backend, and just stick with plain http.
Does anyone have any good suggestions to help the images show properly in my setup?
It your website is served over ssl, you need to configure your Ghost URL to https://[...]. With th cli you can do this as ghost config set url https://...
You need to pass X-Forwarded-Proto: https header from your reverse proxy to Ghost. Because otherwise Ghost will accept to serve itself with a proper https connection, since the url set as https://
I checked that the moment I got the 301. X-Forwarded-Proto was already set to https. In fact, I double confirmed the strange behaviour I’m witnessing by telnet-ing directly into Ghost at port 80, and supplying the headers directly. Something like:
GET / HTTP/1.1
Host: [FQDN, same as configured in Ghost]
X-Forwarded-Proto: https
Anyone knows if there is a way to use “relative URLs” for images instead? There may be a reason why Ghost is using “full URLs”. But maybe there is some undocumented way to disable this?
We’ve had several people run into this issue before, and the only correct fix is to get the URL updated - the URL is used in many other places, so relative urls for this broken case is a band-aid.
I am not sure if my architectural use case where the [Reverse Proxy], which overlays with HTTPS, then proxies to [Ghost] backend, which serves HTTP, is rare…
IMO the correct solution is to figure out what you’ve done wrong in your webserver configuration. It’s quite difficult to help without seeing it, so try comparing it with the template used by the CLI
If you want your site to work over ssl, you should be connecting over 443, and nginx should be configured to use your SSL certificate. I don’t see it here which might be why it’s not working
Remember the setup I have? As follows:
[Internet] — [Reverse Proxy] — [Ghost]
The Reverse Proxy proxies to Ghost over port 80. That is what I’m simulating. By connecting to Ghost over port 80, but with the correct proxy headers. If the solution is to put SSL certificate in Ghost, then it does not help me in my desired setup where Ghost does not need to perform encryption/decryption, as Reverse Proxy is already doing it.
Nginx still needs to listen to port 443, unless you have another proxy in front of nginx that does TLS termination?
The listen 80 means nginx is listening on port 80 on the outside. Secured https connections come in on port 443 though (again, assuming you don’t have another proxy in front of nginx).
Edit: re-reading the entire thread, I do think you might have a second reverse proxy there. For the full picture, it will be helpful to also have the config of that. The issue might not be in nginx > Ghost but in [reverse proxy] > nginx?
Reverse Proxy listens at 443, and serves the outside Internet
Reverse Proxy connects/proxies (unencrypted) to Ghost. Thus, Ghost listens at 80.
Ghost has an internal nginx, which performs this job to response at 80. It then redirects as appropriate to the relevant localhost web servers on other ports.
The problem was that with the above setup, all [img] returned by Ghost are tagged absolute URIs beginning with “http”. As described earlier, modern browsers will then block all these as the page is supposed to be over “https” and contains “http” assets.
A reader suggested using “ghost config url https:// FQDN” as a possible solution. That is what I tried. But it gave 301. I thought it may be some config issue. The last few posts are around troubleshooting for this 301 issue.
Ultimately, I am just looking for a solution for my original setup. So far, the solution I have temporarily adopted is to implement a post-processing hack to replace all “http” with “https”. That way, the modern browsers do not block the images which are, for some reason, served using absolute URIs beginning with http. I am still unsure why Ghost does not serve using relative URIs.
What’s the argument against connecting your reverse proxy (the one listening to 443, not nginx listening to port 80) directly to Ghost on port 2369 (as per your nginx config)?
I have read through the thread, but I truly don’t understand the reason for the double proxy. From what I see, that might be a very likely source of the issues. You’re not just going reverse proxy > Ghost, but reverse proxy > nginx > Ghost.