crates-docs 1.0.0

High-performance Rust crate documentation query MCP server, supports Stdio/HTTP/SSE transport and OAuth authentication
Documentation
# nginx reverse proxy for crates-docs: TLS termination + X-API-Key -> Bearer.
#
# What it does:
#   - Terminates HTTPS on :443 (bring your own certificate).
#   - Rejects requests with no `X-API-Key` (except /health) with 401 at the edge.
#   - Rewrites `X-API-Key: <k>` into `Authorization: Bearer <k>` so the
#     crates-docs in-process auth layer enforces the key cryptographically.
#   - Forwards to the loopback-only backend on 127.0.0.1:8080, with the
#     buffering/timeout settings SSE needs.
#
# This is a server{} + the map{} it depends on; drop both into the http{} block
# of your nginx.conf (map MUST live at http scope, not inside server{}).

# Translate the incoming X-API-Key header into a bearer token. When the header
# is absent the variable is empty, which we reject per-location below.
map $http_x_api_key $bearer_token {
    default   "";
    "~.+"     "Bearer $http_x_api_key";
}

server {
    listen 443 ssl;
    http2 on;                       # nginx >= 1.25.1
    # Older nginx (< 1.25.1): delete the line above and use instead:
    #   listen 443 ssl http2;
    server_name docs.example.com;

    ssl_certificate     /etc/ssl/certs/crates-docs.crt;
    ssl_certificate_key /etc/ssl/private/crates-docs.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    # Health check stays open (no key required) for monitoring.
    location = /health {
        proxy_pass http://127.0.0.1:8080;
    }

    # MCP endpoints: /mcp (Streamable HTTP), /sse + /messages (SSE).
    location / {
        # Reject when X-API-Key is missing/empty before touching the backend.
        if ($http_x_api_key = "") {
            return 401;
        }

        # X-API-Key -> Authorization: Bearer for the in-process check.
        proxy_set_header Authorization $bearer_token;
        # Don't leak the raw key header upstream once translated.
        proxy_set_header X-Api-Key "";

        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;

        # SSE / streaming: keep connections open and unbuffered so events flush
        # immediately. These are required for the /sse transport to work.
        proxy_http_version 1.1;
        proxy_set_header   Connection "";
        proxy_buffering    off;
        proxy_read_timeout 3600s;

        proxy_pass http://127.0.0.1:8080;
    }
}