# ── AlexanderWhitestone.com — The Wizard's Tower ──────────────────────────── # # Two rooms. No hallways. No feature creep. # /world/ — The Workshop (3D scene, Three.js) # /blog/ — The Scrolls (static posts, RSS feed) # # Static-first. No tracking. No analytics. No cookie banner. # Site root: /var/www/alexanderwhitestone.com server { listen 80; server_name alexanderwhitestone.com www.alexanderwhitestone.com; root /var/www/alexanderwhitestone.com; index index.html; # ── Security headers ──────────────────────────────────────────────────── add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; add_header Referrer-Policy strict-origin-when-cross-origin always; add_header X-XSS-Protection "1; mode=block" always; # ── Gzip for text assets ──────────────────────────────────────────────── gzip on; gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml application/rss+xml application/atom+xml; gzip_min_length 256; # ── The Workshop — 3D world assets ────────────────────────────────────── location /world/ { try_files $uri $uri/ /world/index.html; # Cache 3D assets aggressively (models, textures) location ~* \.(glb|gltf|bin|png|jpg|webp|hdr)$ { expires 30d; add_header Cache-Control "public, immutable"; } # Cache JS with revalidation (for Three.js updates) location ~* \.js$ { expires 7d; add_header Cache-Control "public, must-revalidate"; } } # ── The Scrolls — blog posts and RSS ──────────────────────────────────── location /blog/ { try_files $uri $uri/ =404; } # RSS/Atom feed — correct content type location ~* \.(rss|atom|xml)$ { types { } default_type application/rss+xml; expires 1h; } # ── Static assets (fonts, favicon) ────────────────────────────────────── location /static/ { expires 30d; add_header Cache-Control "public, immutable"; } # ── Entry hall ────────────────────────────────────────────────────────── location / { try_files $uri $uri/ =404; } # Block dotfiles location ~ /\. { deny all; return 404; } }