1 min read

Ghost Blog behind nginx reverse proxy

If you are trying to make Ghost Blog work behind a Nginx reverse proxy with SSL termination, then you came to the right spot!

I have a K8S cluster running in AWS. In front of the cluster is a server with static IP running Nginx as a reverse proxy with letsencrypt SSL termination.

Problem I had with Ghost blog was that the redirect were not working correctly after setting url environment variable in the pod.

The problem you run into is that http://localhost:2368 is used as the domain in some of the URLs. In order to fix this a correct Nginx configuration to prevent continuos redirects. The secret is to use proxy_set_header X-Forwarded-Proto $scheme; in the configuration so that the portal knows the request was already forwarded over HTTPS.

This is the working configuration that I am using on my setup:

server {
	listen 80;
	server_name blog.domain.com;

	location ^~ /.well-known/acme-challenge/ {
		allow all;
		default_type "text/plain";
		alias /var/www/.well-known/acme-challenge/;
	}
	
	location = /.well-known/acme-challenge/ {
		return 404;
	}

	location / {
		return 301 https://$host$request_uri;
	}
}

server {
	listen 443 ssl http2;
	server_name blog.domain.com;
	access_log /var/log/nginx/blog.domain.com.access.log;
	error_log /var/log/nginx/blog.domain.com.error.log;
	client_max_body_size 10M;
	ssl_dhparam /etc/nginx/dhparam.pem;
	ssl_prefer_server_ciphers off;
	ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
	ssl_protocols TLSv1.2 TLSv1.3;
	add_header Strict-Transport-Security "max-age=63072000" always;
	ssl_certificate /var/lib/acme/live/blog.domain.com/fullchain;
	ssl_certificate_key /var/lib/acme/live/blog.domain.com/privkey;
	
	location / {
		proxy_pass http://blog-upstream;
		proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
		proxy_redirect off;
		proxy_buffering off;
		proxy_ssl_verify off;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header Host $http_host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-NginX-Proxy true;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Ssl on;
	}
}