chore(docker): improve base image and organize docker files

- Add wget, ripgrep, python3, and GitHub CLI (gh) to base image
- Add OPENCODE_ALLOW_ALL_MODELS=true to production ENV
- Move compose files, onboard-smoke Dockerfile to docker/
- Move entrypoint script to scripts/docker-entrypoint.sh
- Add Podman Quadlet unit files (pod, app, db containers)
- Add docker/README.md with build, compose, and quadlet docs
- Add scripts/docker-build-test.sh for local build validation
- Update all doc references for new file locations
- Keep main Dockerfile at project root (no .dockerignore changes needed)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Cody (Radius Red)
2026-04-01 11:06:37 +00:00
parent ebc6888e7d
commit 420cd4fd8d
15 changed files with 249 additions and 27 deletions

View File

@@ -0,0 +1,40 @@
FROM ubuntu:24.04
ARG NODE_MAJOR=20
ARG PAPERCLIPAI_VERSION=latest
ARG HOST_UID=10001
ENV DEBIAN_FRONTEND=noninteractive \
PAPERCLIP_HOME=/paperclip \
PAPERCLIP_OPEN_ON_LISTEN=false \
HOST=0.0.0.0 \
PORT=3100 \
HOME=/home/paperclip \
LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
NPM_CONFIG_UPDATE_NOTIFIER=false \
NODE_MAJOR=${NODE_MAJOR} \
PAPERCLIPAI_VERSION=${PAPERCLIPAI_VERSION}
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl gnupg locales \
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
> /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends nodejs \
&& locale-gen en_US.UTF-8 \
&& groupadd --gid 10001 paperclip \
&& useradd --create-home --shell /bin/bash --uid "${HOST_UID}" --gid 10001 paperclip \
&& mkdir -p /paperclip /home/paperclip/workspace \
&& chown -R paperclip:paperclip /paperclip /home/paperclip \
&& rm -rf /var/lib/apt/lists/*
VOLUME ["/paperclip"]
WORKDIR /home/paperclip/workspace
EXPOSE 3100
USER paperclip
CMD ["bash", "-lc", "set -euo pipefail; mkdir -p \"$PAPERCLIP_HOME\"; npx --yes \"paperclipai@${PAPERCLIPAI_VERSION}\" onboard --yes --data-dir \"$PAPERCLIP_HOME\""]

View File

@@ -0,0 +1,18 @@
services:
paperclip:
build:
context: ..
dockerfile: Dockerfile
ports:
- "${PAPERCLIP_PORT:-3100}:3100"
environment:
HOST: "0.0.0.0"
PAPERCLIP_HOME: "/paperclip"
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
PAPERCLIP_DEPLOYMENT_MODE: "authenticated"
PAPERCLIP_DEPLOYMENT_EXPOSURE: "private"
PAPERCLIP_PUBLIC_URL: "${PAPERCLIP_PUBLIC_URL:-http://localhost:3100}"
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:?BETTER_AUTH_SECRET must be set}"
volumes:
- "${PAPERCLIP_DATA_DIR:-../data/docker-paperclip}:/paperclip"

View File

@@ -0,0 +1,33 @@
services:
review:
build:
context: ..
dockerfile: docker/untrusted-review/Dockerfile
init: true
tty: true
stdin_open: true
working_dir: /work
environment:
HOME: "/home/reviewer"
CODEX_HOME: "/home/reviewer/.codex"
CLAUDE_HOME: "/home/reviewer/.claude"
PAPERCLIP_HOME: "/home/reviewer/.paperclip-review"
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
GITHUB_TOKEN: "${GITHUB_TOKEN:-}"
ports:
- "${REVIEW_PAPERCLIP_PORT:-3100}:3100"
- "${REVIEW_VITE_PORT:-5173}:5173"
volumes:
- review-home:/home/reviewer
- review-work:/work
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp:mode=1777,size=1g
volumes:
review-home:
review-work:

40
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,40 @@
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_USER: paperclip
POSTGRES_PASSWORD: paperclip
POSTGRES_DB: paperclip
healthcheck:
test: ["CMD-SHELL", "pg_isready -U paperclip -d paperclip"]
interval: 2s
timeout: 5s
retries: 30
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
server:
build:
context: ..
dockerfile: Dockerfile
ports:
- "3100:3100"
environment:
DATABASE_URL: postgres://paperclip:paperclip@db:5432/paperclip
PORT: "3100"
SERVE_UI: "true"
PAPERCLIP_DEPLOYMENT_MODE: "authenticated"
PAPERCLIP_DEPLOYMENT_EXPOSURE: "private"
PAPERCLIP_PUBLIC_URL: "${PAPERCLIP_PUBLIC_URL:-http://localhost:3100}"
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:?BETTER_AUTH_SECRET must be set}"
volumes:
- paperclip-data:/paperclip
depends_on:
db:
condition: service_healthy
volumes:
pgdata:
paperclip-data:

View File

@@ -0,0 +1,20 @@
[Unit]
Description=PostgreSQL for Paperclip
[Container]
Image=docker.io/library/postgres:17-alpine
ContainerName=paperclip-db
Pod=paperclip.pod
Volume=paperclip-pgdata:/var/lib/postgresql/data
EnvironmentFile=%h/.config/containers/systemd/paperclip.env
HealthCmd=pg_isready -U $POSTGRES_USER -d $POSTGRES_DB -h localhost || exit 1
HealthInterval=15s
HealthTimeout=5s
HealthRetries=5
[Service]
Restart=on-failure
TimeoutStartSec=60
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,23 @@
[Unit]
Description=Paperclip AI Agent Orchestrator
Requires=paperclip-db.service
After=paperclip-db.service
[Container]
Image=paperclip-local
ContainerName=paperclip
Pod=paperclip.pod
Volume=%h/.local/share/paperclip:/paperclip:Z
Environment=HOST=0.0.0.0
Environment=PAPERCLIP_HOME=/paperclip
Environment=PAPERCLIP_DEPLOYMENT_MODE=authenticated
Environment=PAPERCLIP_DEPLOYMENT_EXPOSURE=private
Environment=PAPERCLIP_PUBLIC_URL=http://localhost:3100
EnvironmentFile=%h/.config/containers/systemd/paperclip.env
[Service]
Restart=on-failure
TimeoutStartSec=120
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,3 @@
[Pod]
PodName=paperclip
PublishPort=3100:3100