Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ COPY --from=builder /venv /venv
# Create a non-root user to run the application.
RUN useradd -m -u 1000 clawmetry

# Install gosu to drop privileges safely.
RUN apt-get update && \
apt-get install -y --no-install-recommends gosu && \
rm -rf /var/lib/apt/lists/*

# Create the default OpenClaw data directory so the container starts
# without requiring a volume mount (clawmetry auto-detects ~/.openclaw).
RUN mkdir -p /home/clawmetry/.openclaw && \
Expand All @@ -35,7 +40,15 @@ COPY wsgi.py .
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

USER clawmetry
# SECURITY NOTE:
# The container intentionally starts as root so that entrypoint.sh can perform any
# required permission and ownership fixes (e.g., chown/chmod on mounted volumes)
# before the application runs. The script is expected to call 'gosu' as early as
# possible to drop privileges to the non-root 'clawmetry' user for the actual
# application process.
# This increases the attack surface if a vulnerability exists in the portion of
# entrypoint.sh that runs before 'gosu'. Keep that logic minimal, avoid parsing
# untrusted input there, and review any changes to entrypoint.sh carefully.

EXPOSE 8900

Expand Down
42 changes: 41 additions & 1 deletion entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ while [ $# -gt 0 ]; do
export MC_URL="$2"; shift 2 ;;
--fleet-api-key)
export CLAWMETRY_FLEET_KEY="$2"; shift 2 ;;
--fleet-db-path)
export FLEET_DB_PATH="$2"; shift 2 ;;
Comment on lines +34 to +35
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new --fleet-db-path flag and FLEET_DB_PATH environment variable are not documented in the README.md or docs/guide/configuration.md. According to the stored memory about configuration documentation conventions (docs/guide/configuration.md:9-17), all environment variables should be documented in the configuration reference with per-variable subsections. Add documentation for this new variable including its CLI equivalent, description, and usage example.

Copilot uses AI. Check for mistakes.
--no-debug|--debug)
# Debug mode is not applicable under gunicorn; silently ignore.
shift ;;
Expand All @@ -40,7 +42,45 @@ while [ $# -gt 0 ]; do
esac
done

exec /venv/bin/gunicorn \
# Ensure HOME is set correctly for the non-root user.
export HOME="${HOME:-/home/clawmetry}"
export OPENCLAW_HOME="${OPENCLAW_HOME:-/home/clawmetry/.openclaw}"
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting OPENCLAW_HOME as a default after command-line arguments have been processed will override any user-provided --workspace flag. Line 21 exports OPENCLAW_HOME if the user passes --workspace, but line 47 unconditionally sets a default that will replace the user's value. Move this default setting to before the argument parsing loop, or only set it if it's not already defined (similar to the pattern used for DATA_DIR on line 51).

Copilot uses AI. Check for mistakes.

# The container starts as root. We ensure the data directory exists and
# has the correct permissions before dropping privileges.
# We intentionally do NOT recurse into existing content to avoid mutating
# host-side ownership when DATA_DIR is a bind mount where the host user's
# UID differs from the container's 'clawmetry' user (UID 1000).
DATA_DIR="${OPENCLAW_DATA_DIR:-/home/clawmetry/.openclaw}"
mkdir -p "$DATA_DIR"
# Only fix ownership when the directory is still owned by root (e.g. just
# created above or a brand-new Docker-managed volume). This preserves the
# original ownership on pre-existing bind mounts.
# Safety guard: never chown '/' or an empty path.
if [ -n "$DATA_DIR" ] && [ "$DATA_DIR" != "/" ] && \
[ "$(stat -c '%u' "$DATA_DIR")" = "0" ]; then
chown clawmetry:clawmetry "$DATA_DIR"
fi

# Also ensure the fleet DB directory exists if FLEET_DB_PATH is set.
if [ -n "$FLEET_DB_PATH" ]; then
DB_DIR=$(dirname "$FLEET_DB_PATH")
# Normalise DB_DIR to an absolute path when FLEET_DB_PATH is relative.
case "$DB_DIR" in
/*) ;;
*) DB_DIR="$HOME/$DB_DIR" ;;
esac
mkdir -p "$DB_DIR"
# Safety guard: never chown '/' (e.g. FLEET_DB_PATH='/fleet.db')
# or an empty string.
if [ -n "$DB_DIR" ] && [ "$DB_DIR" != "/" ] && \
[ "$(stat -c '%u' "$DB_DIR")" = "0" ]; then
chown clawmetry:clawmetry "$DB_DIR"
fi
fi

echo "Dropping privileges to clawmetry user and starting gunicorn..."
exec gosu clawmetry /venv/bin/gunicorn \
--bind "${HOST}:${PORT}" \
--workers 1 \
--threads 16 \
Expand Down