Skip to content

Commit c89ad75

Browse files
committed
Improve container startup for app platforms
1 parent 21034db commit c89ad75

2 files changed

Lines changed: 113 additions & 4 deletions

File tree

packages/core/src/docker/Dockerfile

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ RUN printf '%s\n' \
647647
'Type=simple' \
648648
'User=opencode' \
649649
'WorkingDirectory=/home/opencode/workspace' \
650-
'ExecStart=/opt/opencode/bin/opencode web --port 3000 --hostname 0.0.0.0' \
650+
'ExecStart=/bin/bash -lc "OPENCODE_PORT=$${OPENCODE_PORT:-$${PORT:-3000}}; OPENCODE_HOST=$${OPENCODE_HOST:-0.0.0.0}; exec /opt/opencode/bin/opencode web --port $${OPENCODE_PORT} --hostname $${OPENCODE_HOST}"' \
651651
'Restart=always' \
652652
'RestartSec=5' \
653653
'Environment=PATH=/opt/opencode/bin:/home/opencode/.local/bin:/home/opencode/.cargo/bin:/home/opencode/.local/share/mise/shims:/home/opencode/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' \
@@ -686,14 +686,115 @@ RUN ls -la /home/opencode/.config/opencode/opencode.jsonc && cat /home/opencode/
686686
# Note: Entrypoint runs as root to support both modes; tini mode drops to opencode user
687687
RUN printf '%s\n' \
688688
'#!/bin/bash' \
689-
'if [ "${USE_SYSTEMD}" = "1" ]; then' \
689+
'set -euo pipefail' \
690+
'' \
691+
'log() {' \
692+
' echo "[opencode-cloud] $*"' \
693+
'}' \
694+
'' \
695+
'OPENCODE_PORT="${OPENCODE_PORT:-${PORT:-3000}}"' \
696+
'OPENCODE_HOST="${OPENCODE_HOST:-0.0.0.0}"' \
697+
'export OPENCODE_PORT OPENCODE_HOST' \
698+
'' \
699+
'if [ "${USE_SYSTEMD:-}" = "1" ]; then' \
690700
' exec /sbin/init' \
691701
'else' \
692702
' # Ensure broker socket directory exists' \
693703
' install -d -m 0755 /run/opencode' \
704+
'' \
705+
' # Ensure user records directory exists (ephemeral unless mounted)' \
706+
' install -d -m 0700 /var/lib/opencode-users' \
707+
'' \
708+
' restore_users() {' \
709+
' shopt -s nullglob' \
710+
' local records=(/var/lib/opencode-users/*.json)' \
711+
' if [ ${#records[@]} -eq 0 ]; then' \
712+
' return 1' \
713+
' fi' \
714+
' for record in "${records[@]}"; do' \
715+
' local username password_hash locked' \
716+
' username="$(jq -r ".username // empty" "${record}")"' \
717+
' password_hash="$(jq -r ".password_hash // empty" "${record}")"' \
718+
' locked="$(jq -r ".locked // false" "${record}")"' \
719+
' if [ -z "${username}" ]; then' \
720+
' log "Skipping invalid user record: ${record}"' \
721+
' continue' \
722+
' fi' \
723+
' if ! id -u "${username}" >/dev/null 2>&1; then' \
724+
' log "Creating user: ${username}"' \
725+
' useradd -m -s /bin/bash "${username}"' \
726+
' fi' \
727+
' if [ -n "${password_hash}" ]; then' \
728+
' usermod -p "${password_hash}" "${username}"' \
729+
' fi' \
730+
' if [ "${locked}" = "true" ]; then' \
731+
' passwd -l "${username}" >/dev/null' \
732+
' else' \
733+
' passwd -u "${username}" >/dev/null || true' \
734+
' fi' \
735+
' log "Restored user: ${username}"' \
736+
' done' \
737+
' return 0' \
738+
' }' \
739+
'' \
740+
' persist_user_record() {' \
741+
' local username="$1"' \
742+
' local shadow_hash' \
743+
' shadow_hash="$(getent shadow "${username}" | cut -d: -f2)"' \
744+
' if [ -z "${shadow_hash}" ]; then' \
745+
' log "Failed to read shadow hash for ${username}"' \
746+
' return 1' \
747+
' fi' \
748+
' local status locked' \
749+
' status="$(passwd -S "${username}" | tr -s " " | cut -d" " -f2)"' \
750+
' locked="false"' \
751+
' if [ "${status}" = "L" ]; then' \
752+
' locked="true"' \
753+
' fi' \
754+
' local record_path="/var/lib/opencode-users/${username}.json"' \
755+
' umask 077' \
756+
' jq -n --arg username "${username}" --arg hash "${shadow_hash}" --argjson locked "${locked}" '"'"'{username:$username,password_hash:$hash,locked:$locked}'"'"' > "${record_path}"' \
757+
' chmod 600 "${record_path}"' \
758+
' log "Persisted user record: ${username}"' \
759+
' }' \
760+
'' \
761+
' bootstrap_user() {' \
762+
' local username="${OPENCODE_BOOTSTRAP_USER:-}"' \
763+
' local password="${OPENCODE_BOOTSTRAP_PASSWORD:-}"' \
764+
' local password_hash="${OPENCODE_BOOTSTRAP_PASSWORD_HASH:-}"' \
765+
' if [ -z "${username}" ]; then' \
766+
' return 1' \
767+
' fi' \
768+
' if [ -z "${password_hash}" ] && [ -z "${password}" ]; then' \
769+
' log "OPENCODE_BOOTSTRAP_USER is set but no password or hash provided"' \
770+
' exit 1' \
771+
' fi' \
772+
' if ! id -u "${username}" >/dev/null 2>&1; then' \
773+
' log "Creating bootstrap user: ${username}"' \
774+
' useradd -m -s /bin/bash "${username}"' \
775+
' fi' \
776+
' if [ -n "${password_hash}" ]; then' \
777+
' usermod -p "${password_hash}" "${username}"' \
778+
' else' \
779+
' echo "${username}:${password}" | chpasswd' \
780+
' fi' \
781+
' persist_user_record "${username}"' \
782+
' log "Bootstrap user ready: ${username}"' \
783+
' return 0' \
784+
' }' \
785+
'' \
786+
' if restore_users; then' \
787+
' log "User records restored"' \
788+
' else' \
789+
' if ! bootstrap_user; then' \
790+
' log "No persisted users and no bootstrap user configured"' \
791+
' fi' \
792+
' fi' \
793+
'' \
794+
' log "Starting opencode on ${OPENCODE_HOST}:${OPENCODE_PORT}"' \
694795
' /usr/local/bin/opencode-broker &' \
695796
' # Use runuser to switch to opencode user without password prompt' \
696-
' exec runuser -u opencode -- sh -lc "cd /home/opencode/workspace && /opt/opencode/bin/opencode web --port 3000 --hostname 0.0.0.0"' \
797+
' exec runuser -u opencode -- sh -lc "cd /home/opencode/workspace && /opt/opencode/bin/opencode web --port ${OPENCODE_PORT} --hostname ${OPENCODE_HOST}"' \
697798
'fi' \
698799
> /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh
699800
@@ -706,7 +807,7 @@ RUN printf '%s\n' \
706807
# Check that opencode main page responds
707808
# Works for both tini and systemd modes
708809
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
709-
CMD curl -f -H "Accept: text/html" http://localhost:3000/ || exit 1
810+
CMD ["sh", "-c", "OPENCODE_PORT=\"${OPENCODE_PORT:-${PORT:-3000}}\"; curl -f -H \"Accept: text/html\" \"http://localhost:${OPENCODE_PORT}/\" || exit 1"]
710811
711812
# -----------------------------------------------------------------------------
712813
# opencode Artifacts

packages/core/src/docker/README.dockerhub.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ docker run --rm -it -p 3000:3000 ghcr.io/prizz/opencode-cloud-sandbox:latest
3535

3636
The opencode web UI is available at `http://localhost:3000`.
3737

38+
## App Platform
39+
40+
- Set `http_port` to `3000` or provide `PORT`/`OPENCODE_PORT` so the health check hits the right port.
41+
- App Platform storage is ephemeral. Workspace, config, and PAM users reset on redeploy unless you add external storage.
42+
- Logs are visible in the App Platform UI without extra setup.
43+
- Provide `OPENCODE_BOOTSTRAP_USER` with either `OPENCODE_BOOTSTRAP_PASSWORD` or `OPENCODE_BOOTSTRAP_PASSWORD_HASH` for first-boot access.
44+
- App Platform supports Linux/AMD64 images and favors smaller image sizes.
45+
3846
## Install the opencode-cloud CLI
3947

4048
Cargo:

0 commit comments

Comments
 (0)