Static File Serving Optimization
Nginx's ability to serve static files quickly is a cornerstone of web performance. Correctly configuring expires, Cache-Control, sendfile, and gzip can dramatically improve client load times.
sendfile — Kernel-Level File Transfer
Standard file transfer reads file contents into user space and then sends them to the socket. Enabling sendfile transfers files directly from the kernel to the socket, reducing memory copies and CPU overhead.
[Standard]
Disk → Kernel buffer → User space → Socket buffer → Network
(2 memory copies)
[sendfile]
Disk → Kernel buffer → Socket buffer → Network
(processed entirely in kernel, 1 copy)
http {
sendfile on; # Use sendfile() syscall
tcp_nopush on; # With sendfile: bundle TCP packets to max size
tcp_nodelay on; # Send last packet immediately without delay
}
Cache Control (expires, Cache-Control)
Proper browser caching reduces unnecessary server requests from repeat visitors, lowering both traffic and response times.
expires Directive
server {
root /var/www/html;
location ~* \.(png|jpg|jpeg|gif|webp|svg|ico)$ {
expires 7d;
}
location ~* \.(woff|woff2|ttf|otf|eot)$ {
expires 1y;
}
# JS/CSS with build hash — 1 year (immutable)
location ~* \.(js|css)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML — no cache (always fetch latest)
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
}
Cache-Control Header Values
| Value | Description |
|---|---|
public | Allow CDN and intermediate caches |
private | Browser cache only, no CDN caching |
no-cache | Store cache but revalidate with server before use |
no-store | Do not store cache at all (sensitive data) |
must-revalidate | Expired cache must be revalidated with server |
immutable | Content will never change during cache validity |
max-age=N | Cache valid for N seconds |
Gzip Compression
Compressing text-based files before sending can reduce network traffic by 50–80%.
http {
gzip on;
gzip_comp_level 6; # Level 1–9 (6 balances speed vs ratio)
gzip_min_length 1024; # Don't compress files smaller than 1KB
gzip_http_version 1.0;
gzip_vary on; # Vary header for proxy caching
gzip_types
text/plain
text/css
text/javascript
text/xml
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss
image/svg+xml
font/woff
font/woff2;
}
Verify Gzip
# Check for Content-Encoding: gzip header
curl -H "Accept-Encoding: gzip" -I http://example.com/app.js
# Should see:
# Content-Encoding: gzip
# Vary: Accept-Encoding
Open File Cache — File Descriptor Caching
Reduce the number of open() syscalls in high-traffic static file environments by caching file descriptors.
http {
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
Comprehensive Static Serving Configuration
Production-ready static file serving optimization:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
open_file_cache max=5000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Versioned/hashed assets — 1 year strong cache
location ~* \.[0-9a-f]{8,}\.(js|css)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Images and fonts — 30 day cache
location ~* \.(png|jpg|jpeg|gif|webp|ico|svg|woff|woff2|ttf)$ {
expires 30d;
add_header Cache-Control "public";
access_log off;
}
# HTML — no-cache
location ~* \.html$ {
add_header Cache-Control "no-cache";
}
location / {
try_files $uri $uri/ =404;
expires 7d;
add_header Cache-Control "public";
}
}
Summary
| Optimization | Setting | Effect |
|---|---|---|
sendfile on | Kernel direct transfer | Reduced CPU usage, higher throughput |
tcp_nopush on | Bundle TCP packets | Improved network efficiency |
expires | Browser cache duration | Fewer requests from repeat visitors |
Cache-Control: immutable | Strong cache (no changes guaranteed) | Eliminates unnecessary revalidation |
gzip on | Text compression | 50–80% reduction in transfer size |
open_file_cache | File descriptor caching | Fewer I/O syscalls |