Chatfuel

Deploy Your Chatfuel Wizard App: Vercel, Node.js or Docker

Deploy the Chatfuel wizard app to Vercel, your own Node.js server or Docker, decide who may reach it, and fix the two setups the server refuses to run.

Last updated on

The app the Chatfuel wizard writes runs on Vercel, on your own Node.js server or in Docker, from the same code. The host decides who manages TLS and how long a WebSocket stays open; it does not decide who may use the app. That second question comes first, because the app talks to Chatfuel with your personal API token: whoever reaches the app acts with that token's access unless the auth module asks them to sign in.

How to deploy to Vercel

The wizard offers a Vercel deploy at the end of its run. Later, run it from the app directory:

npm run deploy

The deploy script (scripts/deploy-vercel.mjs in your app) uses the Vercel CLI: it checks that you are signed in, links the project, pushes the variables from your .env to the Vercel project, deploys and asks the new deployment whether it came up configured. Your local .env file is never uploaded; the variables live in the Vercel project.

  • Requests: the proxy runs as a Vercel function behind a rewrite of /chatfuel/*.
  • Live updates: a WebSocket lasts as long as the function's maximum duration, then the app reconnects on its own.
  • Path: the app is served from the domain root; a sub-path such as /app/ needs a Node.js server or Docker.

How to run the app on your own Node.js server

npm run build && npm start

npm run build builds the browser app and the server. npm start runs one Node.js server that serves the built app and the /chatfuel/* proxy on port 3000 (set PORT to change it, HOST to choose the interface). Put a reverse proxy with TLS, such as nginx or Caddy, in front of it.

How to run the app in Docker

The app ships with a Dockerfile that builds the app and starts the same Node.js server on port 3000. Pass the public VITE_* values as build arguments and every secret at runtime, for example with docker run --env-file .env. Never pass CHATFUEL_TOKEN or another secret as a build argument: build arguments stay readable in the image.

Who may reach the deployed app

Without the auth module the app has no sign-in: the proxy forwards every request it receives under your personal API token. Anyone who opens the URL can read conversations and contacts, send messages as the bot and change settings, even though the token itself never leaves the server. That setup suits a tool for your own team, kept off the public internet:

  • on a VPN, a Tailscale or WireGuard network, or behind an office IP allowlist;
  • behind your host's access control, such as Vercel Deployment Protection, nginx auth_basic or Cloudflare Access;
  • on localhost only, which is what npm run dev gives you.

An app that customers or staff open from the internet needs the auth module: each person signs in with your Supabase project before the proxy forwards anything. Add it with npx @chatfuel/wizard --embed. Wizard modules describes auth.

Which setups the server refuses to run

The server refuses two setups instead of warning about them. npm start prints REFUSING TO SERVE and does not start, the Vite dev server with --host stops before it mounts the proxy, and the Vercel function answers 503 with the code ProxyRefusedToServe to everything except the health check.

  • No sign-in on a host that is not loopback. The server listens on all interfaces by default, and without auth anyone who can reach it drives your token. Fix it one of three ways: install the auth module, bind to loopback with HOST=127.0.0.1, or, when something in front of the app already authenticates every visitor, set CHATFUEL_OPEN_PROXY=1 to confirm the open setup is intended.
  • ALLOWED_ORIGINS=* on a host that is not loopback, with or without sign-in. Set ALLOWED_ORIGINS to the origins that serve the app, separated by commas, for example https://app.example.com. CHATFUEL_OPEN_PROXY does not cover this case.

How to check a deployment and protect the admin panel

/chatfuel/healthz answers on every host. It returns {"ok":true} with status 200 when the server is configured, or {"ok":false} with 503 when the configuration has a problem. An HTML page in reply means the path is wrong.

The admin module adds a panel at /admin that can change the whole account behind the token. ADMIN_PASSWORD is its only protection and must be at least 16 characters, or the panel refuses to run. With the auth module installed, also set SUPABASE_SERVICE_ROLE_KEY so every server instance shares one count of wrong passwords; on Vercel, where any warm instance may answer, the count is otherwise kept per instance.

Rules every host must follow

  • Unknown paths answer with index.html. Every screen has a real address, such as /deals, and a reload must return to it. The Node.js server and the shipped vercel.json already do this; on nginx use try_files $uri /index.html;.
  • VITE_* variables are fixed at build time, every other variable is read by the server at runtime. After changing a VITE_* value, rebuild. A browser app built with Supabase settings and a server started without them, or the other way round, fails at sign-in with ProxyAuthMisconfigured or AuthSessionRequired.
  • Secrets stay on the server. Nothing named VITE_* may hold a secret, because those values are compiled into the browser code.

Common issues

REFUSING TO SERVE: open mode on a host that is not loopback

The server runs without the auth module on an address others can reach. Install auth, set HOST=127.0.0.1, or set CHATFUEL_OPEN_PROXY=1 when your own access control already sits in front of the app.

REFUSING TO SERVE: ALLOWED_ORIGINS is '*'

Replace * with the exact origins of your app, for example ALLOWED_ORIGINS=https://app.example.com, and restart the server.

ADMIN_PASSWORD must be at least 16 characters. Set a longer one and restart.

The admin panel refuses a short password. Set a longer ADMIN_PASSWORD in the server environment, or in the Vercel project, and restart or redeploy.

On this page