Setting Up Ghost with Nginx as a Reverse Proxy and SSL

Learn how to set up Ghost with Nginx as a reverse proxy and configure SSL. I faced issues with SSL redirects and theme previews, but resolved them by modifying Ghost's source code. Discover the problem and solution in this detailed guide.

Setting Up Ghost with Nginx as a Reverse Proxy and SSL

When I installed Ghost on my server and configured Nginx as the reverse proxy server, I also set up SSL in Nginx. Additionally, I updated the URL for the website in Ghost's configuration file to https://blog.y9i.cc. However, I encountered an issue where I couldn't access the URL.

The Issue

When I tried to visit localhost:2368 on the server, it attempted to redirect to https://localhost:2368. The output was as follows:

$ curl localhost:2368
Moved Permanently. Redirecting to https://localhost:2368/

Conversely, when I configured the URL as http://blog.y9i.cc, I could access the website via https://blog.y9i.cc. However, updating the theme in Ghost caused the preview page to fail to display. Inspecting the network tab in Chrome's developer tools revealed that the page was being loaded from http://blog.y9i.cc.

Investigation

To solve this problem, I delved into Ghost's source code and discovered that it enforces a redirect to SSL when the website is configured to use an HTTPS link. The relevant code is located in the file /current/core/server/web/shared/middleware/url-redirects.js:

/**
 * Takes care of
 *
 * 1. required SSL redirects
 */
_private.getFrontendRedirectUrl = ({requestedHost, requestedUrl, queryParameters, secure}) => {
    const siteUrl = urlUtils.urlFor('home', true);

    debug('getFrontendRedirectUrl', requestedHost, requestedUrl, siteUrl);

    // CASE: configured canonical url is HTTPS, but request is HTTP, redirect to requested host + SSL
    if (urlUtils.isSSL(siteUrl) && !secure) {
        debug('redirect because protocol does not match');
        return _private.redirectUrl({
            redirectTo: `https://${requestedHost}`,
            pathname: requestedUrl,
            query: queryParameters
        });
    }
};

Solution

The solution to the problem was to modify the function to return null, bypassing the SSL redirect. The updated function is as follows:

_private.getFrontendRedirectUrl = ({requestedHost, requestedUrl, queryParameters, secure}) => {
    return null;
};

After making this change, the admin page displayed correctly, and the theme preview issue was resolved.