Перейти к содержимому
WebShield Docs

Статические сайты

Как создать статический сайт, загрузить файлы и управлять ими в WebShield.

Статический сайт можно разместить прямо в WebShield — без своего хостинга. Файлы хранятся у нас и раздаются через тот же защитный слой, что и проксируемые сайты: CDN-кеш, WAF, защита от ботов.

  • Хостинг статических сайтов доступен на тарифе домена. Объем хранилища и максимальный размер файла зависят от тарифа.
  • Сайт живёт на основном домене или на любом его поддомене. Заранее заводить запись не нужно; если у имени уже есть A, AAAA или CNAME, после снятия сайта она вернётся.
  • Для имени не должно быть включено проксирование.
  1. Откройте раздел Сайты.
  2. Нажмите Создать и выберите имя из списка или пункт Новое имя…. Уже проксируемые и занятые имена отмечены и недоступны.
  3. Сайт создается в статусе Отключен — он не виден посетителям, пока вы не опубликуете его.

Стартовой страницей служит index.html в корне сайта. Загрузить файлы можно несколькими способами:

  • Перетаскивание — перетащите файлы или папки в зону загрузки. Структура подкаталогов сохраняется.
  • Выбрать файлы / Выбрать папку — загрузка через диалог выбора. При выборе папки сохраняются относительные пути.
  • В конкретную папку — кнопка загрузки на строке папки в списке файлов добавляет выбранные файлы именно в нее.
  • ZIP-архив — загрузка архива полностью заменяет текущее содержимое сайта. Остальные способы работают в режиме слияния: новые файлы добавляются, совпадающие пути перезаписываются.

Файлы отображаются деревом с подкаталогами. Для папок показывается суммарный размер содержимого.

  • Скачивание: файл скачивается как есть; папка или весь сайт (кнопка ZIP в шапке списка) — ZIP-архивом.
  • Просмотр: текстовые файлы (HTML, CSS, JS, JSON и другие, до 512 КБ) открываются в окне просмотра.
  • Удаление: отметьте файлы и папки и нажмите Удалить выбранное. Папка удаляется вместе с содержимым. Удалить один элемент можно кнопкой в его строке.
  • Обновление файла: загрузите файл по тому же пути — он перезапишет старый.

Загруженные файлы попадают в черновик (рабочую область) — её показывает файловый менеджер. Посетители видят последнюю опубликованную версию, а не черновик.

Кнопка Опубликовать:

  1. Делает неизменяемый снимок черновика как новой версии (атомарно: посетители не увидят полуобновлённый сайт).
  2. Переключает DNS-запись хоста на инфраструктуру WebShield. Исходная запись сохраняется и будет восстановлена при отключении сайта.
  3. Выпускает TLS-сертификат (если включен HTTPS и домен делегирован).
  4. Делает новую версию доступной посетителям.

Отключить снимает сайт с публикации и восстанавливает исходную DNS-запись; файлы сохраняются. Удаление сайта удаляет файлы и полностью освобождает имя хоста.

Контент кешируется на edge-узлах. Каждая публикация — это новая версия, поэтому кеш сбрасывается автоматически: после публикации посетители сразу получают новый контент, без ручной очистки. Если вы заменили файлы в черновике и хотите, чтобы их увидели посетители, нажмите Опубликовать.

  • Генератор сайта — выбор пресета (Hugo, Jekyll, Astro, Gatsby, Next.js export, SPA, обычный HTML). Пресет задаёт значения остальных настроек; их можно поправить вручную.
  • Чистые URL — как «красивые» адреса разрешаются в файлы под специфику генератора:
    • Индекс каталога — /about → /about/index.html (Hugo, Jekyll, Astro, Eleventy, Gatsby);
    • Расширение .html — /about → /about.html, затем /about/index.html (Next.js export);
    • Только точный путь — без догадок.
  • Страница 404 — документ для отсутствующих путей (например 404.html), отдаётся со статусом 404. Пусто — отдавать ответ origin как есть. Свою страницу для раздела — например, для русской версии сайта — задаёт правило 404 в _redirects.
  • Режим SPA — отдавать index.html (со статусом 200) для неизвестных путей. Включите для одностраничных приложений с client-side маршрутизацией.
  • Публиковать по HTTPS — выпустить сертификат и отдавать сайт по HTTPS с перенаправлением с HTTP.
  • Защита от ботов — Отключено, Проверка браузера или Проверка капчей. Работает так же, как для проксируемых сайтов.

Изменения настроек опубликованного сайта применяются автоматически.

Переехала страница, сменился генератор, поменялась структура разделов — а старые ссылки уже разошлись по поисковикам и чужим статьям. Бросать их на 404 жалко. Положите в корень сайта файл _redirects:

