pimenov.ai

База знаний

Directus — headless CMS и backend как контентный хаб для мультисайтовой архитектуры

Directus превращает любую SQL-базу в общий бэкенд для людей и ИИ-агентов: единый админ-интерфейс, мгновенные REST и GraphQL API, политики доступа, нативный MCP-сервер и простое развёртывание на собственном VPS.

Опубликовано Обновлено
СейчасЧто такое Directus
  1. Что такое Directus
  2. Что нового в ветке Directus 12
  3. Нативные черновики и публикация
  4. Перевод контента с ИИ
  5. Фильтрация по JSON
  6. MCP с OAuth 2.1
  7. Лицензия: source-available, бесплатно для большинства команд
  8. Обновлённый Studio
  9. Что принесли 12.1 и 12.2
  10. Почему именно контентный хаб, а не очередная CMS
  11. Один Directus — несколько сайтов
  12. Один источник для людей и для агентов
  13. Как это выглядит против Strapi и Sanity
  14. Архитектура контентного хаба
  15. Права и политики: зачем это важно для агентов
  16. API и интеграция
  17. REST
  18. GraphQL
  19. Astro Content Layer
  20. Внутренние ИИ-агенты и ассистенты
  21. AI Assistant прямо в админке
  22. Native MCP Server
  23. Flows — короткие автоматизации как «внутренние агенты»
  24. Развёртывание на своём VPS — по шагам
  25. Что понадобится
  26. Шаг 1. Поставить Docker
  27. Шаг 2. Создать структуру папок
  28. Шаг 3. Написать docker-compose.yml
  29. Шаг 4. Заполнить .env
  30. Шаг 5. Запустить и проверить
  31. Шаг 6. Поднять HTTPS через Caddy
  32. Шаг 7. Настроить бэкапы
  33. Шаг 8. Обновлять
  34. Типовые сценарии хаба
  35. Мультисайтовая публикация
  36. База знаний для агентов
  37. Конвейер «агент → черновик → публикация»
  38. Чего стоит избегать
  39. Чеклист перед запуском в прод
  40. Ссылки

Когда вокруг вас уже есть пара сайтов, отдельная база знаний и ИИ-агенты, которые должны где-то читать и куда-то писать — очень быстро становится понятно, что им всем нужен один общий бэкенд. Не три плагина к WordPress, не пять копий контента в Notion, а одно место, где лежит правда.

Directus (directus.com) — это self-hostable source-available headless CMS и backend-платформа, которая надстраивается поверх вашей SQL-базы и превращает её в такой общий контур. В этом руководстве разберу, как он устроен, зачем нужен для мультисайтовой архитектуры и ИИ-агентов и как развернуть его на своём VPS — даже если терминал для вас пока не родной.

Всё описанное сверено с официальной документацией 2 августа 2026 года. Актуальная версия на эту дату — 12.2 от 30 июля 2026. Обратите внимание: вместе с 12-й веткой Directus переехал на домен directus.com.


Что такое Directus

Directus — это self-hostable source-available headless-платформа, которая подключается к вашей SQL-базе (PostgreSQL, MySQL, MariaDB, SQLite, MS SQL, OracleDB, CockroachDB) и достраивает поверх неё четыре вещи:

  • Админку. Удобный веб-интерфейс для редакторов, где можно работать с любыми таблицами как с контент-базой.
  • Мгновенные API. REST и GraphQL появляются автоматически — ничего писать не надо.
  • Права и политики. Кто что видит, кто что правит, вплоть до отдельных строк и полей.
  • Автоматизации и ИИ. Встроенный no-code конструктор Flows и нативный MCP-сервер для агентов.

Главное отличие от классических CMS — Directus не навязывает свою закрытую схему. База данных остаётся вашей, и в любой момент вы можете его отключить и продолжить работать напрямую с PostgreSQL. Это ровно та архитектура, которую я называю «внешний контур»: данные живут в независимом слое, а не внутри конкретного инструмента.

💡
Коротко. Если Strapi и Sanity — это в первую очередь headless CMS, то Directus — это CMS и общий backend сразу. Отсюда и сценарии: мультисайт, базы знаний и хранилища для ИИ-агентов закрываются одним инструментом.

Что нового в ветке Directus 12

