Documentation Index Fetch the complete documentation index at: https://chatbotx.io/docs/llms.txt
Use this file to discover all available pages before exploring further.
ChatbotX exposes three services that need to be proxied:
Service Internal port Recommended subdomain Builder (web UI + API)3123app.yourdomain.comPartySocket (WebSocket)1999ws.yourdomain.comStorage (S3 API + assets)9000cdn.yourdomain.com
The steps below are written for Ubuntu / Debian . Package and path names differ slightly on RHEL-based distros (dnf instead of apt, /etc/nginx/conf.d/ instead of /etc/nginx/sites-available/).
Installation
Install Nginx and Certbot
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx
Create the webroot directory
sudo mkdir -p /var/www/certbot
Create a temporary HTTP config
Create /etc/nginx/sites-available/chatbotx with a minimal config that lets Certbot complete the ACME challenge: /etc/nginx/sites-available/chatbotx
server {
listen 80 ;
server_name app.yourdomain.com ws.yourdomain.com cdn.yourdomain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
Enable it and reload: sudo ln -s /etc/nginx/sites-available/chatbotx /etc/nginx/sites-enabled/chatbotx
sudo nginx -t && sudo systemctl reload nginx
Obtain TLS certificates
sudo certbot certonly --webroot -w /var/www/certbot \
-d app.yourdomain.com \
-d ws.yourdomain.com \
-d cdn.yourdomain.com \
--email you@yourdomain.com \
--agree-tos --non-interactive
Certificates are saved to /etc/letsencrypt/live/<domain>/.
Replace with the full HTTPS config
Overwrite /etc/nginx/sites-available/chatbotx with the configuration below. Secure (recommended)
Simple
# ── Builder ────────────────────────────────────────────────
server {
listen 80 ;
server_name app.yourdomain.com;
return 301 https://$ host $ request_uri ;
}
server {
listen 443 ssl;
server_name app.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 100M ;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
location / {
proxy_pass http://localhost:3123;
proxy_http_version 1.1 ;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
}
}
# ── PartySocket ────────────────────────────────────────────
server {
listen 80 ;
server_name ws.yourdomain.com;
return 301 https://$ host $ request_uri ;
}
server {
listen 443 ssl;
server_name ws.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/ws.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ws.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:1999;
proxy_http_version 1.1 ;
proxy_set_header Upgrade $ http_upgrade ;
proxy_set_header Connection "upgrade" ;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
proxy_read_timeout 3600s ;
proxy_send_timeout 3600s ;
}
}
# ── Storage ────────────────────────────────────────────────
server {
listen 80 ;
server_name cdn.yourdomain.com;
return 301 https://$ host $ request_uri ;
}
server {
listen 443 ssl;
server_name cdn.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/cdn.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cdn.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 1G ;
location / {
proxy_pass http://localhost:9000;
proxy_http_version 1.1 ;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
}
}
Test and reload Nginx
sudo nginx -t && sudo systemctl reload nginx
Enable automatic certificate renewal
Certbot installs a systemd timer by default. Verify it is active: sudo systemctl status certbot.timer
Add a reload hook so Nginx picks up renewed certificates automatically: echo -e '#!/bin/sh\nsystemctl reload nginx' | sudo tee /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
ChatbotX configuration
Update your .env to use the public HTTPS URLs and restart the services:
NEXT_PUBLIC_BUILDER_URL = https://app.yourdomain.com
NEXT_PUBLIC_PARTYSOCKET_URL = https://ws.yourdomain.com
BETTER_AUTH_URL = https://app.yourdomain.com
NEXT_PUBLIC_ASSET_URL = https://cdn.yourdomain.com/chatbotx/public/
S3_ENDPOINT = https://cdn.yourdomain.com
NEXT_PUBLIC_BUILDER_URL and BETTER_AUTH_URL must match exactly. A mismatch causes authentication callbacks to fail.
WebSocket support
PartySocket requires the Upgrade and Connection headers to be forwarded. The secure config above includes these on the ws.yourdomain.com server block. The extended proxy_read_timeout and proxy_send_timeout values (3600s) prevent Nginx from closing long-lived WebSocket connections.
Storage (RustFS / S3)
The storage service runs on port 9000. Proxying it through Nginx gives you HTTPS asset URLs. Set client_max_body_size to a value larger than your largest expected upload — the example uses 1G.
The storage console (port 9001) does not need to be publicly exposed. Access it directly on the server via an SSH tunnel or restrict it to a local interface.