MAATRIX / Блог / "Gatsby сайт: деплой на VPS"

"Gatsby сайт: деплой на VPS"

"Gatsby сайт: деплой на VPS"

MAATRIX

Gatsby собирает React-приложение в статичные HTML-файлы, но сама сборка требует Node.js, память под webpack и время, которого на слабом хостинге может не хватить. Если вы привыкли деплоить обычный статический сайт — просто залить файлы и настроить Nginx — с Gatsby добавляется этап сборки, и его тоже нужно разместить где-то на сервере или в CI. Ниже — рабочая схема: от установки Node.js и Gatsby CLI до автоматической пересборки при обновлении контента в CMS.

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

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

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

Чем Gatsby отличается от Hugo и других генераторов

Если вы уже деплоили статический сайт на VPS или Hugo, разница с Gatsby ощущается уже на этапе сборки.

Hugo — это один бинарник на Go, который проходит по файлам Markdown и за секунды-десятки секунд рендерит HTML. Ему не нужен Node.js, зависимостей почти нет, память ест по минимуму.

Gatsby — это React-приложение поверх Node.js. Сборка проходит через несколько стадий: Gatsby тянет данные (из локальных файлов, headless CMS вроде Contentful, Strapi или WordPress по GraphQL, из API), строит GraphQL-слой над этими данными, рендерит React-компоненты в статичный HTML и параллельно собирает клиентский JS-бандл для гидратации (оживления интерактивности в браузере). Отсюда и плюсы, и минусы:

  • Плюсы: полноценные React-компоненты, богатая экосистема плагинов (изображения, SEO, PWA, аналитика), удобная интеграция с headless CMS через GraphQL, готовая оптимизация картинок из коробки (gatsby-plugin-image).
  • Минусы: сборка заметно тяжелее и медленнее, особенно на сайтах от нескольких сотен страниц — процесс сборки может упереться в память на VPS с 1-2 ГБ ОЗУ. Нужен Node.js на сервере (или в CI), больше зависимостей, больше поверхность для потенциальных проблем при обновлении версий.

Если сайт небольшой (до сотни страниц) и контент меняется редко — разница на практике не критична. Если страниц тысячи и контент обновляется часто из CMS — время сборки и потребление памяти стоит закладывать в план заранее.

Требования к серверу и выбор VPS

Для комфортной сборки Gatsby рекомендую закладывать с запасом — сама сборка временами потребляет заметно больше памяти, чем работающий сайт после неё:

ПараметрМинимумКомфортно
ОЗУ2 ГБ4 ГБ и больше
CPU1 ядро2 ядра (сборка параллелится)
Диск20 ГБ SSD40 ГБ SSD (node_modules и кэш .cache/ занимают место)
ОСUbuntu 22.04/24.04 или Debian 12

Если сайт крупный (500+ страниц) или страницы тянут много изображений — берите VPS с 4 ГБ ОЗУ, иначе сборка может падать с ошибкой JavaScript heap out of memory. Это не гипотетическая цифра — конкретный порог зависит от количества страниц, объёма данных и плагинов, поэтому ориентируйтесь на свой проект, а не на чужие бенчмарки.

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

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

Арендовать VPS

Установка Node.js и Gatsby CLI

Ставим Node.js через NodeSource (актуальная LTS-ветка на конец августа 2026 — уточняйте текущую LTS-версию на nodejs.org, в примерах используется 20.x как ориентир):

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v

Проверяем, что npm ставит пакеты глобально без прав root (иначе придётся постоянно вызывать sudo для npm-команд):

mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Ставим Gatsby CLI глобально:

npm install -g gatsby-cli
gatsby --version

Создаём отдельного пользователя без root-прав для деплоя (общая практика для любого Node-проекта на сервере — не собирать и не запускать процессы от root):

sudo adduser deploy
sudo su - deploy

Клонирование проекта и первая сборка

Клонируем репозиторий и ставим зависимости:

cd ~
git clone https://github.com/your-org/your-gatsby-site.git site
cd site
npm install

Если проект тянет данные из headless CMS — переменные окружения (API-токены, URL эндпоинта) кладём в .env.production, который Gatsby подхватывает автоматически при сборке в production-режиме:

nano .env.production
CMS_API_URL=https://cms.example.com/graphql
CMS_API_TOKEN=your_token_here

Файл .env.production не коммитим в git — добавьте его в .gitignore, если ещё не добавлен.

Запускаем сборку:

npx gatsby build

Команда gatsby build превращает React-приложение в набор статичных HTML-файлов, JS/CSS-бандлы, оптимизированные изображения и manifest — всё это ложится в папку public/. Именно её содержимое и будет отдавать Nginx. На первой сборке Gatsby создаёт кэш в .cache/ — повторные сборки при не слишком больших изменениях данных проходят заметно быстрее за счёт инкрементальной сборки, но именно "заметно быстрее" сильно зависит от размера сайта и характера изменений, тут не буду называть точные цифры.

Если сборка падает по памяти:

NODE_OPTIONS="--max-old-space-size=4096" npx gatsby build

Это поднимает лимит памяти для V8 (движка Node.js) — полезно, если на сервере есть свободная память сверх стандартного лимита Node, но не спасёт, если физической памяти на сервере реально не хватает. В этом случае либо увеличивайте VPS, либо добавляйте swap.

Настройка Nginx для отдачи статики

Готовые файлы из public/ копируем в директорию, которую будет отдавать Nginx:

