diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml
index f4910a6d..2095f790 100644
--- a/.github/workflows/docs-build.yml
+++ b/.github/workflows/docs-build.yml
@@ -20,3 +20,12 @@ jobs:
- run: npm run build
- name: Check internal links
run: node scripts/check-links.mjs
+ # nginx/default.conf ships straight into the runtime image (see Dockerfile)
+ # and was never validated anywhere in CI. A syntax error there does not fail
+ # the build — it fails `nginx -g daemon off;` at container start, i.e. the
+ # docs go down on deploy. Validate it with the same nginx the image uses.
+ - name: Validate nginx config
+ run: |
+ docker run --rm \
+ -v "$PWD/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro" \
+ nginx:stable-alpine nginx -t
diff --git a/nginx/default.conf b/nginx/default.conf
index f046d404..a7b75323 100644
--- a/nginx/default.conf
+++ b/nginx/default.conf
@@ -45,6 +45,28 @@ server {
location = /docs/usecases/MCP { return 301 /docs/mcp/mcp-server/; }
location = /docs/usecases/MCP/ { return 301 /docs/mcp/mcp-server/; }
+ # Legacy Pump.fun paths. These are covered by plugin-client-redirects, which
+ # emits a real HTML page per old URL: HTTP 200, a meta-refresh, a *relative*
+ # canonical — and an EMPTY
. Verified live on 2026-08-11, all four
+ # sampled paths returned `200` with ``. Nine such URLs exist
+ # for a four-page cluster, and Google indexed them: on 2026-08-09
+ # /docs/examples/Solana/Pump-Fun-API/ ranked position 3 for "pumpfun api",
+ # above the canonical page, which was position 13.4 the same day.
+ #
+ # A 200 with no title is an indexable duplicate, so the client-side redirect
+ # is actively competing with the page it points at. Promote to real 301s;
+ # the client-side redirects stay as a harmless fallback for direct hits that
+ # somehow bypass nginx.
+ #
+ # No redirect loop: the canonical form is /docs/blockchain/Solana/Pumpfun/,
+ # and the capture group below matches only the bare names, never a
+ # "Pumpfun/" segment, so targets cannot re-enter this block. The
+ # ^~ /docs/blockchain/Solana/PumpFun block above does not shadow these
+ # either — "PumpFun" is not a prefix of "Pump-Fun-API" or "pump-swap-api".
+ location ~ ^/docs/(?:examples/Solana|examples/dextrades|blockchain/Solana)/(Pump-Fun-API|Pump-Fun-Marketcap-Bonding-Curve-API|pump-fun-to-pump-swap|pump-swap-api)/?$ {
+ return 301 /docs/blockchain/Solana/Pumpfun/$1/;
+ }
+
# Self-hosted fonts + webpack-hashed /assets (filenames change on update)
location ~* ^/(fonts|assets)/ {
try_files $uri =404;