HxHippy

Static Site Hosting

Optimized Nginx configuration for static websites and SPAs.

Last updated: 2025-01-15

Basic Static Site

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Single Page Application (SPA)

server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;
    index index.html;

    # SPA routing - serve index.html for all routes
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Don't cache HTML
    location ~* \.html$ {
        expires -1;
        add_header Cache-Control "no-store, no-cache, must-revalidate";
    }
}

Production Static Site

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    # SSL
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include snippets/ssl-params.conf;

    # Security
    include snippets/security-headers.conf;

    # Root
    root /var/www/example.com;
    index index.html;

    # Gzip
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
    gzip_min_length 256;

    # Main location
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Static assets with long cache
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Fonts
    location ~* \.(woff|woff2|ttf|eot|otf)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Access-Control-Allow-Origin *;
    }

    # Images
    location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
        expires 30d;
        add_header Cache-Control "public";
    }

    # Deny hidden files
    location ~ /\. {
        deny all;
    }

    # Custom 404
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
}

Next.js Static Export

server {
    listen 443 ssl http2;
    server_name example.com;

    root /var/www/example.com/out;
    index index.html;

    # Clean URLs (no .html extension)
    location / {
        try_files $uri $uri.html $uri/ =404;
    }

    # Static assets
    location /_next/static/ {
        alias /var/www/example.com/out/_next/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Images
    location /images/ {
        expires 30d;
        add_header Cache-Control "public";
    }
}
beginner Recipes Updated 2025-01-15
  • nginx
  • static site
  • spa
  • react
  • vue
  • html