Знакомство с Hugo
Что такое Hugo
Hugo — статический генератор сайтов, написанный на Go. Он превращает Markdown-файлы в готовый HTML-сайт. Вы пишете контент в текстовых файлах (.md), а Hugo генерирует из них готовый сайт.
Многие знакомы с динамическими сайтами, например на WordPress. Там сайт обычно работает так:
- Пользователь открывает страницу.
- Сервер запускает PHP или другой код.
- Код обращается к базе данных.
- Из базы достаются статьи, настройки, комментарии.
- Сервер собирает HTML-страницу и отдаёт её браузеру.
У статического сайта подход другой. Страницы заранее собираются в готовые HTML-файлы. Когда пользователь открывает сайт, сервер просто отдаёт уже готовый файл. То есть:
- не нужна база данных;
- не нужен PHP, Python или другой серверный язык для отображения страниц;
- сайт можно раздавать даже с обычного файлового хостинга или из CDN;
- страницы загружаются очень быстро.
Именно так создан данный сайт. Я пишу статьи в Obsidian → С помощью Hugo генерирую из .md файлов готовый статичный сайт → публикую сайт на хостинге.
Пример статьи в Hugo:
---
title: "Привет, мир!"
date: 2026-04-02
draft: false
tags: ["hugo", "тест"]
categories: ["блог"]
---
Это моя первая статья.
- Блок между
---называется front matter. Это служебные данные страницы: заголовок, дата, теги, черновик, описание и другие параметры страницы. - Всё, что находится ниже, уже является содержимым страницы.
С помощью front matter Hugo может:
- подставлять заголовок в шаблон страницы;
- сортировать статьи по дате;
- скрывать черновики;
- показывать теги и категории;
- формировать списки статей;
- создавать RSS, sitemap и другие служебные страницы.
Типичный сайт на Hugo имеет примерно такую структуру:
.
├── archetypes/ # шаблоны для новых страниц
├── assets/ # CSS, JS и другие ассеты
├── content/ # статьи и страницы сайта
├── data/ # дополнительные данные
├── layouts/ # собственные шаблоны
├── public/ # в этот каталог собирается готовый сайт (html-страницы)
├── static/ # статические файлы: картинки, favicon и т.д.
├── themes/ # темы оформления
└── hugo.toml # основной конфигурационный файл
Рассмотрим основные каталоги.
content/Здесь хранится контент сайта. При генерации, файлы из этого каталога превращаются в страницы сайта (в каталогеpublic/). Например:
content/
├── _index.md
└── posts/
├── hello-world.md
└── second-post.md
public/При генерации статического сайта он помещается в этот каталог, после генерации именно его нужно публиковать на хостинге. Например:
public/
├── 404.html
├── CNAME
├── css/
├── posts/
├── hello-world/
├── second-post/
├── favicons/
├── images/
├── index.html
├── index.xml
├── js/
├── robots.txt
├── scss/
├── sitemap.xml
static/Сюда кладут файлы, которые должны попасть на сайт как есть: картинки, favicon.ico, robots.txt, произвольные файлы для скачивания. Например:
static/
└── images/
└── logo.png
После сборки файл будет доступен как:
public/images/logo.png
layouts/Здесь находятся шаблоны страниц. Если тема вас почти устраивает, но вы хотите изменить какой-то блок, обычно не нужно править саму тему. Можно скопировать нужный шаблон темы в этот каталог и изменить его там.themes/Здесь лежат темы оформления. Тема содержит готовые шаблоны, стили и другие файлы, которые определяют внешний вид сайта. Ниже мы будем использовать тему Ananke.archetypes/Это заготовки для новых страниц. Например, можно создать шаблон статьи, чтобы новые посты автоматически получали нужный набор полей: заголовок, дату, теги, описание.hugo.tomlОсновной файл настроек сайта. Здесь задаются: адрес сайта, язык, название сайта используемая тема, дополнительные параметры. Например:
baseURL = 'http://localhost:1313/'
languageCode = 'ru'
title = 'Мой тестовый Hugo-сайт'
theme = 'ananke'
[params]
description = 'Тестовый сайт на Hugo + Docker'
Hugo хорошо подходит для блогов, документации, персональных сайтов и небольших проектов.
- Он написан на Go и очень быстро генерирует сайт. Даже большие сайты могут собираться за секунды.
- Статьи можно писать в Markdown. Это удобно, потому что не нужно отвлекаться на оформление. Вы пишете текст, а Hugo сам превратит его в HTML.
- Весь сайт можно хранить как набор текстовых файлов. Это хорошо сочетается с Git.
- Не нужна база данных, которую нужно обслуживать, резервировать и защищать от типичных уязвимостей.
- Готовый сайт можно выложить практически на любой статический хостинг.
- Во время разработки можно использовать локальный hugo server. Он запускает локальный веб-сервер и автоматически пересобирает сайт при изменении файлов.
Установка Hugo в Docker и генерация сайта
В этой статье мы развернём Hugo в Docker-контейнере, чтобы не засорять систему зависимостями. Кстати, если у вас ещё не установлены, то нужно установить:
Создаём каталог проекта и сразу переходим внутрь — дальше все файлы будут создаваться относительно этой директории.
mkdir hugo-test/ && cd hugo-test
Создадим docker-compose.yml:
cat << 'EOT' > docker-compose.yml
services:
hugo:
image: hugomods/hugo:0.160.0
container_name: hugo
restart: unless-stopped
ports:
- "1313:1313"
volumes:
- ./site:/src
working_dir: /src
command:
- hugo
- server
- --bind=0.0.0.0
- --baseURL=http://localhost:1313/
- --buildDrafts
- --buildFuture
- --disableFastRender
EOT
Разберём построчно:
image: hugomods/hugo:0.160.0Официальный образ Hugo конкретной версии. Фиксируем версию, чтобы сборка была воспроизводимой.container_name: hugoЗадаём понятное имя контейнера.restart: unless-stoppedКонтейнер автоматически перезапустится после перезагрузки хоста или сбоя, пока мы сами его не остановим.ports: "1313:1313"Пробрасываем порт 1313 из контейнера на хост — по нему будет доступен сайт.volumes: ./site:/srcМонтируем локальный каталогhugo-test/siteвнутрь контейнера как/src. Все файлы сайта живут на хосте, контейнер их только читает и собирает.working_dir: /srcHugo запускается именно в/src, где лежит наш сайт.command- Переопределяем команду по умолчанию: вместо разовой сборки запускаем живой сервер с автоперезагрузкой при изменении файлов.
Флаги сервера:
--bind=0.0.0.0— слушаем на всех интерфейсах (иначе сервер доступен только внутри контейнера);--baseURL— базовый URL, по которому мы открываем сайт в браузере;--buildDrafts— показывать черновики (draft: true);--buildFuture— показывать посты с датой в будущем;--disableFastRender— полная пересборка при каждом изменении (медленнее, но надёжнее на этапе разработки).
Генерируем каркас нового сайта:
docker compose run --rm hugo new site /src
run --rmзапускает одноразовый контейнер (после завершения он удалится);- переопределяем
commandиз compose-файла. Вместо сервера выполняетсяhugo new site /src— команда создаёт пустую структуру проекта в примонтированном каталоге./site.
В результате получаем:
site/
├── archetypes/ # шаблоны для новых постов
├── assets/ # CSS/JS, которые обрабатывает Hugo
├── content/ # весь контент сайта (статьи, страницы)
├── data/ # доп. данные в YAML/JSON/TOML
├── hugo.toml # главный конфиг сайта
├── i18n/ # файлы локализации
├── layouts/ # собственные шаблоны (переопределяют тему)
├── static/ # статика: картинки, favicon, robots.txt
└── themes/ # сюда кладём темы оформления
Создаём каталог для постов:
sudo mkdir -p site/content/posts
- Hugo строит дерево страниц из структуры каталогов внутри
content/. Каталогpostsстанет разделом «Статьи» — каждый.md-файл внутри него будет отдельной записью.
Настраиваем hugo.toml:
cat << 'EOT' | sudo tee site/hugo.toml
baseURL = 'http://localhost:1313/'
languageCode = 'ru'
title = 'Мой тестовый Hugo-сайт'
theme = 'ananke'
[params]
description = 'Тестовый сайт на Hugo + Docker'
EOT
baseURLКорневой адрес сайта. При деплое на реальный домен меняем на свой.languageCodeЯзык контента — влияет на теги<html lang="ru">.titleНазвание сайта, отображается в шапке и в<title>.themeИмя каталога с темой внутриthemes/.[params] descriptionПроизвольные параметры, которые тема использует в своих шаблонах.
Подключаем тему Ananke:
cd site && sudo git init && \
sudo git submodule add https://github.com/gohugo-ananke/ananke.git themes/ananke
- Тема оформляется как git-подмодуль: она лежит в
themes/ananke/, но хранится в отдельном репозитории. Так её легко обновлять (git submodule update --remote) и не смешивать со своим кодом.
Возвращаемся в hugo-test/:
cd ..
Создаём главную страницу:
cat << 'EOT' | sudo tee site/content/_index.md
---
title: "Добро пожаловать"
date: 2026-04-02
draft: false
---
# Привет!
Это мой тестовый сайт на **Hugo + Docker + Ananke**.
[Перейти к статьям →](/posts/)
EOT
- Файл
_index.mdв корнеcontent/— это главная страница сайта. Блок между---называется front matter (про него я уже писал), ниже — сам контент.
Пишем первый пост:
cat << 'EOT' | sudo tee site/content/posts/hello-world.md
---
title: "Привет, мир!"
date: 2026-04-02
draft: false
description: "Моя первая статья на hugo"
tags: ["hugo", "docker", "тест"]
categories: ["hugo"]
---
## Введение
Это моя **первая статья** на Hugo!
Спасибо, что читаете!
EOT
- Любой
.mdвcontent/posts/автоматически становится записью в разделе «Статьи».tagsиcategoriesиз front matter позволяют теме группировать посты и строить навигацию.
Запускаем сайт:
docker compose up -d && \
docker compose ps
up -dподнимает контейнер в фоне.ps- проверяем, что контейнер работает.
Если что-то пошло не так — смотрим логи:
docker compose logs -f hugo
-f(follow) выводит лог в реальном времени, какtail -f. Успешный запуск выглядит так:
hugo | Web Server is available at http://localhost:1313/ (bind address 0.0.0.0)
hugo | Press Ctrl+C to stop
Проверяем в браузере:
http://localhost:1313/
Видим главную страницу и пост:

При любом изменении .md файлов сервер автоматически пересоберёт сайт и обновит вкладку браузера.
Итог
В этой статье мы прошли путь с нуля: создали каталог проекта, настроили Docker-контейнер с Hugo, подключили тему Ananke и написали первую статью. Сайт уже работает, доступен в браузере и автоматически обновляется при изменении файлов.
Не нужно запоминать все команды. Важно понять концептуально:
- Существует такой генератор — Hugo. Он превращает Markdown-файлы в готовый HTML-сайт. Это удобно для блогов и документации.
- Hugo можно запускать через Docker. Тогда в вашей системе не появится лишних пакетов, а сам контейнер легко удалить или пересоздать.
- Контент живёт отдельно от кода. Все статьи лежат в
content/, тема — вthemes/, настройки — вhugo.toml. Это разделение позволяет спокойно обновлять тему или Hugo, не ломая свои материалы. - Все файлы — обычный текст. Их удобно хранить в Git, делать резервные копии, переносить между компьютерами.
Остальное — это просто синтаксис, к которому привыкаешь со временем. А пока можно держать эту статью как шпаргалку и возвращаться к ней по мере необходимости.
Шпаргалка основных команд⬇
Запуск и остановка сайта:
docker compose up -d # запустить сайт в фоне
docker compose down # остановить и удалить контейнер
docker compose restart hugo # перезапустить контейнер
docker compose logs -f hugo # посмотреть логи в реальном времени
Сгенерировать сайт для публикации на хостинг:
docker compose run --rm hugo --gc --minify --baseURL=https://example.com/ # без запуска сервера соберёт сайт в каталоге public/
- Эта команда нужна, когда вы хотите получить готовые файлы сайта для размещения на хостинге, а не смотреть его локально через
http://localhost:1313/. - Не забудьте заменить URL на свой.
Создание нового контента:
# Вариант 1 — вручную создать файл в site/content/posts/
# Вариант 2 — через Hugo (используя архетипы темы):
docker compose run --rm hugo new posts/my-new-post.md
На практике я редко создаю и правлю файлы напрямую через консоль. Лично я пишу статьи в Obsidian (это очень удобный редактор Markdown), а для публикации использую небольшой Python-скрипт, который берёт рутину на себя:
- Скрипт копирует готовую статью из хранилища Obsidian прямо на сервер Hugo в
site/content/posts/. - Запускается сборка «боевой» версии сайта со всеми оптимизациями:
docker compose run --rm hugo --gc --minify --baseURL=https://example.com/
- Каталог
site/public/у меня сразу опубликован на локальном web-сервере. Поэтому я могу открыть его в браузере и посмотреть, как статья будет выглядеть именно в продакшене — безhugo server. - После финальной проверки на тестовом сервере я просто синхронизирую каталог
public/с основным хостингом.
Такой подход позволяет писать статьи в комфортной среде, а деплой сводится к нажатию одной кнопки.