Skip to content

Instantly share code, notes, and snippets.

@philipstanislaus
Last active November 22, 2024 13:17
Show Gist options
  • Save philipstanislaus/654adafad91efb6de230845b5bdeae61 to your computer and use it in GitHub Desktop.
Save philipstanislaus/654adafad91efb6de230845b5bdeae61 to your computer and use it in GitHub Desktop.
Sample Nginx config with sane caching settings for modern web development
# Sample Nginx config with sane caching settings for modern web development
#
# Motivation:
# Modern web development often happens with developer tools open, e. g. the Chrome Dev Tools.
# These tools automatically deactivate all sorts of caching for you, so you always have a fresh
# and juicy version of your assets available.
# At some point, however, you want to show your work to testers, your boss or your client.
# After you implemented and deployed their feedback, they reload the testing page – and report
# the exact same issues as before! What happened? Of course, they did not have developer tools
# open, and of course, they did not empty their caches before navigating to your site.
#
# This gist provides you with a sample Nginx config with sane caching settings to prevent the
# above scenario.
#
# Specifically, it
# - deactivates caching by default,
# - allows storing of js and css files, but requires the browser to first check whether newer
# versions are available
# - activates caching for static assets such as images for 5 minutes
#
# Why to cache at all, you wonder?
# This gist should highlight the possibilities you have, and might even be used in a beta testing
# environment with many users yet regular hotfixes. Therefore, I included basic caching for you to
# be adjusted.
#
# Further readings:
# http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/
# https://www.mnot.net/cache_docs/
# http://www.ietf.org/rfc/rfc2616.txt (for a deep dive)
server {
# .domain.com will match both domain.com and anything.domain.com
server_name .example.com;
# It is best to place the root of the server block at the server level, and not the location level
# any location block path will be relative to this root.
root /usr/local/www/$server_name;
# It's always good to set logs, note however you cannot turn off the error log
# setting error_log off; will simply create a file called 'off'.
access_log /var/log/nginx/$host.access.log;
error_log /var/log/nginx/$host.error.log;
# This can also go in the http { } level
index index.html index.htm index.php;
# web app
location / {
try_files $uri $uri/ =404;
# The Expires HTTP header is a basic means of controlling caches; it tells all caches how long
# the associated representation is fresh for. After that time, caches will always check back with
# the origin server to see if a document is changed.
#
# "If a request includes the no-cache directive, it SHOULD NOT include min-fresh, max-stale, or max-age."
# (source: http://www.ietf.org/rfc/rfc2616.txt, p114)
#
# A negative value means that the response expires immediately.
# Nginx automatically sets the `Cache-Control: no-cache` header, if `expires` is negative
#
expires -1;
}
# this block will catch files that might need to change immediately (e. g. to deploy hotfixes), such as js or css
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into $1 which should help improve performance
location ~* \.(?:css|js)$ {
access_log off;
log_not_found off;
# no-cache: forces caches to submit the request to the origin server for validation before releasing a
# cached copy, every time. This is useful to assure that authentication is respected
# (in combination with public), or to maintain rigid freshness, without sacrificing all of the
# benefits of caching.
#
# public: marks authenticated responses as cacheable; normally, if HTTP authentication is required,
# responses are automatically private.
#
# must-revalidate: tells caches that they must obey any freshness information you give them about a
# representation. HTTP allows caches to serve stale representations under special conditions;
# by specifying this header, you’re telling the cache that you want it to strictly follow
# your rules.
#
# proxy-revalidate: similar to must-revalidate, except that it only applies to proxy caches.
#
add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
}
# This block will catch static file requests, such as images
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into $1 which should help improve performance
location ~* \.(?:jpg|jpeg|gif|png|ico|xml|webp)$ {
access_log off;
log_not_found off;
# The Expires HTTP header is a basic means of controlling caches; it tells all caches how long
# the associated representation is fresh for. After that time, caches will always check back with
# the origin server to see if a document is changed.
#
# "If a request includes the no-cache directive, it SHOULD NOT include min-fresh, max-stale, or max-age."
# (source: http://www.ietf.org/rfc/rfc2616.txt, p114)
#
# Nginx automatically sets the `Cache-Control: max-age=t` header, if `expires` is present, where t is a time
# specified in the directive, in seconds. Shortcuts for time can be used, for example 5m for 5 minutes.
#
expires 5m;
# public: marks authenticated responses as cacheable; normally, if HTTP authentication is required,
# responses are automatically private.
#
add_header Cache-Control "public";
}
# This block will catch static file requests of fonts and allows fonts to be requested via CORS
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into $1 which should help improve performance
location ~* \.(?:eot|woff|woff2|ttf|svg|otf) {
access_log off;
log_not_found off;
# The Expires HTTP header is a basic means of controlling caches; it tells all caches how long
# the associated representation is fresh for. After that time, caches will always check back with
# the origin server to see if a document is changed.
#
# "If a request includes the no-cache directive, it SHOULD NOT include min-fresh, max-stale, or max-age."
# (source: http://www.ietf.org/rfc/rfc2616.txt, p114)
#
# Nginx automatically sets the `Cache-Control: max-age=t` header, if `expires` is present, where t is a time
# specified in the directive, in seconds. Shortcuts for time can be used, for example 5m for 5 minutes.
#
expires 5m;
# public: marks authenticated responses as cacheable; normally, if HTTP authentication is required,
# responses are automatically private.
#
add_header Cache-Control "public";
# allow CORS requests
add_header Access-Control-Allow-Origin *;
types {font/opentype otf;}
types {application/vnd.ms-fontobject eot;}
types {font/truetype ttf;}
types {application/font-woff woff;}
types {font/x-woff woff2;}
types {image/svg+xml svg svgz;}
}
# this prevents hidden files (beginning with a period) from being served
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
}
@whittlem
Copy link

This is great, thanks.

@mrkrash
Copy link

mrkrash commented Jun 27, 2023

wow, thank you. Only one question: $server_name var where is defined?

@philipstanislaus
Copy link
Author

wow, thank you. Only one question: $server_name var where is defined?

Sure, it is defined in line 33 of the snippet: https://gist.github.com/philipstanislaus/654adafad91efb6de230845b5bdeae61#file-sane-caching-nginx-conf-L33

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment