Why Self-Hosted?
Most customer support automation guides point you to Zendesk, Intercom, or Freshdesk. They're great products — but they come with per-seat pricing that can crush a small business budget. At $49-99/agent/month, a 3-person support team costs $1,800-3,600/year before you even start customizing.
What if you could build the same thing with open-source tools, running on a $20/month VPS?
Here's the architecture I keep coming back to. It handles WhatsApp as the primary channel, stores everything in a real database (not spreadsheets), and automates the entire pipeline from first contact to resolution.
The Stack
| Component | Tool | Role | Cost |
|---|---|---|---|
| Automation Engine | n8n (self-hosted) | Workflow orchestration | Free (open-source) |
| Database | Supabase (self-hosted) | Customer data, ticket tracking | Free (open-source) |
| Messaging | WhatsApp Business API | Customer communication | ~$0.05/conversation |
| AI | OpenAI API | Intent classification | ~$0.01/request |
| Hosting | Any VPS (Hetzner, DigitalOcean) | Infrastructure | ~$20/month |
Total: ~$25/month vs $150+/month for SaaS equivalents.
Architecture Overview
Customer (WhatsApp) -> WAHA/Cloud API -> n8n Webhook
-> Router Node (by intent)
-> FAQ: AI Response -> Send Reply
-> Appointment: Check Calendar -> Book -> Confirm
-> Complaint: Create Ticket -> Notify Team
-> Sales: Qualify Lead -> CRM Entry -> Assign Agent
-> Supabase (PostgreSQL)
Step 1: Set Up the WhatsApp Webhook
Configure your WhatsApp API (Meta Cloud API or WAHA for self-hosted) to send incoming messages to an n8n webhook:
// n8n Webhook Node Configuration
{
"httpMethod": "POST",
"path": "whatsapp-support",
"responseMode": "onReceived",
"responseCode": 200
}
The webhook receives: from (phone number), body (message text), timestamp, and type (text, image, document).
Step 2: Intent Classification with AI
// n8n Function Node
const message = $input.first().json.body;
const prompt = 'Classify this customer message into ONE category: FAQ, APPOINTMENT, COMPLAINT, SALES, OTHER. Message: "' + message + '"';
return [{ json: { prompt, originalMessage: message } }];
This costs ~$0.001/message and runs in under 500ms. Handles Hebrew, English, and mixed languages automatically.
Step 3: Database Schema (Supabase)
CREATE TABLE customers (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
phone TEXT UNIQUE NOT NULL,
name TEXT,
first_contact TIMESTAMPTZ DEFAULT NOW(),
last_contact TIMESTAMPTZ DEFAULT NOW(),
total_interactions INT DEFAULT 1
);
CREATE TABLE tickets (
id SERIAL PRIMARY KEY,
customer_id UUID REFERENCES customers(id),
category TEXT NOT NULL,
message TEXT NOT NULL,
status TEXT DEFAULT 'open',
priority TEXT DEFAULT 'normal',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE messages (
id SERIAL PRIMARY KEY,
customer_id UUID REFERENCES customers(id),
direction TEXT NOT NULL,
content TEXT NOT NULL,
channel TEXT DEFAULT 'whatsapp',
created_at TIMESTAMPTZ DEFAULT NOW()
);
Step 4: The Router Workflow
Use a Switch node after AI classification:
- FAQ: Match FAQ database -> AI response -> Send via WhatsApp
- Appointment: Parse date -> Check calendar -> Book -> Confirm
- Complaint: Create ticket -> Notify team -> Acknowledge
- Sales: Qualify lead -> CRM entry -> Assign agent
Step 5: Upsert Customer Records
// n8n Supabase Node
{
"operation": "upsert",
"table": "customers",
"conflictColumn": "phone",
"data": {
"phone": "{{ $json.from }}",
"name": "{{ $json.profile_name }}",
"last_contact": "{{ $now }}"
}
}
Step 6: Automated Follow-ups
Set up n8n Cron triggers for:
- 24-hour open ticket alerts
- Post-resolution satisfaction surveys
- 48-hour lead re-engagement
Production Considerations
- Rate limiting: Start with 250 business-initiated conversations/24h
- Error handling: Fall back to templates if AI fails
- Monitoring: Use n8n execution logs + alerts for failed webhooks
-
Backup: Standard
pg_dumpvia n8n cron job
What to Expect
The main benefit of this setup isn't some magical metric — it's that every customer message gets an instant acknowledgment, even at 3am. That alone changes the dynamic. Customers feel heard, and the business owner isn't chained to their phone.
The AI intent classification handles routine questions (hours, pricing, directions) without human involvement. More complex issues get routed to the right person with full context. It's not "80% automation" — it's "the simple stuff happens automatically, and the hard stuff gets escalated properly."
What's Next?
Extend with voice note transcription (Whisper), image processing (vision AI), multi-language support, and analytics dashboards (Metabase).
The key insight: you don't need enterprise software for enterprise-grade support.
Building automation systems for small businesses at Achiya Automation. Try n8n — it's free and open source. We specialize in WhatsApp bots, workflow automation, and AI agents — all self-hosted, no vendor lock-in.
Over to You
If you could only self-host ONE tool in your support stack, which would it be — the automation engine, the database, or the customer inbox?
I chose the inbox first (Chatwoot). That was a mistake. The automation engine should come first because without it, you're just self-hosting a fancy email client.
Here's what I'm still figuring out: at what volume does Chatwoot start struggling? I've seen slowdowns around 10K conversations/month on a 4GB VPS. Anyone running it at higher scale?
Share your self-hosted support stack below — I'll tell you what I'd change. 👇
Top comments (0)