Files
de-roadmap/project/ops/gitea-vps-site/README.md
T
ddadmin 4ad904efd0
Deploy MkDocs to VPS / deploy (push) Successful in 13s
docs(site): дополнены инструкции восстановления публикации
- Зачем:
  - runbook требовал незафиксированного контекста для первого деплоя и восстановления сайта на чистой VPS.
- Что:
  - добавлены prerequisites, установка пакетов, первый workflow, UFW и проверенный атомарный откат.
  - спецификация и PRD обновлены по факту завершённого переноса на VPS.
  - локальные команды Snap uv заменены на persistent Python venv.
- Проверка:
  - mkdocs build --strict выполнен через persistent venv пользователя gitea-runner.
  - последовательность rollback проверена на временном дереве releases и symlink.
2026-08-05 03:14:52 -04:00

284 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Эксплуатация публикации `de.dementev.space`
Этот runbook реализует спецификацию
[`2026-08-04-gitea-vps-site-publishing.md`](../../specs/2026-08-04-gitea-vps-site-publishing.md).
Команды рассчитаны на Ubuntu 26.04 и Gitea 1.27.
## Зафиксированные параметры
- Gitea Runner: `2.3.0`, Linux amd64.
- SHA256: `1e9fb1bea022fdf40993ecbc1a13e87db1bfd3d7f42666e37f15f71d840d53b3`.
- Runner: repository-scoped, метка `de-roadmap-host:host`.
- Пользователь сервиса: `gitea-runner`, без `sudo` и Docker.
- Корень публикации: `/srv/de-roadmap`.
- Хранение: текущий релиз и две предыдущие версии.
- Окружение сборки: `/var/lib/gitea-runner/venvs/site`.
- Публичный IPv4 VPS: `167.224.64.252`.
## Предварительные условия
- Есть пользователь с `sudo` и рабочий SSH-доступ к VPS.
- Есть доступ к управлению DNS-зоной `dementev.space`.
- В репозитории `ddmitry/de-roadmap` включены Gitea Actions.
## Подготовка VPS
Установить Git, HTTP-сервер, Certbot, UFW и Python venv:
```bash
sudo apt-get update
sudo apt-get install \
ca-certificates \
certbot \
curl \
git \
jq \
nginx \
python3-certbot-nginx \
python3-venv \
ufw
```
Получить административный checkout, из которого устанавливаются tracked-файлы:
```bash
git clone https://git.dementev.space/ddmitry/de-roadmap.git
cd de-roadmap
```
Создать пользователя и каталоги:
```bash
sudo useradd \
--system \
--home-dir /var/lib/gitea-runner \
--create-home \
--shell /usr/sbin/nologin \
gitea-runner
sudo install -d -o gitea-runner -g gitea-runner -m 0755 \
/var/lib/gitea-runner/workspaces \
/srv/de-roadmap \
/srv/de-roadmap/releases
sudo install -d -o root -g root -m 0755 /etc/gitea-runner
```
Скачать runner во временный каталог, сверить checksum и установить root-owned
бинарник в `/usr/local/bin/gitea-runner`:
```bash
runner_tmp_dir=$(mktemp -d /tmp/de-roadmap-runner.XXXXXX)
curl -fsSLo "${runner_tmp_dir}/gitea-runner" \
https://dl.gitea.com/gitea-runner/2.3.0/gitea-runner-2.3.0-linux-amd64
printf '%s %s\n' \
'1e9fb1bea022fdf40993ecbc1a13e87db1bfd3d7f42666e37f15f71d840d53b3' \
"${runner_tmp_dir}/gitea-runner" \
| sha256sum --check
sudo install -o root -g root -m 0755 \
"${runner_tmp_dir}/gitea-runner" /usr/local/bin/gitea-runner
rm "${runner_tmp_dir}/gitea-runner"
rmdir "$runner_tmp_dir"
```
Из корня репозитория установить конфигурацию и unit:
```bash
sudo install -o root -g root -m 0644 \
project/ops/gitea-vps-site/gitea-runner.yaml \
/etc/gitea-runner/config.yaml
sudo install -o root -g root -m 0644 \
project/ops/gitea-vps-site/gitea-runner.service \
/etc/systemd/system/gitea-runner.service
sudo systemd-analyze verify /etc/systemd/system/gitea-runner.service
```
## Регистрация runner
Repository registration token получают в Gitea:
`ddmitry/de-roadmap` → Settings → Actions → Runners. Токен не сохраняют в Git
или shell history. Временный файл с токеном создают с владельцем
`gitea-runner:gitea-runner` и режимом `0600`. После регистрации файл
`/var/lib/gitea-runner/.runner` должен принадлежать тому же пользователю и
иметь режим `0600`.
Token-file должен содержать ровно 40 символов без завершающего перевода строки.
При извлечении JSON-ответа через `jq` использовать `jq --join-output '.token'`,
а не `jq --raw-output`, который добавляет newline.
```bash
sudo -u gitea-runner \
/usr/local/bin/gitea-runner \
--config /etc/gitea-runner/config.yaml \
register \
--no-interactive \
--instance https://git.dementev.space \
--token-file /var/lib/gitea-runner/.registration-token \
--name de-roadmap-vps
sudo rm /var/lib/gitea-runner/.registration-token
sudo chmod 0600 /var/lib/gitea-runner/.runner
sudo systemctl daemon-reload
sudo systemctl enable --now gitea-runner
systemctl is-enabled gitea-runner
systemctl is-active gitea-runner
```
Временный файл с токеном удаляют сразу после успешной регистрации. В Gitea на
странице Settings → Actions → Runners runner `de-roadmap-vps` должен перейти в
состояние online и показывать метку `de-roadmap-host`.
## Nginx и первичная публикация
Из корня репозитория установить bootstrap-конфигурацию nginx, создать ссылку,
отключить стандартный сайт Ubuntu и только затем перечитать проверенную
конфигурацию:
```bash
sudo install -o root -g root -m 0644 \
project/ops/gitea-vps-site/nginx.conf \
/etc/nginx/sites-available/de-roadmap
sudo ln -s \
/etc/nginx/sites-available/de-roadmap \
/etc/nginx/sites-enabled/de-roadmap
sudo unlink /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
```
Первый server block в `nginx.conf` возвращает `404` для неизвестных HTTP Host,
не раскрывает версию nginx и отклоняет TLS handshake для IP или неизвестного
SNI. Поэтому сертификат `de.dementev.space` не выдаётся при обращении к VPS по
IP. Если проверка конфигурации не прошла, отключить новый virtual host,
восстановить стандартный сайт и перечитать проверенную конфигурацию:
```bash
sudo unlink /etc/nginx/sites-enabled/de-roadmap
sudo ln -s \
/etc/nginx/sites-available/default \
/etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
```
Файл `project/ops/gitea-vps-site/nginx.conf` предназначен только для запуска до
выпуска сертификата. После выпуска сертификата Certbot изменяет установленный
virtual host. Повторная установка bootstrap-файла поверх рабочего конфига
удалит TLS-директивы.
## Окружение сборки
Скрипт `.gitea/scripts/build-site.sh` создаёт persistent venv при первом запуске
и переиспользует его в следующих сборках. `pip install` выполняется каждый раз,
чтобы применить изменения `.gitea/requirements-site.txt`, но уже установленные
версии пакетов не переустанавливаются.
## Первый деплой
В Gitea открыть Actions → Deploy MkDocs to VPS, выбрать ветку `main` и нажать
Run workflow. Job `deploy` должен завершиться успешно. Проверить опубликованный
release и локальную выдачу nginx до переключения DNS:
```bash
readlink -f /srv/de-roadmap/current
curl --fail --header 'Host: de.dementev.space' http://127.0.0.1/
```
Затем разрешить SSH, HTTP и HTTPS в UFW. Если SSH работает не на стандартном
порту `22`, сначала разрешить фактический порт вместо профиля `OpenSSH`:
```bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose
```
Ожидается политика `deny (incoming)` и разрешения только для SSH, `80/tcp` и
`443/tcp`.
## DNS и TLS
1. Уменьшить TTL записи `de.dementev.space`.
2. Направить `A` на VPS; удалить или корректно направить `AAAA`.
3. Убедиться, что сайт доступен извне по HTTP:
```bash
curl --fail --head http://de.dementev.space/
```
4. Выпустить сертификат и включить перенаправление HTTP на HTTPS:
```bash
sudo certbot --nginx \
--non-interactive \
--agree-tos \
--email me@dementev.space \
--redirect \
-d de.dementev.space
```
5. В созданном Certbot HTTP-блоке для `de.dementev.space` добавить
`server_tokens off;`, затем проверить и перечитать конфигурацию:
```bash
sudoedit /etc/nginx/sites-available/de-roadmap
sudo nginx -t
sudo systemctl reload nginx
```
6. Проверить перенаправление, HTTPS, сертификат и автоматическое продление:
```bash
curl --head http://de.dementev.space/
curl --fail --head https://de.dementev.space/
! curl --insecure --head https://167.224.64.252/
sudo certbot certificates
systemctl is-enabled certbot.timer
systemctl is-active certbot.timer
```
Ожидаются `301 Moved Permanently`, затем `200 OK`, отказ TLS по IP,
действующий сертификат и состояния таймера `enabled` и `active`.
7. Вернуть обычный DNS TTL.
## Проверка и откат
Активная версия определяется ссылкой `/srv/de-roadmap/current`. Для ручного
отката сначала выбрать точный release id из сохранённых каталогов, затем создать
временную ссылку и атомарно заменить `current`:
```bash
find /srv/de-roadmap/releases \
-mindepth 1 \
-maxdepth 1 \
-type d \
-printf '%f\n' \
| sort
rollback_release='<COMMIT_SHA>-<RUN_ID>'
rollback_link='/srv/de-roadmap/.current.rollback'
[[ "$rollback_release" =~ ^[0-9a-f]{40}-[0-9]+$ ]]
sudo test -d "/srv/de-roadmap/releases/${rollback_release}"
sudo test ! -e "$rollback_link"
sudo -u gitea-runner \
ln -s "releases/${rollback_release}" "$rollback_link"
sudo -u gitea-runner \
mv -Tf "$rollback_link" /srv/de-roadmap/current
readlink -f /srv/de-roadmap/current
curl --fail --head https://de.dementev.space/
```
Откат не удаляет более новые releases. Перед их ручным удалением всегда
проверять результат `readlink -f /srv/de-roadmap/current`.
Диагностика:
```bash
sudo systemctl status gitea-runner
sudo journalctl -u gitea-runner
sudo nginx -t
readlink -f /srv/de-roadmap/current
curl --fail --head https://de.dementev.space/
```