# старые адреса → новые
/old-page /new-page 301
/blog/* /posts/:splat 301
/docs/:section/ /guide/:section/ 302
/go/telegram https://t.me/example
# SPA внутри раздела
/app/* /app/index.html 200
# своя страница 404 у каждого языка
/ru/* /ru/404.html 404
/en/* /en/404.html 404
# с корня — на версию на языке браузера
/ /ru/ 302 Language=ru,uk,be
/ /en/ 302

Одна строка — одно правило: откуда, куда и, по желанию, код. Без кода — 301. Пустые строки и строки с # пропускаются. Формат совпадает с Netlify и Cloudflare Pages, так что готовый файл обычно переезжает без правок.

Правила вступают в силу с публикацией. Сам файл посетителям не отдаётся — открыть его по адресу /_redirects не выйдет. Сколько правил сейчас действует, видно в настройках сайта.

Откуда:

  • * — хвост адреса целиком, только в конце: /blog/* ловит и /blog, и /blog/2024/hello. В цели он подставляется как :splat.
  • :имя — ровно один сегмент: /docs/:section ловит /docs/install, но не /docs/install/linux.
  • Регистр латиницы и хвостовой слеш не важны: /Old-Page/ сработает для правила /old-page.
  • Query-строка в источнике не поддерживается. Зато в цель она переносится сама: /old-page?utm=mail уедет на /new-page?utm=mail. Если у цели есть свой ?…, остаётся только он.

Куда и с каким кодом:

  • 301, 308 — постоянный переезд, 302, 303, 307 — временный. Цель — путь на этом сайте или полный адрес https://….
  • 200 — отдать файл этого сайта под другим адресом, без перенаправления. Срабатывает только тогда, когда по запрошенному адресу файла нет: /app/* не заденет настоящий /app/logo.svg.
  • 404 — страница «не найдено» для раздела, подробности ниже.
  • Правила проверяются сверху вниз, выигрывает первое подходящее. Переадресации 3xx срабатывают раньше раздачи файлов: даже если старая страница ещё лежит на месте, посетитель уедет на новую.

Чего здесь нет — и где это искать:

  • /* /404.html 404 — это Страница 404 в настройках сайта.
  • /* /index.html 200 — это Режим SPA.
  • Отправка путей на ваш сервер (/api/* https://api.example.com/:splat 200) — это API на том же домене.
  • Условия по стране и cookie не поддерживаются.

У многоязычного сайта «страница не найдена» тоже должна говорить на языке читателя. Правило с кодом 404 назначает разделу свою страницу:

/ru/* /ru/404.html 404
/en/* /en/404/index.html 404

Страницу раздела получает любой адрес под /ru/, для которого нет ни файла, ни подходящего правила 200, — со статусом 404, как и положено. Адреса вне разделов получают Страницу 404 из настроек сайта. Разделы проверяются сверху вниз: если /ru/docs/* должен отличаться от /ru/*, ставьте его выше.

  • Источник — раздел с * на конце. Весь сайт (/*) настраивается не здесь, а полем Страница 404.
  • Цель — .html-страница этого сайта, без :splat и :имя. Если файла нет в публикации, публикация остановится с ошибкой: битую ссылку на страницу 404 никто бы не заметил.
  • В Режиме SPA правила 404 не работают — приложение отвечает на любой адрес. Сайт с такими правилами в режим SPA не переключится.

Условие Language= отправляет читателя на версию на его языке:

/ /ru/ 302 Language=ru,uk,be
/ /en/ 302

Язык берётся тот, что стоит в настройках браузера первым. ru подходит и для ru-RU, и для ru-BY; pt-BR — только для бразильского португальского. Если условие не совпало, проверка идёт дальше по списку, поэтому общее правило без условия ставьте ниже.

Здесь нарочно строже, чем у Netlify:

  • Только временные коды 302, 303, 307. Постоянную переадресацию браузер запоминает навсегда, и читатель, однажды пришедший с русским браузером, уже не откроет английскую версию.
  • Только точный адрес, без * и :имя: чаще всего это корень /. Правило вида /* → /ru/:splat не пустило бы человека на страницу другого языка даже по прямой ссылке.

Поисковые роботы язык не присылают, поэтому по условию никуда не уходят и видят страницу как есть. Подскажите им языковые версии через hreflang на страницах.

Ошибку в файле мы не проглатываем: публикация останавливается, а в ответе будет номер строки и причина. Сайт при этом продолжает работать на прежней версии. Ограничения: до 2000 правил, из них до 100 с * или :имя, файл — до 128 КБ.

Нужна только обработка форм обратной связи? Сервер для неё не обязателен — см. Формы на статическом сайте.

Сайт-генератор редко бывает совсем статичным: форма обратной связи, подписка, поиск — что-то да отправляет запрос. Обычно это решают отдельным доменом api.example.com, а дальше начинаются CORS, preflight-запросы и cookie с SameSite=None.

Проще держать всё на одном имени: страницы отдаём мы, перечисленные пути уходят на ваш сервер.

  1. Откройте сайт в разделе Сайты и найдите блок API на этом домене.
  2. В Маршрутах перечислите пути, по одному на строку: /api/, /form, /feedback.
  3. В Адресе вашего сервера укажите, куда их отправлять: api.example.com или 203.0.113.10, при необходимости с портом.
  4. Сохраните. Всё остальное по-прежнему раздаётся из нашего хранилища.

Что стоит знать:

  • Хвостовой слеш значащий. /api захватывает и /apidocs; /api/ — только вложенные пути. Корень указать нельзя: сайт целиком на вашем сервере — это режим проксирования, а не статический сайт.
  • Заголовок Host мы передаём как у сайта. Ваш сервер должен отвечать на имя сайта, а не только на своё собственное.
  • На этих путях не показывается проверка браузера — она по своей природе ломает fetch и SDK. При этом фильтрация вредоносных запросов, лимиты частоты и блокировки адресов на них работают: WAF никуда не девается.
  • Адрес сервера должен быть публичным. Приватные и локальные адреса мы не принимаем.
  • Если адрес перестал разрешаться, сайт продолжает открываться — отвечать перестают только пути API. Смену IP у вашего сервера мы подхватываем сами, в течение нескольких часов.
  • Соединение к вашему серверу идёт по HTTP/1.1; WebSocket на этих путях не поддерживается.

Сборка и публикация на каждый пуш — это один шаг с CLI. Что нужно подготовить:

  1. В карточке сайта, в блоке Токены публикации, создайте токен. Он умеет ровно две вещи — залить файлы и опубликовать этот сайт; ни настройки сайта, ни домен, ни другие сайты ему не доступны. Полный токен показывается один раз, отозвать его можно там же.
  2. Положите токен в секреты репозитория под именем WS_TOKEN — CLI читает эту переменную сам.
  3. Добавьте в пайплайн два шага: установка CLI и публикация.

Синтаксис workflow у всех трёх один и тот же.

.github/workflows/deploy.yml
name: Deploy site
on:
push:
branches: [main]
# Если пушей несколько подряд — старые сборки отменяем, публикует последняя.
concurrency:
group: deploy-site
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
env:
WS_TOKEN: ${{ secrets.WS_TOKEN }} # токен публикации; CLI берёт его отсюда
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 1 # история для сборки не нужна
- run: npm ci && npm run build # ваша сборка → ./dist
- name: Установка CLI
run: curl -fsSL https://raw.githubusercontent.com/webshieldpro/webshield-cli/main/install.sh | sh
- name: Публикация
run: ~/.local/bin/webshield sites publish www.example.com --dir ./dist
.gitlab-ci.yml
deploy:
image: node:24
rules:
- if: $CI_COMMIT_BRANCH == "main"
interruptible: true # новый пуш отменяет текущую публикацию
script:
- npm ci && npm run build # ваша сборка → ./dist
- curl -fsSL https://raw.githubusercontent.com/webshieldpro/webshield-cli/main/install.sh | sh
- ~/.local/bin/webshield sites publish www.example.com --dir ./dist

Токен добавьте в Settings → CI/CD → Variables как WS_TOKEN с галочками Masked и Protected: masked не пустит его в лог задания, protected — в сборки чужих ветвей.

Если вы пользуетесь объектным хранилищем, сайт можно опубликовать прямо из одного из своих бакетов — контент не заливается через WebShield. Загрузите собранный сайт в любой свой бакет, в любую папку, любым S3-инструментом (rclone, aws s3, s3cmd, артефакты CI), а затем опубликуйте его оттуда.

  • В личном кабинете: откройте карточку сайта, найдите блок Публикация из S3-бакета, выберите бакет, укажите префикс (папку) и нажмите Опубликовать из бакета.

  • В CLI:

    Окно терминала
    webshield sites publish-from-bucket www.example.com --bucket web --path public/

Содержимое выбранного префикса заменяет сайт и публикуется как новая неизменяемая версия. Лимиты тарифа по размеру проверяются в момент публикации. Исходник остаётся в вашем бакете (тарифицируется как объектное хранилище); частью статик-хостинга становится только опубликованная копия — исходный бакет можно затем удалить, снимок публикации сохранится.