Ghost + Nginx + SSL Configuration


I noticed Ghost a while ago and toyed with it a little. Back then I wasn’t as familiar with Node so it quickly made its way into the “Hmm, that was neat” pile. I’ve been working exclusively in Node for the past year or so, so when I thought about starting a blog, I pretty much skipped over the other option completely and jumped in.

My preferred web server is Nginx. It’s light, easy to configure and fast. It’s also good at proxying requests to backend applications like NodeJS or PHP’s built in FastCGI Process Manager. I have lots of experience running the later, but not so much the former. So when I went to setup Ghost to use only SSL requests, I ran into a ’too many redirects’ issue.

Ghost’s config.js has a setting for the url of the blog you’re setting up. Setting this to worked fine and I had Nginx redirecting http traffic to https for me. However, one thing bugged me; Ghost used this URL as a base to it’s links. For SEO purposes, I’d rather not have links out there that 301 to the proper page. So, I changed it to Immediate redirect loop.

Hmmm. Interesting. Then I found this post on All About Ghost showing how to configure Ghost and Nginx for SSL. As I started reading and looking at the Nginx configuration section, I noticed one thing they had that I did not.

proxy_set_header X-Forwarded-Proto $scheme;

Turns out, Ghost uses Express and this is how it deals with proxied requests. Without this header, express can’t see the scheme being used because it’s proxied to an http backend (e.g. http://localhost:2368). Therefore, the express app thinks all requests are being served over http and keeps trying to redirect to the url configured in config.js.

Here’s what my Nginx config looks like:

server {
	listen 80;
	listen 443 ssl;
	root /path/to/root;
	access_log /path/to/logs/access.log;
	error_log /path/to/logs/error.log;
	ssl on;
	ssl_certificate /path/to/ssl.crt;
	ssl_certificate_key /path/to/ssl.key;
	ssl_session_timeout 5m;
	location / {
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header Host $http_host;
		proxy_set_header X-Nginx-Proxy true;
		proxy_set_header X-Forwarded-Proto $scheme;

Edit your config.js to use https, restart Nginx (sudo nginx -s reload), restart your Ghost blog and your should be golden.

P.S. I can also recommend StartSSL for a cheap free SSL certificate.