Skip to content
Closed
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
48 changes: 35 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ RUN apt-get update -y --fix-missing --no-install-recommends \
curl \
rsync \
openssh-client \
git \
xz-utils \
&& apt-get upgrade -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Expand All @@ -45,11 +47,11 @@ WORKDIR /apptoo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

# Create a new group for the hermeswebui and hermeswebuitoo users
RUN groupadd -g 1024 hermeswebui \
RUN groupadd -g 1024 hermeswebui \
&& groupadd -g 1025 hermeswebuitoo

# The hermeswebui (resp. hermeswebuitoo) user will have UID 1024 (resp. 1025),
# be part of the hermeswebui (resp. hermeswebuitoo) and users groups and be sudo capable (passwordless)
# The hermeswebui (resp. hermeswebuitoo) user will have UID 1024 (resp. 1025),
# be part of the hermeswebui (resp. hermeswebuitoo) and users groups and be sudo capable (passwordless)
RUN useradd -u 1024 -d /home/hermeswebui -g hermeswebui -s /bin/bash -m hermeswebui \
&& usermod -G users hermeswebui \
&& adduser hermeswebui sudo
Expand All @@ -60,24 +62,45 @@ RUN chown -R hermeswebuitoo:hermeswebuitoo /apptoo

USER root

COPY --chmod=555 docker_init.bash /hermeswebui_init.bash
# Pre-install uv system-wide so the container doesn't need internet access at runtime.
# Installing as root places uv in /usr/local/bin, available to all users.
# The init script will skip the download when uv is already on PATH.
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh

# Install Node.js 22 LTS (for browser tools)
RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "x86_64" ]; then NODE_ARCH="x64"; \
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then NODE_ARCH="arm64"; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi && \
INDEX_URL="https://nodejs.org/dist/latest-v22.x/" && \
TARBALL=$(curl -fsSL "$INDEX_URL" | grep -oE "node-v22\.[0-9]+\.[0-9]+-linux-${NODE_ARCH}\.tar\.xz" | head -1) && \
[ -n "$TARBALL" ] || { echo "Could not find Node.js tarball"; exit 1; } && \
curl -fsSL "${INDEX_URL}${TARBALL}" -o /tmp/node.tar.xz && \
tar -C /usr/local --strip-components=1 -xJf /tmp/node.tar.xz && \
rm /tmp/node.tar.xz && \
node --version && npm --version

# Pre-bake the Hermes Agent source into the image to avoid runtime network installs.
# Use /opt/hermes which is not affected by the mounted .hermes volume.
COPY hermes-agent-desktop/hermes-agent /opt/hermes/

# Tell the WebUI where to find the agent (used by bootstrap if manually invoked)
ENV HERMES_WEBUI_AGENT_DIR=/opt/hermes

# Copy the init script (must be before using it as CMD)
COPY --chmod=555 hermes-webui/docker_init.bash /hermeswebui_init.bash

# Marker that we're inside a container
RUN touch /.within_container

# Remove APT proxy configuration and clean up APT downloaded files
RUN rm -rf /var/lib/apt/lists/* /etc/apt/apt.conf.d/01proxy \
&& apt-get clean

USER root

# Pre-install uv system-wide so the container doesn't need internet access at runtime.
# Installing as root places uv in /usr/local/bin, available to all users.
# The init script will skip the download when uv is already on PATH.
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh

USER hermeswebuitoo

COPY --chown=hermeswebuitoo:hermeswebuitoo . /apptoo
# Copy the WebUI application code
COPY --chown=hermeswebuitoo:hermeswebuitoo hermes-webui/ /apptoo/

# Bake the git version tag into the image so the settings badge works even
# when .git is not present (it is excluded by .dockerignore).
Expand All @@ -96,4 +119,3 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:8787/health || exit 1

CMD ["/hermeswebui_init.bash"]

4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

services:
hermes-webui:
build: .
build:
context: ..
dockerfile: hermes-webui/Dockerfile
ports:
# select only one; use 127.0.0.1 version to expose to localhost only
- "127.0.0.1:8787:8787"
Expand Down
47 changes: 43 additions & 4 deletions start.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail

# If invoked as root (e.g., via sudo), re-exec as hermeswebui to avoid
# permission issues with bind-mounted .hermes directory.
if [[ $EUID -eq 0 ]]; then
exec sudo -n -u hermeswebui "$0" "$@"
fi

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# When running inside the pre-built Docker container, use the pre-created venv
if [[ -f "/.within_container" && -x "/app/venv/bin/python" ]]; then
export HERMES_WEBUI_PYTHON="/app/venv/bin/python"
exec "/app/venv/bin/python" "${REPO_ROOT}/bootstrap.py" --no-browser "$@"
fi

if [[ -f "${REPO_ROOT}/.env" ]]; then
set -a
# shellcheck source=/dev/null
source "${REPO_ROOT}/.env"
set +a
# Parse .env manually to avoid assigning to readonly vars (UID, GID, etc.)
# This mirrors bootstrap.py's _load_repo_dotenv() logic
while IFS= read -r raw_line || [[ -n "$raw_line" ]]; do
# Strip leading/trailing whitespace
line="${raw_line#"${raw_line%%[![:space:]]*}"}"
line="${line%"${line##*[![:space:]]}"}"
# Skip empty lines and comments
[[ -z "$line" || "$line" == \#* ]] && continue
# Split on first '='
[[ "$line" == *"="* ]] || continue
key="${line%%=*}"
value="${line#*=}"
key="${key%"${key##*[![:space:]]}"}"
key="${key#"${key%%[![:space:]]*}"}"
# Skip readonly shell variables
case "$key" in
UID|GID|EUID|EGID|PPID|PID|_) continue ;;
esac
# Strip optional 'export' prefix and surrounding quotes
if [[ "$key" == export* ]]; then
key="${key#export}"
key="${key#"${key%%[![:space:]]*}"}"
fi
value="${value%"${value##*[![:space:]]}"}"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%\"}"
value="${value#\"}"
value="${value%\'}"
value="${value#\'}"
export "$key=$value"
done < "${REPO_ROOT}/.env"
fi

PYTHON="${HERMES_WEBUI_PYTHON:-}"
Expand Down
Loading