Стек: n8n · Ollama · PostgreSQL · Wiki.js · Docker · Vagrant
Цель: локальный AI-агент с долгосрочной памятью, изолированной БД и внутренней wiki.
┌─────────────────────────────────────────────────────────────┐
│ Локальная подсеть 192.168.56.0/24 │
│ │
│ ┌──────────────┐ SQL ┌──────────────────────────────┐ │
│ │ VM: n8n │◄────────►│ VM: postgresql │ │
│ │ .10 │ │ .11 │ │
│ │ Docker │ │ PostgreSQL 15 │ │
│ │ n8n:5678 │ │ Port 5432 (только подсеть) │ │
│ └──────┬───────┘ │ │ │
│ │ │ БД: │ │
│ │ HTTP │ • n8n_db / n8n_user │ │
│ │ :11434 │ • wiki_db / wiki_user │ │
│ ┌──────▼───────┐ │ • agent_db / agent_user │ │
│ │ VM: ollama │ └──────────────────────────────┘ │
│ │ .12 │ ▲ │
│ │ Docker │ │ SQL │
│ │ Ollama │ ┌─────────────┴──────────────┐ │
│ └──────────────┘ │ VM: wikijs │ │
│ │ .13 │ │
│ │ Docker │ │
│ │ Wiki.js :3000 │ │
│ └────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ Host-only сеть (доступ с хоста)
Браузер хоста:
• n8n → http://192.168.56.10:5678
• Ollama → http://192.168.56.12:11434
• Wiki.js→ http://192.168.56.13:3000
| Компонент | VM IP | Порт | Роль |
|---|---|---|---|
| n8n | 192.168.56.10 | 5678 | Оркестратор воркфлоу / AI-агент |
| PostgreSQL | 192.168.56.11 | 5432 | Хранилище данных (n8n, wiki, память) |
| Ollama | 192.168.56.12 | 11434 | LLM inference сервер |
| Wiki.js | 192.168.56.13 | 3000 | Внутренняя документация |
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/jammy64"
# ── PostgreSQL ──────────────────────────────────────────────
config.vm.define "postgresql" do |pg|
pg.vm.hostname = "postgresql"
pg.vm.network "private_network", ip: "192.168.56.11"
pg.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.cpus = 1
end
pg.vm.provision "shell", path: "scripts/provision_postgresql.sh"
end
# ── n8n ─────────────────────────────────────────────────────
config.vm.define "n8n" do |n8n|
n8n.vm.hostname = "n8n"
n8n.vm.network "private_network", ip: "192.168.56.10"
n8n.vm.network "forwarded_port", guest: 5678, host: 5678
n8n.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
vb.cpus = 2
end
n8n.vm.provision "shell", path: "scripts/provision_n8n.sh"
end
# ── Ollama ──────────────────────────────────────────────────
config.vm.define "ollama" do |ol|
ol.vm.hostname = "ollama"
ol.vm.network "private_network", ip: "192.168.56.12"
ol.vm.network "forwarded_port", guest: 11434, host: 11434
ol.vm.provider "virtualbox" do |vb|
vb.memory = "4096" # LLM требует памяти
vb.cpus = 4
end
ol.vm.provision "shell", path: "scripts/provision_ollama.sh"
end
# ── Wiki.js ─────────────────────────────────────────────────
config.vm.define "wikijs" do |wiki|
wiki.vm.hostname = "wikijs"
wiki.vm.network "private_network", ip: "192.168.56.13"
wiki.vm.network "forwarded_port", guest: 3000, host: 3000
wiki.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.cpus = 1
end
wiki.vm.provision "shell", path: "scripts/provision_wikijs.sh"
end
end
# Поднять все VM (займёт ~10 минут при первом запуске)
vagrant up
# Поднять отдельную VM
vagrant up postgresql
# SSH в VM
vagrant ssh postgresql
vagrant ssh n8n
vagrant ssh ollama
vagrant ssh wikijs
# Остановить все
vagrant halt
# Пересоздать с нуля
vagrant destroy -f && vagrant up
# Файл: scripts/provision_postgresql.sh
#!/bin/bash
set -e
# Установка PostgreSQL 15
apt-get update -qq
apt-get install -y postgresql postgresql-contrib
# Запуск и автозапуск
systemctl enable postgresql
systemctl start postgresql
PostgreSQL по умолчанию слушает только localhost. Нужно открыть доступ только из подсети VM (192.168.56.0/24).
# Редактируем postgresql.conf
# Найти параметр listen_addresses
sudo nano /etc/postgresql/15/main/postgresql.conf
# postgresql.conf
listen_addresses = 'localhost,192.168.56.11'
# Редактируем pg_hba.conf — правила аутентификации
sudo nano /etc/postgresql/15/main/pg_hba.conf
# pg_hba.conf — добавить строки в конец файла
# TYPE DATABASE USER ADDRESS METHOD
host n8n_db n8n_user 192.168.56.0/24 scram-sha-256
host wiki_db wiki_user 192.168.56.0/24 scram-sha-256
host agent_db agent_user 192.168.56.0/24 scram-sha-256
# Применить изменения
sudo systemctl restart postgresql
sudo -u postgres psql << 'EOF'
-- ── Пользователь и БД для n8n ──────────────────────────────
CREATE USER n8n_user WITH PASSWORD 'n8n_strong_password_123';
CREATE DATABASE n8n_db OWNER n8n_user;
GRANT ALL PRIVILEGES ON DATABASE n8n_db TO n8n_user;
-- ── Пользователь и БД для Wiki.js ──────────────────────────
CREATE USER wiki_user WITH PASSWORD 'wiki_strong_password_123';
CREATE DATABASE wiki_db OWNER wiki_user;
GRANT ALL PRIVILEGES ON DATABASE wiki_db TO wiki_user;
-- ── Пользователь и БД для памяти агента ────────────────────
CREATE USER agent_user WITH PASSWORD 'agent_strong_password_123';
CREATE DATABASE agent_db OWNER agent_user;
GRANT ALL PRIVILEGES ON DATABASE agent_db TO agent_user;
-- Проверка
\l
\du
EOF
# С VM n8n (192.168.56.10) — проверяем подключение к PostgreSQL
psql -h 192.168.56.11 -U n8n_user -d n8n_db -c "SELECT version();"
# Пароль: n8n_strong_password_123
# С VM wikijs (192.168.56.13) — аналогично
psql -h 192.168.56.11 -U wiki_user -d wiki_db -c "SELECT version();"
# С внешней машины (не из подсети 192.168.56.0/24) — должен получить отказ
psql -h 192.168.56.11 -U n8n_user -d n8n_db
# Ожидаемый результат: connection refused или authentication failed
# Файл: scripts/provision_n8n.sh
#!/bin/bash
set -e
# Установка Docker (официальный способ)
apt-get update -qq
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update -qq
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Добавить vagrant в группу docker
usermod -aG docker vagrant
systemctl enable docker
systemctl start docker
# Самый простой запуск — n8n с SQLite (временно, для проверки UI)
docker run -d \
--name n8n \
--restart unless-stopped \
-p 5678:5678 \
-e N8N_HOST=0.0.0.0 \
-e WEBHOOK_URL=http://192.168.56.10:5678 \
n8nio/n8n:latest
# Проверить статус
docker ps
docker logs n8n -f
Открой в браузере: http://192.168.56.10:5678 (или http://localhost:5678 если пробросил порт)
docker stop n8n && docker rm n8n
docker volume create n8n_data
docker run -d \
--name n8n \
--restart unless-stopped \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
-e N8N_HOST=0.0.0.0 \
-e WEBHOOK_URL=http://192.168.56.10:5678 \
-e DB_TYPE=postgresdb \
-e DB_POSTGRESDB_HOST=192.168.56.11 \
-e DB_POSTGRESDB_PORT=5432 \
-e DB_POSTGRESDB_DATABASE=n8n_db \
-e DB_POSTGRESDB_USER=n8n_user \
-e DB_POSTGRESDB_PASSWORD=n8n_strong_password_123 \
-e N8N_ENCRYPTION_KEY=change-this-to-random-32-char-string \
n8nio/n8n:latest
⚠️
N8N_ENCRYPTION_KEY— произвольная строка длиной 32+ символа. Запиши её и не меняй: она шифрует credentials.
mkdir -p /opt/n8n && cd /opt/n8n
nano docker-compose.yml
# /opt/n8n/docker-compose.yml
version: "3.8"
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
volumes:
- n8n_data:/home/node/.n8n
environment:
- N8N_HOST=0.0.0.0
- WEBHOOK_URL=http://192.168.56.10:5678
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=192.168.56.11
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n_db
- DB_POSTGRESDB_USER=n8n_user
- DB_POSTGRESDB_PASSWORD=n8n_strong_password_123
- N8N_ENCRYPTION_KEY=change-this-to-random-32-char-string
volumes:
n8n_data:
docker compose up -d
docker compose logs -f
# 1. Открыть n8n UI и создать воркфлоу с каким-нибудь именем
# 2. Перезапустить контейнер
docker restart n8n
# 3. Открыть UI снова — воркфлоу должен быть на месте
# 4. Проверить данные в PostgreSQL
psql -h 192.168.56.11 -U n8n_user -d n8n_db -c "SELECT name, created_at FROM workflow_entity;"
# Файл: scripts/provision_ollama.sh
#!/bin/bash
set -e
apt-get update -qq
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update -qq
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
usermod -aG docker vagrant
systemctl enable docker
systemctl start docker
mkdir -p /opt/ollama && cd /opt/ollama
nano docker-compose.yml
# /opt/ollama/docker-compose.yml
version: "3.8"
services:
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0
volumes:
ollama_data:
docker compose up -d
docker compose logs -f
# Войти в контейнер
docker exec -it ollama ollama pull llama3.2
# Другие подходящие модели (выбери одну под свои ресурсы):
# docker exec -it ollama ollama pull qwen2.5:3b # лёгкая ~2GB
# docker exec -it ollama ollama pull mistral:7b # хорошая ~4GB
# docker exec -it ollama ollama pull llama3.2:3b # рекомендуем ~2GB
# Список загруженных моделей
docker exec -it ollama ollama list
# Тест прямо в терминале
docker exec -it ollama ollama run llama3.2 "Привет! Кто ты?"
# Введи /bye чтобы выйти
# С VM ollama (или любой VM в подсети)
curl http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.2",
"prompt": "Скажи привет по-русски.",
"stream": false
}'
# С другой VM в подсети
curl http://192.168.56.12:11434/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.2",
"prompt": "Hello!",
"stream": false
}'
# Проверить список моделей через API
curl http://192.168.56.12:11434/api/tags
http://192.168.56.12:11434Создай новый воркфлоу с тремя нодами:
[Chat Trigger] ──► [Ollama Chat Model] ──► (ответ в чат)
Нода 1: Chat Trigger
Chat TriggerRespond to WebhookНода 2: Basic LLM Chain
Basic LLM ChainOllama Chat Model
llama3.2Активация воркфлоу:
"Привет! Как тебя зовут?"[Chat Trigger] ──► [AI Agent] ──► [Ollama Chat Model]
│
[Window Buffer Memory]
Нода 1: Chat Trigger
Chat TriggerНода 2: AI Agent
AI AgentConversational AgentТы полезный AI-ассистент. Отвечай на русском языке.
Помни контекст разговора и используй его в своих ответах.
Нода 3: Ollama Chat Model (подключить к AI Agent → Chat Model)
Ollama Chat Modelllama3.20.7Нода 4: Window Buffer Memory (подключить к AI Agent → Memory)
Window Buffer Memory={{ $('Chat Trigger').item.json.sessionId }}10 (запоминать последние 10 сообщений)Протестируй последовательно в чате:
1. "Привет! Меня зовут Саня."
→ Агент должен поприветствовать тебя по имени
2. "Что ты умеешь?"
→ Агент описывает возможности
3. "Как меня зовут?"
→ Агент должен ответить: "Тебя зовут Саня"
4. "Придумай мне шутку про программирование"
→ Агент генерирует шутку
5. "Переведи на английский то, что ты только что сказал"
→ Агент переводит предыдущий ответ (помнит контекст)
# Подключиться к agent_db
psql -h 192.168.56.11 -U agent_user -d agent_db << 'EOF'
CREATE TABLE IF NOT EXISTS agent_memory (
id SERIAL PRIMARY KEY,
session_id VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL, -- 'user' или 'assistant'
content TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_agent_memory_session
ON agent_memory(session_id, created_at);
-- Проверка
\d agent_memory
EOF
Вместо Window Buffer Memory используй Postgres Chat Memory:
Нода Memory: Postgres Chat Memory
Postgres Chat MemoryPostgreSQL credential:
192.168.56.115432agent_dbagent_useragent_strong_password_123agent_memory={{ $('Chat Trigger').item.json.sessionId }}20[Chat Trigger] ──► [AI Agent] ──► [Ollama Chat Model]
│
[Postgres Chat Memory]
(agent_db на 192.168.56.11)
# Шаг 1: Отправь сообщение в чат
# "Меня зовут Саня"
# → Агент: "Приятно познакомиться, Саня!"
# Шаг 2: Спроси
# "Как меня зовут?"
# → Агент: "Тебя зовут Саня"
# Шаг 3: Рестарт n8n
docker restart n8n
# Шаг 4: Дождись запуска (30-60 секунд), открой чат с тем же session_id
# "Как меня зовут?"
# → Агент: "Тебя зовут Саня" ← данные из PostgreSQL!
# Проверка данных в БД
psql -h 192.168.56.11 -U agent_user -d agent_db \
-c "SELECT session_id, role, left(content,60) as content, created_at FROM agent_memory ORDER BY created_at;"
# Файл: scripts/provision_wikijs.sh
#!/bin/bash
set -e
# Установка Docker (аналогично другим VM)
apt-get update -qq
apt-get install -y ca-certificates curl gnupg
# ... (те же шаги что для n8n)
mkdir -p /opt/wikijs && cd /opt/wikijs
# /opt/wikijs/docker-compose.yml
version: "3.8"
services:
wikijs:
image: ghcr.io/requarks/wiki:2
container_name: wikijs
restart: unless-stopped
ports:
- "3000:3000"
environment:
DB_TYPE: postgres
DB_HOST: 192.168.56.11
DB_PORT: 5432
DB_USER: wiki_user
DB_PASS: wiki_strong_password_123
DB_NAME: wiki_db
cd /opt/wikijs
docker compose up -d
docker compose logs -f
admin@local.devhttp://192.168.56.13:3000psql -h 192.168.56.11 -U wiki_user -d wiki_db \
-c "SELECT table_name FROM information_schema.tables WHERE table_schema='public' LIMIT 10;"
architecture/ai-agentАрхитектура AI-агента# Архитектура AI-агента
> Локальный AI-агент на базе n8n + Ollama + PostgreSQL + Wiki.js.
> Версия: 1.0 | Обновлено: 2025
## Компоненты системы
| Компонент | IP | Порт | Технология | Роль |
|-----------|-----|------|------------|------|
| **n8n** | 192.168.56.10 | 5678 | Docker + n8n | Оркестратор воркфлоу, AI-агент |
| **PostgreSQL** | 192.168.56.11 | 5432 | PostgreSQL 15 | Централизованное хранилище данных |
| **Ollama** | 192.168.56.12 | 11434 | Docker + Ollama | LLM inference, языковая модель |
| **Wiki.js** | 192.168.56.13 | 3000 | Docker + Wiki.js 2 | Документация, эта страница |
## Схема взаимодействия
Пользователь (браузер)
│
▼ HTTP :5678
┌────────────┐
│ n8n │
│ AI Agent │
└─────┬──────┘
│ │
▼ HTTP :11434 ▼ PostgreSQL :5432
┌────────────┐ ┌─────────────────────┐
│ Ollama │ │ PostgreSQL │
│ llama3.2 │ │ │
└────────────┘ │ • n8n_db (воркфлоу) │
│ • agent_db (память) │
│ • wiki_db (вики) │
└─────────────────────┘
## Базы данных PostgreSQL
### n8n_db
- **Пользователь:** `n8n_user`
- **Назначение:** Воркфлоу, credentials, история выполнений n8n
- **Доступ:** Только с 192.168.56.10 (VM n8n)
### agent_db
- **Пользователь:** `agent_user`
- **Назначение:** Долгосрочная память AI-агента (история диалогов)
- **Ключевая таблица:** `agent_memory(session_id, role, content, created_at)`
- **Доступ:** Только с 192.168.56.10 (VM n8n)
### wiki_db
- **Пользователь:** `wiki_user`
- **Назначение:** Содержимое Wiki.js (страницы, пользователи, настройки)
- **Доступ:** Только с 192.168.56.13 (VM wikijs)
## Воркфлоу AI-агента в n8n
Chat Trigger
│
▼
AI Agent ────► Ollama Chat Model (llama3.2)
│
▼
Postgres Chat Memory
(agent_db)
### Поток данных
1. Пользователь отправляет сообщение через Chat Trigger
2. AI Agent загружает историю из PostgreSQL (agent_db)
3. AI Agent формирует промпт с контекстом и передаёт в Ollama
4. Ollama генерирует ответ (LLM inference)
5. AI Agent сохраняет сообщение и ответ в PostgreSQL
6. Ответ возвращается пользователю
## Что где хранится
| Данные | Где хранятся | Путь / Таблица |
|--------|-------------|----------------|
| Воркфлоу n8n | PostgreSQL `n8n_db` | таблица `workflow_entity` |
| Credentials n8n | PostgreSQL `n8n_db` | таблица `credentials_entity` |
| Память агента | PostgreSQL `agent_db` | таблица `agent_memory` |
| Модели Ollama | Docker Volume `ollama_data` | `/root/.ollama/models/` |
| Конфиг n8n | Docker Volume `n8n_data` | `/home/node/.n8n/` |
| Страницы Wiki | PostgreSQL `wiki_db` | таблица `pages` |
## Сетевая безопасность
- PostgreSQL слушает только `192.168.56.11` — недоступен снаружи подсети VM
- `pg_hba.conf` ограничивает доступ к каждой БД конкретным источником
- Ollama слушает `0.0.0.0:11434` — доступен из подсети (в продакшне закрыть файрволом)
- n8n доступен с хоста через forwarded port 5678
## Управление
### Перезапуск сервисов
```bash
# n8n
vagrant ssh n8n -c "docker restart n8n"
# Ollama
vagrant ssh ollama -c "cd /opt/ollama && docker compose restart"
# Wiki.js
vagrant ssh wikijs -c "cd /opt/wikijs && docker compose restart"
# PostgreSQL
vagrant ssh postgresql -c "sudo systemctl restart postgresql"
vagrant ssh n8n -c "docker logs n8n --tail 50 -f"
vagrant ssh ollama -c "docker logs ollama --tail 50 -f"
vagrant ssh wikijs -c "docker logs wikijs --tail 50 -f"
vagrant ssh postgresql -c "sudo journalctl -u postgresql -f"
# Бэкап всех БД
vagrant ssh postgresql -c "
sudo -u postgres pg_dump n8n_db > /tmp/n8n_db.sql
sudo -u postgres pg_dump agent_db > /tmp/agent_db.sql
sudo -u postgres pg_dump wiki_db > /tmp/wiki_db.sql
"
# Скопировать бэкапы на хост
vagrant scp postgresql:/tmp/n8n_db.sql ./backups/
vagrant scp postgresql:/tmp/agent_db.sql ./backups/
vagrant scp postgresql:/tmp/wiki_db.sql ./backups/
---
## 12. Справочник портов и переменных
### Порты
| Сервис | VM | Порт внутри подсети | Порт на хосте |
|--------|-----|---------------------|---------------|
| n8n UI | 192.168.56.10 | :5678 | localhost:5678 |
| PostgreSQL | 192.168.56.11 | :5432 | — (не пробрасывается) |
| Ollama API | 192.168.56.12 | :11434 | localhost:11434 |
| Wiki.js UI | 192.168.56.13 | :3000 | localhost:3000 |
### Переменные окружения n8n
| Переменная | Значение | Описание |
|-----------|---------|---------|
| `DB_TYPE` | `postgresdb` | Тип БД |
| `DB_POSTGRESDB_HOST` | `192.168.56.11` | IP PostgreSQL |
| `DB_POSTGRESDB_PORT` | `5432` | Порт PostgreSQL |
| `DB_POSTGRESDB_DATABASE` | `n8n_db` | Имя БД |
| `DB_POSTGRESDB_USER` | `n8n_user` | Пользователь |
| `DB_POSTGRESDB_PASSWORD` | `n8n_strong_password_123` | Пароль |
| `N8N_ENCRYPTION_KEY` | `<32+ символа>` | Ключ шифрования credentials |
### Переменные окружения Wiki.js
| Переменная | Значение |
|-----------|---------|
| `DB_TYPE` | `postgres` |
| `DB_HOST` | `192.168.56.11` |
| `DB_PORT` | `5432` |
| `DB_USER` | `wiki_user` |
| `DB_PASS` | `wiki_strong_password_123` |
| `DB_NAME` | `wiki_db` |
### Учётные данные PostgreSQL
| БД | Пользователь | Пароль (поменяй!) |
|----|-------------|-------------------|
| `n8n_db` | `n8n_user` | `n8n_strong_password_123` |
| `wiki_db` | `wiki_user` | `wiki_strong_password_123` |
| `agent_db` | `agent_user` | `agent_strong_password_123` |
---
*Документация создана для проекта локального AI-агента. Обновляй при изменении конфигурации.*