Руководство по установке и администрированию
Для того, кто ставит сайт на сервер и ведёт его содержимое. Ниже — вся схема: установка, настройка, обновление и работа в админке.
Как устроен сайт
Сайт — это ASP.NET Core (Razor Pages) на .NET 10, без базы данных и без JavaScript на публичных страницах. Весь контент лежит файлами в git-репозитории: репозиторий одновременно и база данных, и бэкап, и механизм обновления.
- Контент — каталог
Content/: структура сайта, тексты, статьи, каталог программ. Бинарники — вwwwroot/downloads/, медиа статей — вwwwroot/media/. - Админка — нестандартный секретный адрес (задаётся при установке, здесь не публикуется), вход по одному паролю. Каждое сохранение пишет файлы контента и сразу коммитит их в git.
- Сервер — Kestrel за nginx. Код попадает на сервер
только через
git push— из админки это невозможно.
Разделы сайта модульные: набор, порядок, названия и адреса задаются в
Content/site.json через админку «Структура». Один тип раздела
можно включить несколько раз (например, два файловых архива); выключенный
раздел пропадает из меню, его адреса отдают 404.
Установка на сервер
Требования: Ubuntu 26, от 1 ГБ RAM (обязательно swap 2 ГБ — иначе сборка
на сервере может падать по памяти), .NET SDK 10, nginx. Домен (и поддомен
www) должен указывать на сервер A-записями.
Самый простой путь — скрипт deploy/install.sh:
- Скопируйте репозиторий (или папку
deploy/) на сервер. - Заполните поля вверху скрипта: минимум
SSH_USER(ваш SSH-пользователь) иADMIN_PASSWORD(пароль входа в админку); остальные поля уже заполнены разумными значениями. - Запустите:
sudo bash deploy/install.sh
Скрипт делает всё: swap, ставит .NET SDK 10, создаёт системного пользователя
viruzober и bare-репозиторий /srv/git/viruzober.git,
ставит post-receive хук, systemd-сервис, nginx, создаёт файл секретов и
запускает certbot (HTTPS). Повторный запуск безопасен: уже сделанные шаги
пропускаются. Сервис стартует только после первого git push —
хук рестартует его сам.
Если ставите вручную — те же шаги расписаны по порядку в
deploy/README.md: swap, пользователь и каталоги, bare-репозиторий,
хук, разрешение на рестарт сервиса через sudo visudo, systemd,
nginx, certbot.
После установки — первый пуш с вашей машины:
git remote add origin ssh://ВАШ_ПОЛЬЗОВАТЕЛЬ@СЕРВЕР/srv/git/viruzober.git
git push -u origin main
Первый пуш запускает сборку на сервере (около минуты на одном ядре; в это время сайт может не отвечать), дальше — только перезапуск сервиса.
Настройка: пароль, почта, git
Секреты живут в одном файле на сервере —
/srv/www/viruzober/appsettings.Production.json. В git он не попадает
никогда (в .gitignore), права на файл — только у пользователя сервиса
(chmod 600). Обновления через push этот файл не трогают.
{
"Admin": { "Password": "ПРИДУМАЙТЕ_НАДЁЖНЫЙ_ПАРОЛЬ" },
"Mail": { "To": "адрес@куда-приходят-письма" },
"Git": {
"RepositoryDir": "/srv/git/viruzober.git",
"AuthorName": "Viruzober",
"AuthorEmail": "admin@viruzober.com"
}
}
- Admin:Password — пароль входа в админку. Если поле
пустое, при входе админка честно скажет «Пароль не задан: добавьте
Admin:Password в конфигурацию сервера» — задайте пароль и перезапустите
сервис (
sudo systemctl restart viruzober). - Mail:To — адрес, на который приходят письма формы «Обратная связь». Отправка идёт через postfix на самом сервере.
- Git:* — куда админка коммитит контент и от чьего имени.
Обновление сайта
Изменения кода публикуются только через git push: хук на сервере
делает checkout, собирает проект и перезапускает сервис. Контент при этом
читается прямо из рабочего дерева, так что правки админки видны сразу.
Админка на сервере коммитит в тот же bare-репозиторий, поэтому изменения не теряются при следующем пуше. Одно предостережение: checkout при пуше перетирает незакоммиченные изменения в дереве — админка коммитит сразу после каждого сохранения, окно маленькое, но не сохраняйте ничего в админке в момент пуша.
Вход в админку
Адрес — нестандартный (не /admin), задаётся при установке сайта
и хранится в коде сервера — здесь намеренно не публикуется, это защита от
автоматического перебора типовых адресов админки ботами. Пароль — из
Admin:Password. Ссылка «Админка» в навигации сайта
появляется после входа. На страницах админки меню сайта нет — сверху
«Viruzober — админка» и ссылка «На сайт», навигация инструментов внутри.
- Пять неудачных попыток подряд — блок на 15 минут (защита от подбора).
- Все формы админки защищены от подделки запросов.
- Выход — кнопка «Выйти» в админке.
Структура разделов
Админка → «Структура» — дерево всех разделов сайта в том порядке, в каком они стоят в меню. Что здесь можно:
- Включить/выключить — выключенный раздел исчезает из меню и поиска, его адреса отдают 404, контент остаётся в git.
- Перемещать — стрелками дерева меняется порядок в меню.
- Вкладывать — вложенный раздел показывается второй строкой меню на страницах раздела-родителя (меню показывает два уровня; глубже навигация идёт такими же шагами).
- Настроить — название, адрес (slug), путь к контенту.
- Удалить — страница подтверждения перечислит всё, что будет стёрто: раздел, подразделы, их контент и медиа. Восстановление — из git-истории. «Главную» удалить нельзя.
Типы разделов:
| Тип | Что это | Настройки |
|---|---|---|
| Главная | Текст главной страницы (markdown) + список разделов | одна, не создаётся и не удаляется |
| Программы | Каталог программ: категории, подкатегории, версии со скачиванием | путь к Content/*.json |
| Статьи | Статьи в markdown, сгруппированные в разделы-папки | путь к каталогу (например Content/articles) |
| Листинг файлов | Файловый архив с папками и скачиванием | путь к каталогу |
| Обратная связь | Форма, отправка письма через postfix | без контента |
| Страница | Одна произвольная markdown-страница | путь к файлу .md |
| Ссылка | Пункт меню — переход на любой адрес | URL: /… — свой сайт, https://… — внешний |
| Сервис | Отдельное приложение на этом же домене (конвертер, редактор — что угодно), показывается во фрейме поверх шапки и подвала; под фреймом — ссылка открыть сервис в отдельной вкладке (запасной путь для скринридера) | адрес сервиса /s/имя (выдаёт deploy/add-service.sh на сервере) |
У «Ссылки» и «Сервиса» не бывает подразделов. Если экземпляров одного типа несколько, вверху страниц контента появляется выбор «Раздел» — переключение между ними.
Контент
Всё содержимое правится в админке; каждое сохранение коммитится в git.
Главная и страницы
Админка → «Главная» — текст главной страницы в markdown (заголовки, списки, ссылки, таблицы). Админка → «Страницы» — так же правятся страницы разделов типа «Страница» (например, «О сайте»).
Программы
Админка → «Программы»: категории, внутри — подкатегории (один уровень)
и программы. У программы: название, краткое описание, полное описание
(markdown) и таблица версий. Каждая версия — это версия, дата, имя файла,
размер и заметки об изменениях. Сам файл кладётся в
wwwroot/downloads/ (в поле указывается только имя файла, не
путь). На странице программы версии показываются таблицей со ссылками
«Скачать».
Статьи
Админка → «Статьи»: статьи в markdown, сгруппированные в разделы
(как папки). Каждая статья — файл Content/articles/…/*.md с
шапкой в формате YAML:
---
title: Название статьи
date: 2026-08-22
description: Краткое описание (показывается в списке)
tags: [первый, второй]
---
Текст статьи в markdown.
В статьях бывают картинки, аудио и видео. Файлы загружаются в админке
(правка статьи → «Медиафайлы»), а в тексте на них ссылаются единым
синтаксисом  — по расширению сайт
сам покажет изображение, плеер или ссылку на скачивание. Описание у картинок
обязательно (его озвучивает скринридер).
Файлы
Админка → «Файлы»: папки, загрузка нескольких файлов сразу,
переименование и удаление. На сайте раздел отдаёт листинг папок и скачивание
файлов. Имена файлов и папок: без / и \, не
. и .., не начинаются с точки (такие файлы скрыты
из листинга).
Поиск
Форма в шапке ищет по программам, статьям (включая текст), файлам и страницам — только по включённым разделам.
Git и бэкапы
- Коммиты админки затрагивают только контент:
Content/,wwwroot/downloads/иwwwroot/media/. - Локально контент-коммиты идут в обычный репозиторий, на сервере —
в bare-репозиторий
/srv/git/viruzober.git. - История git — это и есть бэкап: удалённый в админке файл или раздел можно достать из прошлых коммитов.
- Код в git-истории от админки не меняется никогда.
Локальная разработка
На своей машине сайт поднимается одной командой из каталога репозитория:
dotnet run
→ http://localhost:5000. Адрес админки локально — тот же
секретный путь, что и на сервере (см. deploy/README.md
в репозитории), тестовый пароль —
dev-password (задан в appsettings.Development.json,
используется только для разработки; на сервере пароль свой — в
appsettings.Production.json). Контент читается из файлов при
каждом запросе: файл, положенный в Content/ вручную, виден
сразу, перезапуск не нужен.
Админка с NVDA
Все формы подписаны, сообщения об ошибках и подтверждениях озвучиваются автоматически (в NVDA для этого должна быть включена настройка «Сообщать динамические изменения содержимого» — она включена по умолчанию). Отдельно — дерево в «Структуре»:
- фокус встаёт на дерево один раз: Вверх/Вниз — по разделам; «свёрнуто» читается только у разделов, у которых есть подразделы, Вправо/Влево — развернуть/свернуть (озвучивается «Раздел … развёрнут/свёрнут»);
- Пробел берёт раздел для перемещения (озвучивается «Выбран для перемещения раздел …»), стрелки перемещают его — каждый шаг озвучивается: «Раздел … перемещён в позицию 3 вместо раздела …»; второй Пробел или Enter — отпустить;
- Вправо в режиме перемещения — вложить под раздел выше («Раздел … перемещён в раздел …: позиция 2, всего пунктов 3»), Влево — поднять на уровень выше с озвучкой позиции;
- Enter в обычном режиме — открыть настройки раздела;
- без JavaScript дерево работает кнопками: «↑», «↓», «→» — вложить, «←» — поднять.
Лучше всего сайт работает в Firefox с последней версией NVDA.