
Деплой Hugo на GitHub Pages из приватного репозитория
en: Deploy Hugo to GitHub Pages from a Private Repository
Хотите опубликовать свой сайт на GitHub Pages из приватного репозитория, но не хотите покупать Pro подписку на GitHub? Можно сделать так, что бы сайт жил в публичном репозитории и деплоился автоматически при каждом пуше, а исходники при этом оставались в приватном. Расскажу, как настроил у себя — заодно и шпаргалка получится.
Разумеется, не подойдет, если вы храните что-то важное за UUID (или вообще просто случайными) ссылками, которые не должны быть публичными.
Способ работает без персональных токенов (PAT), которые имеют неприятное свойство истекать. SSH-ключи бессрочны, и GitHub официально рекомендует их для деплоя во внешние репозитории.
Публичный репозиторий — будущий дом сайта
Создаём на GitHub новый публичный репозиторий. Назовём его, скажем, username.github.io (для пользовательского сайта) или username/public-repo-name (для проектного). Это будет «лицевая» часть — сюда экшен будет закидывать сгенерированный public/.
Генерируем SSH-пару
На своей машине делаем ключ специально для этого деплоя:
ssh-keygen -t rsa -b 4096 -C "for github pages deploy" -f gh-pages -N ""Флаги:-t rsa -b 4096 — надёжный ключ,-C — любой комментарий,-f gh-pages — файлы назовутся gh-pages (приватный) и gh-pages.pub (публичный),-N "" — пустой пароль, иначе в GitHub Actions придётся вводить его интерактивно, что не работает.
Приватный gh-pages — никому не показываем. Публичный gh-pages.pub — пойдёт в публичный репозиторий.
Публичный ключ в публичный репозиторий
В только что созданном публичном репозитории: Settings → Deploy keys → Add deploy key. Заголовок любой, например GH Actions Deploy Key. Вставляем содержимое gh-pages.pub.
Важно: ставим галочку Allow write access — без неё экшен не сможет пушить.

Жмём Add key. Готово, публичный репозиторий теперь доверяет нашему ключу.
Приватный ключ — в секреты приватного репозитория
Переходим в репозиторий с исходниками Hugo (тот, что приватный): Settings → Secrets and variables → Actions → New repository secret.
Имя: ACTIONS_DEPLOY_KEY
Значение: весь приватный ключ целиком, со строками
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
Сохраняем. Теперь у экшена есть доступ к деплою.
Workflow — собираем и пушим
В приватном репозитории создаём .github/workflows/deploy.yml:
name: Deploy Hugo site to public repo
on:
push:
branches: [ master ]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: 'latest'
- name: Build site
run: hugo --minify
- name: Deploy to public repository
uses: peaceiris/actions-gh-pages@v4
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
external_repository: username/public-repo-name
publish_branch: master
publish_dir: ./publicНа что обратить внимание:
external_repository— пропишите свой публичный репозиторийpublish_branch— та ветка, которую указали в Pages (обычноmasterилиmain)submodules: true— если тему подключали как сабмодульfetch-depth: 0— нужен, чтобы Hugo корректно работал с датами (lastmod и т.п.)
Включение Pages
Пушим в master приватного репозитория. Заходим во вкладку Actions — должен запуститься workflow.
В публичном репозитории должен появиться сгенерённый сайт.
В настройках публичного репозитория включаем Pages: Settings → Pages → Source: Deploy from a branch, бранч master (или main, если вы на предыдущем шаге использовали его).

Проверяем
https://username.github.io/public-repo-name/— для проектногоhttps://username.github.io/— если репозиторийusername.github.io

Custom domain — свой домен вместо github.io
Хотите blog.example.com вместо username.github.io? Делается за пару минут.
В публичном репозитории: Settings → Pages → Custom domain — вписываете свой домен (например,
blog.example.com), жмёте Save. GitHub создаст файлCNAMEв ветке публикации.У вашего DNS-провайдера добавляете записи:
- Для поддомена (
blog.example.com) — CNAME наusername.github.io - Для домена (
example.com) — A записи на IP GitHub Pages:185.199.108.153 185.199.109.153 185.199.110.153 185.199.111.153
- Для поддомена (
После распространения DNS (обычно пару минут) в настройках Pages появится галочка Enforce HTTPS — включите её. GitHub сам выдаст и обновит Let’s Encrypt сертификат.
Важно: если используете Cloudflare, проксируйте (оранжевое облачко) только после того, как HTTPS заработает — иначе проверка домена может не пройти.
Альтернатива: Personal Access Token (PAT)
Если по каким-то причинам SSH не вариант — можно использовать классический PAT.
- Создайте токен: Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token. Выдайте права
repo(полный доступ к репозиториям). - Добавьте его как секрет в приватный репозиторий: имя
PAGES_DEPLOY_TOKEN, значение — сам токен. - В workflow замените
deploy_keyнаpersonal_token:
- name: Deploy to public repository
uses: peaceiris/actions-gh-pages@v4
with:
personal_token: ${{ secrets.PAGES_DEPLOY_TOKEN }}
external_repository: username/public-repo-name
publish_branch: master
publish_dir: ./publicНо SSH-ключи предпочтительнее: PAT истекает, его нужно периодически обновлять, а ключ — поставил и забыл.
Нюансы, на которые стоит обратить внимание
GITHUB_TOKENне работает с другими репозиториями — только с тем, где запускается экшен. Поэтому SSH-ключ или PAT обязательны.- PAT удобен для разовых задач, но он истекает. SSH-ключ — поставь и забудь.
- Если тема Hugo — сабмодуль, не забудьте
submodules: trueв checkout, иначе сборка упадёт с пустымthemes/. - Hugo версии
latestв экшене — удобно, но для продакшена лучше зафиксировать версию (hugo-version: '0.165.0'), чтобы не сломалось неожиданно.
Теперь при каждом пуше в master сайт сам соберётся и обновится. Исходники — у вас в приватном, публичная часть — чистая и быстрая. Удобно, надёжно, и главное — раз настроил, больше не думаешь.