Directus 12.0 вышел 10 июня 2026 года и сместил фокус с разработчиков на всю команду: к гибкому API и database-first архитектуре добавились редакторские сценарии, ИИ-перевод контента, обновлённый Studio и активное лицензирование. Дальше ветка обновляется примерно раз в месяц: 12.1.1 — 1 июля, 12.2 — 30 июля 2026. Для контентного хаба это важно: часть того, что раньше приходилось собирать вручную, теперь работает из коробки.

Нативные черновики и публикация

Раньше статусы draft/published приходилось заводить самому отдельным полем (как в примерах ниже). Глобальные черновики появились ещё в 11.16 (март 2026), и в 12-й ветке это штатный редакторский сценарий: у каждой версионируемой записи автоматически есть черновик, изменения можно посмотреть в live-превью и продвинуть в публикацию отдельным действием. Индикаторы версии и кнопка публикации стали обычными элементами интерфейса.

Перевод контента с ИИ

Мультиязычность была и раньше, но требовала ручной настройки схемы. Теперь перевод включается на коллекции одним переключателем: Directus сам достраивает нужную схему. ИИ-перевод помогает масштабироваться на несколько языков — можно выбрать модель, задать глоссарий терминов и style guide, чтобы голос бренда не плыл между языками. Для критичного контента человеческая вычитка всё ещё нужна, но рутинный объём это закрывает. Учитывайте тариф: в матрице на странице Pricing AI Translations указаны для Enterprise и для Open Innovation Grant, тогда как обычный AI Assistant доступен даже в Core.

Фильтрация по JSON

Для разработчиков: к JSON-полям добавились запросы по dot-notation пути через оператор _json, с фильтрацией на уровне базы. Больше не нужно тянуть весь blob на клиент и разбирать его вручную.

# Статьи, где metadata.color = blue
GET /items/articles?filter={"metadata":{"_json":{"color":{"_eq":"blue"}}}}

В документации это два разных инструмента с одинаковой записью пути: оператор _json фильтрует записи внутри filter, а функция json(field, path) достаёт значение из JSON в параметрах fields, sort и alias. В filter функция json() не работает. Оба варианта доступны в REST, GraphQL и SDK, а в Studio фильтрация по JSON вынесена в обычный UI фильтров.

MCP с OAuth 2.1

Это ключевое изменение для ИИ-агентов. Раньше каждый MCP-клиент требовал статический токен: без динамической идентичности пользователя и без consent-флоу. Теперь MCP поддерживает OAuth 2.1 — агент действует от имени реального пользователя, с его политиками доступа и после его согласия. Для корпоративных команд это снимает главный барьер: прохождение security review.

Включается OAuth переменными окружения MCP_OAUTH_ENABLED и способом регистрации клиента: MCP_OAUTH_CIMD_ENABLED для Client ID Metadata Document или MCP_OAUTH_DCR_ENABLED для Dynamic Client Registration. Те же переключатели нужно включить в настройках проекта.

Лицензия: source-available, бесплатно для большинства команд

В Directus 12 изменилась лицензионная модель: вместо BSL платформа распространяется по лицензии MSCL — Monospace Sustainable Core License. Это source-available лицензия: код открыт для просмотра, Directus можно разворачивать самостоятельно, но текущая версия не является классическим open-source сразу после выхода. По условиям MSCL каждая версия автоматически переходит в GPLv3 через 4 года после публикации.

Одновременно появился механизм license keys. Кому что доступно:

КомуЧто даётКлюч
Open Innovation GrantПолный доступ бесплатно: при выручке до $5 млн в год и штате до 50 человекНужна регистрация
Free Core TierБесплатно для всех: до 3 пользователей, 25 коллекций и 5 FlowsНе нужен
Team$499 в месяц при годовой оплате или $599 помесячно: 10 SSO-мест, 50 коллекций, 20 Flows, SSO и базовая поддержкаНужен
EnterpriseИндивидуальные лимиты, offline-лицензия, собственный LLM, отключение телеметрииНужен

Без лицензии self-hosted-инстанс работает в Core tier — он бесплатный, но ограничен (3 пользователя, 25 коллекций и 5 Flows). Для небольших команд платформа остаётся полностью бесплатной по программе Open Innovation Grant: при выручке меньше $5 млн в год и штате меньше 50 человек её можно использовать без ограничений, в том числе в коммерческих проектах. Ключ такой лицензии допускает до 5 активаций — этого хватает на локальную, dev-, staging- и прод-среду одного проекта. Self-hosting доступен на любом тарифе, Directus Cloud подключается отдельно за $99 в месяц.

🔴
Лицензия в Directus 12 работает с реальным принуждением. Если инстанс вышел за лимиты и grace-период закончился, он переходит в состояние locked-down: блокируются /items, GraphQL, WebSockets и MCP, вход остаётся только у администраторов. Данные при этом не удаляются, но контентный хаб и все агенты встают. Для полноценного хаба получите ключ Open Innovation Grant заранее.
⚠️
Если инсталляция обновляется до 12 и укладывается в лимиты Core tier, она просто продолжает работать. Если лимиты превышены, включается 30-дневный grace-период: за это время получите ключ (существующим клиентам — через licensing@directus.com) и задайте его переменной LICENSE_KEY или внесите через Settings → License в Studio. Активация проходит только при заданном абсолютном PUBLIC_URL.
⚖️
Для крупных компаний и коммерческого внедрения с превышением лимитов Core tier актуальные условия MSCL и тарифы стоит проверять отдельно на официальном сайте Directus.

Обновлённый Studio

Навигация, шапки и боковые панели переработаны под редакторские сценарии: индикаторы черновиков, выбор версий и кнопка публикации стали штатными элементами интерфейса. Нетехническим членам команды стало понятнее, разработчикам — меньше вопросов от коллег.

Что принесли 12.1 и 12.2

Минорные релизы в этой ветке иногда меняют поведение по умолчанию, поэтому смотреть только на мажорный номер недостаточно.

  • Tiptap вместо TinyMCE. В 12.2 заменён движок всех WYSIWYG-полей. Параметр tinymceOverrides больше не действует: значение остаётся в конфиге, в лог пишется предупреждение, а кастомные плагины, скины и content CSS перестают применяться. Если существующий HTML новый редактор нормализовал бы иначе, поле блокируется в режиме чтения и показывает предупреждение — пока вы его не подтвердите, автосохранение контент не перезапишет.
  • Строже права по умолчанию. Аккаунты с минимальным доступом больше не читают лишние поля directus_settings, включая admin-only и настройки ИИ. Ручные Flows нельзя запускать без авторизации, предпросмотр лицензионного ключа после первичной настройки доступен только администраторам, а IP-денилист применяется и к скачиванию файлов из ИИ-чата.
  • Лимиты на импорт и трансформации. Появились IMPORT_MAX_FILE_SIZE (по умолчанию 50 МБ на файл импорта и snapshot схемы) и ASSETS_TRANSFORM_IMAGE_MAX_OUTPUT_DIMENSION (по умолчанию 3000 px по любой стороне). Заодно добавились импорт плоских данных сразу в несколько коллекций и частичные snapshot'ы схемы.
⚠️
Перед обновлением на 12.2 проверьте две вещи: используете ли вы кастомную конфигурацию TinyMCE и не упираются ли ваши импорты или генерация изображений в новые лимиты. Файлы и трансформации сверх лимита теперь отклоняются с ошибкой.

Почему именно контентный хаб, а не очередная CMS

Когда у вас один сайт — вам достаточно любой CMS. Когда их становится больше, начинаются странные вещи. У каждого сайта свой админ, каждому нужна своя авторизация, контент дублируется, агенты не понимают, куда ходить, и в итоге половина времени уходит на то, чтобы синхронизировать всё это вручную.

Контентный хаб решает эту задачу одним движением: один бэкенд, одна база, много витрин.

Один Directus — несколько сайтов

В моей архитектуре один экземпляр Directus может обслуживать сразу:

  • pimenov.ai на Astro
  • pimenov.ru на Astro или Nuxt
  • reload.pimenov.ai — закрытую платформу клуба
  • внутренние базы знаний и справочники
  • хранилища данных для ИИ-агентов и Telegram-ботов

Каждая витрина ходит в один и тот же API, но видит только свой срез контента — за это отвечают политики доступа, а не отдельные инсталляции.

Один источник для людей и для агентов

