diff --git a/Dockerfile.agent b/Dockerfile.agent new file mode 100644 index 000000000..46159d3d7 --- /dev/null +++ b/Dockerfile.agent @@ -0,0 +1,22 @@ +# Railway Deployment Dockerfile for bytebot-agent +# Build context: repository root +FROM node:20-alpine + +WORKDIR /app + +# Copy shared package +COPY packages/shared ./shared + +# Copy agent package +COPY packages/bytebot-agent ./bytebot-agent + +WORKDIR /app/bytebot-agent + +# Install dependencies +RUN npm install + +# Build the application +RUN npm run build + +# Start the application +CMD ["npm", "run", "start:prod"] diff --git a/Dockerfile.desktop b/Dockerfile.desktop new file mode 100644 index 000000000..3b450f752 --- /dev/null +++ b/Dockerfile.desktop @@ -0,0 +1,252 @@ +# ----------------------------------------------------------------------------- +# Bytebot Dockerfile - Virtual Desktop Environment +# ----------------------------------------------------------------------------- + +# Base image +FROM ubuntu:22.04 + +# ----------------------------------------------------------------------------- +# 1. Environment setup +# ----------------------------------------------------------------------------- +# Set non-interactive installation +ARG DEBIAN_FRONTEND=noninteractive +# Configure display for X11 applications +ENV DISPLAY=:0 + +# ----------------------------------------------------------------------------- +# 2. System dependencies installation +# ----------------------------------------------------------------------------- +RUN apt-get update && apt-get install -y \ + # X11 / VNC + xvfb x11vnc xauth x11-xserver-utils \ + x11-apps sudo software-properties-common \ + # Desktop environment + xfce4 xfce4-goodies dbus wmctrl \ + # Display manager with autologin capability + lightdm \ + # Development tools + python3 python3-pip curl wget git vim \ + # Utilities + supervisor netcat-openbsd \ + # Applications + xpdf gedit xpaint \ + # Libraries + libxtst-dev \ + # Remove unneeded dependencies + && apt-get remove -y light-locker xfce4-screensaver xfce4-power-manager || true \ + # Clean up to reduce image size + && apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /run/dbus && \ + # Generate a machine-id so dbus-daemon doesn't complain + dbus-uuidgen --ensure=/etc/machine-id + +# ----------------------------------------------------------------------------- +# 3. Additional software installation +# ----------------------------------------------------------------------------- +# Install Firefox +RUN apt-get update && apt-get install -y \ + # Install necessary for adding PPA + software-properties-common apt-transport-https wget gnupg \ + # Install Additional Graphics Libraries + mesa-utils \ + libgl1-mesa-dri \ + libgl1-mesa-glx \ + # Install Sandbox Capabilities + libcap2-bin \ + # Install Fonts + fontconfig \ + fonts-dejavu \ + fonts-liberation \ + fonts-freefont-ttf \ + && add-apt-repository -y ppa:mozillateam/ppa \ + && apt-get update \ + && apt-get install -y firefox-esr thunderbird \ + && apt-get clean && rm -rf /var/lib/apt/lists/* \ + # Set Firefox as default browser system-wide + && update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/bin/firefox-esr 200 \ + && update-alternatives --set x-www-browser /usr/bin/firefox-esr \ + && fc-cache -f -v + + +# Install 1Password based on architecture +RUN ARCH=$(dpkg --print-architecture) && \ + if [ "$ARCH" = "amd64" ]; then \ + # Install from APT repository for AMD64 + curl -sS https://downloads.1password.com/linux/keys/1password.asc | \ + gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg && \ + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/amd64 stable main" | \ + tee /etc/apt/sources.list.d/1password.list && \ + mkdir -p /etc/debsig/policies/AC2D62742012EA22/ && \ + curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | \ + tee /etc/debsig/policies/AC2D62742012EA22/1password.pol && \ + mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22 && \ + curl -sS https://downloads.1password.com/linux/keys/1password.asc | \ + gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg && \ + apt-get update && apt-get install -y 1password && \ + apt-get clean && rm -rf /var/lib/apt/lists/*; \ + elif [ "$ARCH" = "arm64" ]; then \ + # Install from tar.gz for ARM64 + apt-get update && apt-get install -y \ + libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils \ + libatspi2.0-0 libdrm2 libgbm1 libxcb-dri3-0 libxkbcommon0 \ + libsecret-1-0 && \ + apt-get clean && rm -rf /var/lib/apt/lists/* && \ + curl -sSL https://downloads.1password.com/linux/tar/beta/aarch64/1password-latest.tar.gz -o /tmp/1password.tar.gz && \ + # Extract the full 1Password bundle so libraries like libffmpeg.so remain in their expected relative paths + mkdir -p /opt/1password && \ + tar -xzf /tmp/1password.tar.gz -C /opt/1password --strip-components=1 && \ + # Link the main executable into the global PATH + ln -sf /opt/1password/1password /usr/bin/1password && \ + chmod +x /opt/1password/1password && \ + # Copy icons to standard locations + mkdir -p /usr/share/pixmaps /usr/share/icons/hicolor/512x512/apps /usr/share/icons/hicolor/256x256/apps && \ + find /opt/1password -name "*1password*.png" -o -name "*1password*.svg" | while read icon; do \ + if [[ "$icon" == *"512"* ]]; then \ + cp "$icon" /usr/share/icons/hicolor/512x512/apps/1password.png 2>/dev/null || true; \ + elif [[ "$icon" == *"256"* ]]; then \ + cp "$icon" /usr/share/icons/hicolor/256x256/apps/1password.png 2>/dev/null || true; \ + fi; \ + cp "$icon" /usr/share/pixmaps/1password.png 2>/dev/null || true; \ + done && \ + # Clean up temporary files + rm -rf /tmp/1password.tar.gz && \ + # Update icon cache + gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true; \ + else \ + echo "1Password is not available for $ARCH architecture."; \ + fi + +# Install Visual Studio Code +RUN ARCH=$(dpkg --print-architecture) && \ + if [ "$ARCH" = "amd64" ]; then \ + apt-get update && apt-get install -y wget gpg apt-transport-https software-properties-common && \ + wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/ms_vscode.gpg && \ + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/ms_vscode.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list && \ + apt-get update && apt-get install -y code && \ + apt-get clean && rm -rf /var/lib/apt/lists/* ; \ + elif [ "$ARCH" = "arm64" ]; then \ + apt-get update && apt-get install -y wget gpg && \ + wget -qO /tmp/code_arm64.deb https://update.code.visualstudio.com/latest/linux-deb-arm64/stable && \ + apt-get install -y /tmp/code_arm64.deb && \ + rm -f /tmp/code_arm64.deb && \ + apt-get clean && rm -rf /var/lib/apt/lists/* ; \ + else \ + echo "VSCode is not available for $ARCH architecture."; \ + fi + +# Install Node.js +RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ + && apt-get update \ + && apt-get install -y nodejs \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Upgrade pip +RUN pip3 install --upgrade pip + +# ----------------------------------------------------------------------------- +# 4. VNC and remote access setup +# ----------------------------------------------------------------------------- +# Install noVNC and websockify +RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC \ + && git clone https://github.com/novnc/websockify.git /opt/websockify \ + && cd /opt/websockify \ + && pip3 install --break-system-packages . + +# ----------------------------------------------------------------------------- +# 5. Application setup (bytebotd) +# ----------------------------------------------------------------------------- +# Copy package files first to leverage Docker cache + +# Install dependencies required to build libnut-core and uiohook-napi +RUN apt-get update && \ + apt-get install -y \ + cmake \ + libx11-dev \ + libxtst-dev \ + libxinerama-dev \ + libxi-dev \ + libxt-dev \ + libxrandr-dev \ + libxkbcommon-dev \ + libxkbcommon-x11-dev \ + xclip \ + git build-essential && \ + rm -rf /var/lib/apt/lists/* + +# Copy app source from repository root +# Note: Build context is the repository root for Railway +COPY packages/shared /bytebot/shared/ +COPY packages/bytebotd /bytebot/bytebotd/ +WORKDIR /bytebot/bytebotd +RUN npm install --build-from-source +RUN npm rebuild uiohook-napi --build-from-source + +RUN npm run build + +WORKDIR /compile + +RUN git clone https://github.com/ZachJW34/libnut-core.git && \ + cd libnut-core && \ + npm install && \ + npm run build:release + +# replace /bytebotd/node_modules/@nut-tree-fork/libnut-linux/build/Release/libnut.node with /compile/libnut-core/build/Release/libnut.node +RUN rm -f /bytebot/bytebotd/node_modules/@nut-tree-fork/libnut-linux/build/Release/libnut.node && \ + cp /compile/libnut-core/build/Release/libnut.node /bytebot/bytebotd/node_modules/@nut-tree-fork/libnut-linux/build/Release/libnut.node + +RUN rm -rf /compile + +WORKDIR /bytebot/bytebotd + +# ----------------------------------------------------------------------------- +# 7. User setup and autologin configuration +# ----------------------------------------------------------------------------- +# Create non-root user +RUN useradd -ms /bin/bash user && echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +RUN mkdir -p /var/run/dbus && \ + chmod 755 /var/run/dbus && \ + chown user:user /var/run/dbus + +RUN mkdir -p /tmp/bytebot-screenshots && \ + chown -R user:user /tmp/bytebot-screenshots + +# ----------------------------------------------------------------------------- +# Copy staged system files and keep sane permissions +# ----------------------------------------------------------------------------- +# 1. Ensure everything under /bytebotd/root is owned by root (files + dirs) +# 2. Set *files* to 0644 and *directories* to 0755 so that applications can +# traverse directories (execute bit!) while keeping the contents read-only. +# 3. Copy the tree to / +RUN chown -R root:root /bytebot/bytebotd/root && \ + find /bytebot/bytebotd/root -type f -exec chmod 644 {} + && \ + find /bytebot/bytebotd/root -type d -exec chmod 755 {} + && \ + find /bytebot/bytebotd/root -type f -executable -exec chmod +x {} + && \ + cp -a /bytebot/bytebotd/root/. / + +RUN chown -R user:user /home/user +RUN chmod -R 755 /home/user + +RUN mkdir -p /home/user/Desktop && \ + cp -f /usr/share/applications/firefox.desktop /home/user/Desktop/ && \ + cp -f /usr/share/applications/thunderbird.desktop /home/user/Desktop/ && \ + cp -f /usr/share/applications/1password.desktop /home/user/Desktop/ && \ + cp -f /usr/share/applications/code.desktop /home/user/Desktop/ && \ + cp -f /usr/share/applications/terminal.desktop /home/user/Desktop/ && \ + chmod +x /home/user/Desktop/*.desktop && \ + chown user:user /home/user/Desktop/*.desktop + +RUN mkdir -p /home/user/.config /home/user/.local/share /home/user/.cache \ + && chown -R user:user /home/user/.config /home/user/.local /home/user/.cache + +WORKDIR /home/user + +# ----------------------------------------------------------------------------- +# 8. Port configuration and runtime +# ----------------------------------------------------------------------------- +# - Port 9990: bytebotd and external noVNC websocket +EXPOSE 9990 + +# Start supervisor to manage all services +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf", "-n"] \ No newline at end of file diff --git a/Dockerfile.ui b/Dockerfile.ui new file mode 100644 index 000000000..ad205d96f --- /dev/null +++ b/Dockerfile.ui @@ -0,0 +1,29 @@ +# Railway Deployment Dockerfile for bytebot-ui +# Build context: repository root +FROM node:20-alpine + +# Build arguments for Next.js +ARG BYTEBOT_AGENT_BASE_URL +ARG BYTEBOT_DESKTOP_VNC_URL + +ENV BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL} +ENV BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL} + +WORKDIR /app + +# Copy shared package +COPY packages/shared ./shared + +# Copy UI package +COPY packages/bytebot-ui ./bytebot-ui + +WORKDIR /app/bytebot-ui + +# Install dependencies +RUN npm install + +# Build the application +RUN npm run build + +# Start the application +CMD ["npm", "run", "start"] diff --git a/RAILWAY_DEPLOYMENT.md b/RAILWAY_DEPLOYMENT.md new file mode 100644 index 000000000..afcd81b11 --- /dev/null +++ b/RAILWAY_DEPLOYMENT.md @@ -0,0 +1,305 @@ +# Railway Deployment Guide + +This guide shows how to deploy Bytebot on Railway **directly from this repository** without using pre-built templates or container images. + +## Overview + +Bytebot consists of four services that work together: + +**Important:** This is a monorepo deployment. Railway requires **manual configuration via the UI** for each service. Do not rely on auto-detection - follow the step-by-step instructions below to configure each service explicitly. + +1. **PostgreSQL** - Database for tasks, messages, and summaries +2. **bytebot-agent** - NestJS backend for task orchestration and LLM integration +3. **bytebot-ui** - Next.js frontend with Express server for proxying +4. **bytebot-desktop** - Ubuntu desktop environment with XFCE, VNC, and automation tools + +## Prerequisites + +- Railway account ([sign up here](https://railway.app/)) +- At least one AI provider API key: + - [Anthropic Claude](https://console.anthropic.com/) + - [OpenAI](https://platform.openai.com/api-keys) + - [Google Gemini](https://aistudio.google.com/app/apikey) +- Recommended Railway plan: **Pro or higher** (desktop service requires significant resources) + +## Deployment Steps + +### 1. Create a New Railway Project + +1. Go to [railway.app](https://railway.app/) and sign in +2. Click **"New Project"** +3. Select **"Empty Project"** (we'll manually configure each service) +4. Name your project (e.g., "Bytebot Production") + +### 2. Add PostgreSQL Database + +1. In your Railway project, click **"New"** +2. Select **"Database"** → **"Add PostgreSQL"** +3. Railway will automatically provision a PostgreSQL instance +4. The `DATABASE_URL` environment variable will be available as `${{Postgres.DATABASE_URL}}` + +### 3. Deploy bytebot-desktop Service + +⚠️ **Deploy this first** - other services depend on it. + +1. Click **"New"** → **"GitHub Repo"** +2. Connect your GitHub account and select this repository +3. Name the service: `bytebot-desktop` (exact name matters for internal DNS) + +4. Configure build settings (Settings → Build): + - **Builder:** Dockerfile + - **Dockerfile Path:** `Dockerfile.desktop` + - **Watch Paths:** `packages/bytebotd/**,packages/shared/**` + +5. Add environment variables (Variables tab): + ``` + DISPLAY=:0 + ``` + +6. Configure resources (Settings → Resources): + - **Memory:** 2GB minimum (4GB recommended) + - **CPU:** 2 vCPU minimum + - **Disk:** 2GB minimum + +7. Click **"Deploy"** + + **Note:** This service takes 5-10 minutes for initial build due to the Ubuntu desktop environment. Wait for it to be fully active before proceeding. + +### 4. Deploy bytebot-agent Service + +1. Click **"New"** → **"GitHub Repo"** → Select this repository +2. Name the service: `bytebot-agent` + +3. Configure build settings (Settings → Build): + - **Builder:** Dockerfile + - **Dockerfile Path:** `Dockerfile.agent` + - **Watch Paths:** `packages/bytebot-agent/**,packages/shared/**` + +4. Add environment variables (Variables tab): + ``` + DATABASE_URL=${{Postgres.DATABASE_URL}} + BYTEBOT_DESKTOP_BASE_URL=http://bytebot-desktop.railway.internal:9990 + ANTHROPIC_API_KEY=your-anthropic-api-key-here + ``` + + Optional variables: + ``` + OPENAI_API_KEY=your-openai-api-key-here + GEMINI_API_KEY=your-gemini-api-key-here + ``` + +5. Click **"Deploy"** + +### 5. Deploy bytebot-ui Service + +1. Click **"New"** → **"GitHub Repo"** → Select this repository +2. Name the service: `bytebot-ui` + +3. Configure build settings (Settings → Build): + - **Builder:** Dockerfile + - **Dockerfile Path:** `Dockerfile.ui` + - **Watch Paths:** `packages/bytebot-ui/**,packages/shared/**` + +4. Add build variables (Settings → Variables → Add Variable → Check "Build Variable"): + ``` + BYTEBOT_AGENT_BASE_URL=http://bytebot-agent.railway.internal:9991 + BYTEBOT_DESKTOP_VNC_URL=ws://bytebot-desktop.railway.internal:9990/websockify + ``` + +5. Add runtime environment variables (Variables tab): + ``` + BYTEBOT_AGENT_BASE_URL=http://bytebot-agent.railway.internal:9991 + BYTEBOT_DESKTOP_VNC_URL=ws://bytebot-desktop.railway.internal:9990/websockify + NEXT_PUBLIC_API_URL=http://bytebot-agent.railway.internal:9991 + NODE_ENV=production + HOSTNAME=0.0.0.0 + ``` + +6. Enable public networking (Settings → Networking): + - Toggle **"Public Networking"** ON + - Railway will assign a public URL (e.g., `https://bytebot-ui-production.up.railway.app`) + +7. Click **"Deploy"** + +### 6. Verify Deployment + +1. Wait for all services to show **"Active"** status +2. Click on the **bytebot-ui** service to get the public URL +3. Open the URL in your browser +4. You should see the Bytebot task interface +5. Try creating a task to verify the full stack is working + +## Railway Service Discovery + +Railway provides automatic service discovery via internal DNS: + +- Format: `.railway.internal:` +- Examples: + - `bytebot-agent.railway.internal:9991` + - `bytebot-desktop.railway.internal:9990` + - `postgres.railway.internal:5432` + +Services communicate internally using these URLs, and only the UI is exposed publicly. + +## Configuration Files + +This repository includes Railway-specific configuration: + +- `railway.json` - Root project configuration +- `packages/bytebot-agent/railway.toml` - Agent service configuration +- `packages/bytebot-ui/railway.toml` - UI service configuration +- `packages/bytebotd/railway.toml` - Desktop service configuration +- `.env.example` files in each package directory + +## Troubleshooting + +### Service won't start + +- **Check logs:** Click on the service → "Deployments" → Select latest deployment → "View Logs" +- **Verify environment variables:** Ensure all required variables are set correctly +- **Check service names:** Internal URLs must match the exact service names in Railway + +### Desktop service build timeout + +- The desktop service takes 5-10 minutes to build initially +- If build fails, check the Railway plan limits (free tier may have build time restrictions) +- Upgrade to Pro plan for longer build times and better resources + +### Agent can't connect to desktop + +- Verify `BYTEBOT_DESKTOP_BASE_URL` uses the correct internal URL +- Ensure desktop service is deployed and active before agent starts +- Check that service name matches exactly (case-sensitive) + +### UI shows "connecting..." indefinitely + +- Verify all services are active and healthy +- Check UI environment variables match internal service URLs +- Open browser console (F12) to check for WebSocket connection errors +- Verify desktop service is fully started (check logs for "supervisord started") + +### Database connection errors + +- Ensure PostgreSQL service is active +- Verify `DATABASE_URL` is set correctly in agent service +- Check database service logs for connection issues +- For first deployment, wait for Prisma migrations to complete + +### Out of memory errors + +- Desktop service requires minimum 2GB RAM +- Upgrade Railway plan if on free tier +- Check resource usage in Railway dashboard +- Consider reducing desktop applications if needed + +## Cost Optimization + +Railway charges based on resource usage. To optimize costs: + +1. **Use appropriate plan:** + - Free trial: Limited resources, good for testing + - Pro: $20/month + usage, recommended for production + +2. **Scale resources appropriately:** + - Agent: 512MB RAM, 0.5 vCPU sufficient + - UI: 512MB RAM, 0.5 vCPU sufficient + - Desktop: 2GB RAM, 2 vCPU minimum + - Database: Use default settings + +3. **Monitor usage:** + - Check Railway dashboard regularly + - Set up usage alerts + - Review deployment logs for errors that cause restarts + +## Security Considerations + +1. **Environment Variables:** + - Never commit API keys to version control + - Use Railway's environment variable system + - Rotate API keys regularly + +2. **Network Security:** + - Only UI service should be publicly accessible + - All internal services use private Railway networking + - Add authentication to UI if exposing to internet + +3. **Database Security:** + - Railway PostgreSQL uses encrypted connections by default + - Database is only accessible via private network + - Regular backups are recommended + +## Advanced Configuration + +### Custom Domain + +1. Go to UI service → Settings → Networking +2. Click "Add Custom Domain" +3. Follow Railway's DNS configuration instructions +4. Optional: Enable Cloudflare integration for CDN/WAF + +### Environment-Specific Configuration + +Deploy to different Railway projects for different environments: + +- **Development:** Use `development` branch, lower resources +- **Staging:** Use `staging` branch, production-like resources +- **Production:** Use `main` branch, full resources + +### Adding LLM Proxy (Optional) + +If you want to use the optional LiteLLM proxy: + +1. Click **"New"** → **"Service"** +2. Configure: + - **Name:** `bytebot-llm-proxy` + - **Root Directory:** `packages/bytebot-llm-proxy` + - **Dockerfile Path:** `packages/bytebot-llm-proxy/Dockerfile` +3. Add environment variables (your AI provider keys) +4. Update agent service: + ``` + BYTEBOT_LLM_PROXY_URL=http://bytebot-llm-proxy.railway.internal:4000 + ``` + +## Monitoring and Maintenance + +### View Logs + +- Click on any service → "Deployments" → "View Logs" +- Logs are real-time and searchable +- Use logs to debug issues and monitor performance + +### Restart Service + +- Click on service → Settings → "Restart" +- Or trigger redeploy by pushing to GitHub + +### Database Migrations + +- Prisma migrations run automatically on agent startup +- Check agent logs for migration status +- For manual migrations, use Railway CLI or database GUI + +### Scaling + +Railway auto-scales within configured resource limits. To adjust: + +1. Click service → Settings → Resources +2. Adjust Memory, CPU, and Replicas +3. Click "Save" +4. Service will restart with new resources + +## Support + +- **Railway Documentation:** https://docs.railway.app/ +- **Bytebot Issues:** https://github.com/bytebot-ai/bytebot/issues +- **Railway Community:** https://discord.gg/railway +- **Bytebot Discord:** https://discord.com/invite/d9ewZkWPTP + +## Next Steps + +After deployment: + +1. Explore the REST APIs at `/api/tasks`, `/api/messages`, etc. +2. Review the [API documentation](/docs/api-reference/introduction) +3. Join the Bytebot community on Discord +4. Share your automation workflows! diff --git a/RAILWAY_QUICKSTART.md b/RAILWAY_QUICKSTART.md new file mode 100644 index 000000000..c095aa226 --- /dev/null +++ b/RAILWAY_QUICKSTART.md @@ -0,0 +1,155 @@ +# Railway Quick Start Guide + +Deploy Bytebot to Railway from this repository in under 15 minutes. + +## Prerequisites + +- Railway account with credit card (Pro plan recommended for desktop service) +- One AI API key: [Anthropic](https://console.anthropic.com/) | [OpenAI](https://platform.openai.com/api-keys) | [Gemini](https://aistudio.google.com/app/apikey) + +## Quick Deploy Checklist + +### 1. Create Railway Project (2 min) + +- [ ] Go to [railway.app](https://railway.app/) → New Project +- [ ] Select **Empty Project** (don't use GitHub auto-deploy yet) +- [ ] Name your project (e.g., "Bytebot") + +### 2. Add PostgreSQL (1 min) + +- [ ] Click **New** → **Database** → **PostgreSQL** +- [ ] Wait for provisioning (auto-completes in ~30 seconds) + +### 3. Deploy bytebot-desktop (10 min) + +- [ ] Click **New** → **GitHub Repo** → Select this repository +- [ ] **Service Name:** `bytebot-desktop` (exact name matters!) + +**Configure Build (Settings → Build):** +- **Builder:** Dockerfile +- **Dockerfile Path:** `Dockerfile.desktop` +- **Watch Paths:** `packages/bytebotd/**,packages/shared/**` + +**Environment Variables (Variables tab):** +```bash +DISPLAY=:0 +``` + +**Resources (Settings → Resources):** +- Memory: 2048 MB (minimum) +- CPU: 2 vCPU (minimum) + +- [ ] Click **Deploy** → Wait 5-10 minutes for Ubuntu desktop build + +### 4. Deploy bytebot-agent (3 min) + +- [ ] Click **New** → **GitHub Repo** → Select this repository +- [ ] **Service Name:** `bytebot-agent` + +**Configure Build (Settings → Build):** +- **Builder:** Dockerfile +- **Dockerfile Path:** `Dockerfile.agent` +- **Watch Paths:** `packages/bytebot-agent/**,packages/shared/**` + +**Environment Variables (Variables tab):** +```bash +DATABASE_URL=${{Postgres.DATABASE_URL}} +BYTEBOT_DESKTOP_BASE_URL=http://bytebot-desktop.railway.internal:9990 +ANTHROPIC_API_KEY=sk-ant-xxxxx +``` + +Optional (add more AI providers): +```bash +OPENAI_API_KEY=sk-xxxxx +GEMINI_API_KEY=xxxxx +``` + +- [ ] Click **Deploy** + +### 5. Deploy bytebot-ui (3 min) + +- [ ] Click **New** → **GitHub Repo** → Select this repository +- [ ] **Service Name:** `bytebot-ui` + +**Configure Build (Settings → Build):** +- **Builder:** Dockerfile +- **Dockerfile Path:** `Dockerfile.ui` +- **Watch Paths:** `packages/bytebot-ui/**,packages/shared/**` + +**Build Variables (Settings → Variables → Add Variable → Make Build Variable):** +```bash +BYTEBOT_AGENT_BASE_URL=http://bytebot-agent.railway.internal:9991 +BYTEBOT_DESKTOP_VNC_URL=ws://bytebot-desktop.railway.internal:9990/websockify +``` + +**Environment Variables:** +```bash +BYTEBOT_AGENT_BASE_URL=http://bytebot-agent.railway.internal:9991 +BYTEBOT_DESKTOP_VNC_URL=ws://bytebot-desktop.railway.internal:9990/websockify +NEXT_PUBLIC_API_URL=http://bytebot-agent.railway.internal:9991 +NODE_ENV=production +HOSTNAME=0.0.0.0 +``` + +**Networking:** +- Enable **Public Networking** (Settings → Networking) +- Copy the generated public URL + +- [ ] Click **Deploy** + +### 6. Test (1 min) + +- [ ] Wait for all services to show **Active** status +- [ ] Open the bytebot-ui public URL +- [ ] Create a test task (e.g., "Open Firefox and search for Railway") +- [ ] Watch the desktop stream execute the task + +## Service Names Matter! + +Railway's internal DNS uses exact service names. If you used different names, update these environment variables: + +```bash +# In bytebot-agent: +BYTEBOT_DESKTOP_BASE_URL=http://YOUR-DESKTOP-SERVICE-NAME.railway.internal:9990 + +# In bytebot-ui: +BYTEBOT_AGENT_BASE_URL=http://YOUR-AGENT-SERVICE-NAME.railway.internal:9991 +BYTEBOT_DESKTOP_VNC_URL=ws://YOUR-DESKTOP-SERVICE-NAME.railway.internal:9990/websockify +``` + +## Troubleshooting + +| Problem | Solution | +|---------|----------| +| Desktop build timeout | Use Pro plan (free tier has build time limits) | +| Agent can't connect | Check service names match exactly | +| UI shows "connecting..." | Wait for desktop to fully start (check logs) | +| Out of memory | Increase desktop RAM to 4GB | + +## Cost Estimate (Pro Plan) + +- **Plan:** $20/month +- **Usage:** ~$30-60/month for moderate use + - Desktop: ~$20-40/month (2GB RAM, always-on) + - Agent + UI: ~$5-10/month + - Database: ~$5-10/month +- **Total:** ~$50-80/month + +Optimize costs by: +- Stopping desktop service when not in use +- Using Hobby plan for testing ($5/month) +- Monitoring usage in Railway dashboard + +## Next Steps + +- [ ] Add custom domain (Settings → Networking → Custom Domain) +- [ ] Set up environment-specific deployments (dev/staging/prod) +- [ ] Configure monitoring and alerts +- [ ] Review [full deployment guide](RAILWAY_DEPLOYMENT.md) + +## Support + +- 📚 [Full Guide](RAILWAY_DEPLOYMENT.md) +- 🚂 [Railway Docs](https://docs.railway.app/) +- 💬 [Railway Discord](https://discord.gg/railway) +- 🤖 [Bytebot Discord](https://discord.com/invite/d9ewZkWPTP) diff --git a/docker/docker-compose-claude-code.yml b/docker/docker-compose-claude-code.yml index 3b714c5ab..cb329df39 100644 --- a/docker/docker-compose-claude-code.yml +++ b/docker/docker-compose-claude-code.yml @@ -4,8 +4,8 @@ services: bytebot-desktop: # Build from source build: - context: ../packages/ - dockerfile: bytebotd/Dockerfile + context: ../ + dockerfile: packages/bytebotd/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-desktop:edge shm_size: "2g" @@ -37,8 +37,8 @@ services: bytebot-agent-cc: build: - context: ../packages/ - dockerfile: bytebot-agent-cc/Dockerfile + context: ../ + dockerfile: packages/bytebot-agent-cc/Dockerfile container_name: bytebot-agent-cc restart: unless-stopped ports: @@ -54,8 +54,8 @@ services: bytebot-ui: build: - context: ../packages/ - dockerfile: bytebot-ui/Dockerfile + context: ../ + dockerfile: packages/bytebot-ui/Dockerfile args: - BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL:-http://bytebot-agent-cc:9991} - BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL:-http://bytebot-desktop:9990/websockify} diff --git a/docker/docker-compose.core.yml b/docker/docker-compose.core.yml index dee5e736c..6048d30b9 100644 --- a/docker/docker-compose.core.yml +++ b/docker/docker-compose.core.yml @@ -4,8 +4,8 @@ services: bytebot-desktop: # Build from source build: - context: ../packages/ - dockerfile: bytebotd/Dockerfile + context: ../ + dockerfile: packages/bytebotd/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-desktop:edge shm_size: "2g" diff --git a/docker/docker-compose.development.yml b/docker/docker-compose.development.yml index 4d7bc5ef9..2a2269ac3 100644 --- a/docker/docker-compose.development.yml +++ b/docker/docker-compose.development.yml @@ -9,8 +9,8 @@ services: bytebot-desktop: # Build from source build: - context: ../packages/ - dockerfile: bytebotd/Dockerfile + context: ../ + dockerfile: packages/bytebotd/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-desktop:edge shm_size: "2g" diff --git a/docker/docker-compose.proxy.yml b/docker/docker-compose.proxy.yml index 2a68a6303..b39d940b3 100644 --- a/docker/docker-compose.proxy.yml +++ b/docker/docker-compose.proxy.yml @@ -4,8 +4,8 @@ services: bytebot-desktop: # Build from source build: - context: ../packages/ - dockerfile: bytebotd/Dockerfile + context: ../ + dockerfile: packages/bytebotd/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-desktop:edge shm_size: "2g" @@ -37,8 +37,8 @@ services: bytebot-agent: build: - context: ../packages/ - dockerfile: bytebot-agent/Dockerfile + context: ../ + dockerfile: packages/bytebot-agent/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-agent:edge container_name: bytebot-agent @@ -56,8 +56,8 @@ services: bytebot-llm-proxy: build: - context: ../packages/ - dockerfile: bytebot-llm-proxy/Dockerfile + context: ../ + dockerfile: packages/bytebot-llm-proxy/Dockerfile ports: - "4000:4000" environment: @@ -69,8 +69,8 @@ services: bytebot-ui: build: - context: ../packages/ - dockerfile: bytebot-ui/Dockerfile + context: ../ + dockerfile: packages/bytebot-ui/Dockerfile args: - BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL:-http://bytebot-agent:9991} - BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL:-http://bytebot-desktop:9990/websockify} diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 7d4c1e1dc..f62b1f418 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -4,8 +4,8 @@ services: bytebot-desktop: # Build from source build: - context: ../packages/ - dockerfile: bytebotd/Dockerfile + context: ../ + dockerfile: packages/bytebotd/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-desktop:edge shm_size: "2g" @@ -37,8 +37,8 @@ services: bytebot-agent: build: - context: ../packages/ - dockerfile: bytebot-agent/Dockerfile + context: ../ + dockerfile: packages/bytebot-agent/Dockerfile # Use pre-built image image: ghcr.io/bytebot-ai/bytebot-agent:edge container_name: bytebot-agent @@ -58,8 +58,8 @@ services: bytebot-ui: build: - context: ../packages/ - dockerfile: bytebot-ui/Dockerfile + context: ../ + dockerfile: packages/bytebot-ui/Dockerfile args: - BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL:-http://bytebot-agent:9991} - BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL:-http://bytebot-desktop:9990/websockify} diff --git a/packages/bytebot-agent/.env.example b/packages/bytebot-agent/.env.example index 713c70043..5a116cb50 100644 --- a/packages/bytebot-agent/.env.example +++ b/packages/bytebot-agent/.env.example @@ -1,4 +1,26 @@ +# Database connection string (Required) +# Local: postgresql://postgres:postgres@postgres:5432/bytebotdb +# Railway: Automatically set via ${{Postgres.DATABASE_URL}} reference variable DATABASE_URL=postgresql://postgres:postgres@postgres:5432/bytebotdb + +# AI Provider API Keys (At least one required) +# Get Anthropic key at: https://console.anthropic.com/ ANTHROPIC_API_KEY= +# Get OpenAI key at: https://platform.openai.com/api-keys +OPENAI_API_KEY= +# Get Gemini key at: https://aistudio.google.com/app/apikey +GEMINI_API_KEY= + +# Desktop service URL (Required) +# Local: http://localhost:9990 +# Railway: http://bytebot-desktop.railway.internal:9990 BYTEBOT_DESKTOP_BASE_URL=http://localhost:9990 + +# Optional: LLM Proxy URL (if using bytebot-llm-proxy service) +# BYTEBOT_LLM_PROXY_URL=http://localhost:4000 + +# Optional: Analytics endpoint BYTEBOT_ANALYTICS_ENDPOINT= + +# Optional: Port override (default: 9991) +# PORT=9991 diff --git a/packages/bytebot-agent/Dockerfile b/packages/bytebot-agent/Dockerfile index 1192007c9..025fd31f8 100644 --- a/packages/bytebot-agent/Dockerfile +++ b/packages/bytebot-agent/Dockerfile @@ -4,16 +4,16 @@ FROM node:20-alpine # Create app directory WORKDIR /app -# Copy app source -COPY ./shared ./shared -COPY ./bytebot-agent/ ./bytebot-agent/ +# Copy app source from repository root +# Note: Build context is the repository root for Railway +COPY packages/shared ./shared +COPY packages/bytebot-agent ./bytebot-agent WORKDIR /app/bytebot-agent # Install dependencies RUN npm install - RUN npm run build # Run the application diff --git a/packages/bytebot-ui/.env.example b/packages/bytebot-ui/.env.example index a458a6bec..51ee82591 100644 --- a/packages/bytebot-ui/.env.example +++ b/packages/bytebot-ui/.env.example @@ -1,3 +1,24 @@ +# Agent service URL (Required) +# Local: http://localhost:9991 +# Railway: http://bytebot-agent.railway.internal:9991 BYTEBOT_AGENT_BASE_URL=http://localhost:9991 + +# Desktop VNC WebSocket URL (Required) +# Local: ws://localhost:9990/websockify +# Railway: ws://bytebot-desktop.railway.internal:9990/websockify BYTEBOT_DESKTOP_VNC_URL=ws://localhost:9990/websockify + +# Public API URL for browser (Required) +# Local: http://localhost:9991 +# Railway: Use internal URL, Express server proxies requests NEXT_PUBLIC_API_URL=http://localhost:9991 + +# Node environment (development | production) +# Railway: Set to production automatically +NODE_ENV=development + +# Optional: Port override (default: 9992) +# PORT=9992 + +# Optional: Hostname (default: localhost, Railway: 0.0.0.0) +# HOSTNAME=0.0.0.0 diff --git a/packages/bytebot-ui/Dockerfile b/packages/bytebot-ui/Dockerfile index c2a71e8d7..d3cb0a739 100644 --- a/packages/bytebot-ui/Dockerfile +++ b/packages/bytebot-ui/Dockerfile @@ -12,9 +12,10 @@ ENV BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL} # Create app directory WORKDIR /app -# Copy app source -COPY ./shared ./shared -COPY ./bytebot-ui/ ./bytebot-ui +# Copy app source from repository root +# Note: Build context is the repository root for Railway +COPY packages/shared ./shared +COPY packages/bytebot-ui ./bytebot-ui WORKDIR /app/bytebot-ui diff --git a/packages/bytebot-ui/server.ts b/packages/bytebot-ui/server.ts index c942f7799..b7c1be4b8 100644 --- a/packages/bytebot-ui/server.ts +++ b/packages/bytebot-ui/server.ts @@ -9,7 +9,8 @@ import dotenv from "dotenv"; dotenv.config(); const dev = process.env.NODE_ENV !== "production"; -const hostname = process.env.HOSTNAME || "localhost"; +// In production, bind to 0.0.0.0 to accept connections from load balancers (Railway, etc.) +const hostname = process.env.HOSTNAME || (dev ? "localhost" : "0.0.0.0"); const port = parseInt(process.env.PORT || "9992", 10); // Backend URLs diff --git a/packages/bytebotd/.env.example b/packages/bytebotd/.env.example new file mode 100644 index 000000000..7602f88a2 --- /dev/null +++ b/packages/bytebotd/.env.example @@ -0,0 +1,36 @@ +# Bytebot Desktop (bytebotd) Environment Variables +# Copy this file to .env and fill in the values + +# ============================================================================ +# X11 DISPLAY (Required for Desktop Environment) +# ============================================================================ +# X11 display number for the virtual desktop +# Default: :0 (first display) +DISPLAY=:0 + +# ============================================================================ +# SERVER CONFIGURATION +# ============================================================================ +# Server port (default: 9990) +# Serves both bytebotd API and noVNC websocket endpoint +# PORT=9990 + +# ============================================================================ +# RESOURCE NOTES +# ============================================================================ +# This service runs a full Ubuntu desktop environment including: +# - XFCE desktop +# - X11 server (Xvfb) +# - VNC server (x11vnc) +# - noVNC web client +# - Firefox ESR +# - VS Code +# - 1Password +# - Node.js 20 +# +# Recommended resources: +# - Memory: 2GB minimum, 4GB recommended +# - CPU: 2 vCPU minimum +# - Disk: 2GB minimum +# +# Railway Plan Recommendation: Pro or higher for optimal performance diff --git a/packages/bytebotd/Dockerfile b/packages/bytebotd/Dockerfile index f8a893bc8..3b450f752 100644 --- a/packages/bytebotd/Dockerfile +++ b/packages/bytebotd/Dockerfile @@ -174,8 +174,10 @@ RUN apt-get update && \ git build-essential && \ rm -rf /var/lib/apt/lists/* -COPY ./shared/ /bytebot/shared/ -COPY ./bytebotd/ /bytebot/bytebotd/ +# Copy app source from repository root +# Note: Build context is the repository root for Railway +COPY packages/shared /bytebot/shared/ +COPY packages/bytebotd /bytebot/bytebotd/ WORKDIR /bytebot/bytebotd RUN npm install --build-from-source RUN npm rebuild uiohook-napi --build-from-source diff --git a/packages/bytebotd/src/main.ts b/packages/bytebotd/src/main.ts index 3999c8eb4..5dcf93706 100644 --- a/packages/bytebotd/src/main.ts +++ b/packages/bytebotd/src/main.ts @@ -25,7 +25,7 @@ async function bootstrap() { pathRewrite: { '^/websockify': '/' }, }); app.use('/websockify', express.raw({ type: '*/*' }), wsProxy); - const server = await app.listen(9990); + const server = await app.listen(process.env.PORT ?? 9990); // Selective upgrade routing server.on('upgrade', (req, socket, head) => { diff --git a/railway.toml b/railway.toml new file mode 100644 index 000000000..176263174 --- /dev/null +++ b/railway.toml @@ -0,0 +1,23 @@ +# Railway Configuration for Bytebot Monorepo +# +# IMPORTANT: This file is for documentation only. +# Railway requires manual service configuration for monorepos. +# +# Railway automatically sets the build context based on the Dockerfile location. +# To ensure the context is the repository root, we use Dockerfiles at the root level. +# +# For each service, configure in Railway UI: +# +# Service: bytebot-agent +# - Dockerfile Path: Dockerfile.agent +# - Watch Paths: packages/bytebot-agent/**, packages/shared/** +# +# Service: bytebot-ui +# - Dockerfile Path: Dockerfile.ui +# - Watch Paths: packages/bytebot-ui/**, packages/shared/** +# +# Service: bytebot-desktop +# - Dockerfile Path: Dockerfile.desktop +# - Watch Paths: packages/bytebotd/**, packages/shared/** +# +# All Dockerfiles are at the repository root, ensuring the build context is correct.