# angular builds to index.html
index index.html;
# tor onion redirect
add_header Onion-Location http://$onion.onion$request_uri;
# HSTS preload enable
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
# generate frame configuration from origin header
if ($contentSecurityPolicy = '')
{
set $contentSecurityPolicy "frame-ancestors 'self'";
}
# used for iframes on https://mempool.space/network
if ($http_referer ~ ^https://mempool.space/)
{
set $contentSecurityPolicy "frame-ancestors https://mempool.space";
}
# used for iframes on https://mempool.ninja/network
if ($http_referer ~ ^https://mempool.ninja/)
{
set $contentSecurityPolicy "frame-ancestors https://mempool.ninja";
}
# used for iframes on https://wiz.biz/bitcoin/nodes
if ($http_referer ~ ^https://wiz.biz/)
{
set $contentSecurityPolicy "frame-ancestors https://wiz.biz";
}
# restrict usage of frames
add_header Content-Security-Policy $contentSecurityPolicy;
# enable browser and proxy caching
add_header Pragma "public";
add_header Cache-Control "public";
# vary cache if user changes language preference
add_header Vary Accept-Language;
add_header Vary Cookie;
# see order of nginx location rules
# https://stackoverflow.com/questions/5238377/nginx-location-priority
# for exact / requests, redirect based on $lang
# cache redirect for 5 minutes
location = / {
if ($unfurlprefix != '') {
rewrite ^(.*)$ $unfurlprefix$1 last;
}
if ($lang != '') {
return 302 $scheme://$host/$lang/;
}
try_files /en-US/index.html =404;
expires 5m;
}
# cache //main.f40e91d908a068a2.js forever since they never change
location ~ ^/([a-z][a-z])/(.+\..+\.(js|css))$ {
try_files $uri =404;
expires 1y;
}
# cache everything else for 5 minutes
location ~ ^/([a-z][a-z])$ {
if ($unfurlprefix != '') {
rewrite ^(.*)$ $unfurlprefix$1 last;
}
try_files $uri /$1/index.html /en-US/index.html =404;
expires 5m;
}
location ~ ^/([a-z][a-z])/ {
if ($unfurlprefix != '') {
rewrite ^(.*)$ $unfurlprefix$1 last;
}
try_files $uri /$1/index.html /en-US/index.html =404;
expires 5m;
}
# cache /resources/** for 1 week since they don't change often
location /resources {
try_files $uri /en-US/index.html;
expires 1w;
}
# only cache /resources/config.* for 5 minutes since it changes often
location /resources/config. {
try_files $uri =404;
expires 5m;
}
# only cache /resources/customize.* for 5 minutes since it changes often
location /resources/customize. {
try_files $uri =404;
expires 5m;
}
# cache /main.f40e91d908a068a2.js forever since they never change
location ~* ^/.+\..+\.(js|css)$ {
try_files /$lang/$uri /en-US/$uri =404;
expires 1y;
}
# old stuff is gone
location /explorer/ {
return 410;
}
location /sitemap/ {
return 410;
}
# unfurl preview
location /preview {
try_files /$lang/$uri $uri /en-US/$uri /en-US/index.html =404;
expires 10m;
}
# unfurl renderer
location ^~ /render {
try_files /dev/null @mempool-space-unfurler;
}
# unfurl handler
location /unfurl/ {
try_files /dev/null @mempool-space-unfurler;
}
location /slurp/ {
try_files /dev/null @mempool-space-slurper;
}
# add hack for twitter widget
location ~ ^/twidget/([A-z0-9_]*)$ {
proxy_pass https://syndication.twitter.com/srv/timeline-profile/screen-name/$1?creatorScreenName=mempool&dnt=true&embedId=twitter-widget-0&features=eyJ0ZndfdGltZWxpbmVfgbGlzdCI6eyJidWNrZXQiOltdLCJ2ZXJzaW9uIjpudWxsfSwidGZ3X2ZvbGxvd2VyX2NvdW50X3N1bnNldCI6eyJidWNrZXQiOnRydWUsInZlcnNpb24iOm51bGx9LCJ0ZndfdHdlZXRfZWRpdF9iYWNrZW5kIjp7ImJ1Y2tldCI6Im9uIiwidmVyc2lvbiI6bnVsbH0sInRmd19yZWZzcmNfc2Vzc2lvbiI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9LCJ0ZndfZm9zbnJfc29mdF9pbnRlcnZlbnRpb25zX2VuYWJsZWQiOnsiYnVja2V0Ijoib24iLCJ2ZXJzaW9uIjpudWxsfSwidGZ3X21peGVkX21lZGlhXzE1ODk3Ijp7ImJ1Y2tldCI6InRyZWF0bWVudCIsInZlcnNpb24iOm51bGx9LCJ0ZndfZXhwZXJpbWVudHNfY29va2llX2V4cGlyYXRpb24iOnsiYnVja2V0IjoxMjA5NjAwLCJ2ZXJzaW9uIjpudWxsfSwidGZ3X3Nob3dfYmlyZHdhdGNoX3Bpdm90c19lbmFibGVkIjp7ImJ1Y2tldCI6Im9uIiwidmVyc2lvbiI6bnVsbH0sInRmd19kdXBsaWNhdGVfc2NyaWJlc190b19zZXR0aW5ncyI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9LCJ0ZndfdXNlX3Byb2ZpbGVfaW1hZ2Vfc2hhcGVfZW5hYmxlZCI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9LCJ0ZndfdmlkZW9faGxzX2R5bmFtaWNfbWFuaWZlc3RzXzE1MDgyIjp7ImJ1Y2tldCI6InRydWVfYml0cmF0ZSIsInZlcnNpb24iOm51bGx9LCJ0ZndfbGVnYWN5X3RpbWVsaW5lX3N1bnNldCI6eyJidWNrZXQiOnRydWUsInZlcnNpb24iOm51bGx9LCJ0ZndfdHdlZXRfZWRpdF9mcm9udGVuZCI6eyJidWNrZXQiOiJvbiIsInZlcnNpb24iOm51bGx9fQ%3D%3D&frame=false&hideBorder=true&hideFooter=false&hideHeader=true&hideScrollBar=false&lang=en&maxHeight=500px&origin=$scheme%3A%2F%2F$http_host%2F&showHeader=false&showReplies=false&siteScreenName=mempool&theme=dark&transparent=true&widgetsVersion=2615f7e52b7e0%3A1702314776716;
proxy_ssl_server_name on;
proxy_cache_background_update on;
proxy_cache_use_stale http_429;
proxy_cache apicold;
proxy_cache_valid 200 60s;
proxy_redirect off;
add_header 'Pragma' 'no-cache';
add_header 'Cache-Control' 'private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
expires -1;
}
# catch-all for all URLs i.e. /address/foo /tx/foo /block/000
# cache 5 minutes since they change frequently
location / {
if ($unfurlprefix != '') {
rewrite ^(.*)$ $unfurlprefix$1 last;
}
try_files /$lang/$uri $uri /en-US/$uri /en-US/index.html =404;
expires 5m;
}
location @mempool-space-unfurler {
proxy_pass $mempoolSpaceUnfurler;
proxy_set_header Host $host;
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_cache_background_update on;
proxy_cache_use_stale updating;
proxy_cache unfurler;
proxy_cache_valid 200 1h; # will re-render page if older than this
proxy_redirect off;
expires 1d;
}
location @mempool-space-slurper {
proxy_pass $mempoolSpaceUnfurler;
proxy_set_header Host $host;
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_cache_background_update on;
proxy_cache_use_stale updating;
proxy_cache slurper;
proxy_cache_valid 200 1h; # will re-render page if older than this
proxy_redirect off;
expires 10d;
}