Notion image
flowchart LR
	DB[(PostgreSQL)] --> D[Directus]
	D -->|REST / GraphQL| S1["pimenov.ai"]
	D -->|REST / GraphQL| S2["reload.pimenov.ai"]
	D -->|REST / GraphQL| S3["pimenov.ru"]
	D -->|MCP| A1["ИИ-агенты контента"]
	D -->|Flows| A2["Автоматизации"]
	D -->|App| U["Редакторы"]

Фронтенд, редактор и агент читают и пишут в одну и ту же базу через один и тот же слой правил. Никакой дублирующей логики, никаких разных источников правды.


Как это выглядит против Strapi и Sanity

Практичное сравнение — на что смотреть, если выбираете headless CMS именно под сценарий «много сайтов и агенты».

Что сравниваемDirectusStrapiSanity
База данныхЛюбая существующая SQLСвоя SQL-схемаПроприетарный облачный datastore
Self-hosted на своём VPSДа, один Docker-образДаТолько Studio; контент живёт в облаке Sanity
Админка «из коробки»Полная, без кодаПолная, с настройкойStudio, требует JS-кода
Нативный MCP для ИИДа, встроен в ядро с 11.12Да, встроен с 5.47, GA в 5.49 (июль 2026)Да, удалённый сервер mcp.sanity.io
Встроенные автоматизацииFlowsЧерез внешние сервисыЧерез Functions
Глубина политикКоллекция + поле + строкаКоллекция + полеDataset + роль
⚖️
Честный trade-off. Sanity удобнее, если у вас чистый контент и важна скорость редактирования. Strapi ближе к классической Node-разработке. Directus выигрывает там, где нужен общий backend для данных и контента одновременно и прямой доступ ИИ-агентов к нему без прослоек. Важная поправка на лето 2026: нативный MCP есть уже у всех троих, поэтому сам факт поддержки перестал быть аргументом — сравнивайте глубину прав, которыми ограничен агент, и то, может ли он менять схему, а не только записи.
📌
Практический вывод. Для задач pimenov.ai и мультисайтового контентного хаба Directus 12 можно использовать бесплатно на своём сервере, если команда проходит по условиям Open Innovation Grant. Но в архитектурной документации стоит фиксировать: Directus 12 — не «просто open-source», а source-available платформа с бесплатным использованием для малых команд и переходом версии в GPLv3 через 4 года.

Архитектура контентного хаба

В простом виде всё выглядит так: один VPS, один PostgreSQL, один Directus и несколько логических зон внутри.

flowchart TB
	subgraph VPS["VPS (Docker Compose)"]
		subgraph DB["PostgreSQL"]
			C1["Зона Sites"]
			C2["Зона Knowledge"]
			C3["Зона Agents"]
		end
		D["Directus"]
		R["Redis (кэш)"]
		N["Caddy / Nginx"]
	end
	D --- DB
	D --- R
	N --- D
	N -->|HTTPS| Web["Сайты и ИИ-агенты"]

И четыре логических зоны, которые удобно держать в голове с самого начала:

ЗонаЧто хранитКто пишетКто читает
SitesСтраницы, статьи, блоки, медиа сайтовРедакторы, ИИ-ассистентФронтенды, агенты
KnowledgeСправочники, методички, канонические документыВы, редакторыИИ-агенты, чат-боты
AgentsПромпты, логи, задачи и результаты агентовАгенты, оркестраторВы, другие агенты
MediaФайлы, изображения, аудио, PDFРедакторы, агентыВсе
📌
Привязку контента к сайту делайте через отдельную коллекцию sites и поле-связь на неё, а не через префикс в названии. Так одна политика закрывает весь контент одного сайта от другого и от агентов, которым туда нельзя.

Права и политики: зачем это важно для агентов

В Directus используется policy-based access control — политика это набор правил, который прикрепляется к роли или напрямую к пользователю.

Для контентного хаба минимально достаточно пяти ролей:

РольЧто можетКому
AdminВсёВам
EditorCRUD по контенту своего сайтаРедакторам
Agent-WriterСоздавать черновики статей, читать базу знанийАгентам-писателям
Agent-ReaderТолько чтение базы знаний и сайтовRAG-ботам и чат-агентам
PublicЧтение опубликованного контентаФронтендам

Правила умеют учитывать значения в строках. Например, редактору pimenov.ai можно разрешить править статьи только своего сайта:

