Adds 7 SEO improvements across the full stack: 1. Enhanced index.html: - Open Graph tags (og:title, og:description, og:image, og:locale sv_SE) - Twitter Card tags (summary_large_image) - Canonical URL (https://bilhej.se/) - Meta keywords, author, robots, language tags - Structured data in JSON-LD (Organization, WebSite, Service, FAQPage) - FAQ structured data with 4 Q&A pairs (pris, anonymitet, hur funkar det) - Preconnect hints for analytics origin 2. robots.txt: - Disallow: auth pages, admin, orders, payment, guest pages - Allow: public pages (/, /om-oss, /kontakt, /integritetspolicy, /villkor) - Crawl-delay: 10s - Points to sitemap 3. sitemap.xml: - 6 public URLs with proper changefreq and priority - Home (1.0), Om (0.7), Kontakt (0.6), GDPR/Villkor (0.5) 4. useSeo composable: - Dynamic document.title, meta description/OG/Twitter on route change - Canonical URL updates per page - Reset fallback for unnamed routes 5. Route-level SEO data: - 16 routes with unique title, description, keywords - Covers all public pages + key auth pages 6. App.vue: wired useSeo with route.name watcher (immediate: true) 7. nginx.conf: - Security headers: X-Frame-Options DENY, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy, Permissions-Policy, HSTS - Far-future cache (1y, immutable) for static assets - No-cache for robots.txt and sitemap.xml - Deny access to dotfiles - Stronger gzip config
69 lines
2.8 KiB
Nginx Configuration File
69 lines
2.8 KiB
Nginx Configuration File
server {
|
|
listen 80;
|
|
listen 443 ssl;
|
|
server_name bilhej.se www.bilhej.se;
|
|
|
|
ssl_certificate /etc/nginx/certs/cert.crt;
|
|
ssl_certificate_key /etc/nginx/certs/cert.key;
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# ── Security headers ──────────────────────────────────────────
|
|
add_header X-Frame-Options "DENY" always;
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
# Strict-Transport-Security only when HTTPS is active
|
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
|
|
|
# ── Gzip ──────────────────────────────────────────────────────
|
|
gzip on;
|
|
gzip_types text/plain text/css application/json application/javascript text/xml
|
|
application/xml text/javascript image/svg+xml text/markdown;
|
|
gzip_vary on;
|
|
gzip_min_length 256;
|
|
gzip_comp_level 6;
|
|
|
|
# ── API reverse proxy ─────────────────────────────────────────
|
|
location /api/ {
|
|
proxy_pass http://backend:8080;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header X-Forwarded-Host $host;
|
|
}
|
|
|
|
# ── Static assets with far-future cache ───────────────────────
|
|
location ~* \.(?:ico|svg|css|js|woff2?|ttf|eot|png|jpg|jpeg|gif|webp|avif)$ {
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
add_header Vary "Accept-Encoding";
|
|
try_files $uri =404;
|
|
}
|
|
|
|
# ── Robots + sitemap (never cached, fresh every time) ─────────
|
|
location = /robots.txt {
|
|
add_header Cache-Control "no-cache, must-revalidate";
|
|
try_files $uri =404;
|
|
}
|
|
location = /sitemap.xml {
|
|
add_header Cache-Control "no-cache, must-revalidate";
|
|
try_files $uri =404;
|
|
}
|
|
|
|
# ── SPA fallback — serve index.html for all other routes ──────
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
# ── Deny access to dotfiles ───────────────────────────────────
|
|
location ~ /\. {
|
|
deny all;
|
|
return 404;
|
|
}
|
|
}
|