From 6b1191d68c46123474a781c54aa96108952a41f8 Mon Sep 17 00:00:00 2001 From: Artem Baranovskyi <artem.baranovsky1980@gmail.com> Date: Fri, 28 Feb 2025 23:04:36 +0200 Subject: [PATCH] Partial solution with Nginx user access separation (to be finished). Summarising. --- .env.Example | 23 ++- docker-compose.yml | 59 ++++++- nginx/nginx.conf | 39 +++++ ollama-models/Dockerfile | 3 + ollama-models/load_model.py | 4 +- ollama-models/start.sh | 12 +- readme.MD | 299 ++++++++++++++++++++++++++++++++++++ 7 files changed, 420 insertions(+), 19 deletions(-) create mode 100644 nginx/nginx.conf create mode 100644 readme.MD diff --git a/.env.Example b/.env.Example index ea1554d..375ab87 100644 --- a/.env.Example +++ b/.env.Example @@ -2,8 +2,9 @@ HF_TOKEN= LANGCHAIN_API_KEY= PORT=3000 -FLOWISE_USERNAME= -FLOWISE_PASSWORD= +# Flowise student's access creds on http://localhost:3000/ +FLOWISE_USERNAME=student +FLOWISE_PASSWORD=student APIKEY_PATH=/root/.flowise SECRETKEY_PATH=/root/.flowise @@ -14,7 +15,21 @@ DATABASE_TYPE=postgres DATABASE_PORT=5432 DATABASE_HOST=localhost DATABASE_NAME=flowise -DATABASE_USER= -DATABASE_PASSWORD= +DATABASE_USER=user +DATABASE_PASSWORD=pass PGSSLMODE=require +OLLAMA_CPU=1 +OLLAMA_KEEP_ALIVE=5m +OLLAMA_NUM_PARALLEL=1 +OLLAMA_HOST=http://localhost:11435 +#MODEL_NAME=llama3.2:1b +MODEL_NAME=bartowski/DeepSeek-R1-Distill-Qwen-14B-GGUF +OLLAMA_MODEL=llama3.2:1b +MODEL=llama3.2:1b + +# Nginx +NGINX_PORT=8080 +# Nginx admin access creds on http://localhost:8080/ +ADMIN_USER=admin +ADMIN_PASSWORD=admin \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 67bdf25..2997740 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,14 +23,16 @@ services: container_name: flowiseai hostname: flowise healthcheck: - test: wget --no-verbose --tries=1 --spider http://localhost:${PORT} - interval: 5s - timeout: 5s - retries: 5 + test: ["CMD", "curl", "-f", "http://localhost:3000/api/v1/health"] + interval: 60s + timeout: 20s + retries: 10 + start_period: 120s ports: - ${PORT}:${PORT} volumes: - ./flowiseai:/root/.flowise + env_file: .env environment: DEBUG: 'false' PORT: ${PORT} @@ -46,9 +48,12 @@ services: DATABASE_NAME: ${DATABASE_NAME} DATABASE_USER: ${DATABASE_USER} DATABASE_PASSWORD: ${DATABASE_PASSWORD} +# DATABASE_URL: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@flowise-db:${DATABASE_PORT}/${DATABASE_NAME}?sslmode=disable depends_on: - - ollama - - flowise-db + flowise-db: + condition: service_healthy + ollama: + condition: service_started entrypoint: /bin/sh -c "sleep 3; flowise start" networks: - flowise_network @@ -62,16 +67,54 @@ services: volumes: - ollama_data:/root/.ollama ports: - - "11434:11434" + - "11435:11434" + env_file: .env environment: HF_TOKEN: ${HF_TOKEN} GIN_MODE: ${GIN_MODE} + OLLAMA_CPU: "1" + OLLAMA_HOST: ${OLLAMA_HOST} + OLLAMA_MODEL: ${OLLAMA_MODEL} + MODEL_NAME: ${MODEL_NAME} + networks: + - flowise_network + + nginx: + image: nginx:alpine + ports: + - "${NGINX_PORT}:80" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf + - ./nginx/.htpasswd:/etc/nginx/.htpasswd + depends_on: + - flowise + - htpasswd-generator +# flowise: +# condition: service_healthy +# htpasswd-generator: +# condition: service_completed_successfully + networks: + - flowise_network + + htpasswd-generator: + image: httpd:alpine + command: sh -c "htpasswd -Bbn $${ADMIN_USER} $${ADMIN_PASSWORD} > /etc/nginx/.htpasswd" + env_file: .env + environment: + ADMIN_USER: ${ADMIN_USER} + ADMIN_PASSWORD: ${ADMIN_PASSWORD} + volumes: + - ./nginx:/etc/nginx networks: - flowise_network + restart: on-failure volumes: flowise-db-data: ollama_data: networks: - flowise_network: \ No newline at end of file + flowise_network: + driver: bridge + name: flowise_network + attachable: true \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..afff986 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,39 @@ +events {} + +http { + server { + listen 80; + + # Public chat interface + location / { + proxy_pass http://flowise:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # Admin API (protected) + location /api/v1/ { + #allow 192.168.1.0/24; # Access only from internal network + #deny all; + + # Basic Auth for admins + auth_basic "Admin Area"; + auth_basic_user_file /etc/nginx/.htpasswd; + + # Flowise auth headers + proxy_set_header Authorization $http_authorization; + proxy_pass_header Authorization; + + proxy_pass http://flowise:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # Exclude login endpoint from basic auth + location /api/v1/login { + proxy_pass http://flowise:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } +} \ No newline at end of file diff --git a/ollama-models/Dockerfile b/ollama-models/Dockerfile index 229c55f..92622ce 100644 --- a/ollama-models/Dockerfile +++ b/ollama-models/Dockerfile @@ -20,6 +20,9 @@ COPY load_model.py /app/load_model.py ARG HF_TOKEN ENV HF_TOKEN=${HF_TOKEN} +ARG MODEL_NAME +ENV MODEL_NAME=${MODEL_NAME} + COPY start.sh /app/start.sh RUN chmod +x /app/start.sh diff --git a/ollama-models/load_model.py b/ollama-models/load_model.py index 3436565..0f75719 100644 --- a/ollama-models/load_model.py +++ b/ollama-models/load_model.py @@ -1,3 +1,4 @@ +# load_model.py import os from transformers import AutoModelForCausalLM, AutoTokenizer @@ -6,8 +7,7 @@ hf_token = os.environ.get("HF_TOKEN") if hf_token is None: raise ValueError("Hugging Face token is not set") -model_name = "meta-llama/Llama-3.2-1B" - +model_name = os.environ.get("MODEL_NAME") model = AutoModelForCausalLM.from_pretrained(model_name) tokenizer = AutoTokenizer.from_pretrained(model_name) diff --git a/ollama-models/start.sh b/ollama-models/start.sh index 112bcad..0aed2fa 100644 --- a/ollama-models/start.sh +++ b/ollama-models/start.sh @@ -1,13 +1,15 @@ #!/bin/bash - -MODEL_NAME="llama3.2:1b" +# start.sh if ! ollama list | grep -q "$MODEL_NAME"; then echo "Model is not found. Loading..." - ollama pull "$MODEL_NAME" + HUGGING_FACE_HUB_TOKEN=${HF_TOKEN} ollama pull "$MODEL_NAME" else echo "Model is already loaded." fi -ollama run "$MODEL_NAME" & -ollama serve \ No newline at end of file +ollama serve & +sleep 10 +ollama run "$MODEL_NAME" + +tail -f /dev/null \ No newline at end of file diff --git a/readme.MD b/readme.MD new file mode 100644 index 0000000..679199f --- /dev/null +++ b/readme.MD @@ -0,0 +1,299 @@ +### IMPETUS Educational Chatbot Project + +The **IMPETUS** project focuses on developing specialized chatbots for educational purposes, analyzing student-bot interactions to optimize learning experiences. The initiative leverages **LangChain** for chatbot prototyping and **Flowise** for workflow management, with emphasis on secure deployment, database integration, and access control. + +--- + +### Project Overview +**Primary Goal**: Investigate optimization strategies for educational chatbots and identify effective prompting techniques to maximize student engagement. +**Focus Areas**: +- Interaction analytics via custom database logging +- Secure deployment architecture for chatbot interfaces +- Migration from SQLite to PostgreSQL for long-term scalability +- Access control separation between admin/student interfaces + +**Core Technologies**: +- **LangChain**: Python-based framework for LLM pipeline construction ([Documentation](https://python.langchain.com/docs/tutorials/)) +- **Flowise**: Drag-and-drop UI for chatbot workflows ([GitHub Integration Example](https://github.com/AXRoux/Flowise-LangChain)) +- **Docker**: Containerization for service isolation and deployment reproducibility + +**Project Repositories**: +[https://transfer.hft-stuttgart.de/gitlab/22baar1mst/flowise-ollama](https://transfer.hft-stuttgart.de/gitlab/22baar1mst/flowise-ollama) + +[https://github.com/ArtemBaranovsky/flowise-ollama](https://github.com/ArtemBaranovsky/flowise-ollama) (mirror) + +### Key Objectives +1. **Global Service Installation**: + - Dockerize Flowise/LangChain for system-wide availability + - Separate student-facing chat interface (port 3000) from admin panel + +2. **Database Migration**: + - Replace SQLite with PostgreSQL for production-grade reliability + - Implement volume persistence for critical data + +3. **Security Hardening**: + - Isolate administrative endpoints via Nginx routing + - Implement Basic Auth with fallback to JWT/OAuth2 + +4. **LLM Infrastructure**: + - Integrate Ollama for local model management + - Configure RAG (Retrieval-Augmented Generation) workflows + +--- + +### Implementation Highlights + +#### 1. Dockerized Architecture +```yaml +# docker-compose.yml (simplified) +services: + flowise: + image: flowiseai/flowise:latest + ports: ["3000:3000"] + depends_on: [postgres, ollama] + + postgres: + image: postgres:16-alpine + volumes: ["./pgdata:/var/lib/postgresql/data"] + + ollama: + build: ./ollama-models + ports: ["11435:11434"] + + nginx: + image: nginx:alpine + ports: ["8080:80"] + configs: ["./nginx/:/etc/nginx/"] +``` + +#### 2. Access Control Implementation +```nginx +# nginx.conf (security routing) +location /admin/ { + auth_basic "Restricted Area"; + auth_basic_user_file /etc/nginx/.htpasswd; + proxy_pass http://flowise:3000/api/v1/; +} + +location /chat/ { + proxy_pass http://flowise:3000/; +} +``` + +#### 3. Ollama Model Integration +```Dockerfile +# Custom Ollama Dockerfile +FROM ollama/ollama +RUN ollama pull ${MODEL_NAME} +CMD ["ollama", "serve"] +``` + +--- + +### Challenges & Solutions + +| Challenge | Resolution | +|-----------|------------| +| **Flowise Admin/Chat Interface Collision** | Implemented Nginx path-based routing with Basic Auth | +| **SQLite Scalability Limitations** | Migrated to PostgreSQL with automated schema migration | +| **Model Loading Failures** | Created pre-loading script for Ollama containers | +| **Student Access Exploits** | Added IP filtering + rate limiting in Nginx | + +Stable implemented version of this simple solution is at https://transfer.hft-stuttgart.de/gitlab/22baar1mst/flowise-ollama/-/commit/5c4d44705f550546423afcd06bc7e69a54e4276a + + +**Unresolved Issues**: +- Basic Auth bypass vulnerabilities in shared port configuration +- LangChain migration incomplete due to time constraints + +--- + +### Deployment Workflow + +1. **Infrastructure Setup**: +```bash +ssh impetus@193.196.53.83 -i <key.pem> +docker-compose up -d --build +``` + +2. **Environment Configuration**: +```.env +DATABASE_URL=postgresql://user:pass@postgres:5432/db +OLLAMA_MODEL=llama2-uncensored +NGINX_PORT=8080 +``` + +3. **Security Hardening**: +```bash +# Generate admin credentials +htpasswd -c ./nginx/.htpasswd admin +``` + +--- + +### Future Development Plan + +1. **LangChain Migration**: + - Port Flowise workflows to LangChain agents + - Implement dual interface system: + - `/chat` – student-facing endpoint + - `/admin` – JWT-protected management UI + +2. **Enhanced Security**: + - Implement OAuth2 via Keycloak/Linkding + - Add audit logging for all admin actions + +3. **CI/CD Pipeline**: + - Automated Docker builds on GitLab + - Canary deployment strategy + +4. **Analytics Integration**: + - ClickHouse for interaction telemetry + - Grafana dashboard for usage metrics + +--- + +### Conclusion +The IMPETUS project demonstrates a viable architecture for educational chatbots using Dockerized LLM components. While Flowise provided rapid prototyping capabilities, future work will focus on transitioning to LangChain for greater flexibility. The current implementation achieves: +- Isolated PostgreSQL database with persistent storage +- Basic access control through Nginx +- Local LLM management via Ollama + +**Next Steps**: Address security vulnerabilities in access control and complete LangChain migration using [Flowise-LangChain integration templates](https://volcano-ice-cd6.notion.site/Introduction-to-Practical-Building-LLM-Applications-with-Flowise-LangChain-03d6d75bfd20495d96dfdae964bea5a5). + +--- + +(Due to technical issues, the search service is temporarily unavailable.) + +### Deployment Guide: Flowise-Ollama Chatbot System + +#### Prerequisites +1. **Docker** and **Docker Compose** installed +2. **Hugging Face Account** (for accessing LLM models) +3. Minimum **8GB RAM** and **20GB Disk Space** + +--- + +### Step-by-Step Deployment + +#### 1. Clone Repository +```bash +git clone https://transfer.hft-stuttgart.de/gitlab/22baar1mst/flowise-ollama.git +cd flowise-ollama +``` + +#### 2. Configure Environment +Create `.env` file or copy from .env.Example: +```ini +# Database +DATABASE_NAME=flowise +DATABASE_USER=admin +DATABASE_PASSWORD=SecurePass123! +DATABASE_TYPE=postgres +DATABASE_PORT=5432 + +# Flowise +PORT=3000 +FLOWISE_USERNAME=admin +FLOWISE_PASSWORD=AdminSecure456! + +# Ollama +HF_TOKEN=your_huggingface_token +GIN_MODE=release +``` + +Don't forget to register and use credentials for +HF_TOKEN= +LANGCHAIN_API_KEY= + + +#### 3. Start Services +```bash +docker-compose up -d --build +``` +*This will:* +- Launch PostgreSQL database with persistent storage +- Start Flowise with Ollama integration +- Automatically load specified LLM models + +#### 4. Verify Services +```bash +docker ps -a +``` +Expected output: +``` +CONTAINER ID IMAGE STATUS PORTS +a1b2c3d4e5f6 flowiseai/flowise:latest Up 5 minutes (healthy) 0.0.0.0:3000->3000/tcp +g7h8i9j0k1l2 postgres:16-alpine Up 5 minutes (healthy) 5432/tcp +m3n4o5p6q7r8 ollama Up 5 minutes 0.0.0.0:11434->11434/tcp +``` + +#### 5. Access Flowise UI +1. Open `http://localhost:3000` in browser +2. Log in using credentials from `.env`: + - **Username**: `admin` + - **Password**: `AdminSecure456!` + +#### 6. Import Chatflow +1. Navigate to **Chatflows** → **Add New** +2. Import `Ollama_RAG_Chatflow.json` (drag-and-drop or use file picker) +3. Configure RAG parameters: + ```json + { + "model": "llama2-uncensored", + "temperature": 0.7, + "max_tokens": 500 + } + ``` + +#### 7. Test Ollama Integration +```bash +curl http://localhost:11434/api/tags +``` +Expected response: +```json +{"models":[{"name":"llama2-uncensored","modified_at":"2024-03-15T12:34:56.789Z"}]} +``` + +--- + +### Key Endpoints +| Service | URL | Port | +|---------|-----|------| +| Flowise UI | `http://<server-ip>:3000` | 3000 | +| Ollama API | `http://<server-ip>:11434` | 11434 | +| PostgreSQL | `postgres://admin:SecurePass123!@localhost:5432/flowise` | 5432 | + +--- + +### Troubleshooting +1. **Healthcheck Failures**: + ```bash + docker logs flowiseai --tail 50 + docker exec -it flowise-db psql -U admin -d flowise + ``` + +2. **Model Loading Issues**: + ```bash + docker exec ollama ollama list + docker exec ollama ollama pull llama2-uncensored + ``` + +3. **Port Conflicts**: + Update `PORT` in `.env` and restart: + ```bash + docker-compose down && docker-compose up -d + ``` + +--- + +### Security Recommendations +1. Add Nginx reverse proxy with SSL +2. Implement IP whitelisting for `/api/v1` endpoints +3. Rotate database credentials monthly +4. Monitor Ollama GPU utilization: + ```bash + docker stats ollama + ``` + +This deployment provides a fully functional educational chatbot system with RAG capabilities. For advanced configuration, refer to [Flowise-Ollama Integration Guide](https://github.com/ArtemBaranovsky/flowise-ollama). \ No newline at end of file -- GitLab