{
	"collection": "articles",
	"action": "update",
	"permissions": { "site": { "_eq": "pimenov.ai" } },
	"fields": ["title", "body", "status", "tags"]
}

И отдельный важный момент для ИИ-агентов — никогда не давайте одного токена на всех. Для каждого агента заводите отдельного пользователя с узкой ролью и своим статическим токеном. Это даёт три вещи:

  • Раздельные логи действий в directus_activity
  • Возможность моментально отозвать доступ одному конкретному агенту
  • Понятную историю: кто из агентов что и когда изменил

API и интеграция

REST

Каждая коллекция автоматически получает REST-эндпоинт:

# Опубликованные статьи для pimenov.ai
curl "https://directus.your-domain.com/items/articles?filter[site][_eq]=pimenov.ai&filter[status][_eq]=published&fields=title,slug,body,tags.*" \
	-H "Authorization: Bearer $DIRECTUS_TOKEN"

GraphQL

То же самое через GraphQL — удобно, когда нужно забирать связанные сущности одним запросом:

query PublishedArticles {
	articles(
		filter: { site: { _eq: "pimenov.ai" }, status: { _eq: "published" } }
	) {
		title
		slug
		body
		tags { name }
	}
}

Astro Content Layer

Для Astro-сайта (как pimenov.ai) официальный путь — SDK @directus/sdk: один клиент на проект и по одному запросу на витрину.

npm install @directus/sdk
// src/lib/directus.ts
import { createDirectus, rest, readItems, staticToken } from '@directus/sdk';

const client = createDirectus(import.meta.env.DIRECTUS_URL)
	.with(staticToken(import.meta.env.DIRECTUS_TOKEN))
	.with(rest());

export function getArticles(site: string) {
	return client.request(
		readItems('articles', {
			fields: ['title', 'slug', 'body', 'tags.*'],
			filter: { site: { _eq: site }, status: { _eq: 'published' } },
		}),
	);
}

Результат можно отдавать в Astro Content Collections через собственный build-time loader или запрашивать прямо в .astro-странице на этапе сборки. На каждый сайт — свой фильтр, база при этом одна.

Как проверить, что связка работает: запустите npm run dev и выведите await getArticles('pimenov.ai') в консоль. Пустой массив при заполненной базе почти всегда означает, что политика Public или токен не дают доступа к коллекции, а не ошибку в коде.


Внутренние ИИ-агенты и ассистенты

Это, пожалуй, самая интересная часть истории. Directus предлагает три уровня работы с ИИ, и их можно спокойно использовать вместе.

AI Assistant прямо в админке

Встроенный помощник в интерфейсе Directus. Умеет писать и переписывать текст в полях, переводить контент между языками, суммировать длинные документы и выполнять простые действия по запросу редактора.

Это инструмент для тех, кто работает руками в админке и хочет быстрого ассистента «под рукой» — без отдельного чат-окна и копи-пасты.

📌
AI Assistant наследует права вызывающего пользователя. Редактор pimenov.ai физически не сможет через ассистента отредактировать материал pimenov.ru — политики закрывают это раньше, чем до модели дойдёт запрос.

Native MCP Server

Дальше становится интереснее. Directus работает как нативный MCP-сервер — это значит, что любой MCP-клиент (Claude Desktop, Claude Code, ChatGPT, Cursor, VS Code, Raycast, ваши собственные агенты на OpenAI или Anthropic SDK) может подключиться к нему и получить набор инструментов: чтение, запись, поиск, работа с файлами.

Встроенный MCP доступен начиная с версии 11.12 и по умолчанию выключен. Включается он в Settings → AI → Model Context Protocol, после чего сервер отвечает по адресу https://directus.your-domain.com/mcp. Удаление объектов через MCP — отдельный переключатель Allow Deletes, он тоже выключен по умолчанию, и включать его для агентов-писателей не нужно.

Типичный конвейер для контент-агента:

  1. Агент «Писатель» подключается к Directus через MCP с токеном роли Agent-Writer
  2. Читает базу знаний и предыдущие публикации по теме
  3. Создаёт черновик статьи со статусом draft и автором = токен агента
  4. Редактор видит черновик в админке, правит, меняет статус на published
  5. Фронтенд (Astro ISR) подхватывает опубликованную статью и ребилдит страницу

Рекомендуемый способ подключения — OAuth. В окружении Directus:

# .env Directus
MCP_OAUTH_ENABLED=true
MCP_OAUTH_CIMD_ENABLED=true          # регистрация клиента через Client ID Metadata Document
PUBLIC_URL=https://directus.your-domain.com

После рестарта включите OAuth Enabled и соответствующий режим регистрации клиентов в настройках проекта. Для прода сузьте периметр: MCP_OAUTH_ALLOWED_REDIRECT_DOMAINS ограничивает домены redirect-URI, а MCP_OAUTH_CIMD_ALLOWED_DOMAINS — хосты, с которых принимается метадокумент клиента. Дальше клиент указывает только адрес https://directus.your-domain.com/mcp без токена в заголовках: пользователь входит в Directus и подтверждает доступ на странице согласия.

Если клиент не умеет MCP OAuth, остаётся статический токен: заведите отдельного пользователя с ролью Agent-Writer, сгенерируйте токен в его профиле и передайте его клиенту заголовком Authorization: Bearer <токен>. Для инстансов старше 11.12 существует отдельный локальный MCP-сервер на Node.js — он описан в документации как Local MCP.

💡
MCP наследует права того, кто подключился: лишних доступов агент не получает. Отдельный эксплуатационный нюанс: если инстанс уйдёт в locked-down по лицензии, MCP отключается вместе с /items, GraphQL и WebSockets, и все агенты остановятся одновременно.

Flows — короткие автоматизации как «внутренние агенты»

Flows — встроенный конструктор потоков с триггерами и операциями. Триггеры: изменение данных, расписание, webhook, ручной запуск. Операции: условия, работа с коллекциями, HTTP-запросы, скрипты и вызовы LLM через расширения.

Что удобно собирать на Flows:

  • Авто-теггер. При создании статьи LLM расставляет теги по тексту.
  • Перевод. При смене языка карточки запускается перевод, результат пишется в соседнее поле.
  • Индексация базы знаний. При обновлении документа автоматически пересчитываются чанки и эмбеддинги в knowledge_chunks (pgvector).
  • Уведомления. При переводе статьи в статус review бот пишет автору в Telegram.

Граница простая: Flows — для коротких реактивных автоматизаций внутри Directus. Длинные многошаговые сценарии — уже задача внешнего оркестратора, например OpenClaw. Обе системы ходят в одну и ту же базу, но с разными токенами и ролями.


Развёртывание на своём VPS — по шагам

Дальше — практика. Я описываю её так, чтобы можно было пройти по шагам, даже если терминал для вас пока не родной. Все команды выполняются через SSH к вашему VPS: ssh user@ip-адрес-vps.

Что понадобится

  • VPS с Ubuntu 22.04+, минимум 2 vCPU / 4 ГБ RAM / 40 ГБ SSD
  • Домен (например, directus.your-domain.com) с A-записью на IP VPS
  • Docker и Docker Compose
  • Caddy или Nginx перед Directus для HTTPS

Шаг 1. Поставить Docker

# Обновляем список пакетов
sudo apt update

# Ставим Docker и плагин Compose
sudo apt install -y docker.io docker-compose-plugin

# Разрешаем текущему пользователю запускать docker без sudo
sudo usermod -aG docker $USER

# Выходим, чтобы изменения применились
exit

После повторного ssh проверяем:

docker --version
docker compose version

Шаг 2. Создать структуру папок

mkdir -p ~/directus && cd ~/directus
mkdir -p uploads extensions database

Шаг 3. Написать docker-compose.yml

Создайте файл ~/directus/docker-compose.yml со следующим содержимым:

services:
	database:
		image: postgres:16-alpine
		restart: unless-stopped
		volumes:
			- ./database:/var/lib/postgresql/data
		environment:
			POSTGRES_USER: directus
			POSTGRES_PASSWORD: ${DB_PASSWORD}
			POSTGRES_DB: directus
		healthcheck:
			test: ["CMD", "pg_isready", "-U", "directus"]
			interval: 10s
			timeout: 5s
			retries: 5

	cache:
		image: redis:7-alpine
		restart: unless-stopped

	directus:
		image: directus/directus:12.2  # фиксируем конкретную версию, а не latest
		restart: unless-stopped
		ports:
			- "127.0.0.1:8055:8055"  # слушаем только локально, наружу через Caddy
		volumes:
			- ./uploads:/directus/uploads
			- ./extensions:/directus/extensions
		depends_on:
			database:
				condition: service_healthy
		environment:
			KEY: ${DIRECTUS_KEY}
			SECRET: ${DIRECTUS_SECRET}

			DB_CLIENT: pg
			DB_HOST: database
			DB_PORT: 5432
			DB_DATABASE: directus
			DB_USER: directus
			DB_PASSWORD: ${DB_PASSWORD}

			CACHE_ENABLED: "true"
			CACHE_STORE: redis
			REDIS: redis://cache:6379

			ADMIN_EMAIL: ${ADMIN_EMAIL}
			ADMIN_PASSWORD: ${ADMIN_PASSWORD}

			PUBLIC_URL: https://directus.your-domain.com  # обязателен: без абсолютного URL лицензия не активируется

			LICENSE_KEY: ${LICENSE_KEY}  # ключ OIG или платного тарифа; без него — Core tier
⚠️
Не используйте latest в production. Крупные обновления Directus могут принести breaking changes, изменения лимитов Core tier или лицензионные особенности. Фиксируйте версию явно — конкретным тегом вроде directus/directus:12.2, проверенным в вашем проекте. Перед переходом на новую минорную версию читайте release notes: в 12.2, например, сменился движок WYSIWYG и появились лимиты на импорт и трансформацию изображений.

Шаг 4. Заполнить .env

Рядом с docker-compose.yml создаём .env. Секреты генерируются один раз и никуда не коммитятся:

openssl rand -hex 16  # для KEY
openssl rand -hex 32  # для SECRET и DB_PASSWORD

Пример .env:

DB_PASSWORD=<сгенерированное значение>
DIRECTUS_KEY=<uuid>
DIRECTUS_SECRET=<строка 32+ символов>
ADMIN_EMAIL=sergey@pimenov.am
ADMIN_PASSWORD=<надёжный пароль>
LICENSE_KEY=<ключ вида DXXXX-XXXXX-XXXXX-XXXXX-XXXXC, если он получен>
⚠️
Важно. .env не должен попадать в git — сразу добавьте его в .gitignore. На сервере ставим права строго для владельца: chmod 600 .env.

Шаг 5. Запустить и проверить

# Запускаем все сервисы в фоне
docker compose up -d

# Смотрим логи Directus
docker compose logs -f directus

При первом старте Directus создаст схему и админа. Когда в логах появится строка Server started at http://0.0.0.0:8055 — сервис готов.

Шаг 6. Поднять HTTPS через Caddy

Caddy выдаёт сертификаты Let's Encrypt автоматически — не нужно ни certbot, ни руками писать конфиги SSL.

sudo apt install -y caddy
sudo nano /etc/caddy/Caddyfile

Содержимое Caddyfile:

directus.your-domain.com {
	reverse_proxy 127.0.0.1:8055
	encode gzip
}
sudo systemctl reload caddy

Через минуту https://directus.your-domain.com работает с валидным сертификатом.

Шаг 7. Настроить бэкапы

Минимум — ежедневный дамп базы и архив загруженных файлов:

# ~/directus/backup.sh
#!/bin/bash
STAMP=$(date +%Y%m%d-%H%M)
mkdir -p ~/backups

# Дамп PostgreSQL
docker compose exec -T database pg_dump -U directus directus | gzip > ~/backups/db-$STAMP.sql.gz

# Архив медиа
tar -czf ~/backups/uploads-$STAMP.tar.gz -C ~/directus uploads

# Удаляем бэкапы старше 14 дней
find ~/backups -type f -mtime +14 -delete

Добавляем в cron:

crontab -e
# Каждый день в 03:15
15 3 * * * /bin/bash /home/$USER/directus/backup.sh >> /home/$USER/backups/backup.log 2>&1
💡
Бэкап, лежащий рядом с продом, — это не бэкап. Настройте выгрузку дампов на второй сервер, S3 или Backblaze B2, чтобы в момент сбоя вам было куда восстанавливаться.

Шаг 8. Обновлять

cd ~/directus
docker compose pull
docker compose up -d
docker compose logs -f directus  # проверяем, что миграции прошли

Directus сам накатывает миграции схемы при запуске. Перед любым мажорным апдейтом — обязательный свежий бэкап.


Типовые сценарии хаба

Мультисайтовая публикация

  1. В коллекции sites — записи pimenov.ai, reload.pimenov.ai, pimenov.ru
  2. В articles обязательное поле-связь site на эту коллекцию
  3. Политика Public отдаёт только status = published
  4. Каждый фронтенд на Astro тянет свой срез по filter[site][_eq]
  5. Кэш на уровне фронтенда (Astro ISR) и Redis на уровне Directus

База знаний для агентов

  1. Коллекция knowledge_docs — канонические документы
  2. Flow на обновление документа режет текст на чанки и считает эмбеддинги в knowledge_chunks через pgvector
  3. Агент-ресёрчер через MCP делает семантический поиск по чанкам и отдаёт релевантные куски в контекст LLM
  4. Обновление источника = автоматическое обновление индекса. Агент всегда работает с актуальной базой

Конвейер «агент → черновик → публикация»

  1. Внешний оркестратор (у меня это OpenClaw) получает задачу «написать статью про X»
  2. Агент через MCP читает базу знаний и предыдущие статьи по теме
  3. Пишет черновик в articles со статусом draft, автор — токен агента
  4. Flow отправляет уведомление в Telegram автору
  5. Автор правит в админке, меняет статус на published
  6. Webhook запускает ребилд сайта
💡
Ветка 12. Статусы draft/published можно не собирать вручную: включите версионирование контента — и у каждой записи появится черновик, live-превью и отдельное действие публикации. Агенту при этом достаточно прав на создание версий без права публикации.

Чего стоит избегать

  • ❌ Один токен на всех агентов — теряете аудит и не можете точечно отозвать доступ
  • ❌ Directus наружу без HTTPS и rate-limit — в продакшене обязателен reverse proxy с ограничениями
  • ❌ Хранить API-ключи в полях коллекций — для секретов есть .env и переменные окружения Flows
  • ❌ Смешивать оперативные данные и контент в одной схеме без политик
  • ❌ Разрешать агентам сразу публиковать — статус draft и человеческая валидация до published экономят много нервов
  • ❌ Игнорировать бэкапы — без крона и выноса дампов восстановление после сбоя невозможно
  • ❌ Использовать SQLite для контентного хаба в продакшене — для мультисайта и параллельной записи нужен PostgreSQL
  • ❌ Сносить инстанс, не деактивировав лицензию — активация остаётся привязанной к старому PUBLIC_URL и продолжает занимать слот
  • ❌ Обновлять версию без чтения release notes — в 12.2, например, перестали действовать кастомные настройки TinyMCE
  • ❌ Включать в MCP параметр Allow Deletes «на всякий случай» — агент получит право удалять элементы, файлы, поля и коллекции

Чеклист перед запуском в прод

PostgreSQL с надёжным паролем, порт не торчит наружу
Directus слушает только 127.0.0.1, наружу — через Caddy или Nginx с HTTPS
KEY и SECRET сгенерированы случайно, лежат в .env, не в git
Админский аккаунт — с 2FA
Для каждого ИИ-агента — отдельный пользователь и токен
Политика Public отдаёт только опубликованный контент
Redis-кэш включён
Ежедневный бэкап базы и uploads, дампы уезжают с VPS
Мониторинг uptime (UptimeRobot или Healthchecks) на directus.your-domain.com/server/health
Логи Flows и directus_activity просматриваются раз в неделю
PUBLIC_URL задан абсолютным адресом, лицензия активирована или использование укладывается в Core tier
MCP включён осознанно: Allow Deletes выключен, у MCP-пользователя узкая роль, для внешних клиентов настроен OAuth

Ссылки

🕓
Актуальность. Версии, лимиты и условия лицензирования проверены 2 августа 2026 года по официальным источникам Directus: release notes 12.2 и 12.0, документация по лицензированию и MCP, страницы Pricing и Open Innovation Grant. Перед крупным production-внедрением сверьте текущие условия — тарифы и лицензионная модель меняются.

По теме

Если вы уже чувствуете, что один сайт и один Notion перестают вмещать всё, что вы делаете, — такой контентный хаб обычно проще спроектировать один раз аккуратно, чем потом вытаскивать контент из пяти разных систем. Если захотите обсудить, как это применить у себя или в команде — пишите в Telegram @pimenov