Self-hosted AI website support assistant β a fully functional RAG-based chat widget that learns from your data, deployable with a single command.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WEBSITE (any site) β
β <script src="stackpilot.try.direct/widget.js"></script> β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β STACKPILOT API (FastAPI) β
β β’ Widget endpoint β’ Admin dashboard β’ RAG pipeline β
βββββ¬βββββββββββ¬βββββββββββ¬βββββββββββ¬βββββββββββββββββββββββββ
βΌ βΌ βΌ βΌ
ββββββββββ ββββββββββ ββββββββββ ββββββββββββββ
βPostgresβ β Redis β βOllama β β n8n β
β+pgvec β β β β β β β
ββββββββββ ββββββββββ ββββββββββ ββββββββββββββ
stacker install stackpilot
stacker deploy --target cloud --key htz-0- Embeddable chat widget β one
<script>tag adds AI support to any website - RAG-powered answers β semantic search over your knowledge base using pgvector
- Website crawler β automatically ingests your site content into the knowledge base
- Self-hosted AI β runs Ollama locally, no OpenAI/Anthropic API keys needed
- Conversation learning β stores chat history, tracks feedback, improves over time
- Workflow automation β escalates low-confidence answers via n8n webhooks
- Admin dashboard β manage knowledge base, view conversations, pull models
- Production-ready β Nginx Proxy Manager with auto-SSL, health checks, status panel
| Service | Image | Purpose |
|---|---|---|
| app | Custom Python (FastAPI) | API, RAG pipeline, admin dashboard, widget |
| stackpilot-db | pgvector/pgvector:0.8.0-pg16 |
Knowledge base vectors + conversation history |
| stackpilot-redis | redis:7-alpine |
Caching, rate limiting, session store |
| stackpilot-ollama | ollama/ollama:latest |
Self-hosted LLM inference + embeddings |
| stackpilot-n8n | n8nio/n8n:latest |
Workflow automation, escalation, notifications |
| nginx-proxy-manager | jc21/nginx-proxy-manager:latest |
Reverse proxy with auto-SSL |
- A server with Docker and Docker Compose installed
- At least 2GB RAM + 2GB swap (8GB+ recommended for running larger LLMs)
- (Optional) A domain pointed at your server for SSL
Quick server setup (installs Docker, creates swap):
./scripts/setup-server.sh YOUR_SERVER_IPgit clone https://github.com/trydirect/awesome-selfhosted-stacker.git
cd awesome-selfhosted-stacker/stacker-projects/stackpilot
# Generate secrets
cp .env.example .env
./scripts/generate-secrets.sh
# Deploy to your server
stacker deploygit clone https://github.com/trydirect/awesome-selfhosted-stacker.git
cd awesome-selfhosted-stacker/stacker-projects/stackpilot
# Copy compose file and build
cp .stacker/docker-compose.yml .
docker compose up -d --build-
Open the admin dashboard
http://YOUR_SERVER_IP:8080/api/admin/dashboard -
Sign in with the
ADMIN_PASSWORDfrom your.envfile -
Pull AI models β go to the Ollama tab and pull:
llama3.1β the LLM for generating responsesnomic-embed-textβ the embedding model for semantic search
-
Build your knowledge base β go to the Websites tab and crawl your website:
https://your-website.comOr add documents manually via the Knowledge Base tab.
-
Embed the widget on your website:
<script src="http://YOUR_SERVER_IP:8080/api/widget/widget.js"></script>
-
(Optional) Set up SSL β configure Nginx Proxy Manager at port
81to route your domain to the app.
All configuration is via environment variables in .env:
| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
auto-generated | Session signing key |
DB_PASSWORD |
auto-generated | PostgreSQL password |
ADMIN_PASSWORD |
auto-generated | Dashboard login password |
N8N_PASSWORD |
auto-generated | n8n basic auth password |
OLLAMA_MODEL |
llama3.1 |
LLM model for generating responses |
OLLAMA_EMBED_MODEL |
nomic-embed-text |
Embedding model for vector search |
DEPLOY_HOST |
β | Server IP for Stacker deployment |
BASE_PATH |
β | Local project path for Stacker |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/widget/chat |
Send a message, get an AI response |
GET |
/api/widget/widget.js |
Embeddable chat widget JavaScript |
POST |
/api/widget/feedback |
Submit feedback on a conversation |
POST |
/api/widget/resolve |
Mark a conversation as resolved |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/admin/stats |
Dashboard statistics |
GET |
/api/admin/dashboard |
Admin dashboard HTML |
POST |
/api/admin/login |
Authenticate |
POST |
/api/admin/logout |
Sign out |
GET |
/api/admin/documents |
List knowledge base documents |
POST |
/api/admin/documents |
Add a document |
DELETE |
/api/admin/documents/{id} |
Remove a document |
GET |
/api/admin/websites |
List crawled websites |
POST |
/api/admin/websites |
Register a website |
POST |
/api/admin/websites/crawl |
Start crawling a website |
DELETE |
/api/admin/websites/{id} |
Remove a website |
GET |
/api/admin/conversations |
List conversations |
GET |
/api/admin/ollama/status |
Check Ollama health + installed models |
POST |
/api/admin/ollama/pull |
Pull a new model |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/webhooks/n8n |
n8n callback for escalation events |
POST |
/api/webhooks/ingest |
External content ingestion endpoint |
1. Visitor asks a question on your website
β
2. widget.js sends message to /api/widget/chat
β
3. Query is embedded using nomic-embed-text via Ollama
β
4. pgvector performs cosine similarity search (top-K results)
β
5. Retrieved documents are injected into the prompt as context
β
6. llama3.1 generates a response using the context
β
7. Response is returned to the visitor in real-time
β
8. Conversation is stored for analytics and learning
β
9. If confidence < 0.3 β escalation via n8n webhook
Website URL β Crawler β Text extraction β Chunking (500 tokens)
β Embedding (nomic-embed-text) β pgvector storage
Documents are automatically chunked into 500-token pieces with 100-token overlap for context continuity.
deploy:
target: localdeploy:
target: server
server:
host: ${DEPLOY_HOST}
user: root
ssh_key: ${BASE_PATH}/stacker-project-testdeploy:
target: cloud
cloud:
provider: hetzner
region: fsn1
size: cpx32
public_ports:
- "80"
- "443"
- "8080"
- "5678"| Service | External Port | Internal Port | Purpose |
|---|---|---|---|
| StackPilot App | 8080 |
8000 |
API + Dashboard + Widget |
| Nginx Proxy Manager | 80, 443, 81 |
80, 443, 81 |
Reverse proxy + SSL + admin |
| n8n | 5678 |
5678 |
Workflow automation |
| Ollama | 11434 |
11434 |
LLM inference |
| PostgreSQL | internal | 5432 |
Database |
| Redis | internal | 6379 |
Cache |
Check logs:
docker logs stackpilot-app-1 --tail 50Common issues:
- Database connection error β PostgreSQL may still be starting. The app retries automatically for 60 seconds.
invalid DSNβ EnsureDATABASE_URLusespostgresql://(notpostgresql+asyncpg://).
- Ensure the
<script>tag points to the correct URL - Check browser console for CORS errors
- Verify the app is running:
curl http://YOUR_IP:8080/health
docker exec stackpilot-stackpilot-ollama-1 ollama listIf no models are listed, pull them via the dashboard or:
docker exec stackpilot-stackpilot-ollama-1 ollama pull llama3.1
docker exec stackpilot-stackpilot-ollama-1 ollama pull nomic-embed-textEnsure the proxy host forward hostname is set to app (not stackpilot-app).
stackpilot/
βββ stacker.yml # Stacker deployment config
βββ .env.example # Environment template
βββ Dockerfile # Python backend build
βββ requirements.txt # Python dependencies
βββ scripts/
β βββ generate-secrets.sh # Secret generation
β βββ download-model.sh # Pre-pull Ollama models
β βββ seed-knowledge.sh # Crawl a URL into KB
βββ app/
βββ main.py # FastAPI entry point
βββ config.py # Settings from env vars
βββ database.py # asyncpg + pgvector setup
βββ models.py # Pydantic schemas
βββ knowledge.py # KB CRUD, crawling, chunking
βββ rag.py # RAG pipeline, Ollama, n8n
βββ routes/
β βββ widget.py # Chat API + widget.js
β βββ admin.py # Dashboard, KB management
β βββ webhooks.py # n8n + ingestion webhooks
βββ templates/
βββ dashboard.html # Admin SPA
MIT