flag92 flag92
Deploy

Run Chatwoot + Dify on Cloudflare + your own VPS

Cloudflare handles DNS, WAF and Tunnel; the VPS runs the core services. From zero to live in about 90 minutes.

Cloudflare + VPS (Hetzner / DigitalOcean / Vultr) 90 min

Prerequisites#

  • A 4 vCPU / 8 GB VPS (Ubuntu 24.04)
  • A domain on Cloudflare (e.g. support.yourdomain.com, dify.yourdomain.com)
  • An LLM provider API key (OpenAI / Anthropic / Qwen / etc.)

Step 1 — Install Docker & Compose#

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Step 2 — Expose services via Cloudflare Tunnel#

Skip opening 80/443 directly — route everything through Cloudflare Tunnel:

docker run -d --name cloudflared --network host \
  cloudflare/cloudflared:latest tunnel --no-autoupdate run --token <YOUR_TOKEN>

In Cloudflare Zero Trust, add public hostnames for support.yourdomain.comhttp://localhost:3000 and dify.yourdomain.comhttp://localhost:5001.

Step 3 — Bring up Dify#

git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
# Edit .env — set CONSOLE_WEB_URL and APP_API_URL to https://dify.yourdomain.com
docker compose up -d

Open https://dify.yourdomain.com, register the admin, configure a model, create a Chatbot app, upload knowledge, publish, copy the API key.

Step 4 — Bring up Chatwoot#

git clone https://github.com/chatwoot/chatwoot.git
cd chatwoot
cp .env.example .env
# Edit .env — FRONTEND_URL=https://support.yourdomain.com
docker compose -f docker-compose.production.yaml run --rm rails bundle exec rails db:chatwoot_prepare
docker compose -f docker-compose.production.yaml up -d

Open https://support.yourdomain.com, register, create an account and an inbox.

Step 5 — Wire Dify as Chatwoot’s Agent Bot#

Settings → Agent Bots → New:

  • Outgoing URL — https://dify.yourdomain.com/v1/chat-messages
  • Header — Authorization: Bearer app-xxxxxxxx

Then in your target inbox, set this bot as the fallback.

Step 6 — Verify#

Send a message through the website widget; the bot should reply, and Dify’s logs should show the call.

Common pitfalls#

  • Chatwoot can’t send mail — use Postmark / SES SMTP; MAILER_SENDER_EMAIL must match the verified sender domain
  • Slow Chinese embeddings — switch to bge-m3 or use SiliconFlow’s free tier
  • Cloudflare Tunnel returns 502 — make sure containers listen on 0.0.0.0, not 127.0.0.1

Search

Press ⌘ K to open