Files
nanobot/Dockerfile
T
770d89b430 feat: add one-click Deploy to Render support
Adds a Render Blueprint (render.yaml) and supporting pieces so nanobot can
be deployed to Render in one click, with persistent memory across deploys.

- render.yaml: web service + 1GB persistent disk mounted at
  /home/nanobot/.nanobot. Prompts for ANTHROPIC_API_KEY and
  NANOBOT_WEB_TOKEN at deploy time (sync: false).
- render-config.json: committed gateway config that wires secrets via
  ${VAR} placeholders (resolved at runtime). Nothing secret is committed.
- entrypoint.sh: adds a branch gated on RENDER=true that copies the config
  onto the mounted disk, chowns the root-owned mount, and drops to the
  non-root nanobot user via setpriv. Local (non-Render) path is unchanged.
- Dockerfile: COPY render-config.json; USER nanobot -> USER root so the
  entrypoint can chown the freshly-mounted disk before dropping privileges;
  add PYTHONUNBUFFERED/PYTHONFAULTHANDLER for diagnosable crash output.
- README.md: Deploy to Render button + section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 17:39:59 +08:00

59 lines
2.2 KiB
Docker

FROM node:24-bookworm-slim AS webui-builder
WORKDIR /app
COPY webui/package.json webui/package-lock.json ./webui/
WORKDIR /app/webui
RUN npm ci
COPY webui/ ./
RUN mkdir -p /app/nanobot/web && npm run build
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates git bubblewrap openssh-client libmagic1 && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install Python dependencies first (cached layer). Hatch reads the custom build
# hook from hatch_build.py even for this metadata-only install.
ARG NANOBOT_EXTRAS=whatsapp
COPY pyproject.toml README.md LICENSE THIRD_PARTY_NOTICES.md hatch_build.py ./
RUN mkdir -p nanobot && touch nanobot/__init__.py && \
NANOBOT_SKIP_WEBUI_BUILD=1 uv pip install --system --no-cache ".[$NANOBOT_EXTRAS]" && \
rm -rf nanobot
# Copy the full source and install
COPY nanobot/ nanobot/
COPY --from=webui-builder /app/nanobot/web/dist/ nanobot/web/dist/
RUN NANOBOT_SKIP_WEBUI_BUILD=1 uv pip install --system --no-cache ".[$NANOBOT_EXTRAS]"
# Render deploy template (see render.yaml): committed gateway config that wires
# secrets through ${ANTHROPIC_API_KEY} / ${NANOBOT_WEB_TOKEN} env vars (resolved
# at startup). Lives in the code dir (/app), not the data dir, so a mounted disk
# won't shadow it. Only used when RENDER=true; ignored by local runs.
COPY render-config.json ./
# Create non-root user and config directory
RUN useradd -m -u 1000 -s /bin/bash nanobot && \
mkdir -p /home/nanobot/.nanobot && \
chown -R nanobot:nanobot /home/nanobot /app
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN sed -i 's/\r$//' /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh
# Start as root so the Render entrypoint can chown the freshly-mounted
# (root-owned) persistent disk, then drop to the non-root nanobot user via
# setpriv (see entrypoint.sh). Local runs without a disk are unaffected.
USER root
ENV HOME=/home/nanobot
# Ensure crash output reaches Render logs (app output is otherwise swallowed on
# non-graceful exit).
ENV PYTHONUNBUFFERED=1 PYTHONFAULTHANDLER=1
# Gateway health endpoint and optional WebUI/WebSocket channel ports
EXPOSE 18790 8765
ENTRYPOINT ["entrypoint.sh"]
CMD ["status"]