MAATRIX / Блог / Eleventy (11ty) на Ubuntu 24.04: пошаговая установка

Eleventy (11ty) на Ubuntu 24.04: пошаговая установка

MAATRIX

Если вам надоели генераторы статики с тремя слоями абстракции, темами на непонятном шаблонизаторе и конфигом на полтысячи строк — Eleventy устроен ровно наоборот. Он не тащит за собой виртуальный DOM, не требует React ради вывода трёх абзацев текста и честно говорит: вот входные файлы, вот шаблонизатор, вот HTML на выходе. Ниже — установка 11ty на чистый Ubuntu 24.04, от apt update до рабочего сайта за nginx с автоматическим HTTPS.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Eleventy и когда он оправдан

Eleventy (11ty) — генератор статических сайтов на Node.js, который не навязывает фреймворк для шаблонов: можно писать на Nunjucks, Liquid, Handlebars, EJS, Pug или чистом JavaScript, а можно смешивать несколько движков в одном проекте. Он не собирает клиентский JS-бандл сам по себе (для этого при желании подключают esbuild или Vite отдельно) и не тянет зависимости, которые вам не нужны — в базовой установке это буквально один npm-пакет.

Это разумный выбор, если у вас:

  • документационный или блог-сайт, где важна скорость сборки и чистый HTML без лишнего JS;
  • лендинг или портфолио, где не нужна сложная логика на клиенте;
  • проект, который раньше был на Jekyll или Hugo, но команде удобнее работать в экосистеме Node.js.

Если нужен сайт с интерактивными островками (карточки товаров, фильтры на клиенте), возможно, вам ближе Astro или Gatsby — Eleventy тоже умеет добавлять JS-виджеты, но делает это без встроенного «островного» рантайма, всё руками.

Собирать статику можно на своей машине, но если сайт растёт, появляются CI-сборки по git push, нужен постоянный HTTPS-эндпоинт для превью — держать это на VPS удобнее и предсказуемее, чем на ноутбуке, который иногда выключен.

Подготовка сервера: Node.js через nvm

Первым делом обновляем систему и заводим отдельного пользователя без root — работать под root на постоянной основе не стоит.

apt update && apt upgrade -y
adduser deploy
usermod -aG sudo deploy
su - deploy

Дальше — Node.js. Ставить его лучше через nvm (Node Version Manager), а не через apt: в репозиториях Ubuntu 24.04 версия Node может отставать, а nvm даёт возможность держать несколько версий и переключаться без пересборки системных пакетов.

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install 22
nvm alias default 22
node -v
npm -v

Проверьте актуальную версию скрипта установки nvm на странице проекта на GitHub — номера релизов nvm и Node меняются, и к моменту, когда вы это читаете, актуальными могут быть уже другие цифры. Node 22 — LTS-ветка на момент написания статьи (конец августа 2026 года), но это тоже стоит перепроверить перед установкой на продакшн.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Создание проекта Eleventy

Создаём директорию проекта и инициализируем npm-пакет:

mkdir -p ~/apps/my-site && cd ~/apps/my-site
npm init -y
npm install --save-dev @11ty/eleventy

Минимальный каркас — это просто файл .md или .html в корне и конфиг:

mkdir src
cat > src/index.md << 'EOF'
---
title: Главная
---
# Привет, это Eleventy

Первая страница на статическом генераторе.
EOF

Конфигурационный файл eleventy.config.js (в версии 3.x он в ESM-формате, что важно учитывать, если копируете старые примеры из интернета — во второй версии Eleventy файл назывался .eleventy.js и использовал CommonJS):

export default function (eleventyConfig) {
  eleventyConfig.addPassthroughCopy("src/assets");
  return {
    dir: {
      input: "src",
      output: "_site",
    },
  };
}

Проверяем локальную сборку и dev-сервер (по умолчанию слушает порт 8080):

npx @11ty/eleventy --serve

Если сервер арендован без графического окружения, откройте порт наружу временно через --port и проверьте в браузере по IP, либо сразу переходите к боевой настройке через nginx ниже — постоянно гонять dev-сервер на проде не нужно, он предназначен для локальной разработки.

Соберите статику командой:

npx @11ty/eleventy

Результат окажется в _site/ — именно эту директорию отдаёт веб-сервер.

Структура шаблонов и данных

Типичный проект на Eleventy быстро обрастает такой структурой:

src/
├── _includes/
│   ├── base.njk
│   └── partials/
├── _data/
│   └── site.json
├── posts/
│   ├── posts.json
│   └── first-post.md
├── assets/
│   ├── css/
│   └── img/
└── index.md

Файл _data/site.json — глобальные данные, доступные во всех шаблонах:

{
  "title": "Мой сайт",
  "url": "https://example.com"
}

posts/posts.json задаёт общий layout и permalink для всех файлов в папке posts/ через директивные данные каталога:

{
  "layout": "post.njk",
  "tags": "posts"
}

Базовый шаблон _includes/base.njk на Nunjucks:

<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>{{ title }} — {{ site.title }}</title>
</head>
<body>
  {{ content | safe }}
</body>
</html>

Такой подход — данные отдельно, шаблоны отдельно, контент в markdown — даёт предсказуемую сборку без магии: что написали в файлах, то и получили в _site/.

Отдача сайта через nginx

Ставим nginx, если его ещё нет:

sudo apt install -y nginx

Конфиг для статики из _site/ — с кэшированием ассетов и корректной обработкой 404:

server {
    listen 80;
    server_name example.com www.example.com;
    root /home/deploy/apps/my-site/_site;
    index index.html;

    location / {
        try_files $uri $uri/ $uri.html =404;
    }

    location /assets/ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    error_page 404 /404.html;
}

