Skip to main content
Advertisement

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

ValueDescription
publicAllow CDN and intermediate caches
privateBrowser cache only, no CDN caching
no-cacheStore cache but revalidate with server before use
no-storeDo not store cache at all (sensitive data)
must-revalidateExpired cache must be revalidated with server
immutableContent will never change during cache validity
max-age=NCache 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

OptimizationSettingEffect
sendfile onKernel direct transferReduced CPU usage, higher throughput
tcp_nopush onBundle TCP packetsImproved network efficiency
expiresBrowser cache durationFewer requests from repeat visitors
Cache-Control: immutableStrong cache (no changes guaranteed)Eliminates unnecessary revalidation
gzip onText compression50–80% reduction in transfer size
open_file_cacheFile descriptor cachingFewer I/O syscalls
Advertisement