Дата: 11 декабря 2025 Проект: Интеграция AI чата на openaiua.fr с n8n workflow
Создать работающий чат на сайте, который отправляет сообщения в n8n workflow и получает ответы от AI агента.
Браузер (openaiua.fr)
→ JavaScript (chat.js)
→ POST запрос
→ Caddy (reverse proxy)
→ n8n webhook
→ AI Agent (Ollama)
→ Ответ обратно в браузер
JavaScript (chat.js):
this.webhookUrl = 'https://n8n.openaiua.fr/webhook/485504f9-9cb8-4134-988b-5b856e881144/chat';
// Отправка данных
body: JSON.stringify({
action: 'sendMessage',
sessionId: this.sessionId,
chatInput: message
})
Проблема: Webhook URL был старым, формат данных не совпадал с ожидаемым.
Симптом: При тестировании webhook получали:
{
"body": {}, // ← Пустой объект!
"query": {},
"params": {}
}
Метод обнаружения:
curl -X POST https://n8n.openaiua.fr/webhook-test/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "Привет, это тест"}'
Анализ:
Причина: Пользователь открывал webhook URL в браузере, который отправляет GET запрос вместо POST.
Исправление: Использовать POST запрос через curl или JavaScript fetch:
# Правильный способ тестирования
curl -X POST https://n8n.openaiua.fr/webhook-test/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "Тестовое сообщение"}'
Результат:
{
"body": {
"message": "Тестовое сообщение" // ✅ Данные пришли!
}
}
Симптом:
Метод обнаружения:
docker logs n8n --tail 50 | grep webhook
Вывод:
Received request for unknown webhook: The requested webhook "webhook/chat" is not registered.
/webhook-test/webhook/chat ← Тестовый URL!
Причина:
Использовался тестовый webhook URL (/webhook-test/), который:
Production vs Test URLs:
❌ Тестовый: /webhook-test/webhook/chat (работает 1 раз)
✅ Production: /webhook/chat (работает всегда)
Исправление в JavaScript:
// БЫЛО (неправильно):
this.webhookUrl = 'https://n8n.openaiua.fr/webhook-test/webhook/chat';
// СТАЛО (правильно):
this.webhookUrl = 'https://n8n.openaiua.fr/webhook/chat';
Важно: Workflow должен быть активирован (кнопка Active = ON в n8n)!
Файл: /home/ubuntu/projects/landing/public/js/chat.js:10
Симптом: После изменения на production URL получили:
curl -X POST https://n8n.openaiua.fr/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "тест"}'
# Ошибка:
{"code":404,"message":"The requested webhook \"POST chat\" is not registered."}
Метод обнаружения:
# Скопировали БД из контейнера
docker cp n8n:/home/node/.n8n/database.sqlite /tmp/n8n_db.sqlite
# Проверили зарегистрированные webhooks
sqlite3 /tmp/n8n_db.sqlite "SELECT * FROM webhook_entity;"
Результат:
plUL5TUpSeibV6le|webhook/chat|POST|Webhook||
# Вариант 1:
curl https://n8n.openaiua.fr/webhook/chat # ❌ 404
# Вариант 2 (догадка - двойной префикс):
curl https://n8n.openaiua.fr/webhook/webhook/chat # ✅ РАБОТАЕТ!
Причина:
В n8n узле Webhook path указан как webhook/chat, но n8n автоматически добавляет префикс /webhook/:
Path в узле: webhook/chat
n8n добавляет: /webhook/
Итоговый URL: /webhook/webhook/chat ← Двойной префикс!
Исправление в JavaScript:
// БЫЛО:
this.webhookUrl = 'https://n8n.openaiua.fr/webhook/chat';
// СТАЛО (правильный URL):
this.webhookUrl = 'https://n8n.openaiua.fr/webhook/webhook/chat';
Файл: /home/ubuntu/projects/landing/public/js/chat.js:10
Проверка:
curl -X POST https://n8n.openaiua.fr/webhook/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "Hello from test"}'
# Ответ:
{"text":"Hello! How can I assist you today?"} # ✅ Работает!
Симптом:
Метод обнаружения:
curl -X POST https://n8n.openaiua.fr/webhook/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "test"}'
# Ответ:
{"text":"Hello! How can I assist you today?"}
// В коде проверялось:
if (data.message) {
return data.message; // ❌ Поле "message" не существует!
} else if (data.output) {
return data.output; // ❌ Поле "output" не существует!
} else {
return 'Получен ответ от AI агента.'; // ← Попадали сюда
}
{
"text": "Hello! How can I assist you today?"
}
Проблема: JavaScript искал поля message, output, response, но n8n возвращал text.
Исправление в JavaScript:
// БЫЛО:
const data = await response.json();
if (data.message) {
return data.message;
} else if (data.output) {
return data.output;
} else if (data.response) {
return data.response;
} else if (typeof data === 'string') {
return data;
} else {
return 'Получен ответ от AI агента.'; // ← Fallback
}
// СТАЛО:
const data = await response.json();
if (data.text) { // ← Добавлена проверка первой!
return data.text;
} else if (data.message) {
return data.message;
} else if (data.output) {
return data.output;
} else if (data.response) {
return data.response;
} else if (typeof data === 'string') {
return data;
} else {
return JSON.stringify(data); // ← Показываем весь JSON для отладки
}
Файл: /home/ubuntu/projects/landing/public/js/chat.js:74-87
Результат: ✅ Ответ от AI теперь корректно отображается на сайте!
Симптом:
Метод обнаружения:
echo | openssl s_client -connect n8n.openaiua.fr:443 -servername n8n.openaiua.fr 2>&1 | \
grep "Verify return code"
# Результат:
Verify return code: 0 (ok) # ✅ Сертификат валидный
curl -I https://n8n.openaiua.fr | grep -i "strict-transport\|x-frame\|x-content"
# Результат: (пусто) ← Отсутствуют security headers!
environment:
- N8N_PROTOCOL=http # ❌ HTTP вместо HTTPS!
- WEBHOOK_URL=https://... # ✅ Правильно, но недостаточно
Проблема:
Часть 1: Исправление n8n конфигурации
# Файл: /home/ubuntu/projects/n8n/docker-compose.yml
environment:
# БЫЛО:
- N8N_PROTOCOL=http
# СТАЛО:
- N8N_PROTOCOL=https
- N8N_EDITOR_BASE_URL=https://n8n.openaiua.fr
# Остальное без изменений:
- WEBHOOK_URL=https://n8n.openaiua.fr/
- N8N_TRUST_PROXY=true
Перезапуск:
cd /home/ubuntu/projects/n8n
docker compose down
docker compose up -d
Часть 2: Добавление Security Headers в Caddy
# Файл: /etc/caddy/Caddyfile
# БЫЛО:
n8n.openaiua.fr {
reverse_proxy localhost:5678
}
# СТАЛО:
n8n.openaiua.fr {
# Security headers для совместимости с Chrome
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
reverse_proxy localhost:5678
}
# То же самое для основного сайта:
openaiua.fr, www.openaiua.fr {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
reverse_proxy localhost:3001
}
Применение изменений:
sudo cp /tmp/Caddyfile.new /etc/caddy/Caddyfile
sudo systemctl reload caddy
Проверка:
curl -I https://n8n.openaiua.fr | grep -i "strict-transport"
# Результат:
strict-transport-security: max-age=31536000; includeSubDomains; preload # ✅
Решение для Chrome: После изменений нужно очистить кеш в Chrome:
/home/ubuntu/projects/
├── landing/
│ ├── public/
│ │ ├── index.html
│ │ └── js/
│ │ └── chat.js ← Основной файл чата
│ ├── server.js ← Express сервер (порт 3001)
│ └── package.json
│
├── n8n/
│ └── docker-compose.yml ← n8n конфигурация
│
└── /etc/caddy/
└── Caddyfile ← Reverse proxy конфигурация
Файл: /home/ubuntu/projects/landing/public/js/chat.js
class ChatBot {
constructor() {
this.chatForm = document.getElementById('chatForm');
this.chatInput = document.getElementById('chatInput');
this.chatMessages = document.getElementById('chatMessages');
this.sessionId = this.generateSessionId();
// ✅ Правильный production webhook URL
this.webhookUrl = 'https://n8n.openaiua.fr/webhook/webhook/chat';
this.init();
}
async sendToN8N(message) {
try {
const response = await fetch(this.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
// ✅ Правильный формат данных
body: JSON.stringify({
message: message
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// ✅ Правильная обработка ответа (проверяем data.text первым!)
if (data.text) {
return data.text;
} else if (data.message) {
return data.message;
} else if (data.output) {
return data.output;
} else if (data.response) {
return data.response;
} else if (typeof data === 'string') {
return data;
} else {
return JSON.stringify(data);
}
} catch (error) {
console.error('N8N Error:', error);
throw error;
}
}
}
Ключевые моменты:
https://n8n.openaiua.fr/webhook/webhook/chat (двойной префикс){"message": "текст"}data.text первымФайл: /home/ubuntu/projects/n8n/docker-compose.yml
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- GENERIC_TIMEZONE=Europe/Kiev
- N8N_HOST=0.0.0.0
- N8N_PORT=5678
# ✅ HTTPS конфигурация (исправлено!)
- N8N_PROTOCOL=https
- N8N_EDITOR_BASE_URL=https://n8n.openaiua.fr
- NODE_ENV=production
- N8N_SECURE_COOKIE=false
- N8N_GIT_NODE_DISABLE_BARE_REPOS=true
# ✅ Webhook URL
- WEBHOOK_URL=https://n8n.openaiua.fr/
- N8N_TRUST_PROXY=true
- EXECUTIONS_TIMEOUT=3600
- EXECUTIONS_TIMEOUT_MAX=7200
volumes:
- n8n_data:/home/node/.n8n
networks:
- default
- ai-stack_llm-net
volumes:
n8n_data:
networks:
default:
ai-stack_llm-net:
external: true
Перезапуск после изменений:
cd /home/ubuntu/projects/n8n
docker compose down
docker compose up -d
Файл: /etc/caddy/Caddyfile
# n8n subdomain with automatic HTTPS
n8n.openaiua.fr {
# ✅ Security headers для Chrome
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
reverse_proxy localhost:5678
}
# Main website - Node.js landing page
openaiua.fr, www.openaiua.fr {
# ✅ Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
reverse_proxy localhost:3001
}
Применение изменений:
sudo systemctl reload caddy
Workflow Name: n8n_express
Status: Active ✅
Узлы:
Webhook
webhook/chatPOSTlastNodeExtract Data (Set node)
{{ $json.body.message }}userMessageAI Agent (LLM Chain)
Respond
Важно: Workflow должен быть активирован (кнопка Active)!
# 1. Проверить что n8n запущен
docker ps | grep n8n
# 2. Проверить логи n8n
docker logs n8n --tail 50
# 3. Проверить зарегистрированные webhooks в БД
docker cp n8n:/home/node/.n8n/database.sqlite /tmp/n8n_db.sqlite
sqlite3 /tmp/n8n_db.sqlite "SELECT * FROM webhook_entity;"
# 4. Проверить что workflow активен
sqlite3 /tmp/n8n_db.sqlite "SELECT id, name, active FROM workflow_entity;"
# 5. Тест webhook через curl
curl -X POST https://n8n.openaiua.fr/webhook/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "test"}'
# 6. Проверить SSL сертификат
echo | openssl s_client -connect n8n.openaiua.fr:443 -servername n8n.openaiua.fr | \
grep "Verify return code"
# 7. Проверить security headers
curl -I https://n8n.openaiua.fr | grep -i "strict-transport"
// 1. Откройте DevTools (F12) в браузере
// 2. Перейдите на вкладку Console
// 3. Отправьте сообщение в чат
// 4. Проверьте что выводится в консоли
// Должны увидеть:
// - POST запрос на webhook URL
// - Статус 200 OK
// - JSON ответ с данными
// 5. Если ошибка CORS:
// - Проверьте что n8n_PROTOCOL=https
// - Перезапустите n8n: docker compose restart
# n8n
docker compose -f /home/ubuntu/projects/n8n/docker-compose.yml restart
docker logs n8n --tail 100 -f
# Caddy
sudo systemctl reload caddy
sudo systemctl status caddy
journalctl -u caddy -f
# Landing page
cd /home/ubuntu/projects/landing
ps aux | grep "node.*server.js"
kill <PID> # если нужно перезапустить
node server.js &
# Тест webhook
curl -X POST https://n8n.openaiua.fr/webhook/webhook/chat \
-H "Content-Type: application/json" \
-d '{"message": "Hello"}' \
-v
# Тест с кириллицей (используйте --data-binary)
curl -X POST https://n8n.openaiua.fr/webhook/webhook/chat \
-H "Content-Type: application/json; charset=utf-8" \
--data-binary '{"message": "Привет"}'
# Проверка SSL
curl -I https://n8n.openaiua.fr
# Проверка DNS
dig n8n.openaiua.fr
/home/ubuntu/projects/landing/public/js/chat.js/home/ubuntu/projects/n8n/docker-compose.yml/etc/caddy/CaddyfileАвтор: Claude Sonnet 4.5 Дата создания: 11 декабря 2025 Версия: 1.0