Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/EllisYuan/ChatAgents/llms.txt

Use this file to discover all available pages before exploring further.

In development, the Streamlit frontend (port 8501) and FastAPI backend (port 8080) are accessed directly. In production you almost always want a single public-facing domain, HTTPS termination, and correct handling of Streamlit’s persistent WebSocket connection — all of which Nginx handles cleanly as a reverse proxy. This guide walks through copying the bundled config template, customising it for your domain and ports, and verifying the deployment.

Prerequisites

  • Docker containers already running (see the Docker deployment guide)
  • Nginx installed on the host (sudo apt install nginx on Ubuntu/Debian)
  • A domain name with its DNS A record pointing to the server’s IP address
  • An SSL certificate — Let’s Encrypt / Certbot is recommended for free automated certificates

Setup

1

Start the Docker containers

Build images and start both services in detached mode:
docker-compose up -d --build
Confirm both containers are healthy before proceeding:
docker ps | grep chatbot
# chatbot-backend   ... (healthy)
# chatbot-frontend  ... Up
2

Copy the Nginx config template

The repository ships a ready-to-use example at docs/nginx.conf.example:
sudo cp docs/nginx.conf.example /etc/nginx/sites-available/chatbot.conf
BaoTa Panel users — copy to the panel’s vhost directory instead:
sudo cp docs/nginx.conf.example /www/server/panel/vhost/nginx/your-domain.conf
3

Edit the config

Open the file and update the three required values:
sudo vim /etc/nginx/sites-available/chatbot.conf
PlaceholderReplace with
your-domain.comYour actual domain name
/path/to/fullchain.pemPath to your SSL certificate
/path/to/privkey.pemPath to your SSL private key
If you changed BACKEND_PORT or FRONTEND_PORT in .env (defaults are 8080 / 8501), update the proxy_pass port numbers in every location block accordingly.
4

Enable the config

Create a symlink so Nginx loads the config on startup:
sudo ln -s /etc/nginx/sites-available/chatbot.conf /etc/nginx/sites-enabled/
BaoTa Panel users can skip this step — the panel manages symlinks automatically.
5

Test and reload Nginx

Always test the config syntax before reloading to avoid downtime:
sudo nginx -t && sudo systemctl reload nginx
A successful test outputs:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
6

Verify the deployment

Hit the backend health endpoint through Nginx to confirm the full path is working:
curl https://your-domain.com/health
# Expected: {"message":"后端 API 正在运行","status":"healthy"}
Then open https://your-domain.com in a browser — Streamlit should load without WebSocket errors.

Nginx configuration explained

The bundled docs/nginx.conf.example contains three groups of location blocks. Here is the full file for reference:
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    # SSL certificate configuration
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    # SSL security settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # Logging
    access_log /var/log/nginx/chatbot.access.log;
    error_log /var/log/nginx/chatbot.error.log;

    # ==================== Backend API ====================
    location /health {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8080;  # No trailing slash — full path preserved
        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;
    }

    # Streaming responses (SSE)
    location /stream_agent {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        chunked_transfer_encoding on;
    }

    # ==================== Frontend Streamlit ====================
    location /_stcore/stream {
        proxy_pass http://127.0.0.1:8501/_stcore/stream;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 86400;
    }

    location /_stcore/health {
        proxy_pass http://127.0.0.1:8501/_stcore/health;
        proxy_set_header Host $host;
    }

    location / {
        proxy_pass http://127.0.0.1:8501;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
Location blockProxies toPurpose
/healthFastAPI port 8080Backend health check used by Docker and monitoring
/api/FastAPI port 8080All session management REST endpoints
/stream_agentFastAPI port 8080Server-Sent Events streaming with buffering disabled
/_stcore/streamStreamlit port 8501Streamlit WebSocket — requires HTTP upgrade headers
/_stcore/healthStreamlit port 8501Streamlit internal health check
/Streamlit port 8501All other Streamlit traffic (pages, static assets)

WebSocket configuration

Streamlit uses a persistent WebSocket connection on /_stcore/stream to push UI updates to the browser. Without the upgrade headers, the browser falls back to polling and the page either hangs or shows a connection error. The required location block — taken directly from docs/nginx.conf.example:
location /_stcore/stream {
    proxy_pass http://127.0.0.1:8501/_stcore/stream;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 86400;
}
  • proxy_http_version 1.1 — required; HTTP/1.0 does not support persistent connections.
  • Upgrade $http_upgrade + Connection "upgrade" — signals to Nginx to pass the WebSocket handshake through to Streamlit.
  • proxy_read_timeout 86400 — 24-hour timeout keeps the WebSocket open for long-lived browser sessions.

Critical: proxy_pass trailing slash

The most common misconfiguration when setting up the /api/ route is adding a trailing slash to proxy_pass. Nginx strips the matched prefix when a trailing slash is present, breaking every API path.
A trailing slash on proxy_pass causes Nginx to strip the /api/ prefix, so /api/sessions becomes /sessions on the backend — which returns 404 because FastAPI registers it under /api/sessions.
# Wrong — trailing slash strips /api/ prefix
location /api/ {
    proxy_pass http://127.0.0.1:8080/;
}

# Correct — no trailing slash, full path is preserved
location /api/ {
    proxy_pass http://127.0.0.1:8080;
}

Streaming response timeout

ChatAgents streams long agent responses over SSE via /stream_agent. The default Nginx proxy_read_timeout is 60 seconds, which is too short for deep-thinking mode queries that may run for several minutes. The bundled config already sets this to 3600s for the /stream_agent location. If you are customising the config, ensure the streaming location includes:
location /stream_agent {
    proxy_pass http://127.0.0.1:8080;
    proxy_read_timeout 3600s;
    proxy_buffering off;
    proxy_cache off;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding on;
}
For shorter agent runs, a value of 300 (5 minutes) is a reasonable minimum.

Verification commands

# Test the backend health endpoint through Nginx
curl https://your-domain.com/health

# Test the session API endpoint through Nginx
curl https://your-domain.com/api/sessions

# Stream the Nginx error log in real time
sudo tail -f /var/log/nginx/chatbot.error.log

# Stream the Nginx access log in real time
sudo tail -f /var/log/nginx/chatbot.access.log

# Check Nginx process status
sudo systemctl status nginx
If you use non-default ports by setting BACKEND_PORT and FRONTEND_PORT in .env, update the proxy_pass target port numbers in chatbot.conf to match. For example, if BACKEND_PORT=9080 then every proxy_pass http://127.0.0.1:8080 for backend routes becomes proxy_pass http://127.0.0.1:9080.

Build docs developers (and LLMs) love