VPSРейтинг
AI13 августа 2026 · 18 мин

Dify на VPS: конструктор ИИ-агентов и RAG-ботов без кода

Загрузили инструкции и договоры — получили чат-бота, который отвечает по ним и ссылается на источник. Ставим Dify 1.16 на Ubuntu, закрываем всё лишнее от интернета, подключаем модель и собираем первого бота. Без единой строчки кода — но с честным разговором о том, сколько это ест памяти.

Зачем нужен отдельный инструмент, если есть API нейросети

Задача «чтобы бот отвечал по нашим документам» звучит просто, а на деле состоит из десятка мелких. Документы нужно разобрать из PDF и DOCX в текст. Текст — разрезать на фрагменты так, чтобы мысль не обрывалась на середине. Каждый фрагмент — превратить в набор чисел и сложить в специальную базу. На вопрос пользователя — найти в этой базе подходящие фрагменты, приложить их к вопросу и отправить модели. Ответ — вернуть в чат, сохранить историю переписки и не потерять контекст в следующем сообщении.

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

Что такое Dify. Открытая платформа для приложений на базе нейросетей: визуальный редактор сценариев, база знаний с поиском, агенты с доступом к инструментам, логи всех диалогов и публикация готового приложения как ссылки, виджета для сайта или HTTP-API. Проект собрал более 152 тысяч звёзд на GitHub — это один из самых популярных опенсорс-проектов вообще. Актуальная версия на момент написания — 1.16.1 от 28 июля 2026 года.

Dify, n8n или Flowise — что брать

Все три — визуальные конструкторы, и их постоянно путают. Разница в том, вокруг чего построен инструмент.

ИнструментВ центреКогда братьRAM
DifyДиалог и база знанийБот по документам, помощник для команды, чат на сайтот 4 ГБ
n8nСобытие и интеграцииАвтоматизация по расписанию и вебхукам, нейросеть — один из шаговот 1 ГБ
FlowiseСхема на холстеПрототипы в стиле LangChain, тонкая ручная настройка поискаот 2 ГБ
AnythingLLMТолько чат по файламНужен именно чат по документам и ничего большеот 2 ГБ

Простое правило. Нужен только чат по документам и минимум возни — AnythingLLM. Нужны расписания, почта, таблицы и десятки сервисов — n8n. Нужно собрать продукт с чатом, знаниями, историей и публичной ссылкой — Dify. Именно за это он платит самым тяжёлым набором сервисов из всех четырёх.

Сколько это ест на самом деле

Dify — это не один контейнер. На чистой установке запускаются 15 контейнеров: сам API, отдельный сервис веб-сокетов для совместного редактирования, фоновый обработчик задач и его планировщик, веб-интерфейс, PostgreSQL, Redis, векторная база Weaviate, демон плагинов, бэкенд агентов, две песочницы для выполнения кода, два прокси и внутренний Nginx. Цифры, снятые на реальной установке 1.16.1 сразу после запуска:

≈ 2 ГБ

RAM в простое, без единого запроса

≈ 8 ГБ

занимают скачанные образы на диске

15

контейнеров в работе

Что брать. Минимум — 2 ядра, 4 ГБ RAM, 40 ГБ диска и обязательный файл подкачки. Комфортно — 8 ГБ RAM: тогда рядом помещается Ollama с моделью эмбеддингов, а индексация документов не воюет за память с самой Dify. Диск лучше NVMe: и PostgreSQL, и векторная база упираются в скорость случайного чтения, а на индексации это заметно.

Шаг 1. Подготовка сервера

Дальше всё делается на чистой Ubuntu 24.04. Нужен домен: заранее направьте A-запись поддомена (например dify.example.com) на IP сервера — сертификат без этого не выпустится. Ставим обновления и Docker:

обновление системы и установка Docker
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER

Последняя команда разрешает запускать Docker без sudo, но применится только после нового входа. Выйдите из SSH и зайдите заново, затем проверьте версию Compose — нужна 2.24 или новее, на ней держится вся конфигурация Dify:

проверка
docker compose version

Если у сервера 4 ГБ памяти, сразу сделайте файл подкачки. Это не роскошь: без него индексация первого же большого документа может закончиться тем, что ядро убьёт контейнер.

файл подкачки на 4 ГБ — только если RAM 4 ГБ или меньше
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Шаг 2. Скачать Dify

Берём конкретную версию, а не главную ветку: в main попадают недоделанные изменения. Флаг --depth 1 скачивает только последний срез вместо всей истории проекта — около 190 МБ.

скачиваем версию 1.16.1
git clone --depth 1 --branch 1.16.1 https://github.com/langgenius/dify.git ~/dify
cd ~/dify/docker
cp .env.example .env

Всё дальнейшее происходит в папке ~/dify/docker. Сам docker-compose.yamlтрогать не нужно вообще: вся настройка живёт в .env плюс один маленький файл-дополнение, который мы создадим на шаге 4. Это важно для будущих обновлений — изменённый docker-compose.yaml помешал бы переключиться на новую версию.

Шаг 3. Пароли и ключи

В .env.example пароли баз заполнены значениями по умолчанию, одинаковыми у всех и лежащими в открытом репозитории, а ключи подписи оставлены пустыми или с пометкой «замени перед продакшеном». Базы наружу не смотрят, но привести это в порядок всё равно нужно — и обязательно до первого запуска: пароль PostgreSQL задаётся в момент создания базы, после этого его так просто не поменять. Команда ниже генерирует случайные значения и подставляет их сама:

~/dify/docker — генерация и подстановка секретов
SECRET=$(openssl rand -base64 42)
DBPASS=$(openssl rand -base64 32 | tr -d '=+/')
REDISPASS=$(openssl rand -base64 32 | tr -d '=+/')
AGENTKEY=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
AGENTTOKEN=$(openssl rand -base64 32 | tr -d '=+/')

sed -i \
  -e "s|^SECRET_KEY=.*|SECRET_KEY=$SECRET|" \
  -e "s|^DB_PASSWORD=.*|DB_PASSWORD=$DBPASS|" \
  -e "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$REDISPASS|" \
  -e "s|^CELERY_BROKER_URL=.*|CELERY_BROKER_URL=redis://:$REDISPASS@redis:6379/1|" \
  -e "s|^DIFY_AGENT_SERVER_SECRET_KEY=.*|DIFY_AGENT_SERVER_SECRET_KEY=$AGENTKEY|" \
  -e "s|^DIFY_AGENT_API_TOKEN=.*|DIFY_AGENT_API_TOKEN=$AGENTTOKEN|" \
  .env

Три детали, из-за которых ручная правка часто ломает установку. Пароль Redis попадает ещё и в адрес очереди CELERY_BROKER_URL — поменяли в одном месте, обязаны поменять во втором, иначе фоновый обработчик молча не запустится. Пароли баз очищены от символов = + /, потому что они подставляются внутрь адреса подключения и слэш его сломает. А ключ DIFY_AGENT_SERVER_SECRET_KEY обязан быть ровно 32 байтами в формате base64url без выравнивания — именно это делает связка tr; любое другое значение и сервис агентов уйдёт в бесконечный перезапуск.

Теперь пароль установки. Пока он задан, посторонний не сможет создать администратора, даже если наткнётся на ваш адрес раньше вас. Придумайте свой, до 30 символов:

замените на свой пароль
sed -i 's|^INIT_PASSWORD=.*|INIT_PASSWORD=MoyParolUstanovki2026|' .env

Шаг 4. Домен и закрытые порты

Dify нужно знать свой публичный адрес: по нему строятся ссылки в письмах, адреса загруженных файлов, возвраты после входа через сторонние сервисы и адрес веб-сокета. Если этого не сделать, интерфейс откроется, но редактор сценариев будет ругаться на потерянное соединение, а превью файлов не заработает.

Заодно уводим внутренний Nginx Dify с портов 80 и 443 на локальный адрес: наружу его выставит настоящий Nginx с сертификатом. Подставьте свой домен в первую строку:

замените dify.example.com на свой домен
DOMAIN=dify.example.com

sed -i \
  -e "s|^CONSOLE_API_URL=.*|CONSOLE_API_URL=https://$DOMAIN|" \
  -e "s|^CONSOLE_WEB_URL=.*|CONSOLE_WEB_URL=https://$DOMAIN|" \
  -e "s|^SERVICE_API_URL=.*|SERVICE_API_URL=https://$DOMAIN|" \
  -e "s|^APP_API_URL=.*|APP_API_URL=https://$DOMAIN|" \
  -e "s|^APP_WEB_URL=.*|APP_WEB_URL=https://$DOMAIN|" \
  -e "s|^FILES_URL=.*|FILES_URL=https://$DOMAIN|" \
  -e "s|^TRIGGER_URL=.*|TRIGGER_URL=https://$DOMAIN|" \
  -e "s|^ENDPOINT_URL_TEMPLATE=.*|ENDPOINT_URL_TEMPLATE=https://$DOMAIN/e/{hook_id}|" \
  -e "s|^NEXT_PUBLIC_SOCKET_URL=.*|NEXT_PUBLIC_SOCKET_URL=wss://$DOMAIN|" \
  -e "s|^EXPOSE_NGINX_PORT=.*|EXPOSE_NGINX_PORT=127.0.0.1:8080|" \
  -e "s|^EXPOSE_NGINX_SSL_PORT=.*|EXPOSE_NGINX_SSL_PORT=127.0.0.1:8443|" \
  .env

Остался один порт, про который забывают все инструкции. Демон плагинов публикует наружу порт 5003 для удалённой отладки — на всех интерфейсах, а не только на локальном. Закрыть его через ufw не получится: Docker пишет свои правила ниже пользовательских и обходит их. Правильный способ — файл-дополнение к конфигурации, который переопределяет привязку порта:

создать файл ~/dify/docker/docker-compose.override.yaml
cat > docker-compose.override.yaml <<'EOF'
services:
  plugin_daemon:
    ports: !override
      - "127.0.0.1:5003:5003"
EOF

Метка !override означает «замени список портов целиком, а не добавь к нему». Без неё Compose просто дописал бы вторую строку к первой, и открытый порт остался бы на месте. Compose подхватывает файл с таким именем автоматически, дополнительных ключей в командах не нужно.

И необязательное, но приятное. Раз в полчаса Dify отправляет на свои серверы анонимную статистику использования. Если это не нравится, допишите в .env строку DISABLE_TELEMETRY=true — в примере конфигурации её нет, но платформа её понимает.

Шаг 5. Запуск

первый запуск: скачает около 8 ГБ образов
docker compose up -d

Первый запуск занимает от пяти до пятнадцати минут — почти всё время уходит на скачивание образов. Дальше контейнер API применяет миграции базы и только потом начинает отвечать. Смотрим, что получилось:

проверка
docker compose ps

В колонке состояния всё должно быть Up или Up (healthy). Единственное исключение — init_permissions со статусом Exited (0): это разовая задача, которая выставляет права на папки и штатно завершается. Если что-то в состоянии Restarting, смотрите логи именно этого контейнера, например docker compose logs api --tail 50.

Убедимся, что интерфейс отвечает локально и что наружу ничего не торчит:

ожидаем 200 и три строки только с 127.0.0.1
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/install
ss -tln | grep -E ':8080|:8443|:5003'

Шаг 6. Nginx и сертификат

Ставим веб-сервер и создаём для Dify отдельный конфиг:

установка
sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/dify — замените домен на свой
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name dify.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_buffering off;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

Три строки здесь неочевидные, и без каждой что-нибудь сломается. client_max_body_size 100M — иначе загрузка документа больше мегабайта упрётся в стандартный лимит Nginx и вернёт ошибку 413. Блок map вместе с заголовками Upgrade и Connection пропускает веб-сокет, на котором держится редактор сценариев. proxy_read_timeout 3600s — ответ модели может идти минутами, а стандартная минута Nginx оборвёт его на середине.

Блок map стоит снаружи server — так и должно быть, он объявляется на весь веб-сервер. Если точно такой же блок уже есть в конфиге другого вашего сайта, ничего страшного: Nginx разрешает объявить его повторно и не ругается.

Включаем конфиг, проверяем синтаксис и выпускаем сертификат:

включение и HTTPS
sudo ln -s /etc/nginx/sites-available/dify /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d dify.example.com

Certbot спросит почту, попросит согласиться с условиями и предложит включить перенаправление с HTTP на HTTPS — соглашайтесь. Он сам допишет в конфиг блок с сертификатом и настроит автопродление.

Если файрвол ещё не настроен — самое время. Наружу нужны только SSH и веб:

файрвол
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Шаг 7. Первый вход

Откройте https://dify.example.com/install. Сначала Dify спросит пароль установки — то самое значение INIT_PASSWORD. Затем предложит создать администратора: почта, имя и пароль. Почта используется как логин, отправлять на неё письма Dify не обязан, так что подойдёт любая ваша.

Хорошая новость: в self-hosted-версии свободной регистрации нет вообще. Посторонний не заведёт себе аккаунт, даже зная адрес, — новые люди добавляются только по приглашению в Settings → Members. То есть после того, как вы создали администратора, дверь закрыта. Пароль установки своё дело сделал, но удалять его из .env не нужно: он всё равно перестаёт спрашиваться, как только администратор создан.

Шаг 8. Подключить модель

Без модели Dify — пустой конструктор. Провайдеры подключаются как плагины: аватар в правом верхнем углу → Settings → Model Provider, дальше находите нужного в списке, жмёте установку и вводите ключ.

Провайдеров больше сотни, и выбирать стоит не по названию модели, а по удобству: лучше тот, у кого один ключ открывает доступ сразу ко многим моделям — тогда модель в сценарии меняется в один клик, без новой регистрации. Под это описание хорошо подходит OpenRouter; если нужен один конкретный поставщик подешевле — есть отдельный плагин DeepSeek. Ключ вводится один раз и хранится в базе зашифрованным. Шифруется он парой ключей, которая лежит в файлах внутри volumes/app/storage — запомните это место, к бэкапу мы вернёмся: без этой папки ключи провайдеров из базы уже не расшифровать.

Отдельно нужна вторая модель — эмбеддингов. Она не пишет тексты, а превращает их в наборы чисел, по которым потом ищутся нужные фрагменты. Без неё база знаний работать не будет. И вот её как раз имеет смысл держать локально: она маленькая и спокойно живёт на процессоре. Добавляем Ollama в тот же набор контейнеров — допишите в docker-compose.override.yaml:

~/dify/docker/docker-compose.override.yaml целиком
services:
  plugin_daemon:
    ports: !override
      - "127.0.0.1:5003:5003"

  ollama:
    image: ollama/ollama:latest
    restart: always
    volumes:
      - ./volumes/ollama:/root/.ollama
запуск и скачивание модели эмбеддингов (1,2 ГБ)
docker compose up -d ollama
docker compose exec ollama ollama pull bge-m3

Модель bge-m3 понимает больше сотни языков, включая русский, — для документов на русском это заметно лучше англоязычных моделей. Порт наружу не публикуется: Ollama видна только другим контейнерам Dify.

Теперь в Dify: Settings → Model Provider → установить плагин Ollama → добавить модель. Тип — Text Embedding, имя модели — bge-m3, адрес — http://ollama:11434.

Именно http://ollama:11434, а не localhost. Плагины работают внутри контейнера, и localhost для них — это они сами. Адрес host.docker.internal, который советуют в половине инструкций, на Linux по умолчанию не существует вовсе.

Если Ollama у вас уже установлена на самом сервере, а не в контейнере, — контейнер ollama добавлять не нужно, зато нужно дать плагинам дорогу к хосту. В том же файле-дополнении:

только для случая «Ollama установлена на сервере»
services:
  plugin_daemon:
    ports: !override
      - "127.0.0.1:5003:5003"
    extra_hosts:
      - "host.docker.internal:host-gateway"

После docker compose up -d plugin_daemon адресом модели станет http://host.docker.internal:11434. И проверьте, что сама Ollama слушает не только петлевой адрес: по умолчанию она отвечает лишь на 127.0.0.1 и запрос из контейнера до неё не дойдёт.

Последний штрих: на той же странице Settings → Model Provider есть блок Default Models. Здесь выбираются модели по умолчанию — языковая и эмбеддингов. Пока эмбеддинги не выбраны, создать базу знаний в режиме качественного поиска не получится.

Шаг 9. Бот по своим документам

Собираем то, ради чего всё затевалось. Сначала база знаний, потом приложение, которое ей пользуется.

1. Загрузить документы

Вкладка Knowledge → создать базу → перетащить файлы. Понимает PDF, DOCX, TXT, Markdown, таблицы. Начните с трёх-пяти файлов: так быстрее увидите, где бот врёт, и проще понять почему.

2. Выбрать разбиение

Режим General режет текст на равные куски — годится для статей и заметок. Режим Parent-child ищет по мелким фрагментам, а модели отдаёт крупный кусок вокруг найденного — это заметно лучше для инструкций и договоров, где ответ теряет смысл без соседних абзацев. Кнопка предпросмотра показывает, как именно порезался текст; если фрагменты обрываются на полуслове, поменяйте разделитель.

3. Способ индексации

High Quality — векторный поиск по смыслу, нужна модель эмбеддингов из прошлого шага. Economical — поиск по десяти ключевым словам на фрагмент, без модели и бесплатно, но качество заметно ниже: вопрос «как вернуть товар» не найдёт абзац со словом «возврат». Берите первый, ради него мы и ставили bge-m3.

4. Настройки выдачи

Hybrid Search — сочетание поиска по смыслу и по словам, лучший вариант по умолчанию: находит и синонимы, и точные названия артикулов. Top K — сколько фрагментов приложить к вопросу, по умолчанию 3; для длинных инструкций поднимите до 5–8. Score Threshold — минимальная близость, по умолчанию 0,5: чем выше, тем реже бот тащит в ответ что попало, но тем чаще отвечает «не знаю».

5. Собрать приложение

Вкладка Studio → создать приложение типа Chatbot. В блоке контекста подключите созданную базу знаний. В инструкции напишите правила, например: отвечай только по документам, если ответа в них нет — так и скажи. Справа сразу есть окно для проверки: задайте вопрос и посмотрите, какие фрагменты бот использовал — они показываются под ответом.

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

Шаг 10. Отдать людям

Сначала нажмите Publish — эта кнопка переводит черновик в рабочую версию, до неё бот виден только вам в окне проверки. После публикации на странице приложения появляются три способа отдать его людям.

Ссылка. Готовая страница с чатом на вашем домене — можно просто отправить коллегам.

Виджет на сайт. Кнопка Embedded выдаёт готовый кусок кода с вашим токеном: iframe для встраивания в страницу или скрипт, который рисует кружок чата в углу. Вставляется в шаблон сайта как есть, менять ничего не нужно — адрес там уже ваш, потому что мы прописали домен в .env.

HTTP-API. Раздел API Access внутри приложения выдаёт ключ вида app-.... Дальше бот вызывается откуда угодно — из своего кода, из n8n или из телеграм-бота:

вызов приложения по API
curl -X POST https://dify.example.com/v1/chat-messages \
  -H "Authorization: Bearer app-ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {},
    "query": "Какой срок возврата товара?",
    "response_mode": "blocking",
    "user": "user-1"
  }'

Поле user — ваш собственный идентификатор пользователя, по нему Dify разделяет истории переписки. Режим blocking ждёт готовый ответ целиком; для чата в интерфейсе используют streaming, чтобы текст появлялся по мере генерации.

Бэкап и обновление

Всё ценное лежит в двух местах: папке volumes и файле .env. Внутри volumes важно всё сразу: db — приложения, диалоги и настройки, weaviate — векторный индекс базы знаний, app/storage — загруженные файлы и те самые ключи шифрования, без которых ключи провайдеров из базы не прочитать. Копия делается при остановленных контейнерах — иначе рискуете снять базу в момент записи:

бэкап
cd ~/dify/docker
docker compose down
sudo tar czf ~/dify-backup-$(date +%F).tar.gz volumes .env docker-compose.override.yaml
docker compose up -d

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

обновление на условную версию 1.17.0
cd ~/dify/docker
docker compose down
cd ~/dify
git fetch --depth 1 origin tag 1.17.0
git checkout 1.17.0
cd docker
docker compose pull
docker compose up -d

Ваши .env и docker-compose.override.yaml при переключении не пострадают: git их не отслеживает. Но в новой версии могут появиться переменные, которых у вас нет. Проверить это можно одной командой — она сравнивает не значения, а именно набор имён:

каких переменных не хватает в вашем .env
cd ~/dify/docker
diff <(grep -oE '^[A-Z_]+' .env | sort) <(grep -oE '^[A-Z_]+' .env.example | sort)

Строки со знаком > — это новые переменные, их нужно дописать в свой .env со значениями из примера. И обязательно прочитайте release notes: миграции базы применяются автоматически при первом старте и назад не откатываются — вернуться на старую версию без бэкапа уже не выйдет.

Частые проблемы

Контейнер бесконечно перезапускается

Смотрите последние строки его лога: docker compose logs api --tail 30. В девяти случаях из десяти там прямым текстом написано, какая переменная не нравится. Два самых частых случая. DIFY_AGENT_SERVER_SECRET_KEY must decode to exactly 32 bytes — ключ агента сгенерирован не тем способом, повторите команду из шага 3. Ошибка про пароль PostgreSQL — вы поменяли DB_PASSWORD уже после первого запуска; база создалась со старым паролем и нового не знает. Если данных ещё нет, проще всего начать с чистого листа. Учтите: docker compose down -v здесь не поможет — Dify хранит данные не в томах Docker, а в обычных папках внутри volumes, и они принадлежат root. Удалять нужно вручную:

сброс данных — только пока в Dify ничего не создано
cd ~/dify/docker
docker compose down
sudo rm -rf volumes/db volumes/redis volumes/weaviate volumes/app
docker compose up -d

Именно эти четыре папки, а не volumes целиком: рядом лежит volumes/sandbox с конфигом песочницы, который приехал из репозитория. Удалите его — и контейнер песочницы уйдёт в вечный перезапуск, а вернуть файл можно будет только повторным скачиванием.

502 Bad Gateway после перезапуска или обновления

Внутренний Nginx Dify запоминает адреса контейнеров при старте. Если контейнер API пересоздался и получил новый адрес, а Nginx остался прежним, он продолжает стучаться по старому. Лечится одной командой: docker compose restart nginx. Если 502 держится, проверьте сначала сам API — docker compose ps должен показывать его как healthy.

Документ не загружается или падает индексация

Ошибка 413 при загрузке — не хватает client_max_body_size в вашем конфиге Nginx, вернитесь к шагу 6. Если файл загрузился, а обработка застряла или контейнер погиб — это нехватка памяти: разбор PDF и построение векторов самые прожорливые операции во всей платформе. Проверьте free -h и docker compose logs worker --tail 50; на сервере с 4 ГБ почти всегда достаточно добавить файл подкачки.

Модель не подключается: connection refused

Почти всегда это неверный адрес для локальной Ollama. Из контейнера localhost ведёт в него самого, а host.docker.internal на Linux по умолчанию не существует. Если Ollama запущена рядом в том же наборе контейнеров — адрес http://ollama:11434. Если на самом сервере — нужен extra_hosts из шага 8, а сама Ollama должна слушать не только петлевой адрес. С облачным провайдером та же ошибка означает другое: сервер не может выйти в интернет или API недоступен из вашей страны.

Редактор ругается на потерянное соединение

Не проходит веб-сокет. Проверьте две вещи: в .env строка NEXT_PUBLIC_SOCKET_URL должна начинаться с wss:// и содержать ваш домен, а в конфиге Nginx должны быть блок map и заголовки Upgrade и Connection. После правки .env нужен docker compose up -d web, чтобы контейнер интерфейса перечитал переменные.

Плагин не устанавливается

Магазин плагинов живёт на внешнем сервере marketplace.dify.ai, и установка требует выхода в интернет с вашего VPS. Проверьте доступность: curl -I https://marketplace.dify.ai. Если магазин недоступен, плагин можно скачать файлом с расширением .difypkg и загрузить вручную — Install from Local Package File на той же странице плагинов. Работает это только с пакетами из официального магазина: у них есть подпись, а проверка подписи в Dify включена по умолчанию.

Коротко: план с нуля

  1. VPS от 4 ГБ RAM и 40 ГБ диска, Ubuntu 24.04, Docker через get.docker.com
  2. На 4 ГБ — обязательно файл подкачки, иначе умрёт на первой индексации
  3. A-запись поддомена на IP сервера
  4. git clone --depth 1 --branch 1.16.1, затем cp .env.example .env
  5. Сгенерировать пароли и ключи — до первого запуска, не после
  6. Прописать домен и увести порты на 127.0.0.1, закрыть 5003 через override
  7. docker compose up -d и дождаться healthy у API
  8. Nginx с map, лимитом 100M и таймаутом, потом certbot
  9. Зайти на /install первым и создать администратора
  10. Подключить модель и эмбеддинги, выбрать их в System Model Settings
  11. Загрузить документы, собрать чат-бота, проверить выдачу поиска
  12. Настроить бэкап папки volumes и файла .env

Под Dify нужен VPS от 4 ГБ RAM и быстрый диск — векторная база и PostgreSQL упираются именно в него

VPS на NVMe →