sudo mkdir -p /var/www/gatsby-site
sudo cp -r ~/site/public/* /var/www/gatsby-site/
sudo chown -R www-data:www-data /var/www/gatsby-site

Конфиг Nginx — почти такой же, как для обычного статического сайта, но с поправкой на особенности Gatsby: хэшированные имена файлов в page-data/ и static/ можно кэшировать агрессивно и надолго, а сам HTML — с более коротким сроком:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/gatsby-site;
    index index.html;

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

    location ~* ^/(static|page-data)/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location ~* \.(js|css)$ {
        expires 30d;
        add_header Cache-Control "public";
    }

    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}

Проверяем конфиг и перезапускаем:

sudo nginx -t
sudo systemctl reload nginx

SSL можно навесить стандартно через Let's Encrypt — этот шаг подробно разобран в статье про установку и настройку Let's Encrypt SSL на VPS, процедура для Gatsby ничем не отличается от любого другого сайта на Nginx.

Автоматизация: деплой-скрипт и systemd

Собирать и копировать файлы вручную неудобно, поэтому оформим это в скрипт:

nano ~/deploy.sh
#!/bin/bash
set -e
cd /home/deploy/site
git pull origin main
npm install
npx gatsby build
sudo rsync -a --delete public/ /var/www/gatsby-site/
sudo systemctl reload nginx
echo "Деплой завершён: $(date)"
chmod +x ~/deploy.sh

rsync --delete синхронизирует папку и удаляет файлы, которых больше нет в новой сборке (иначе старые страницы, которые вы удалили из CMS, будут годами висеть на сайте). Для запуска rsync и reload nginx без пароля добавьте точечное правило в sudoers для пользователя deploy — это безопаснее, чем давать ему полный sudo без пароля.

Если хотите, чтобы деплой отрабатывал как управляемый systemd-сервис (полезно для логирования и таймаутов), можно обернуть скрипт в oneshot-юнит:

# /etc/systemd/system/gatsby-deploy.service
[Unit]
Description=Gatsby site deploy

[Service]
Type=oneshot
User=deploy
ExecStart=/home/deploy/deploy.sh

Запуск: sudo systemctl start gatsby-deploy.service, логи — journalctl -u gatsby-deploy.service.

Автопересборка по вебхуку из CMS

Смысл в том, чтобы редактор в CMS нажал «Опубликовать» — и сайт пересобрался сам, без ручного захода на сервер. Для этого нужен небольшой HTTP-эндпоинт на сервере, который слушает вебхук и запускает deploy.sh.

Самый простой вариант — маленький Node.js-сервис на Express, который принимает POST-запрос и по секретному токену в заголовке запускает деплой:

// webhook.js
const express = require('express');
const { exec } = require('child_process');
const app = express();

app.post('/deploy-webhook', (req, res) => {
  const token = req.headers['x-webhook-token'];
  if (token !== process.env.WEBHOOK_SECRET) {
    return res.status(403).send('Forbidden');
  }
  res.status(202).send('Deploy started');
  exec('/home/deploy/deploy.sh', (err, stdout, stderr) => {
    if (err) console.error('Deploy failed:', stderr);
    else console.log('Deploy done:', stdout);
  });
});

app.listen(3001, () => console.log('Webhook listener on :3001'));

Запускаем через pm2, чтобы сервис жил постоянно и переживал перезагрузку сервера:

npm install -g pm2
WEBHOOK_SECRET=your_random_secret pm2 start webhook.js --name gatsby-webhook
pm2 save
pm2 startup

Порт 3001 наружу не открываем — проксируем через Nginx на приватный путь и закрываем его через тот же секретный токен в заголовке, который CMS должна передавать в настройках вебхука:

location /deploy-webhook {
    proxy_pass http://127.0.0.1:3001/deploy-webhook;
    proxy_set_header Host $host;
}

В настройках CMS (Contentful, Strapi, WordPress с плагином вебхуков и т.д.) указываете URL https://example.com/deploy-webhook и заголовок с секретным токеном — событие «публикация записи» триггерит запрос, сервер запускает пересборку. Если у вас в целом много интеграций через вебхуки (телеграм-боты, CI/CD), общие принципы разобраны в статье webhook или polling: что выгоднее и когда — логика применима не только к телеграм-ботам.

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

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

Арендовать VPS

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

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

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

Обязательно ли использовать Node.js на сервере, или можно собирать локально и заливать готовые файлы?

Можно собирать где угодно — локально, в GitHub Actions, в любом CI — и заливать на сервер только содержимое public/ через rsync или scp. Это даже снижает нагрузку на VPS. Схема с деплоем на самом сервере удобна, когда нет отдельного CI или хочется держать всё в одном месте.

Сколько занимает сборка Gatsby на VPS?

Зависит от количества страниц, объёма данных из CMS, числа плагинов и мощности сервера — единой цифры нет, и я не буду называть её вслепую. Ориентируйтесь на собственные замеры: соберите проект первый раз и засеките время, дальше инкрементальные сборки обычно быстрее.

Что делать, если сборка падает с ошибкой нехватки памяти?

Сначала попробуйте поднять лимит V8 через NODE_OPTIONS="--max-old-space-size=4096". Если это не помогает — значит физической памяти на сервере действительно не хватает, нужно либо увеличить VPS, либо добавить swap-файл, либо переносить сборку в CI и заливать только готовые файлы.

Нужен ли Nginx именно, или подойдёт Apache?

Подойдёт любой веб-сервер, умеющий отдавать статику. Разница между ними разобрана в статье Nginx или Apache: что выбрать для сервера — для отдачи готовых Gatsby-файлов Nginx проще в настройке кэширования и чуть экономнее по ресурсам.

Как обновлять Gatsby и зависимости без риска сломать сборку?

Обновляйте в отдельной ветке или на копии сервера, прогоняйте gatsby build локально до деплоя на прод, и держите package-lock.json в git — это фиксирует версии зависимостей и убирает сюрпризы «на моей машине работало».

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

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

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