This guide explains how to deploy the askUOS chatbot using Docker Compose. Caddy is provided as a suggested reverse proxy, but you can use any reverse proxy of your choice (e.g., Nginx).
- Prerequisites
- Directory Structure
- Environment Variables (
.env.prod) - Backend Configuration (
backend_config.yaml) - UI Configuration (
ui_config.yml) - Streamlit Configuration (
config.toml) - Prompts Configuration (
prompt_text.py) - Caddy Configuration (
Caddyfile) - Optional - Deployment Steps
- Access Points
- Troubleshooting
- Updating
- Docker and Docker Compose installed on the server
- A domain name pointing to the server (e.g.,
chat.your-university.de) - SSL/TLS certificate (Caddy auto-provides via Let's Encrypt; configure separately for other proxies)
- Access to required API keys (see Environment Variables section)
- A RAGFlow instance
Create the installation directory:
sudo mkdir -p /opt/chatbot
cd /opt/chatbotThe following files and directories should be placed in /opt/chatbot/:
/opt/chatbot/
├── .env.prod # Environment variables (see below)
├── backend_config.yaml # Backend configuration
├── ui_config.yml # UI configuration
├── config.toml # Streamlit configuration
├── Caddyfile # Caddy reverse proxy config (optional)
├── datenschutz.html # Privacy policy page
├── impressum.html # Imprint/legal notice page
├── promtail-config.yml # Log collection config (optional)
├── config_loki.yml # Loki log storage config (optional)
Create .env.prod. Take a look at .env.prod.example
The Google API key must have access to:
- Custom Search API
- You need to configure a Programmable Search Engine and index the sites you want to search (e.g., the Website of your University). The engine endpoint should be configured in the
.env.prodfile asSEARCH_URL.
- You need to configure a Programmable Search Engine and index the sites you want to search (e.g., the Website of your University). The engine endpoint should be configured in the
- Generative Language API (If using Google as LLM provider)
- Vertex AI API (If using Google as LLM provider)
- The
STREAMLIT_API_KEYmust match one of the keys listed inAPI_KEYS(Follow same procedure to set up theHISTORY_API_KEYS). - Generate secure random strings for all API keys.
This file, backend_config.yaml, configures the models and other backend settings. See the example: backend_config_example.yaml.
To use the example configuration:
cp docs/backend_config_example.yaml ./backend_config.yaml
# Edit backend_config.yaml with your specific settingsThis file, ui_config.yml, configures the user interface settings. Follow this example: ui_example_config.yml.
To use the example configuration:
cp docs/ui_example_config.yml ./ui_config.yml
# Edit ui_config.yml with your specific settingsNote: For the icons, mount (to the container) your own custom icons to the /app/ui/static/icons/ directory with the same filenames: Icon-User.svg, Icon-chatbot.svg, Icon-chatbot.png.
[server]
enableStaticServing = true
[theme]
primaryColor = "#ad1034"
[client]
showErrorDetails = "none"
toolbarMode = "minimal"
showSidebarNavigation = false
[browser]
gatherUsageStats = falseaskUOS's wording — what the bot says, what it's allowed to answer, how tools are described to it — comes from three different places, each with a different audience. This guide explains which is which, so you edit the right one.
Where: src/chatbot/prompt/internal_prompt_text.py
These are implementation details of the graph's own control flow: a description field consumed only by an internal grading step's structured output, and a short internal message inserted when the graph corrects the agent's own decision. None of this text is ever shown to end users, and none of it defines the bot's behavior, tone, or scope — it only makes sense in the context of the exact Python code that reads it. That's why it's kept in Python source rather than a config file: there's nothing here a university admin needs, or should want, to customize. Changing it requires a code change and redeploy, same as any other application logic.
Where: prompts_example/ (copy to prompts/ to activate your changes)
This is the bot's actual personality and guardrails: the system prompts that define what it is, what it's allowed to talk about, how it should ask clarifying questions, and how it should use retrieved context — plus a couple of short, always-active tool descriptions. These apply to every installation regardless of which optional tools or MCP integrations are turned on, so every institution adopting askUOS should review and adjust these, not just leave the shipped University of Osnabrück wording in place.
Layout: one .md file per long prompt, per language (prompts/en/system_message.md, prompts/de/system_message.md, etc.), plus a short strings.yaml per language for the couple of always-on tool descriptions.
Rules when editing:
- Each file may contain
{placeholder}markers (e.g.{current_date},{user_query},{context}). These are filled in automatically at runtime — keep them, spelled exactly as they are, but feel free to move them to a different part of the text. - Deleting a placeholder or introducing a typo in its name makes the application fail to start, with an error naming the exact file and the missing/wrong placeholder. This is intentional: a wording mistake gets caught immediately, not discovered later as a broken or nonsensical answer.
- Changes require restarting (rebuilding) the app to take effect — there's no live reload.
Where: backend_config.yaml
Some prompts belong to one specific optional feature — a standalone tool or an MCP-connected subagent — and are meaningless outside that feature's own configuration block. These live next to the feature they describe in backend_config.yaml, not in prompts/, and you only need to fill them in if you actually enable that feature:
- Standalone tools, e.g. the troubleshooting tool:
graph: troubleshooting: activate: True # only if True is a description required description: | What this tool is for and when the agent should use it.
- MCP subagents, one block per agent under
mcp_agents::mcp_agents: - agent_name: "some_agent" enabled: True description: | # tells the main agent when to route a task to this subagent ... prompt: | # the system prompt for the subagent itself ...
If a tool/agent is disabled (activate: False / enabled: False), its prompt fields are ignored and don't need to be provided at all.
- Keep the structure: Maintain the overall structure and format of the prompts
- Preserve tool usage instructions: The chatbot relies on tools for accurate information
- Update both languages: Ensure both English and German sections are updated
- Test thoroughly: After customization, test the chatbot with common queries
| Type | Location | Who edits it | When needed |
|---|---|---|---|
| Internal | src/chatbot/prompt/internal_prompt_text.py |
Developers only | Never (not user-facing) |
| General application | prompts/ (from prompts_example/) |
Every installer | Always |
| Tool/MCP-specific | backend_config.yaml |
Every installer, per feature | Only if that tool/agent is activated |
Create docker-compose.yml:
The easiest way to install askUOS is using Docker Compose. Follow this example: docker-compose.prod.example.yml.
To use the example configuration:
cp docs/docker-compose.prod.example.yml ./docker-compose.yml
# Edit docker-compose.yml with your specific settings (e.g., image tag)If using Caddy as your reverse proxy, follow this example: Caddy.example.j2.
To use the example configuration:
cp docs/Caddy.example ./Caddyfile
# Edit Caddyfile with your domain nameIf you prefer Nginx, Traefik, or another reverse proxy, configure it to:
- Forward
/v1/*and/healthtolocalhost:8000(FastAPI backend) - Forward all other requests to
localhost:8501(Streamlit UI) - Handle SSL termination
- Serve static files (
datenschutz.html,impressum.html)
-
Clone or copy all configuration files to
/opt/chatbot/ -
Update environment variables in
.env.prodwith your actual API keys -
Generate secure authentication keys: Set
API_KEYSandSTREAMLIT_API_KEYin.env.prod. -
Customize prompts for your university
-
Configure your reverse proxy:
- If using Caddy, update the
Caddyfilewith your domain name - If using another proxy, configure it according to the routing rules above
- If using Caddy, update the
-
Start the services:
cd /opt/chatbot docker compose up -d -
Check service status:
docker compose ps
-
View logs:
docker compose logs -f app_name
| Service | URL |
|---|---|
| Chatbot UI | https://your-domain.de |
| API | https://your-domain.de/v1/* |
| Health Check | https://your-domain.de/health |
| Issue | Solution |
|---|---|
| Container won't start | Check .env.prod for missing or invalid API keys |
| SSL certificate issues | Ensure port 80 and 443 are open for Let's Encrypt (Caddy) |
| Slow responses | Check recursion_limit and consider reducing it |
To update to a new version:
cd /opt/chatbot
docker compose pull
docker compose up -dTo rollback, specify a previous image tag in the docker-compose.yml file:
image: ghcr.io/virtuos/askuos:previous-version
- Explore architecture in Architecture Overview