:8080 { root * /srv # Устаревшие пути llms.txt в подпапках → корень. # Без этого опечатка `/docs/llms.txt` уходит в SPA-фолбэк и # отдаёт HTML под видом text/plain — агент верит, что получил llms.txt. redir /docs/llms.txt /llms.txt 301 redir /docs/llms-full.txt /llms-full.txt 301 # Чистые URL: запросы вида `/docs/foo.html` редиректим на `/docs/foo`. # Канон сайта — без `.html` (cleanUrls в VitePress). # Не трогаем index.html в корне — он не имеет смысловой пары без расширения. @legacyHtml { path_regexp legacyHtml ^(/.+)\.html$ not path /index.html } redir @legacyHtml {re.legacyHtml.1} 301 # Подсказка агентам, где лежит карта документации (RFC 8288). # Позволяет найти llms.txt без парсинга DOM — по HTTP-заголовку. header Link "; rel=\"llms\"" # Кириллица в .txt/.md ломается без явного charset. # Применяем заголовок только к РЕАЛЬНО существующим файлам, # иначе SPA-фолбэк (HTML) уезжает с Content-Type: text/plain. @existingText { path *.txt *.md file } header @existingText Content-Type "text/plain; charset=utf-8" # Несуществующие .txt/.md → 404, не HTML-фолбэк. # Это критично для llms.txt: агент должен получить честный 404, # а не валидный «как бы текст» с лендингом внутри. @missingText { path *.txt *.md not file } respond @missingText 404 file_server # cleanUrls: пробуем точное совпадение → +.html → каталог → SPA-фолбэк. try_files {path} {path}.html {path}/ /index.html }