Ctrl K
ComunidadGuías…

nginx.conf

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# =============================================================================
# Nginx Configuration for FlowWink (SPA)
# =============================================================================
# Optimized for:
# - Single Page Application routing (all routes -> index.html)
# - Static asset caching with proper headers
# - Gzip compression
# - Security headers
# - Social media crawler detection for SSR meta tags
# =============================================================================

# Detect social media crawlers for SSR meta tag rendering
# These bots need server-rendered OG tags since they don't execute JavaScript
map $http_user_agent $is_social_crawler {
    default                             0;
    "~*facebookexternalhit"             1;
    "~*Facebot"                         1;
    "~*Twitterbot"                      1;
    "~*LinkedInBot"                     1;
    "~*WhatsApp"                        1;
    "~*Slackbot"                        1;
    "~*Discordbot"                      1;
    "~*TelegramBot"                     1;
    "~*Pinterestbot"                    1;
    "~*Googlebot"                       1;
    "~*bingbot"                         1;
}

server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/json
        application/xml+rss
        application/rss+xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject
        image/svg+xml;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" 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;

    # Static assets with long-term caching (hashed filenames from Vite)
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Favicon and other root assets
    location ~* \.(ico|png|jpg|jpeg|gif|svg|webp|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # index.html - no cache (always fetch latest)
    location = /index.html {
        add_header Cache-Control "no-cache, must-revalidate";
        try_files $uri =404;
    }

    # SPA routing with social crawler detection
    # Social crawlers get redirected to render-page edge function for SSR meta tags
    # Regular users get the SPA
    location / {
        # Route social crawlers to SSR endpoint for proper OG tags
        # IMPORTANT: Replace SUPABASE_PROJECT_URL with your actual Supabase URL
        # Example: https://abcdefghijklmnop.supabase.co
        if ($is_social_crawler) {
            # Uncomment and configure the following lines for production:
            # rewrite ^(.*)$ /functions/v1/render-page?path=$1 break;
            # proxy_pass SUPABASE_PROJECT_URL;
            # proxy_set_header Host $proxy_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;
            
            # For now, fall through to SPA (social sharing will use index.html defaults)
            # Configure the proxy_pass above with your Supabase URL to enable SSR
        }
        
        # Normal SPA routing
        try_files $uri $uri/ /index.html;
        add_header Cache-Control "no-cache, must-revalidate";
    }

    # The MCP gateway at the site's own address — /mcp, the shape every other
    # integration uses (mcp.stripe.com, mcp.linear.app/mcp). On Vercel api/mcp.ts
    # does this; here it is one proxy_pass to the instance's mcp-server, query
    # string and headers (Authorization, Mcp-Session-Id, Accept) intact, with
    # buffering OFF so Streamable HTTP's event stream reaches the client as it
    # is written. Without it the gateway is still reachable at
    # SUPABASE_PROJECT_URL/functions/v1/mcp-server, which the admin shows.
    # IMPORTANT: Replace SUPABASE_PROJECT_URL with your actual Supabase URL
    location /mcp {
        # Uncomment and configure for production:
        # rewrite ^/mcp(/.*)?$ /functions/v1/mcp-server$1 break;
        # proxy_pass SUPABASE_PROJECT_URL;
        # proxy_http_version 1.1;
        # proxy_set_header Host $proxy_host;
        # proxy_set_header X-Forwarded-Host $host;
        # proxy_set_header X-Forwarded-Proto $scheme;
        # proxy_buffering off;
        # proxy_read_timeout 150s;
        # add_header X-FlowWink-MCP proxy always;
        return 404;
    }

    # Proxy sitemap.xml to Supabase edge function
    # IMPORTANT: Replace SUPABASE_PROJECT_URL with your actual Supabase URL
    # Example: https://abcdefghijklmnop.supabase.co
    location = /sitemap.xml {
        # Uncomment and configure for production:
        # proxy_pass SUPABASE_PROJECT_URL/functions/v1/sitemap-xml;
        # proxy_set_header Host $proxy_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;
        # proxy_cache_valid 200 1h;
        
        # Fallback: return empty sitemap until proxy is configured
        default_type application/xml;
        return 200 '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></urlset>';
    }

    # The blog's RSS feed (the archive's RSS button) — api/blog-rss.ts on Vercel.
    # Pass the site's own address as base_url, or every link names the functions host.
    location = /api/blog-rss {
        # Uncomment and configure for production:
        # rewrite ^ /functions/v1/blog-rss?base_url=$scheme://$host&$args break;
        # proxy_pass SUPABASE_PROJECT_URL;
        # proxy_set_header Host $proxy_host;
        # proxy_set_header apikey SUPABASE_ANON_KEY;
        # proxy_set_header Authorization "Bearer SUPABASE_ANON_KEY";

        # Fallback: an empty feed until the proxy is configured
        default_type application/rss+xml;
        return 200 '<?xml version="1.0" encoding="UTF-8"?>\n<rss version="2.0"><channel><title>Blog</title><link>https://$host/blog</link><description></description></channel></rss>';
    }

    # Proxy robots.txt (optional: can also be a static file)
    location = /robots.txt {
        default_type text/plain;
        return 200 'User-agent: *\nAllow: /\nSitemap: https://$host/sitemap.xml\n';
    }

    # Health check endpoint for container orchestration
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
}