this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(deploy): add Dockerfile and Coolify deployment guide (#4)

* feat(deploy): add Dockerfile and Coolify deployment guide

- Add multi-stage Dockerfile for production Bun app
- Add .dockerignore to optimize build context
- Add comprehensive DEPLOY.md with Hetzner CX33 + Coolify setup
- Fix TOOL_WEBHOOK_URL in docker-compose.yml for Linux/production

* fix(deploy): set correct ownership on data directory

Fix permissions issue where /app/data was created as root but container
runs as non-root 'bun' user. Now correctly sets bun:bun ownership before
switching users.

---------

Co-authored-by: Claude <noreply@anthropic.com>

authored by

Alice
Claude
and committed by
GitHub
4307375e 0473bc31

+471
+47
.dockerignore
··· 1 + # Dependencies 2 + node_modules/ 3 + 4 + # Data (mounted as volume) 5 + data/ 6 + 7 + # Git 8 + .git/ 9 + .gitignore 10 + 11 + # IDE 12 + .vscode/ 13 + .idea/ 14 + *.swp 15 + *.swo 16 + 17 + # Logs 18 + *.log 19 + logs/ 20 + 21 + # Environment files (secrets) 22 + .env 23 + .env.* 24 + !.env.example 25 + 26 + # Build artifacts 27 + dist/ 28 + *.tsbuildinfo 29 + 30 + # Tests 31 + *.test.ts 32 + **/*.test.ts 33 + coverage/ 34 + 35 + # Documentation 36 + *.md 37 + !README.md 38 + docs/ 39 + history/ 40 + 41 + # Misc 42 + .DS_Store 43 + Thumbs.db 44 + 45 + # Other Dockerfiles (not needed in context) 46 + Dockerfile.* 47 + docker-compose*.yml
+376
DEPLOY.md
··· 1 + # Deploying to Hetzner CX33 with Coolify 2 + 3 + Complete guide to deploy the ADHD Support Agent on a Hetzner CX33 VPS using Coolify. 4 + 5 + ## Prerequisites 6 + 7 + - Hetzner Cloud account 8 + - Domain name (for HTTPS/webhooks) 9 + - GitHub account (repo must be accessible) 10 + - Telegram bot token (from @BotFather) 11 + - OpenAI API key (for embeddings) 12 + 13 + --- 14 + 15 + ## Step 1: Create Hetzner VPS 16 + 17 + 1. Go to [Hetzner Cloud Console](https://console.hetzner.cloud/) 18 + 2. Create new project or select existing 19 + 3. Click **Add Server** 20 + 4. Configure: 21 + - **Location**: Falkenstein or Nuremberg (Germany) - cheapest 22 + - **Image**: Ubuntu 24.04 23 + - **Type**: CX33 (4 vCPU, 8GB RAM, 80GB) - €5.49/mo 24 + - **Networking**: Public IPv4 (default) 25 + - **SSH Key**: Add your public key 26 + - **Name**: `assistant` or similar 27 + 5. Click **Create & Buy Now** 28 + 6. Note the IP address 29 + 30 + --- 31 + 32 + ## Step 2: Point Domain to Server 33 + 34 + Add DNS records for your domain: 35 + 36 + ``` 37 + Type Name Value TTL 38 + A assistant YOUR_SERVER_IP 300 39 + A *.assistant YOUR_SERVER_IP 300 40 + ``` 41 + 42 + Example: `assistant.yourdomain.com` → `YOUR_SERVER_IP` 43 + 44 + Wait 5-10 minutes for DNS propagation. 45 + 46 + --- 47 + 48 + ## Step 3: Initial Server Setup 49 + 50 + SSH into your server: 51 + 52 + ```bash 53 + ssh root@YOUR_SERVER_IP 54 + ``` 55 + 56 + Run initial setup: 57 + 58 + ```bash 59 + # Update system 60 + apt update && apt upgrade -y 61 + 62 + # Set timezone (optional) 63 + timedatectl set-timezone UTC 64 + 65 + # Enable firewall 66 + ufw allow 22/tcp # SSH 67 + ufw allow 80/tcp # HTTP (for SSL verification) 68 + ufw allow 443/tcp # HTTPS 69 + ufw allow 8000/tcp # Coolify UI (temporary, remove later) 70 + ufw --force enable 71 + 72 + # Reboot to apply kernel updates 73 + reboot 74 + ``` 75 + 76 + --- 77 + 78 + ## Step 4: Install Coolify 79 + 80 + SSH back in after reboot: 81 + 82 + ```bash 83 + ssh root@YOUR_SERVER_IP 84 + ``` 85 + 86 + Install Coolify: 87 + 88 + ```bash 89 + curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash 90 + ``` 91 + 92 + This takes 2-5 minutes. When done, you'll see: 93 + 94 + ``` 95 + Coolify is now running! 96 + Access it at: http://YOUR_IP:8000 97 + ``` 98 + 99 + --- 100 + 101 + ## Step 5: Configure Coolify 102 + 103 + 1. Open `http://YOUR_SERVER_IP:8000` in your browser 104 + 2. Create admin account (use a strong password) 105 + 3. Complete the setup wizard: 106 + - **Instance Settings**: Set your instance name 107 + - **SSH Key**: Coolify generates one automatically 108 + 109 + ### Connect GitHub 110 + 111 + 1. Go to **Sources** → **Add New** 112 + 2. Select **GitHub App** (recommended) or **Deploy Key** 113 + 3. Follow the OAuth flow to connect your GitHub account 114 + 4. Grant access to your assistant repository 115 + 116 + --- 117 + 118 + ## Step 6: Create the Application Stack 119 + 120 + Your app needs multiple services. In Coolify: 121 + 122 + ### 6.1 Create New Project 123 + 124 + 1. Go to **Projects** → **New Project** 125 + 2. Name: `assistant` 126 + 127 + ### 6.2 Add Docker Compose Resource 128 + 129 + 1. Inside the project, click **New Resource** 130 + 2. Select **Docker Compose** 131 + 3. Choose **Based on a Git Repository** 132 + 4. Select your repo and branch (`main` or `master`) 133 + 5. Coolify will detect `docker-compose.yml` 134 + 135 + ### 6.3 Configure Environment Variables 136 + 137 + Go to **Environment Variables** and add: 138 + 139 + ```env 140 + # Required 141 + TELEGRAM_BOT_TOKEN=your_telegram_bot_token 142 + ANTHROPIC_PROXY_SESSION_SECRET=generate_a_32_char_random_string 143 + OPENAI_API_KEY=sk-your-openai-key 144 + TELEGRAM_WEBHOOK_SECRET_TOKEN=generate_another_random_string 145 + 146 + # Set after first OAuth login (Step 8) 147 + ANTHROPIC_PROXY_SESSION_ID=will_set_later 148 + 149 + # Webhook URL (use your domain) 150 + TELEGRAM_WEBHOOK_URL=https://assistant.yourdomain.com/webhook 151 + 152 + # Tool webhook (internal Docker network) 153 + TOOL_WEBHOOK_URL=http://app:3000 154 + ``` 155 + 156 + Generate random strings: 157 + ```bash 158 + openssl rand -hex 32 # For SESSION_SECRET 159 + openssl rand -hex 16 # For WEBHOOK_SECRET_TOKEN 160 + ``` 161 + 162 + ### 6.4 Configure Domains 163 + 164 + 1. Go to the **app** service settings 165 + 2. Under **Domains**, add: `assistant.yourdomain.com` 166 + 3. Enable **HTTPS** (Coolify handles Let's Encrypt automatically) 167 + 4. Set port to `3000` 168 + 169 + --- 170 + 171 + ## Step 7: Deploy 172 + 173 + 1. Click **Deploy** in Coolify 174 + 2. Watch the build logs 175 + 3. First deploy takes 5-10 minutes (building Rust proxy, pulling images) 176 + 4. Subsequent deploys are much faster (cached layers) 177 + 178 + ### Verify Services 179 + 180 + Once deployed, check health: 181 + 182 + ```bash 183 + # From your local machine 184 + curl https://assistant.yourdomain.com/health 185 + ``` 186 + 187 + Should return: 188 + ```json 189 + {"status":"healthy","services":{"letta":"healthy","anthropic_proxy":"healthy"}} 190 + ``` 191 + 192 + --- 193 + 194 + ## Step 8: Anthropic OAuth Setup 195 + 196 + The anthropic-proxy needs a one-time OAuth login: 197 + 198 + 1. Open `http://YOUR_SERVER_IP:4001/login` in your browser 199 + 2. Log in with your Anthropic/Claude account 200 + 3. After successful login, you'll see a session ID 201 + 4. Copy the session ID 202 + 5. In Coolify, update the environment variable: 203 + ``` 204 + ANTHROPIC_PROXY_SESSION_ID=your_session_id_here 205 + ``` 206 + 6. Redeploy the stack 207 + 208 + --- 209 + 210 + ## Step 9: Set Telegram Webhook 211 + 212 + ```bash 213 + # Set the webhook URL 214 + curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook" \ 215 + -H "Content-Type: application/json" \ 216 + -d '{ 217 + "url": "https://assistant.yourdomain.com/webhook", 218 + "secret_token": "YOUR_WEBHOOK_SECRET_TOKEN" 219 + }' 220 + 221 + # Verify webhook is set 222 + curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getWebhookInfo" 223 + ``` 224 + 225 + --- 226 + 227 + ## Step 10: Test the Bot 228 + 229 + 1. Open Telegram 230 + 2. Find your bot (@YourBotName) 231 + 3. Send `/start` or any message 232 + 4. The bot should respond! 233 + 234 + --- 235 + 236 + ## Post-Deployment 237 + 238 + ### Secure Coolify UI 239 + 240 + Once everything works, restrict Coolify UI access: 241 + 242 + ```bash 243 + # Remove public access to Coolify 244 + ufw delete allow 8000/tcp 245 + 246 + # Access Coolify through SSH tunnel instead: 247 + # ssh -L 8000:localhost:8000 root@YOUR_SERVER_IP 248 + # Then open http://localhost:8000 249 + ``` 250 + 251 + ### Enable Auto-Deploy 252 + 253 + In Coolify, go to your resource and enable **Webhooks**: 254 + - Push to your repo → automatic redeploy 255 + 256 + ### Monitor Resources 257 + 258 + Coolify Dashboard shows: 259 + - CPU/Memory usage per service 260 + - Container logs 261 + - Deployment history 262 + 263 + ### Backups 264 + 265 + 1. Go to **Servers** → Your server → **Backup** 266 + 2. Configure automatic backups for: 267 + - `letta-data` volume (PostgreSQL) 268 + - `./data` directory (SQLite) 269 + 270 + --- 271 + 272 + ## Troubleshooting 273 + 274 + ### Check Logs 275 + 276 + In Coolify UI: Click any service → **Logs** 277 + 278 + Or via SSH: 279 + ```bash 280 + docker logs assistant-app-1 -f 281 + docker logs assistant-letta-1 -f 282 + docker logs assistant-litellm-1 -f 283 + ``` 284 + 285 + ### Service Won't Start 286 + 287 + ```bash 288 + # Check all containers 289 + docker ps -a 290 + 291 + # Check specific service logs 292 + docker compose -f /path/to/compose logs letta 293 + ``` 294 + 295 + ### Webhook Not Working 296 + 297 + ```bash 298 + # Test webhook endpoint directly 299 + curl -X POST https://assistant.yourdomain.com/webhook \ 300 + -H "Content-Type: application/json" \ 301 + -H "X-Telegram-Bot-Api-Secret-Token: YOUR_SECRET" \ 302 + -d '{"update_id": 1}' 303 + ``` 304 + 305 + ### Out of Memory 306 + 307 + If services are crashing, check memory: 308 + ```bash 309 + docker stats 310 + free -h 311 + ``` 312 + 313 + CX33 has 8GB, which should be plenty. If issues persist, check for memory leaks in logs. 314 + 315 + ### Reset Everything 316 + 317 + Nuclear option - start fresh: 318 + ```bash 319 + cd /path/to/coolify/project 320 + docker compose down -v # Warning: deletes volumes! 321 + docker compose up -d 322 + ``` 323 + 324 + --- 325 + 326 + ## Cost Summary 327 + 328 + | Item | Monthly Cost | 329 + |------|-------------| 330 + | Hetzner CX33 | €5.49 | 331 + | Domain (optional, if new) | ~€1/mo | 332 + | Anthropic API | Usage-based | 333 + | OpenAI API (embeddings) | ~$0.01/mo | 334 + | **Total** | **~€6.50/mo + API usage** | 335 + 336 + --- 337 + 338 + ## Architecture Overview 339 + 340 + ``` 341 + Internet 342 + 343 + 344 + ┌─────────────────────────────────────────────────────┐ 345 + │ Hetzner CX33 (Ubuntu + Docker + Coolify) │ 346 + │ │ 347 + │ ┌─────────────┐ ┌─────────────────────────┐ │ 348 + │ │ Caddy/Nginx │◄────►│ app (Bun :3000) │ │ 349 + │ │ (Coolify) │ │ - Telegram webhook │ │ 350 + │ │ :443 HTTPS │ │ - Tool dispatcher │ │ 351 + │ └─────────────┘ └──────────┬──────────────┘ │ 352 + │ │ │ 353 + │ ▼ │ 354 + │ ┌─────────────────────────┐ │ 355 + │ │ letta (:8283) │ │ 356 + │ │ - Agent orchestration │ │ 357 + │ │ - Memory (PostgreSQL) │ │ 358 + │ └──────────┬──────────────┘ │ 359 + │ │ │ 360 + │ ▼ │ 361 + │ ┌─────────────────────────┐ │ 362 + │ │ litellm (:4000) │ │ 363 + │ │ - OpenAI-compatible API │ │ 364 + │ └──────────┬──────────────┘ │ 365 + │ │ │ 366 + │ ▼ │ 367 + │ ┌─────────────┐ ┌─────────────────────────┐ │ 368 + │ │auth-adapter │◄────►│ anthropic-proxy (:4001) │ │ 369 + │ │ (:4002) │ │ - OAuth session mgmt │ │ 370 + │ └─────────────┘ └──────────┬──────────────┘ │ 371 + │ │ │ 372 + └──────────────────────────────────┼──────────────────┘ 373 + 374 + 375 + Anthropic API (Claude) 376 + ```
+46
Dockerfile
··· 1 + # Build stage - install dependencies 2 + FROM oven/bun:1 AS builder 3 + WORKDIR /app 4 + 5 + # Copy package files first for better caching 6 + COPY package.json bun.lockb* ./ 7 + 8 + # Install all dependencies (including dev for build) 9 + RUN bun install --frozen-lockfile 10 + 11 + # Copy source code 12 + COPY src/ ./src/ 13 + COPY tsconfig.json ./ 14 + 15 + # Production stage - smaller image 16 + FROM oven/bun:1-slim AS production 17 + WORKDIR /app 18 + 19 + # Install curl for health checks 20 + RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* 21 + 22 + # Copy package files 23 + COPY package.json bun.lockb* ./ 24 + 25 + # Install production dependencies only 26 + RUN bun install --frozen-lockfile --production 27 + 28 + # Copy source from builder 29 + COPY --from=builder /app/src ./src 30 + COPY --from=builder /app/tsconfig.json ./ 31 + 32 + # Create data directory for SQLite and set ownership for non-root user 33 + RUN mkdir -p /app/data && chown bun:bun /app/data 34 + 35 + # Run as non-root user for security 36 + USER bun 37 + 38 + # Expose port 39 + EXPOSE 3000 40 + 41 + # Health check 42 + HEALTHCHECK --interval=30s --timeout=10s --retries=3 \ 43 + CMD curl -f http://localhost:3000/health || exit 1 44 + 45 + # Start the app 46 + CMD ["bun", "run", "src/index.ts"]
+2
docker-compose.yml
··· 108 108 - ANTHROPIC_PROXY_URL=http://anthropic-proxy:4001/v1 109 109 - ANTHROPIC_PROXY_SESSION_ID=${ANTHROPIC_PROXY_SESSION_ID} 110 110 - OPENAI_API_KEY=${OPENAI_API_KEY} 111 + # Tool webhook URL - Letta calls back to app via Docker network 112 + - TOOL_WEBHOOK_URL=http://app:3000 111 113 volumes: 112 114 - ./data:/app/data 113 115 networks: