
Деплой Hugo на GitHub Pages из приватного репозитория
Хотите опубликовать свой сайт на 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 сайт сам соберётся и обновится. Исходники — у вас в приватном, публичная часть — чистая и быстрая. Удобно, надёжно, и главное — раз настроил, больше не думаешь.