diff --git a/.dockerignore b/.dockerignore index f199b50..4431c2a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -56,8 +56,9 @@ setup/ docker/ .dockerignore -# Scripts (organized in scripts/ folder - not needed in Docker) -scripts/ +# Scripts installer (not needed in Docker, but keep docker/ folder) +scripts/installer/ +scripts/README.md # Asset files (not needed for runtime) assets/ diff --git a/README.md b/README.md index f9ca208..30c822c 100644 --- a/README.md +++ b/README.md @@ -221,13 +221,16 @@ For containerized deployment with built-in scheduling: ```bash # Ensure accounts.jsonc and config.jsonc exist in src/ -docker compose up -d +npm run docker:compose + +# Or use docker compose directly +docker compose -f docker/compose.yaml up -d # View logs -docker logs -f microsoft-rewards-script +docker logs -f microsoft-rewards-bot # Check status -docker compose ps +docker compose -f docker/compose.yaml ps ``` Container includes: @@ -236,7 +239,7 @@ Container includes: - ✅ Random execution delays (anti-detection) - ✅ Health checks -**📖 [Full Docker Guide](docs/docker.md)** +**📖 [Complete Docker Guide →](docs/docker-deployment.md)** --- diff --git a/docker/compose.yaml b/docker/compose.yaml index 86e9954..19bf528 100644 --- a/docker/compose.yaml +++ b/docker/compose.yaml @@ -1,6 +1,8 @@ services: microsoft-rewards-script: - build: . + build: + context: .. + dockerfile: docker/Dockerfile container_name: microsoft-rewards-bot restart: unless-stopped @@ -20,23 +22,22 @@ services: #MIN_SLEEP_MINUTES: "5" #MAX_SLEEP_MINUTES: "50" SKIP_RANDOM_SLEEP: "false" - # Optionally set how long to wait before killing a stuck script run (prevents blocking future runs, default: 8 hours) #STUCK_PROCESS_TIMEOUT_HOURS: "8" - # Optional resource limits for the container + # Optional resource limits for the container mem_limit: 4g cpus: 2 # Health check - monitors if cron daemon is running to ensure scheduled jobs can execute # Container marked unhealthy if cron process dies healthcheck: - test: ["CMD", "sh", "-c", "pgrep cron > /dev/null || exit 1"] + test: [ "CMD", "sh", "-c", "pgrep cron > /dev/null || exit 1" ] interval: 60s timeout: 10s retries: 3 start_period: 30s - + # Security hardening security_opt: - no-new-privileges:true diff --git a/docs/docker-deployment.md b/docs/docker-deployment.md index 4ac93ce..b31055a 100644 --- a/docs/docker-deployment.md +++ b/docs/docker-deployment.md @@ -1,19 +1,47 @@ # Docker Deployment Guide -## 🐳 Quick Start +Complete guide for containerized deployment with built-in scheduling. -### 1. Build the Image -```bash -cd docker -docker build -t microsoft-rewards-bot -f Dockerfile .. +## 📂 Docker File Structure + +``` +Microsoft-Rewards-Bot/ +├── docker/ # All Docker-related files +│ ├── Dockerfile # Multi-stage build configuration +│ ├── compose.yaml # Service definition +│ ├── entrypoint.sh # Container initialization +│ ├── run_daily.sh # Daily execution wrapper + locking +│ └── crontab.template # Cron job template +├── src/ +│ ├── accounts.jsonc # Your accounts (volume mount) +│ └── config.jsonc # Bot configuration (volume mount) +└── package.json # Build scripts ``` -Or use the npm script: +**Important:** All Docker files are in the `docker/` folder, but the build context is the **project root** (to access `src/`, `package.json`, etc.) + +--- + +## 🚀 Quick Start + +### 1. Build the Image + +**Option A: Using npm script (recommended)** ```bash +# From project root npm run docker:build ``` +**Option B: Direct Docker command** +```bash +# From project root +docker build -f docker/Dockerfile -t microsoft-rewards-bot . +``` + +**Why from root?** The Dockerfile needs access to `src/`, `package.json`, `tsconfig.json`. Docker can't copy files outside the build context. + ### 2. Configure Environment + Edit `docker/compose.yaml`: ```yaml environment: @@ -23,27 +51,96 @@ environment: ``` ### 3. Start the Container + +**Option A: Using npm script** ```bash -cd docker -docker compose up -d +npm run docker:compose ``` +**Option B: Direct docker compose command** +```bash +docker compose -f docker/compose.yaml up -d +``` + +**Note:** Volumes in `compose.yaml` use relative paths from `docker/`: +- `./src/` → `docker/../src/` (goes to project root) +- `./sessions/` → `docker/sessions/` (local to docker folder) + ## 📋 Configuration Files The container needs access to your configuration files via volume mounts: ```yaml volumes: - - ../src/accounts.jsonc:/usr/src/microsoft-rewards-bot/dist/accounts.jsonc:ro - - ../src/config.jsonc:/usr/src/microsoft-rewards-bot/dist/config.jsonc:ro + # Read-only mounts for configuration (prevents accidental container edits) + - ./src/accounts.jsonc:/usr/src/microsoft-rewards-bot/dist/accounts.jsonc:ro + - ./src/config.jsonc:/usr/src/microsoft-rewards-bot/dist/config.jsonc:ro + + # Read-write mount for persistent login sessions - ./sessions:/usr/src/microsoft-rewards-bot/dist/browser/sessions ``` +**Paths explained:** +- `./src/accounts.jsonc` = `docker/../src/accounts.jsonc` (relative from compose.yaml location) +- `./sessions` = `docker/sessions/` (local to docker folder) + **Before starting:** 1. Create `src/accounts.jsonc` (copy from `src/accounts.example.jsonc`) 2. Edit `src/config.jsonc` with your settings 3. (Optional) Create `docker/sessions/` directory for persistent login +--- + +## 🏗️ Architecture & Build Process + +### Two-Stage Docker Build + +**Stage 1: Builder** +```dockerfile +FROM node:22-slim AS builder +# 1. Install dependencies + dev dependencies +# 2. Compile TypeScript → JavaScript (dist/) +# 3. Install Playwright Chromium +# 4. Remove dev dependencies (keep only production) +``` + +**Stage 2: Runtime** +```dockerfile +FROM node:22-slim AS runtime +# 1. Install minimal system libraries for Chromium +# 2. Copy compiled code + dependencies from builder +# 3. Copy runtime scripts (entrypoint.sh, run_daily.sh) +# 4. Configure cron daemon +``` + +**Why two stages?** +- Smaller final image (~800 MB vs 1.5 GB) +- No build tools in production +- Security: no dev dependencies + +### Build Context Explained + +```bash +# ❌ WRONG: Building from docker/ folder +cd docker +docker build -t bot . +# Error: Cannot find package.json, src/, etc. + +# ✅ CORRECT: Build from root, specify Dockerfile location +cd /path/to/Microsoft-Rewards-Bot +docker build -f docker/Dockerfile -t bot . +# Success: Access to all project files +``` + +**The Dockerfile copies files relative to project root:** +```dockerfile +COPY package.json tsconfig.json ./ # From project root +COPY src/ ./src/ # From project root +COPY docker/run_daily.sh ./docker/ # Subfolder +``` + +--- + ## 🔧 Environment Variables | Variable | Required | Default | Description | @@ -113,21 +210,50 @@ docker exec microsoft-rewards-bot ps aux ## 🛠️ Troubleshooting -### "Chromium not installed" After First Run +### ❌ Build Error: "Cannot find module 'package.json'" + +**Cause:** Wrong build context - building from `docker/` instead of project root. + +**Solution:** +```bash +# ❌ WRONG +cd docker +docker build -t bot . + +# ✅ CORRECT (from project root) +docker build -f docker/Dockerfile -t bot . +# Or use npm script +npm run docker:build +``` + +### ❌ Build Error: "COPY failed: file not found: docker/run_daily.sh" + +**Cause:** `.dockerignore` file excludes `docker/` folder. + +**Solution:** Check `.dockerignore` - it should NOT contain `docker/`: +```ignore +# ❌ BAD +docker/ + +# ✅ GOOD (current config) +scripts/installer/ +``` + +### ❌ "Chromium not installed" After First Run **Symptoms:** - Bot works on first run - Fails on subsequent scheduled runs with "Chromium not installed" **Root Cause:** -Fixed in latest version! Chromium browser files are now copied correctly from builder stage. +Fixed in v2.56.7+! Chromium browser files are now copied correctly from builder stage. **Solution:** ```bash # Rebuild with latest Dockerfile (includes fix) -docker build --no-cache -t microsoft-rewards-bot -f docker/Dockerfile .. -docker compose down -docker compose up -d +npm run docker:build +docker compose -f docker/compose.yaml down +docker compose -f docker/compose.yaml up -d ``` **Verification:** @@ -138,7 +264,7 @@ docker exec microsoft-rewards-bot ls -la /usr/src/microsoft-rewards-bot/node_mod You should see `browser-chromium/` directory. -### Container Exits Immediately +### ❌ Container Exits Immediately **Check logs:** ```bash @@ -147,183 +273,202 @@ docker logs microsoft-rewards-bot **Common causes:** 1. **Missing CRON_SCHEDULE:** Set environment variable in compose.yaml + ```yaml + environment: + CRON_SCHEDULE: "0 9 * * *" # Required! + ``` + 2. **Invalid cron expression:** Validate at https://crontab.guru -3. **Permission issues:** Ensure config files are readable + +3. **Script not executable:** Dockerfile should handle this automatically + ```dockerfile + COPY --chmod=755 docker/entrypoint.sh /usr/local/bin/entrypoint.sh + ``` **Fix:** ```bash # Update compose.yaml with correct CRON_SCHEDULE -docker compose down -docker compose up -d +docker compose -f docker/compose.yaml down +docker compose -f docker/compose.yaml up -d ``` -### Random Delays Not Working +### ❌ "Permission denied: entrypoint.sh" -**Check environment variables:** -```bash -docker exec microsoft-rewards-bot env | grep SLEEP +**Cause:** Script not executable or Windows CRLF line endings. + +**Solution:** The Dockerfile handles both automatically: +```dockerfile +COPY --chmod=755 docker/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN sed -i 's/\r$//' /usr/local/bin/entrypoint.sh # Convert CRLF → LF ``` -**Verify run_daily.sh receives variables:** -```bash -docker exec microsoft-rewards-bot cat docker/run_daily.sh -``` - -**Test manually:** -```bash -docker exec microsoft-rewards-bot docker/run_daily.sh -``` - -### Timezone Incorrect - -**Check container timezone:** -```bash -docker exec microsoft-rewards-bot date -``` - -**Fix:** -1. Update `TZ` in compose.yaml -2. Restart container: -```bash -docker compose restart -``` - -**Verify:** -```bash -docker exec microsoft-rewards-bot date -docker logs microsoft-rewards-bot | grep "Timezone:" -``` - -### Health Check Failing - -**Check cron daemon:** -```bash -docker exec microsoft-rewards-bot ps aux | grep cron -``` - -**Expected output:** -``` -root 1 0.0 0.0 2576 1024 ? Ss 12:00 0:00 cron -f -``` - -**Restart container if missing:** -```bash -docker compose restart -``` - -### Sessions Not Persisting - -**Check volume mount:** -```bash -docker inspect microsoft-rewards-bot | grep sessions -``` - -**Verify local directory exists:** -```bash -ls -la docker/sessions/ -``` - -**Fix permissions:** +If still failing, manually fix line endings: ```bash # Linux/Mac -chmod -R 755 docker/sessions/ +dos2unix docker/entrypoint.sh docker/run_daily.sh -# Windows -# No action needed (NTFS handles permissions) +# Or with sed +sed -i 's/\r$//' docker/entrypoint.sh +sed -i 's/\r$//' docker/run_daily.sh ``` -### Out of Memory Errors +### ❌ Volumes Not Mounting -**Increase memory limit in compose.yaml:** -```yaml -mem_limit: 6g # Increase from 4g -``` +### ❌ Volumes Not Mounting -**Restart:** +**Check if files exist:** ```bash -docker compose down -docker compose up -d +# From docker/ folder +ls -la ../src/accounts.jsonc ../src/config.jsonc + +# Or from project root +ls -la src/accounts.jsonc src/config.jsonc ``` -**Monitor memory usage:** +**Verify volume paths in running container:** ```bash -docker stats microsoft-rewards-bot +docker inspect microsoft-rewards-bot | grep -A 10 Mounts ``` -## 🔄 Updates +**Fix paths in compose.yaml:** +```yaml +# Paths are relative to compose.yaml location (docker/) +volumes: + - ./src/accounts.jsonc:/usr/src/microsoft-rewards-bot/dist/accounts.jsonc:ro + # This resolves to: docker/../src/accounts.jsonc (project root) +``` -### Update to Latest Version +--- -**Method 1: Rebuild (Recommended)** +## 📚 Complete File Reference + +### `docker/Dockerfile` +Multi-stage build configuration: +- **Builder stage:** Compiles TypeScript, installs Playwright +- **Runtime stage:** Minimal image with only production dependencies + +### `docker/compose.yaml` +Service definition with: +- Build context (points to project root) +- Volume mounts (configuration files) +- Environment variables (scheduling, timezone) +- Resource limits (CPU, memory) +- Health checks (cron daemon monitoring) + +### `docker/entrypoint.sh` +Container initialization script: +1. Configures timezone from `TZ` env var +2. Validates `CRON_SCHEDULE` is set +3. Optionally runs bot immediately (`RUN_ON_START=true`) +4. Templates cron job with environment variables +5. Starts cron daemon in foreground + +### `docker/run_daily.sh` +Daily execution wrapper: +- File-based locking (prevents concurrent runs) +- Self-healing lockfile validation +- Random sleep delay (anti-detection) +- Stuck process killer (timeout after N hours) +- Executes `npm start` + +### `docker/crontab.template` +Cron job template with variable interpolation: ```bash -# Pull latest code -git pull origin main - -# Rebuild image -docker build --no-cache -t microsoft-rewards-bot -f docker/Dockerfile .. - -# Restart container -docker compose down -docker compose up -d +${CRON_SCHEDULE} TZ=${TZ} /bin/bash /usr/src/microsoft-rewards-bot/docker/run_daily.sh >> /proc/1/fd/1 2>&1 ``` -**Method 2: Auto-Update (If Enabled in config.jsonc)** -The bot can auto-update itself if `update.enabled: true` in config.jsonc. -After auto-update, container will restart automatically (Docker restarts on exit). +Expanded by `entrypoint.sh` using `envsubst`. -### Backup Before Update +--- + +## 🎯 Build & Deployment Checklist + +### Pre-Build Checklist +- [ ] Files exist: `src/accounts.jsonc`, `src/config.jsonc` +- [ ] Docker installed and running +- [ ] At project root (not in `docker/` folder) +- [ ] `.dockerignore` does NOT exclude `docker/` folder + +### Build Steps ```bash -# Backup sessions -cp -r docker/sessions/ docker/sessions.backup/ +# 1. Clean previous builds (optional) +docker rmi microsoft-rewards-bot -# Backup config -cp src/config.jsonc src/config.jsonc.backup -cp src/accounts.jsonc src/accounts.jsonc.backup +# 2. Build image +npm run docker:build +# Or: docker build -f docker/Dockerfile -t microsoft-rewards-bot . + +# 3. Verify image created +docker images | grep microsoft-rewards-bot ``` -## 📊 Resource Usage +### Deployment Steps +```bash +# 1. Configure compose.yaml +# - Set CRON_SCHEDULE (required) +# - Set TZ (optional, default UTC) +# - Set RUN_ON_START (optional, default false) -**Typical resource consumption:** -- **CPU:** 50-80% during active runs, <1% idle -- **RAM:** 1-3 GB during active runs, <100 MB idle -- **Disk:** ~500 MB (base image + browsers) -- **Network:** Minimal (<10 MB per run) +# 2. Start container +npm run docker:compose +# Or: docker compose -f docker/compose.yaml up -d -**Recommended limits:** -```yaml -mem_limit: 4g -cpus: 2 +# 3. Verify running +docker ps | grep microsoft-rewards-bot + +# 4. Check logs +docker logs -f microsoft-rewards-bot + +# 5. Verify health +docker inspect microsoft-rewards-bot --format='{{.State.Health.Status}}' ``` -## 🔐 Security Hardening +--- -The default compose.yaml includes: -```yaml -security_opt: - - no-new-privileges:true # Prevent privilege escalation +## 🔍 Debugging Commands + +### Check Build Context +```bash +# List files Docker can see during build +docker build -f docker/Dockerfile -t test . --progress=plain 2>&1 | grep "COPY" ``` -**Additional hardening (optional):** -```yaml -security_opt: - - no-new-privileges:true - - seccomp:unconfined # Only if Chromium fails to start -read_only: false # Must be false (Chromium needs write access) -tmpfs: - - /tmp - - /root/.cache +### Inspect Running Container +```bash +# Shell access +docker exec -it microsoft-rewards-bot bash + +# Check environment variables +docker exec microsoft-rewards-bot env + +# Check cron jobs +docker exec microsoft-rewards-bot crontab -l + +# Check timezone +docker exec microsoft-rewards-bot date + +# Check Playwright browsers +docker exec microsoft-rewards-bot ls -la node_modules/@playwright/ + +# Check running processes +docker exec microsoft-rewards-bot ps aux ``` -## 🆘 Getting Help +### Test Scripts Manually +```bash +# Test entrypoint +docker exec microsoft-rewards-bot /usr/local/bin/entrypoint.sh -If issues persist: -1. **Check logs:** `docker logs -f microsoft-rewards-bot` -2. **Rebuild with no cache:** `docker build --no-cache ...` -3. **Verify Chromium:** `docker exec microsoft-rewards-bot ls -la node_modules/@playwright/` -4. **Discord Support:** https://discord.gg/k5uHkx9mne -5. **GitHub Issues:** https://github.com/Obsidian-wtf/Microsoft-Rewards-Bot/issues +# Test run_daily (bypass lock) +docker exec microsoft-rewards-bot bash -c "rm -f /tmp/run_daily.lock && docker/run_daily.sh" -## 📚 Related Documentation +# Test bot directly +docker exec microsoft-rewards-bot npm start +``` + +--- + +## 📖 Additional Resources - **Build System:** [docs/build-system.md](build-system.md) - **Scheduling:** [src/scheduler/README.md](../src/scheduler/README.md) diff --git a/docs/index.md b/docs/index.md index 8e55066..e415171 100644 --- a/docs/index.md +++ b/docs/index.md @@ -64,33 +64,20 @@ Explore advanced features and customization options:| **[NTFY Alerts](ntfy.md)** | **[Proxy Setup](proxy.md)** | IP rotation (optional) | -### Core Features| **[Docker](docker.md)** | Container deployment | - - - -| Guide | Description |--- +### Core Features +| Guide | Description | |-------|-------------| - -| **[🔔 Notifications](notifications.md)** | Discord webhooks and mobile push alerts |## 🆘 Troubleshooting - +| **[🔔 Notifications](notifications.md)** | Discord webhooks and mobile push alerts | | **[📊 Dashboard](../src/dashboard/README.md)** | Web interface for monitoring and control | +| **[🌐 Proxy Setup](proxy.md)** | Configure proxies for privacy | +| **[🤖 Humanization](humanization.md)** | Anti-detection and natural behavior patterns | -| **[🌐 Proxy Setup](proxy.md)** | Configure proxies for privacy || Issue | Solution | +### Deployment -| **[🤖 Humanization](humanization.md)** | Anti-detection and natural behavior patterns ||-------|----------| - -| **Bot not working?** | [Troubleshooting Guide](diagnostics.md) | - -### Deployment| **Login failed?** | [Accounts & 2FA](accounts.md#troubleshooting) | - -| **Account banned?** | [Security Guide](security.md) | - -| Guide | Description || **Git conflicts?** | [Conflict Resolution](git-conflict-resolution.md) | - -|-------|-------------|| **General questions?** | [FAQ](FAQ.md) | - -| **[🐳 Docker](docker.md)** | Containerized deployment with Docker Compose | +| Guide | Description | +|-------|-------------| +| **[🐳 Docker](docker-deployment.md)** | Containerized deployment with Docker Compose | | **[☁️ Cloud Deployment](cloud-deployment.md)** | Deploy to VPS, Raspberry Pi, or cloud services |**Need help?** → [Discord Community](https://discord.gg/k5uHkx9mne) @@ -186,7 +173,7 @@ Technical references and detailed information: ### For Docker Users -1. [Docker Guide](docker.md) — Setup Docker Compose +1. [Docker Guide](docker-deployment.md) — Setup Docker Compose 2. [Environment Variables](environment-variables.md) — Configure via env vars 3. [Notifications](notifications.md) — Monitor container runs diff --git a/package.json b/package.json index 3568f2d..d9ae587 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,9 @@ "lint": "eslint \"src/**/*.{ts,tsx}\"", "setup": "node ./scripts/installer/setup.mjs", "kill-chrome": "node -e \"const { execSync } = require('child_process'); const isWin = process.platform === 'win32'; try { execSync(isWin ? 'taskkill /F /IM chrome.exe 2>nul || exit 0' : 'pkill -f chrome || true', {stdio: 'inherit'}); } catch(e) {}\"", - "docker:build": "docker build -t microsoft-rewards-bot .", - "docker:run": "docker run -d --name ms-rewards microsoft-rewards-bot" + "docker:build": "docker build -f docker/Dockerfile -t microsoft-rewards-bot .", + "docker:run": "docker run -d --name ms-rewards microsoft-rewards-bot", + "docker:compose": "docker compose -f docker/compose.yaml up -d" }, "keywords": [ "Bing Rewards",