Активируем и проверяем синтаксис:

sudo ln -s /etc/nginx/sites-available/my-site /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Подробный разбор настройки nginx с нуля и с обратным проксированием — в отдельной статье про настройку nginx как reverse proxy на Ubuntu 24.04, если параллельно поднимаете на сервере что-то ещё, кроме статики.

Если DNS для домена ещё не настроен, сначала разберитесь с привязкой домена и DNS на Ubuntu 24.04 — без A-записи, указывающей на IP вашего сервера, ни nginx, ни certbot дальше не пойдут.

HTTPS через Let's Encrypt

Certbot с плагином для nginx автоматически пропишет сертификат и перенастроит виртуальный хост:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

Certbot сам добавит listen 443 ssl и редирект с 80 на 443 в конфиг. Автопродление сертификатов Let's Encrypt обычно уже настроено через systemd-таймер, который ставится вместе с пакетом — проверить можно так:

sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run

Если по какой-то причине хотите альтернативу — почитайте сравнение Certbot и acme.sh для этой конкретной задачи.

Автосборка по git push

Ручная пересборка на сервере после каждого изменения — плохая идея. Практичный минимум — git-хук на bare-репозитории, который сам делает npm run build после каждого push.

Создаём bare-репозиторий:

mkdir -p ~/repos/my-site.git
cd ~/repos/my-site.git
git init --bare

Хук hooks/post-receive:

cat > ~/repos/my-site.git/hooks/post-receive << 'EOF'
#!/bin/bash
WORK_TREE=/home/deploy/apps/my-site
GIT_DIR=/home/deploy/repos/my-site.git

git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -f main

cd $WORK_TREE
source ~/.nvm/nvm.sh
nvm use default
npm install
npx @11ty/eleventy
EOF
chmod +x ~/repos/my-site.git/hooks/post-receive

На локальной машине добавляем сервер как remote и пушим:

git remote add production deploy@ваш-сервер:repos/my-site.git
git push production main

После каждого push хук пересоберёт сайт в _site/, а nginx сразу начнёт отдавать новую версию — перезапускать сервис не нужно, это же статика. Для более сложных сценариев (несколько окружений, preview-сборки для веток) имеет смысл посмотреть в сторону GitHub Actions с деплоем по SSH, но для одного сайта на одном сервере git-хука обычно достаточно годами.

Обслуживание: обновления и типовые проблемы

Пара нюансов, с которыми практически гарантированно столкнётесь:

  • Несовпадение версии Node. Eleventy 3.x требует относительно свежий Node (18+ на момент выхода мажорной версии), и если в CI или на другом сервере стоит более старая LTS — сборка падает с невнятной ошибкой про синтаксис ESM. Фиксируйте версию через .nvmrc в корне репозитория и добавляйте nvm use в хук деплоя.
  • ESM vs CommonJS в конфиге. Если копируете фрагменты конфигурации из старых туториалов под Eleventy 1.x/2.x, велик шанс получить require is not defined — проект в 3.x по умолчанию ожидает ESM-синтаксис (export default), если в package.json не указано иное через "type": "commonjs".
  • Passthrough-копирование забытых ассетов. Файлы, которые не проходят через шаблонизатор (изображения, шрифты, готовый CSS), нужно явно перечислить через addPassthroughCopy — иначе их просто не будет в _site/, и nginx отдаст 404 на, казалось бы, существующий файл.
  • Кэш браузера после деплоя. Если статические ассеты закэшированы на 30 дней (как в конфиге выше), а вы поменяли CSS без изменения имени файла — читатели увидят старую версию. Решается версионированием файлов в имени (style.a1b2c3.css) или через ?v= в build-скрипте.

Регулярно обновляйте npm-зависимости (npm outdated, затем точечно npm update конкретных пакетов, а не слепой npm update всего сразу) и держите Node.js на поддерживаемой LTS-ветке — Eleventy сам по себе лёгкий, но экосистема плагинов вокруг него так же подвержена уязвимостям в зависимостях, как и любой другой Node-проект.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Eleventy требует React или Vue?

Нет, это не обязательно. По умолчанию 11ty работает без клиентского фреймворка — он просто рендерит шаблоны в HTML на этапе сборки. JS-фреймворк можно подключить как отдельный слой, но это не входит в базовую установку.

Можно ли использовать несколько шаблонизаторов в одном проекте?

Да, это одна из фирменных фич Eleventy — Nunjucks для одних страниц, markdown с front-matter для других, JavaScript-шаблоны для третьих, всё в одной сборке без конфликтов.

Нужен ли Node.js на сервере в момент отдачи сайта посетителям?

Нет. Node нужен только для сборки — на выходе получается чистый HTML/CSS/JS в _site/, который отдаёт nginx без какого-либо серверного рантайма. Это плюс с точки зрения нагрузки и безопасности: атаковать нечего, кроме самого nginx.

Чем Eleventy принципиально отличается от Hugo?

Hugo написан на Go, собирает даже большие сайты быстрее и не требует Node.js вообще — но его шаблонизатор (Go templates) менее привычен фронтенд-разработчикам. Если у вас команда на JavaScript и хочется остаться в этой экосистеме — Eleventy логичнее; сравнение можно посмотреть в статье про установку Hugo на Ubuntu 24.04.

Как быть с формами и динамикой на полностью статическом сайте?

Формы обычно вешают на сторонний сервис (Formspree, свой небольшой backend) или на serverless-функцию — сам Eleventy никакой server-side логики не выполняет, это его осознанное ограничение, а не недоработка.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →