Skip to content

Instantly share code, notes, and snippets.



Last active Mar 29, 2020
What would you like to do?
Example nginx.conf for Ghost blog with Nginx and Naxsi -
user nginx;
worker_processes 2; # Set this equal to the number of CPU cores
events { worker_connections 1024; }
http {
server_names_hash_bucket_size 64;
types_hash_max_size 2048;
server_tokens off;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 15;
gzip on;
gzip_comp_level 6;
gzip_disable "msie6";
gzip_min_length 150;
gzip_proxied any;
gzip_types text/plain text/xml text/css application/json application/javascript;
gzip_vary on;
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=one:8m max_size=1000M inactive=60m;
proxy_temp_path /var/tmp;
client_max_body_size 20m;
client_body_buffer_size 128k;
include /etc/nginx/naxsi_core.rules;
upstream ghost_upstream {
keepalive 64;
server {
listen 80;
listen 443 ssl;
server_name YOUR.DOMAIN.NAME;
ssl_certificate /opt/nginx/conf/ssl-unified.crt;
ssl_certificate_key /opt/nginx/conf/YOUR.DOMAIN.NAME.pem;
# Due to the SSLv3 POODLE vulnerability, it is excluded from the protocol list.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers RC4:HIGH:!MEDIUM:!aNULL:!MD5:!DH:!EDH;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE)$ ) { return 444; }
if ($host != $server_name) {
return 301 $scheme://$server_name$request_uri;
location ~* \.(db|hbs|conf)$ { deny all; }
location ~ /\. { deny all; }
location ~ ~$ { deny all; }
# Uncomment this block if you wish to use your own files
# instead of those auto-generated by Ghost blog
# location ~ ^/(sitemap\.xml|robots\.txt|favicon\.ico)$ {
# root /var/www/YOUR.DOMAIN.NAME/public;
# access_log off;
# log_not_found off;
# }
# Static files served directly by Nginx
location ~ ^/assets/(img|js|css|fonts)/ {
root /var/www/YOUR.DOMAIN.NAME/content/themes/casper;
expires 30d;
access_log off;
location ~ ^/(img/|css/|lib/|vendor/|fonts/) {
root /var/www/YOUR.DOMAIN.NAME/core/client/assets;
expires 30d;
access_log off;
location ~ ^/content/images/ {
root /var/www/YOUR.DOMAIN.NAME;
expires 30d;
access_log off;
location ~ ^/(shared/|built/) {
root /var/www/YOUR.DOMAIN.NAME/core;
expires 30d;
access_log off;
location / {
include /etc/nginx/mysite.rules;
proxy_pass http://ghost_upstream;
proxy_redirect off;
proxy_read_timeout 180s;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_pass_header X-CSRF-TOKEN;
proxy_http_version 1.1;
proxy_cache one;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_intercept_errors on;
proxy_hide_header X-Powered-By;
location = /RequestDenied { return 500; }
location = /50x.html { root html; internal; }
#error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

This comment has been minimized.

Copy link

@mettacrawler mettacrawler commented Mar 29, 2020

Very impressive. Thank you.
I benefited most from seeing how you set the headers in the proxy. I used a subset of the ones you provided and it works for me.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
should be
ssl_protocols TLSv1.1 TLSv1.2;
these days now that TLSv1 is no longer considered to be secure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.