Actual nginx.conf for Lin's Tech Blog (http://blog.ls20.com - click for tutorial). Published with Ghost, Nginx and ModSecurity
user nginx; | |
# Set this to match the number of CPU cores | |
worker_processes 2; | |
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; | |
add_header X-Frame-Options SAMEORIGIN; | |
add_header X-XSS-Protection "1; mode=block"; | |
add_header X-Content-Type-Options nosniff; | |
# HTTP Strict Transport Security - force secure HTTPS connections | |
# add_header Strict-Transport-Security max-age=15768000; | |
# add_header X-Cache-Status $upstream_cache_status; | |
sendfile on; | |
gzip on; | |
gzip_comp_level 6; | |
gzip_disable "msie6"; | |
gzip_min_length 150; | |
gzip_proxied any; | |
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json application/javascript; | |
gzip_vary on; | |
proxy_cache_path /run/shm/nginx levels=1:2 keys_zone=one:8m max_size=200M inactive=1y; | |
proxy_temp_path /run/shm/nginx/tmp; | |
# If you do not manage your blog via SSH port forwarding, set these to higher values: | |
# client_body_buffer_size 128k; | |
# client_max_body_size 20m; | |
# Controlling buffer overflow attacks | |
# http://www.cyberciti.biz/tips/linux-unix-bsd-nginx-webserver-security.html | |
client_body_buffer_size 8k; | |
client_header_buffer_size 1k; | |
client_max_body_size 1m; | |
large_client_header_buffers 4 8k; | |
client_body_timeout 12; | |
client_header_timeout 12; | |
keepalive_timeout 15 15; | |
send_timeout 10; | |
map_hash_bucket_size 256; | |
# This is for use with CloudFlare Flexible SSL, to identify the "real" scheme of requests | |
map $http_x_forwarded_proto $real_scheme { | |
default $scheme; | |
https https; | |
} | |
map $request_uri $loggable { | |
default 1; | |
"~^/rss/?$" 0; | |
"/favicon.ico" 0; | |
"/browserconfig.xml" 0; | |
"/sitemap.xml" 0; | |
"/robots.txt" 0; | |
} | |
# These settings provide more detailed Nginx logs. For example, "$real_scheme" is added | |
# to the default log format. In addition, extra logs will be created in "access_logs". | |
# Please be sure to create folder "/opt/nginx/logs/access_logs" with these permissions: | |
# drwx------ 2 nginx root 4096 Apr 9 00:35 access_logs/ | |
log_format main '$remote_addr - $remote_user [$time_local] "$real_scheme" "$request" ' | |
'$status $body_bytes_sent "$http_referer" ' | |
'"$http_user_agent" "$http_x_forwarded_for"'; | |
access_log /opt/nginx/logs/access.log main if=$loggable; | |
access_log /opt/nginx/logs/access_logs/$host.log main if=$loggable; | |
access_log /opt/nginx/logs/access_logs/$host-$status.log main if=$loggable; | |
ModSecurityEnabled on; | |
ModSecurityConfig modsecurity.conf; | |
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m; | |
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=1r/s; | |
# In this block, put all IP addresses (or ranges) that | |
# you do not want Nginx to log in "access.log" | |
geo $myips { | |
default 0; | |
127.0.0.0/8 1; YOUR_IP_ADDRESS 1; | |
} | |
# Try to identify some robots by their IPs (NOT complete!) | |
geo $botips { | |
default 0; | |
# bingbot/msnbot: | |
157.55.32.0/22 1; 157.55.36.0/24 1; 157.56.229.0/24 1; 157.56.92.0/24 1; | |
157.56.93.0/24 1; 65.55.24.0/24 1; 65.55.52.0/24 1; 65.55.55.0/24 1; | |
65.55.213.0/24 1; 65.55.215.0/24 1; 131.253.24.0/22 1; 199.30.16.0/20 1; | |
157.55.39.0/24 1; 207.46.13.0/24 1; 40.77.167.0/24 1; | |
# Baiduspider: | |
123.125.71.0/24 1; 180.76.5.0/24 1; 180.76.6.0/24 1; 220.181.108.0/24 1; | |
# Googlebot: | |
209.85.238.0/24 1; 72.14.199.0/24 1; 66.249.64.0/19 1; | |
} | |
map $http_user_agent $isbot { | |
default 0; | |
"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 1; | |
"Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 1; | |
"Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google Favicon" 1; | |
"Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 1; | |
"Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)" 1; | |
"Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)" 1; | |
"Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B411 Safari/600.1.4 (compatible; YandexMobileBot/3.0; +http://yandex.com/bots)" 1; | |
"Mozilla/5.0 (compatible; YandexImages/3.0; +http://yandex.com/bots)" 1; | |
"Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)" 1; | |
"Mozilla/5.0 (compatible; linkdexbot/2.0; +http://www.linkdex.com/bots/)" 1; | |
"Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" 1; | |
"Mozilla/5.0 (compatible; archive.org_bot; Wayback Machine Live Record; +http://archive.org/details/archive.org_bot)" 1; | |
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0); 360Spider(compatible; HaosouSpider; http://www.haosou.com/help/help_3_2.html)" 1; | |
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1; 360Spider(compatible; HaosouSpider; http://www.haosou.com/help/help_3_2.html)" 1; | |
"Mozilla/5.0 (compatible; MojeekBot/0.6; +https://www.mojeek.com/bot.html)" 1; | |
"Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, help@moz.com)" 1; | |
"Mozilla/5.0 (compatible; coccoc/1.0; +http://help.coccoc.com/)" 1; | |
"Mozilla/5.0 (compatible; MJ12bot/v1.4.5; http://www.majestic12.co.uk/bot.php?+)" 1; | |
"Mozilla/5.0 (compatible; MegaIndex.ru/2.0; +http://megaindex.com/crawler)" 1; | |
"Mozilla/5.0 (compatible; SeznamBot/3.2; +http://fulltext.sblog.cz/)" 1; | |
"Mozilla/5.0 (compatible; AhrefsBot/5.1; +http://ahrefs.com/robot/)" 1; | |
"Mozilla/5.0 (compatible; Lipperhey-Kaus-Australis/5.0; +https://www.lipperhey.com/en/about/)" 1; | |
"Mozilla/5.0 (compatible; BLEXBot/1.0; +http://webmeup-crawler.com/)" 1; | |
"Mozilla/5.0 (compatible; spbot/4.4.2; +http://OpenLinkProfiler.org/bot )" 1; | |
"Mozilla/5.0 (compatible; Qwantify/2.2w; +https://www.qwant.com/)/*" 1; | |
"Mozilla/5.0 (compatible; archive.org_bot +http://www.archive.org/details/archive.org_bot)" 1; | |
"Mozilla/5.0 (compatible; SemrushBot/1.1~bl; +http://www.semrush.com/bot.html)" 1; | |
"Mozilla/5.0 (compatible; Findxbot/1.0; +http://www.findxbot.com)" 1; | |
"Y!J-ASR/0.1 crawler (http://www.yahoo-help.jp/app/answers/detail/p/595/a_id/42716/)" 1; | |
"Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)" 1; | |
"AddThis.com (http://support.addthis.com/)" 1; | |
"~Tiny Tiny RSS/.* \(http://tt-rss\.org/\)" 1; | |
"~Googlebot-Mobile/2\.1" 1; | |
} | |
map $http_referer $badref { | |
default 0; | |
"~*try\.php\?u=http" 1; | |
"~*(semalt|rankings-analytics|(buttons|videos)-for|(best|success|100dollars|top1)-seo).*\.com" 1; | |
"~*(baltkurs|(burger|pizza)-imperia|hundejo|hvd-store|pizza-tycoon|wrennmusic|magnet-to-torrent|torrent-to-magnet)\.com" 1; | |
"~*(cyberspacers\.us|exchange\.cx|nanoyou\.org|justprofit\.xyz|(wordpress-crew|acuclubs|responsive-test)\.net|buyessaynow\.biz)" 1; | |
} | |
map $http_user_agent $blocked_ua { | |
default 0; | |
"" 1; | |
"~^$" 1; | |
"Mozilla/4.0" 1; | |
"~Mozilla/4\.0 \(compatible; MSIE (4\.0|5\.0|5\.5|6\.0)" 1; | |
"~*(Indy Library|Squider|User-Agent|libwww-perl|morfeus|urllib|ZmEu|Nutch|masscan|libcurl|Wget)" 1; | |
} | |
upstream ghost_upstream { | |
server 127.0.0.1:2368; | |
keepalive 64; | |
} | |
# These settings are for use with CloudFlare ONLY. They provide | |
# "real" visitor IPs in your logs instead of CloudFlare IPs. | |
set_real_ip_from 199.27.128.0/21; | |
set_real_ip_from 173.245.48.0/20; | |
set_real_ip_from 103.21.244.0/22; | |
set_real_ip_from 103.22.200.0/22; | |
set_real_ip_from 103.31.4.0/22; | |
set_real_ip_from 141.101.64.0/18; | |
set_real_ip_from 108.162.192.0/18; | |
set_real_ip_from 190.93.240.0/20; | |
set_real_ip_from 188.114.96.0/20; | |
set_real_ip_from 197.234.240.0/22; | |
set_real_ip_from 198.41.128.0/17; | |
set_real_ip_from 162.158.0.0/15; | |
set_real_ip_from 104.16.0.0/12; | |
set_real_ip_from 172.64.0.0/13; | |
real_ip_header CF-Connecting-IP; | |
server { | |
listen 80; | |
# HTTP/2 is the second major version of the HTTP network protocol | |
# with many benefits such as improved page loading speed. | |
listen 443 ssl http2; | |
server_name blog.ls20.com; | |
ssl_certificate /opt/nginx/conf/ssl-unified_startssl.crt; | |
ssl_certificate_key /path/to/my/private_key.pem; | |
# These SSL settings enable Perfect Forward Secrecy (PFS) if supported | |
# by the browser. Test your server at: https://www.ssllabs.com/ssltest/ | |
# Due to the SSLv3 POODLE vulnerability, it is excluded from the protocol list. | |
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; | |
ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS; | |
ssl_prefer_server_ciphers on; | |
ssl_session_cache shared:SSL:10m; | |
ssl_session_timeout 10m; | |
# Refer to: https://weakdh.org/sysadmin.html | |
ssl_dhparam /opt/nginx/conf/dhparams.pem; | |
# SSL Stapling - reduces latency and improves SSL performance | |
ssl_stapling on; | |
ssl_stapling_verify on; | |
ssl_trusted_certificate /opt/nginx/conf/ssl-stapling_startssl.crt; | |
resolver 8.8.8.8 8.8.4.4 valid=300s; | |
resolver_timeout 10s; | |
# Reject all invalid hostnames and un-needed HTTP methods | |
if ($http_host = '') { return 404; } | |
if ($host !~* ^blog\.ls20\.com$ ) { return 404; } | |
if ($request_method !~ ^(GET|HEAD|OPTIONS)$ ) { return 405; } | |
# Block some referral spams | |
if ($badref = 1) { return 403; } | |
root /var/www/blog.ls20.com/public; | |
# Block "sensitive" locations in Nginx | |
location ~* \.(db|hbs|conf)$ { deny all; } | |
location ~ /\. { deny all; } | |
location ~ ~$ { deny all; } | |
# If you do not manage your blog via SSH port forwarding, comment out this line: | |
location ~ ^/(ghost/|signout/) { deny all; } | |
# Return 404 for some URLs requested by web scanners. They are not needed for Ghost blog. | |
# Comment out this location block if you use e.g. WordPress or PHP. | |
location ~* (\.php|manager/html|webdav|invoker|myadmin|pma|phptest|phppath|cgi-bin|wp-admin|wp-login|cfide|web-console|administrator|filemanager|busybox|uploadify|nyet\.gif) { | |
return 404; | |
} | |
# Generate favicons for different devices for your blog | |
# at this website: http://realfavicongenerator.net/ | |
location ~ ^/(apple-touch-icon|favicon|mstile).*\.png$ { | |
expires 30d; | |
access_log off; | |
} | |
location ~ ^/(favicon\.ico|browserconfig\.xml)$ { expires 30d; access_log off; } | |
location ~ ^/(sitemap\.xml|robots\.txt|BingSiteAuth\.xml)$ { access_log off; } | |
# Static files served directly by Nginx | |
location ~ ^/assets/(js|css|fonts)/ { | |
root /var/www/blog.ls20.com/content/themes/casper; | |
expires 30d; | |
access_log off; | |
} | |
location ~ ^/content/images/ { | |
root /var/www/blog.ls20.com; | |
expires 30d; | |
access_log off; | |
} | |
# If you do not manage your blog via SSH port forwarding | |
# at http://localhost:2368/ghost/, uncomment these two blocks. | |
# location ~ ^/(img/|css/|lib/|vendor/|fonts/) { | |
# root /var/www/blog.ls20.com/core/client/assets; | |
# expires 30d; | |
# access_log off; | |
# } | |
# location ~ ^/(shared/|built/) { | |
# root /var/www/blog.ls20.com/core; | |
# expires 30d; | |
# access_log off; | |
# } | |
location / { | |
limit_conn conn_limit_per_ip 10; | |
limit_req zone=req_limit_per_ip burst=10 nodelay; | |
if ($uri ~ ^/rss/?$ ) { set $blocked_ua 0; } | |
if ($isbot = 1) { set $blocked_ua 0; access_log off; } | |
if ($botips = 1) { set $blocked_ua 0; access_log off; } | |
if ($myips = 1) { set $blocked_ua 0; access_log off; } | |
# Block "bad" user-agents | |
if ($blocked_ua = 1) { return 307 http://www.browser-update.org/update.html; } | |
# if ($isbot = 1) { access_log off; } | |
# if ($botips = 1) { access_log off; } | |
# if ($myips = 1) { access_log off; } | |
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 $real_scheme; | |
proxy_set_header Host $http_host; | |
proxy_set_header X-NginX-Proxy true; | |
proxy_set_header Connection ""; | |
# If you do not manage your blog via SSH port forwarding, uncomment this line: | |
# proxy_pass_header X-CSRF-TOKEN; | |
proxy_http_version 1.1; | |
proxy_cache one; | |
proxy_cache_key "$real_scheme$host$request_uri"; | |
# To avoid serving "out-of-date" content via Nginx, it is recommended to | |
# use a shorter time period on the line below (e.g. 10m instead of 30d). | |
proxy_cache_valid 200 301 302 30d; | |
proxy_cache_valid 404 10m; | |
proxy_cache_bypass $myips; | |
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; | |
proxy_intercept_errors on; | |
# If you do not manage your blog via SSH port forwarding, comment out this line: | |
proxy_ignore_headers Cache-Control; | |
proxy_hide_header X-Powered-By; | |
} | |
location = /503.html { root html; internal; } | |
location = /50x.html { root html; internal; } | |
location = /404.html { root html; internal; } | |
error_page 404 /404.html; | |
error_page 503 /503.html; | |
error_page 500 502 504 /50x.html; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment