fix: Add n8n environment variables to production deployment
Some checks failed
Production Deployment (Zero Downtime) / deploy-production (push) Failing after 10m24s
Some checks failed
Production Deployment (Zero Downtime) / deploy-production (push) Failing after 10m24s
- Add N8N_WEBHOOK_URL, N8N_SECRET_TOKEN, N8N_API_KEY to docker-compose.production.yml - Export environment variables in workflow before docker-compose up - Improve error logging in chat API for better debugging - Add better error handling in ChatWidget component - Create setup guide for n8n chat configuration
This commit is contained in:
@@ -58,8 +58,21 @@ jobs:
|
|||||||
# Backup current container ID if running
|
# Backup current container ID if running
|
||||||
OLD_CONTAINER=$(docker ps -q -f name=$CONTAINER_NAME || echo "")
|
OLD_CONTAINER=$(docker ps -q -f name=$CONTAINER_NAME || echo "")
|
||||||
|
|
||||||
|
# Export environment variables for docker-compose
|
||||||
|
export N8N_WEBHOOK_URL="${{ vars.N8N_WEBHOOK_URL || '' }}"
|
||||||
|
export N8N_SECRET_TOKEN="${{ secrets.N8N_SECRET_TOKEN || '' }}"
|
||||||
|
export N8N_API_KEY="${{ vars.N8N_API_KEY || '' }}"
|
||||||
|
|
||||||
|
# Also export other variables that docker-compose needs
|
||||||
|
export MY_EMAIL="${{ vars.MY_EMAIL }}"
|
||||||
|
export MY_INFO_EMAIL="${{ vars.MY_INFO_EMAIL }}"
|
||||||
|
export MY_PASSWORD="${{ secrets.MY_PASSWORD }}"
|
||||||
|
export MY_INFO_PASSWORD="${{ secrets.MY_INFO_PASSWORD }}"
|
||||||
|
export ADMIN_BASIC_AUTH="${{ secrets.ADMIN_BASIC_AUTH }}"
|
||||||
|
|
||||||
# Start new container with updated image (docker-compose will handle this)
|
# Start new container with updated image (docker-compose will handle this)
|
||||||
echo "🆕 Starting new production container..."
|
echo "🆕 Starting new production container..."
|
||||||
|
echo "📝 Environment check: N8N_WEBHOOK_URL=${N8N_WEBHOOK_URL:-(not set)}"
|
||||||
docker compose -f $COMPOSE_FILE up -d --no-deps --build portfolio
|
docker compose -f $COMPOSE_FILE up -d --no-deps --build portfolio
|
||||||
|
|
||||||
# Wait for new container to be healthy
|
# Wait for new container to be healthy
|
||||||
@@ -146,6 +159,7 @@ jobs:
|
|||||||
ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }}
|
ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }}
|
||||||
N8N_WEBHOOK_URL: ${{ vars.N8N_WEBHOOK_URL || '' }}
|
N8N_WEBHOOK_URL: ${{ vars.N8N_WEBHOOK_URL || '' }}
|
||||||
N8N_SECRET_TOKEN: ${{ secrets.N8N_SECRET_TOKEN || '' }}
|
N8N_SECRET_TOKEN: ${{ secrets.N8N_SECRET_TOKEN || '' }}
|
||||||
|
N8N_API_KEY: ${{ vars.N8N_API_KEY || '' }}
|
||||||
|
|
||||||
- name: Production Health Check
|
- name: Production Health Check
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -30,15 +30,24 @@ export async function POST(request: NextRequest) {
|
|||||||
// Call your n8n chat webhook
|
// Call your n8n chat webhook
|
||||||
const n8nWebhookUrl = process.env.N8N_WEBHOOK_URL;
|
const n8nWebhookUrl = process.env.N8N_WEBHOOK_URL;
|
||||||
|
|
||||||
if (!n8nWebhookUrl) {
|
if (!n8nWebhookUrl || n8nWebhookUrl.trim() === '') {
|
||||||
console.error("N8N_WEBHOOK_URL not configured");
|
console.error("N8N_WEBHOOK_URL not configured. Environment check:", {
|
||||||
|
hasUrl: !!process.env.N8N_WEBHOOK_URL,
|
||||||
|
urlValue: process.env.N8N_WEBHOOK_URL || '(empty)',
|
||||||
|
nodeEnv: process.env.NODE_ENV,
|
||||||
|
});
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
reply: getFallbackResponse(userMessage),
|
reply: getFallbackResponse(userMessage),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhookUrl = `${n8nWebhookUrl}/webhook/chat`;
|
// Ensure URL doesn't have trailing slash before adding /webhook/chat
|
||||||
console.log(`Sending to n8n: ${webhookUrl}`);
|
const baseUrl = n8nWebhookUrl.replace(/\/$/, '');
|
||||||
|
const webhookUrl = `${baseUrl}/webhook/chat`;
|
||||||
|
console.log(`Sending to n8n: ${webhookUrl}`, {
|
||||||
|
hasSecretToken: !!process.env.N8N_SECRET_TOKEN,
|
||||||
|
hasApiKey: !!process.env.N8N_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
// Add timeout to prevent hanging requests
|
// Add timeout to prevent hanging requests
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
@@ -67,8 +76,13 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorText = await response.text().catch(() => 'Unknown error');
|
const errorText = await response.text().catch(() => 'Unknown error');
|
||||||
console.error(`n8n webhook failed with status: ${response.status}`, errorText);
|
console.error(`n8n webhook failed with status: ${response.status}`, {
|
||||||
throw new Error(`n8n webhook failed: ${response.status} - ${errorText}`);
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
error: errorText,
|
||||||
|
webhookUrl: webhookUrl.replace(/\/\/[^:]+:[^@]+@/, '//***:***@'), // Hide credentials in logs
|
||||||
|
});
|
||||||
|
throw new Error(`n8n webhook failed: ${response.status} - ${errorText.substring(0, 200)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -198,7 +212,10 @@ export async function POST(request: NextRequest) {
|
|||||||
console.error("Error details:", {
|
console.error("Error details:", {
|
||||||
message: error instanceof Error ? error.message : String(error),
|
message: error instanceof Error ? error.message : String(error),
|
||||||
stack: error instanceof Error ? error.stack : undefined,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
n8nUrl: process.env.N8N_WEBHOOK_URL ? 'configured' : 'missing',
|
n8nUrl: process.env.N8N_WEBHOOK_URL ? `configured (${process.env.N8N_WEBHOOK_URL})` : 'missing',
|
||||||
|
hasSecretToken: !!process.env.N8N_SECRET_TOKEN,
|
||||||
|
hasApiKey: !!process.env.N8N_API_KEY,
|
||||||
|
nodeEnv: process.env.NODE_ENV,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fallback to mock responses
|
// Fallback to mock responses
|
||||||
|
|||||||
@@ -129,10 +129,21 @@ export default function ChatWidget() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to get response");
|
const errorText = await response.text().catch(() => 'Unknown error');
|
||||||
|
console.error("Chat API error:", {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
error: errorText,
|
||||||
|
});
|
||||||
|
throw new Error(`Failed to get response: ${response.status} - ${errorText.substring(0, 100)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Log response for debugging (only in development)
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.log("Chat API response:", data);
|
||||||
|
}
|
||||||
|
|
||||||
// Decode HTML entities in the reply
|
// Decode HTML entities in the reply
|
||||||
let replyText = data.reply || "Sorry, I couldn't process that. Please try again.";
|
let replyText = data.reply || "Sorry, I couldn't process that. Please try again.";
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ services:
|
|||||||
- MY_INFO_PASSWORD=${MY_INFO_PASSWORD}
|
- MY_INFO_PASSWORD=${MY_INFO_PASSWORD}
|
||||||
- ADMIN_BASIC_AUTH=${ADMIN_BASIC_AUTH:-admin:your_secure_password_here}
|
- ADMIN_BASIC_AUTH=${ADMIN_BASIC_AUTH:-admin:your_secure_password_here}
|
||||||
- LOG_LEVEL=info
|
- LOG_LEVEL=info
|
||||||
|
- N8N_WEBHOOK_URL=${N8N_WEBHOOK_URL:-}
|
||||||
|
- N8N_SECRET_TOKEN=${N8N_SECRET_TOKEN:-}
|
||||||
|
- N8N_API_KEY=${N8N_API_KEY:-}
|
||||||
volumes:
|
volumes:
|
||||||
- portfolio_data:/app/.next/cache
|
- portfolio_data:/app/.next/cache
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
146
docs/N8N_CHAT_PRODUCTION_SETUP.md
Normal file
146
docs/N8N_CHAT_PRODUCTION_SETUP.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# 🔧 n8n Chat Setup für Production
|
||||||
|
|
||||||
|
## Problem: AI Chat funktioniert nicht auf Production
|
||||||
|
|
||||||
|
Wenn der AI Chat auf Production nicht funktioniert, liegt es meist an fehlenden Environment-Variablen.
|
||||||
|
|
||||||
|
## ✅ Lösung: Environment-Variablen in Gitea setzen
|
||||||
|
|
||||||
|
### Schritt 1: Gehe zu Gitea Repository Settings
|
||||||
|
|
||||||
|
1. Öffne: `https://git.dk0.dev/denshooter/portfolio/settings`
|
||||||
|
2. Klicke auf **"Variables"** im linken Menü
|
||||||
|
|
||||||
|
### Schritt 2: Setze die n8n Variables
|
||||||
|
|
||||||
|
#### Variables (öffentlich):
|
||||||
|
- **Name:** `N8N_WEBHOOK_URL`
|
||||||
|
- **Value:** `https://n8n.dk0.dev`
|
||||||
|
- **Protect:** ✅ (optional)
|
||||||
|
|
||||||
|
- **Name:** `N8N_API_KEY` (optional, falls dein n8n eine API-Key benötigt)
|
||||||
|
- **Value:** Dein n8n API Key
|
||||||
|
- **Protect:** ✅
|
||||||
|
|
||||||
|
#### Secrets (verschlüsselt):
|
||||||
|
- **Name:** `N8N_SECRET_TOKEN`
|
||||||
|
- **Value:** Dein n8n Secret Token (falls du einen verwendest)
|
||||||
|
- **Protect:** ✅
|
||||||
|
|
||||||
|
### Schritt 3: Prüfe die n8n Webhook URL
|
||||||
|
|
||||||
|
Stelle sicher, dass dein n8n Workflow:
|
||||||
|
1. **Aktiv** ist (Toggle oben rechts)
|
||||||
|
2. Den Webhook-Pfad `/webhook/chat` hat
|
||||||
|
3. Die vollständige URL ist: `https://n8n.dk0.dev/webhook/chat`
|
||||||
|
|
||||||
|
### Schritt 4: Teste die Webhook-URL direkt
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://n8n.dk0.dev/webhook/chat \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"message": "Hello"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Wenn du einen `N8N_SECRET_TOKEN` verwendest:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://n8n.dk0.dev/webhook/chat \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
|
||||||
|
-d '{"message": "Hello"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schritt 5: Deploy neu starten
|
||||||
|
|
||||||
|
Nach dem Setzen der Variablen:
|
||||||
|
1. Push einen Commit zum `production` Branch
|
||||||
|
2. Oder manuell den Workflow in Gitea starten
|
||||||
|
3. Die Variablen werden automatisch an den Container übergeben
|
||||||
|
|
||||||
|
## 🔍 Debugging
|
||||||
|
|
||||||
|
### Prüfe Container-Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs portfolio-app | grep -i n8n
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prüfe Environment-Variablen im Container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec portfolio-app env | grep N8N
|
||||||
|
```
|
||||||
|
|
||||||
|
Sollte zeigen:
|
||||||
|
```
|
||||||
|
N8N_WEBHOOK_URL=https://n8n.dk0.dev
|
||||||
|
N8N_SECRET_TOKEN=*** (wenn gesetzt)
|
||||||
|
N8N_API_KEY=*** (wenn gesetzt)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prüfe Browser-Konsole
|
||||||
|
|
||||||
|
Öffne die Browser-Konsole (F12) und schaue nach Fehlern beim Senden einer Chat-Nachricht.
|
||||||
|
|
||||||
|
### Prüfe Server-Logs
|
||||||
|
|
||||||
|
Die Chat-API loggt jetzt detaillierter:
|
||||||
|
- Ob `N8N_WEBHOOK_URL` gesetzt ist
|
||||||
|
- Die vollständige Webhook-URL (ohne Credentials)
|
||||||
|
- HTTP-Fehler mit Status-Codes
|
||||||
|
|
||||||
|
## 🐛 Häufige Probleme
|
||||||
|
|
||||||
|
### Problem 1: "N8N_WEBHOOK_URL not configured"
|
||||||
|
|
||||||
|
**Lösung:** Variable in Gitea setzen (siehe Schritt 2)
|
||||||
|
|
||||||
|
### Problem 2: "n8n webhook failed: 404"
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
- Prüfe, ob der n8n Workflow aktiv ist
|
||||||
|
- Prüfe, ob der Webhook-Pfad `/webhook/chat` ist
|
||||||
|
- Teste die URL direkt mit curl
|
||||||
|
|
||||||
|
### Problem 3: "n8n webhook failed: 401/403"
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
- Prüfe, ob `N8N_SECRET_TOKEN` in Gitea Secrets gesetzt ist
|
||||||
|
- Prüfe, ob der Token im n8n Workflow korrekt konfiguriert ist
|
||||||
|
|
||||||
|
### Problem 4: "Connection timeout"
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
- Prüfe, ob n8n erreichbar ist: `curl https://n8n.dk0.dev`
|
||||||
|
- Prüfe Firewall-Regeln
|
||||||
|
- Prüfe, ob n8n im gleichen Netzwerk ist (Docker Network)
|
||||||
|
|
||||||
|
## 📝 Aktuelle Konfiguration
|
||||||
|
|
||||||
|
Die Chat-API verwendet:
|
||||||
|
- **Webhook URL:** `${N8N_WEBHOOK_URL}/webhook/chat`
|
||||||
|
- **Authentication:**
|
||||||
|
- `Authorization: Bearer ${N8N_SECRET_TOKEN}` (wenn gesetzt)
|
||||||
|
- `X-API-Key: ${N8N_API_KEY}` (wenn gesetzt)
|
||||||
|
- **Timeout:** 30 Sekunden
|
||||||
|
- **Fallback:** Wenn n8n nicht erreichbar ist, werden intelligente Fallback-Antworten verwendet
|
||||||
|
|
||||||
|
## ✅ Checkliste
|
||||||
|
|
||||||
|
- [ ] `N8N_WEBHOOK_URL` in Gitea Variables gesetzt
|
||||||
|
- [ ] `N8N_SECRET_TOKEN` in Gitea Secrets gesetzt (falls benötigt)
|
||||||
|
- [ ] `N8N_API_KEY` in Gitea Variables gesetzt (falls benötigt)
|
||||||
|
- [ ] n8n Workflow ist aktiv
|
||||||
|
- [ ] Webhook-Pfad ist `/webhook/chat`
|
||||||
|
- [ ] Container wurde nach dem Setzen der Variablen neu deployed
|
||||||
|
- [ ] Container-Logs zeigen keine n8n-Fehler
|
||||||
|
|
||||||
|
## 🚀 Nach dem Setup
|
||||||
|
|
||||||
|
Nach dem Setzen der Variablen und einem neuen Deployment sollte der Chat funktionieren. Falls nicht:
|
||||||
|
|
||||||
|
1. Prüfe die Container-Logs: `docker logs portfolio-app`
|
||||||
|
2. Prüfe die Browser-Konsole für Client-seitige Fehler
|
||||||
|
3. Teste die n8n Webhook-URL direkt mit curl
|
||||||
|
4. Prüfe, ob die Environment-Variablen im Container gesetzt sind
|
||||||
Reference in New Issue
Block a user