Deploy on a public server
This guide takes a Helpin installation from localhost to your own domains with HTTPS. By default, Helpin runs its own Caddy proxy, which gets and renews certificates automatically, so you only need DNS and two open ports. If you already run nginx, Traefik, or a load balancer, you can use that instead.
What you'll set up
Hostname (example) | Serves | Upstream |
|---|---|---|
| Staff dashboard, API, and chat widget |
|
| Public help center |
|
| Attachments and images |
|
The widget shares the dashboard hostname by default.
1. Point DNS at your server
Create A records for all three hostnames with your server's IP address. Add AAAA records only if IPv6 actually works on the server. A CNAME must point to a hostname, not a URL.
Open ports 80 and 443 at your firewall or cloud security group. Nothing else needs to be public.
2. Configure Helpin for server mode
helpin configure --dir /srv/helpin --mode server
The wizard asks for:
The three hostnames above.
How HTTPS is handled. Choose
builtin(the default) and Helpin runs Caddy on ports 80 and 443. It trusts only that proxy's fixed address, so there's nothing to look up. Optionally pass--acme-email you@example.comfor certificate expiry notices. Chooseexternalto use your own proxy (see step 3).
Using your own proxy? The wizard also asks for the exact IP or CIDR your proxy appears from, as seen by Helpin's ingress container. For a proxy on the same host, that's usually the Docker network's gateway, not 127.0.0.1. Find it with:
docker network inspect "$(docker network ls -q --filter name=helpin | head -1)" \
--format '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
Never use
0.0.0.0/0. Helpin trusts forwarded client IPs and protocol only from this address. That protects rate limits and HTTPS detection.
This writes the public URLs to .env and generates community/Caddyfile. With built-in HTTPS, skip to step 4. Ports 80 and 443 must be free on the server, so stop any existing web server first.
3. Using your own proxy (optional)
Caddy on the host
Caddy obtains and renews certificates automatically. Install the generated file as your Caddy configuration, or merge it into an existing one:
app.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8085
}
help.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8086
}
files.example.com {
# Keep the Host header: signed file URLs depend on it
reverse_proxy 127.0.0.1:9005
}
Reload Caddy, and make sure its data directory is persistent so certificates survive restarts.
nginx
nginx works too. For each hostname, proxy to the same upstreams and:
Forward WebSockets:
proxy_set_header Upgrade $http_upgrade;andproxy_set_header Connection "upgrade";Disable buffering for streaming responses:
proxy_buffering off;Allow long-lived connections:
proxy_read_timeout 3600s;Preserve the
Hostheader, and setX-Forwarded-Proto. Replace, don't append, any incoming forwarded headers.
server {
listen 443 ssl http2;
server_name app.example.com;
# ssl_certificate ... ssl_certificate_key ...
location / {
proxy_pass http://127.0.0.1:8085;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_read_timeout 3600s;
}
}
4. Apply and verify
helpin restart --dir /srv/helpin
helpin doctor --dir /srv/helpin
With built-in HTTPS, Caddy requests certificates on first start. That only succeeds once your DNS records point at this server and ports 80 and 443 are reachable from the internet. Watch progress with helpin logs caddy.
Doctor checks public HTTPS with normal certificate validation and confirms the public API matches this installation. Then test the parts doctor can't:
Sign in at
https://app.example.com.Add a real website's origin in Settings → Chat widget, embed the snippet there, and exchange messages live.
Send an attachment in both directions.
Confirm a site that isn't on the allowed list receives
403.
5. Finish setup
Publish your help center on
help.example.com, or under a path on your website.Connect GitHub. This needs the public HTTPS URL you just set up.
Work through the security checklist.
Schedule backups.
Never expose these
PostgreSQL, Redis, NATS, Temporal, Agent Runtime, the storage console, and /api/internal/ routes must stay private. The published ports bind to 127.0.0.1. Keep it that way, and put a containerized proxy on an explicitly private network.
Troubleshooting
Problem | Check |
|---|---|
Certificate errors | DNS A/AAAA records, ports 80/443 reachable, and Caddy's persistent storage |
Dashboard loads, but live updates don't | WebSocket headers, buffering, and read timeout on the proxy |
Wrong client IPs or HTTP links |
|
Attachments fail |
|
Can't reach the dashboard |
|
With built-in HTTPS:
"Port 80 (or 443) is already in use": another web server is running. Stop it, or choose
--proxy externaland put Helpin behind it.Certificates aren't issued: check
helpin logs caddy. Let's Encrypt must reach port 80 or 443 on every hostname, so check DNS and your cloud firewall.Network address conflict on start: the bundled proxy network uses
172.30.255.0/28. If that collides with an existing network, changeEDGE_SUBNET,EDGE_IP_RANGE, andEDGE_PROXY_IPin.env. The proxy address must be inside the subnet but outside the range. Then runhelpin configureandhelpin restart.
Was this article helpful?