Document and add multi-bot Docker workflows with env layering scripts, and update agent/tool configuration handling to make MCP/email/calendar behavior more robust for day-to-day operations. Made-with: Cursor
615 lines
15 KiB
Markdown
615 lines
15 KiB
Markdown
# Docker Multi-Bot Setup Guide
|
|
|
|
Complete guide for running multiple nanobot instances with Docker, each with its own Telegram bot.
|
|
|
|
## 📋 Table of Contents
|
|
|
|
1. [Quick Start](#quick-start)
|
|
2. [Architecture Overview](#architecture-overview)
|
|
3. [Setup Instructions](#setup-instructions)
|
|
4. [Running Bots](#running-bots)
|
|
5. [Configuration Management](#configuration-management)
|
|
6. [Development Workflow](#development-workflow)
|
|
7. [Troubleshooting](#troubleshooting)
|
|
8. [Reference](#reference)
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Start Only User1 Bot
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml up -d nanobot-user1
|
|
```
|
|
|
|
### Start All Bots
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml up -d
|
|
```
|
|
|
|
### Stop All Bots
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml down
|
|
```
|
|
|
|
### Stop Specific Bot
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml stop nanobot-user1
|
|
```
|
|
|
|
### View Logs
|
|
```bash
|
|
docker logs -f nanobot-user1
|
|
```
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
### How It Works
|
|
|
|
Each bot runs in its own Docker container with:
|
|
- **Separate config directory**: `~/.nanobot-user1`, `~/.nanobot-user2`, etc.
|
|
- **Shared env file**: `.env.shared` (common settings)
|
|
- **Bot-specific env file**: `.env.user1`, `.env.user2`, etc. (overrides)
|
|
- **Isolated environment**: No conflicts between bots
|
|
|
|
### File Structure
|
|
|
|
```
|
|
nanobot/
|
|
├── .env.shared # Shared settings (API keys, model, etc.)
|
|
├── .env.user1 # Bot 1 overrides
|
|
├── .env.user2 # Bot 2 overrides
|
|
├── .env.user3 # Bot 3 overrides
|
|
├── docker-compose.multi.env.yml # Production compose file
|
|
├── docker-compose.multi.dev.yml # Development compose file
|
|
│
|
|
└── ~/.nanobot-user1/
|
|
└── config.json # Bot 1 channel config (Telegram token, allowFrom)
|
|
└── ~/.nanobot-user2/
|
|
└── config.json # Bot 2 channel config
|
|
└── ~/.nanobot-user3/
|
|
└── config.json # Bot 3 channel config
|
|
```
|
|
|
|
### Configuration Loading
|
|
|
|
1. **Docker Compose** loads environment files:
|
|
- First: `.env.shared` (shared settings)
|
|
- Second: `.env.userX` (bot-specific overrides)
|
|
- Later files override earlier ones
|
|
|
|
2. **Container** mounts config directory:
|
|
- Host: `~/.nanobot-user1` → Container: `/root/.nanobot`
|
|
|
|
3. **Nanobot** loads:
|
|
- Environment variables (from Docker env files)
|
|
- Config file: `/root/.nanobot/config.json` (mounted from host)
|
|
|
|
---
|
|
|
|
## Setup Instructions
|
|
|
|
### Step 1: Create Environment Files
|
|
|
|
Run the setup script:
|
|
```bash
|
|
./env-files-setup.sh
|
|
```
|
|
|
|
This creates:
|
|
- `.env.shared` - Shared settings
|
|
- `.env.user1`, `.env.user2`, `.env.user3` - Bot-specific overrides
|
|
|
|
### Step 2: Edit `.env.shared`
|
|
|
|
Add your shared settings:
|
|
```bash
|
|
nano .env.shared
|
|
```
|
|
|
|
Example:
|
|
```bash
|
|
# Provider Settings
|
|
NANOBOT_PROVIDERS__CUSTOM__API_KEY=no-key
|
|
NANOBOT_PROVIDERS__CUSTOM__API_BASE=http://172.17.0.1:11434/v1
|
|
|
|
# Agent Settings
|
|
NANOBOT_AGENTS__DEFAULTS__MODEL=llama3.1:8b
|
|
NANOBOT_AGENTS__DEFAULTS__WORKSPACE=/mnt/data/nanobot
|
|
NANOBOT_AGENTS__DEFAULTS__TEMPERATURE=0.7
|
|
```
|
|
|
|
**Important**: Use `172.17.0.1` (Docker bridge gateway) instead of `localhost` so containers can reach Ollama on the host.
|
|
|
|
### Step 3: Edit Bot-Specific Env Files
|
|
|
|
Edit `.env.user1`, `.env.user2`, etc. with bot-specific settings:
|
|
```bash
|
|
nano .env.user1
|
|
```
|
|
|
|
Example:
|
|
```bash
|
|
# Telegram Bot Token
|
|
NANOBOT_CHANNELS__TELEGRAM__ENABLED=true
|
|
NANOBOT_CHANNELS__TELEGRAM__TOKEN=your_bot_token_here
|
|
|
|
# Email Credentials (if different per bot)
|
|
NANOBOT_CHANNELS__EMAIL__IMAP_USERNAME=bot1@example.com
|
|
NANOBOT_CHANNELS__EMAIL__IMAP_PASSWORD=password
|
|
```
|
|
|
|
### Step 4: Create Config Files
|
|
|
|
Run the config creation script:
|
|
```bash
|
|
./create-bot-configs.sh
|
|
```
|
|
|
|
Or manually create `~/.nanobot-user1/config.json`:
|
|
```json
|
|
{
|
|
"channels": {
|
|
"telegram": {
|
|
"enabled": true,
|
|
"allowFrom": ["YOUR_TELEGRAM_USERNAME"]
|
|
},
|
|
"email": {
|
|
"enabled": true,
|
|
"allowFrom": ["email@example.com"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: `allowFrom` arrays must be in `config.json`, NOT in env files.
|
|
|
|
### Step 5: Build Docker Image
|
|
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml build
|
|
```
|
|
|
|
---
|
|
|
|
## Running Bots
|
|
|
|
### Start Commands
|
|
|
|
```bash
|
|
# Start only user1
|
|
docker compose -f docker-compose.multi.env.yml up -d nanobot-user1
|
|
|
|
# Start only user2
|
|
docker compose -f docker-compose.multi.env.yml up -d nanobot-user2
|
|
|
|
# Start only user3
|
|
docker compose -f docker-compose.multi.env.yml up -d nanobot-user3
|
|
|
|
# Start all bots
|
|
docker compose -f docker-compose.multi.env.yml up -d
|
|
```
|
|
|
|
### Stop Commands
|
|
|
|
```bash
|
|
# Stop only user1
|
|
docker compose -f docker-compose.multi.env.yml stop nanobot-user1
|
|
|
|
# Stop only user2
|
|
docker compose -f docker-compose.multi.env.yml stop nanobot-user2
|
|
|
|
# Stop only user3
|
|
docker compose -f docker-compose.multi.env.yml stop nanobot-user3
|
|
|
|
# Stop all bots
|
|
docker compose -f docker-compose.multi.env.yml down
|
|
```
|
|
|
|
### Restart Commands
|
|
|
|
```bash
|
|
# Restart only user1
|
|
docker compose -f docker-compose.multi.env.yml restart nanobot-user1
|
|
|
|
# Restart all bots
|
|
docker compose -f docker-compose.multi.env.yml restart
|
|
```
|
|
|
|
### Status Commands
|
|
|
|
```bash
|
|
# Check what's running
|
|
docker compose -f docker-compose.multi.env.yml ps
|
|
|
|
# View logs for user1
|
|
docker logs -f nanobot-user1
|
|
|
|
# View logs for all bots
|
|
docker compose -f docker-compose.multi.env.yml logs -f
|
|
|
|
# View logs for specific bot
|
|
docker compose -f docker-compose.multi.env.yml logs -f nanobot-user1
|
|
```
|
|
|
|
### Remove Commands
|
|
|
|
```bash
|
|
# Stop and remove user1 container
|
|
docker compose -f docker-compose.multi.env.yml stop nanobot-user1
|
|
docker rm nanobot-user1
|
|
|
|
# Stop and remove all containers
|
|
docker compose -f docker-compose.multi.env.yml down
|
|
|
|
# Remove containers and volumes (keeps config files)
|
|
docker compose -f docker-compose.multi.env.yml down -v
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration Management
|
|
|
|
### Updating Shared Settings
|
|
|
|
Edit `.env.shared`:
|
|
```bash
|
|
nano .env.shared
|
|
```
|
|
|
|
Restart affected containers:
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml restart
|
|
```
|
|
|
|
### Updating Bot-Specific Settings
|
|
|
|
Edit `.env.userX`:
|
|
```bash
|
|
nano .env.user1
|
|
```
|
|
|
|
Restart that specific bot:
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml restart nanobot-user1
|
|
```
|
|
|
|
### Updating Config Files
|
|
|
|
Edit config file:
|
|
```bash
|
|
nano ~/.nanobot-user1/config.json
|
|
```
|
|
|
|
Restart container:
|
|
```bash
|
|
docker restart nanobot-user1
|
|
```
|
|
|
|
### Adding Email to allowFrom
|
|
|
|
```bash
|
|
# Add email to user1's allowFrom
|
|
jq '.channels.email.allowFrom += ["newemail@example.com"]' \
|
|
~/.nanobot-user1/config.json > ~/.nanobot-user1/config.json.tmp && \
|
|
mv ~/.nanobot-user1/config.json.tmp ~/.nanobot-user1/config.json
|
|
|
|
# Restart container
|
|
docker restart nanobot-user1
|
|
```
|
|
|
|
### Environment Variable Format
|
|
|
|
Nanobot uses Pydantic's `BaseSettings` with:
|
|
- Prefix: `NANOBOT_`
|
|
- Nested delimiter: `__` (double underscore)
|
|
|
|
Examples:
|
|
- `NANOBOT_PROVIDERS__CUSTOM__API_KEY` → `providers.custom.apiKey`
|
|
- `NANOBOT_CHANNELS__TELEGRAM__TOKEN` → `channels.telegram.token`
|
|
- `NANOBOT_AGENTS__DEFAULTS__MODEL` → `agents.defaults.model`
|
|
|
|
---
|
|
|
|
## Development Workflow
|
|
|
|
### Option 1: Development Mode (Recommended)
|
|
|
|
Use `docker-compose.multi.dev.yml` which mounts source code:
|
|
|
|
```bash
|
|
# Start in development mode
|
|
docker compose -f docker-compose.multi.dev.yml up -d nanobot-user1
|
|
|
|
# Make changes in venv
|
|
source venv/bin/activate
|
|
nano nanobot/channels/telegram.py
|
|
|
|
# Restart container (picks up changes)
|
|
docker compose -f docker-compose.multi.dev.yml restart nanobot-user1
|
|
|
|
# View logs
|
|
docker logs -f nanobot-user1-dev
|
|
```
|
|
|
|
### Option 2: Rebuild After Changes
|
|
|
|
```bash
|
|
# Make changes
|
|
source venv/bin/activate
|
|
nano nanobot/channels/telegram.py
|
|
|
|
# Rebuild image
|
|
docker compose -f docker-compose.multi.env.yml build nanobot-user1
|
|
|
|
# Recreate container
|
|
docker compose -f docker-compose.multi.env.yml up -d --force-recreate nanobot-user1
|
|
```
|
|
|
|
### Option 3: Run on Host (Not Docker)
|
|
|
|
```bash
|
|
# Activate venv
|
|
source venv/bin/activate
|
|
|
|
# Run directly
|
|
nanobot gateway
|
|
```
|
|
|
|
**Note**: Host command uses:
|
|
- Config: `~/.nanobot/config.json` (original)
|
|
- .env: `.env` in current directory (NOT `.env.shared`)
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Bot Not Responding
|
|
|
|
1. **Check if container is running**:
|
|
```bash
|
|
docker ps | grep nanobot-user1
|
|
```
|
|
|
|
2. **Check logs**:
|
|
```bash
|
|
docker logs nanobot-user1 --tail 50
|
|
```
|
|
|
|
3. **Verify Telegram token**:
|
|
```bash
|
|
grep TELEGRAM__TOKEN .env.user1
|
|
```
|
|
|
|
4. **Check allowFrom**:
|
|
```bash
|
|
cat ~/.nanobot-user1/config.json | jq '.channels.telegram.allowFrom'
|
|
```
|
|
|
|
### Connection Error (Ollama)
|
|
|
|
**Problem**: "Connection error" when bot tries to use LLM
|
|
|
|
**Solution**:
|
|
1. Check Ollama is running:
|
|
```bash
|
|
curl http://localhost:11434/api/tags
|
|
```
|
|
|
|
2. Verify API_BASE in `.env.shared`:
|
|
```bash
|
|
grep API_BASE .env.shared
|
|
```
|
|
Should be: `http://172.17.0.1:11434/v1` (NOT `localhost`)
|
|
|
|
3. Restart container:
|
|
```bash
|
|
docker restart nanobot-user1
|
|
```
|
|
|
|
### Config Not Loading
|
|
|
|
1. **Check volume mount**:
|
|
```bash
|
|
docker inspect nanobot-user1 | grep -A 5 Mounts
|
|
```
|
|
|
|
2. **Verify config exists**:
|
|
```bash
|
|
ls -lh ~/.nanobot-user1/config.json
|
|
```
|
|
|
|
3. **Check inside container**:
|
|
```bash
|
|
docker exec nanobot-user1 cat /root/.nanobot/config.json
|
|
```
|
|
|
|
### Environment Variables Not Applied
|
|
|
|
1. **Check env files are loaded**:
|
|
```bash
|
|
docker exec nanobot-user1 env | grep NANOBOT
|
|
```
|
|
|
|
2. **Recreate container** (env files loaded at creation):
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml up -d --force-recreate nanobot-user1
|
|
```
|
|
|
|
### Port Already in Use
|
|
|
|
If port conflicts:
|
|
```bash
|
|
# Check what's using the port
|
|
sudo lsof -i :18790
|
|
|
|
# Stop conflicting container
|
|
docker stop <container_name>
|
|
|
|
# Or change port in docker-compose.multi.env.yml
|
|
```
|
|
|
|
---
|
|
|
|
## Reference
|
|
|
|
### Docker Compose Files
|
|
|
|
| File | Purpose | Use Case | Env Loading |
|
|
|------|---------|----------|-------------|
|
|
| `docker-compose.yml` | Single-bot baseline | One gateway + optional CLI, simplest setup | No `env_file`; uses mounted `~/.nanobot/config.json` and container environment |
|
|
| `docker-compose.multi.yml` | Multi-bot baseline | Multiple bots with separate config dirs, minimal env indirection | No `env_file`; each bot uses mounted `~/.nanobot-userX/config.json` and container environment |
|
|
| `docker-compose.multi.env.yml` | Multi-bot production | Stable multi-bot deployments with shared + per-bot overrides | Loads `.env.shared` first, then `.env.userX` (later file overrides earlier) |
|
|
| `docker-compose.multi.dev.yml` | Multi-bot development | Active code development with source mounted into containers | Same env behavior as `multi.env` (`.env.shared` + `.env.userX`) |
|
|
|
|
### Container Names
|
|
|
|
- `nanobot-user1` - Bot 1 container (production)
|
|
- `nanobot-user1-dev` - Bot 1 container (development)
|
|
- `nanobot-user2` - Bot 2 container
|
|
- `nanobot-user3` - Bot 3 container
|
|
|
|
### Ports
|
|
|
|
- User 1: `18790` (host) → `18790` (container)
|
|
- User 2: `18791` (host) → `18790` (container)
|
|
- User 3: `18792` (host) → `18790` (container)
|
|
|
|
### Config Locations
|
|
|
|
| Location | Used By | Purpose |
|
|
|----------|---------|---------|
|
|
| `~/.nanobot/config.json` | Host `nanobot gateway` | Original config (not used by Docker) |
|
|
| `~/.nanobot-user1/config.json` | Docker user1 | Bot 1 config (mounted into container) |
|
|
| `~/.nanobot-user2/config.json` | Docker user2 | Bot 2 config |
|
|
| `~/.nanobot-user3/config.json` | Docker user3 | Bot 3 config |
|
|
|
|
### Environment Files
|
|
|
|
| File | Loaded By | Purpose |
|
|
|------|-----------|---------|
|
|
| `.env.shared` | All Docker containers | Shared settings (API keys, model, etc.) |
|
|
| `.env.user1` | Docker user1 only | Bot 1 specific overrides |
|
|
| `.env.user2` | Docker user2 only | Bot 2 specific overrides |
|
|
| `.env.user3` | Docker user3 only | Bot 3 specific overrides |
|
|
| `.env` | Host `nanobot gateway` | Host environment (not used by Docker) |
|
|
|
|
### Quick Command Reference
|
|
|
|
```bash
|
|
# === START ===
|
|
docker compose -f docker-compose.multi.env.yml up -d nanobot-user1 # Start user1
|
|
docker compose -f docker-compose.multi.env.yml up -d # Start all
|
|
|
|
# === STOP ===
|
|
docker compose -f docker-compose.multi.env.yml stop nanobot-user1 # Stop user1
|
|
docker compose -f docker-compose.multi.env.yml down # Stop all
|
|
|
|
# === RESTART ===
|
|
docker compose -f docker-compose.multi.env.yml restart nanobot-user1 # Restart user1
|
|
docker compose -f docker-compose.multi.env.yml restart # Restart all
|
|
|
|
# === LOGS ===
|
|
docker logs -f nanobot-user1 # View logs
|
|
docker compose -f docker-compose.multi.env.yml logs -f nanobot-user1 # View logs
|
|
|
|
# === STATUS ===
|
|
docker compose -f docker-compose.multi.env.yml ps # List containers
|
|
docker ps | grep nanobot # List containers
|
|
|
|
# === REBUILD ===
|
|
docker compose -f docker-compose.multi.env.yml build nanobot-user1 # Rebuild user1
|
|
docker compose -f docker-compose.multi.env.yml build # Rebuild all
|
|
|
|
# === RECREATE (after config changes) ===
|
|
docker compose -f docker-compose.multi.env.yml up -d --force-recreate nanobot-user1
|
|
```
|
|
|
|
---
|
|
|
|
## Common Tasks
|
|
|
|
### Add a New Bot (User4)
|
|
|
|
1. Create config directory:
|
|
```bash
|
|
mkdir -p ~/.nanobot-user4
|
|
```
|
|
|
|
2. Create config file:
|
|
```bash
|
|
cat > ~/.nanobot-user4/config.json << 'EOF'
|
|
{
|
|
"channels": {
|
|
"telegram": {
|
|
"enabled": true,
|
|
"allowFrom": ["USERNAME"]
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
```
|
|
|
|
3. Create env file:
|
|
```bash
|
|
cp .env.user1 .env.user4
|
|
nano .env.user4 # Edit with bot-specific settings
|
|
```
|
|
|
|
4. Add to `docker-compose.multi.env.yml`:
|
|
```yaml
|
|
nanobot-user4:
|
|
# ... (copy from nanobot-user1, change port to 18793)
|
|
```
|
|
|
|
5. Start:
|
|
```bash
|
|
docker compose -f docker-compose.multi.env.yml up -d nanobot-user4
|
|
```
|
|
|
|
### Update Ollama API Base
|
|
|
|
If Ollama IP changes:
|
|
```bash
|
|
# Edit .env.shared
|
|
sed -i 's|http://172.17.0.1:11434|http://NEW_IP:11434|g' .env.shared
|
|
|
|
# Restart all containers
|
|
docker compose -f docker-compose.multi.env.yml restart
|
|
```
|
|
|
|
### Backup Configurations
|
|
|
|
```bash
|
|
# Backup all configs
|
|
tar -czf nanobot-configs-backup-$(date +%Y%m%d).tar.gz \
|
|
~/.nanobot-user* \
|
|
.env.shared .env.user*
|
|
|
|
# Restore
|
|
tar -xzf nanobot-configs-backup-YYYYMMDD.tar.gz
|
|
```
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- **Original config** (`~/.nanobot/config.json`) is NOT used by Docker containers
|
|
- **Host venv** is NOT needed to run Docker commands (Docker builds its own environment)
|
|
- **Environment variables** override config file settings
|
|
- **Arrays** (like `allowFrom`) must be in `config.json`, NOT in env files
|
|
- **Ollama API_BASE** must use `172.17.0.1` (Docker bridge) not `localhost`
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- `ENV_FILES_GUIDE.md` - Detailed env file management
|
|
- `DEVELOPMENT_WITH_DOCKER.md` - Development workflow details
|
|
- `SETUP_SUMMARY.md` - Initial setup summary
|
|
- `VERIFY_DOCKER_SETUP.md` - Verification checklist
|
|
|
|
|