feat(service): v2-native path via 'opencode service' + 'serve --service'
- detect OpenCode v2 (serve --help has --service) and configure it with 'opencode service set hostname/port/password/cors'; the unit runs 'opencode serve --service' (what the v2 manager spawns) - v2 stores the password in OpenCode's own service config; v1 keeps the EnvironmentFile + flags - password-based (portable) access for the web app: Add server -> address + password, username 'opencode' - README documents v2 vs v1
This commit is contained in:
parent
8cef2acfa5
commit
3217ee7a07
2 changed files with 65 additions and 22 deletions
|
|
@ -265,6 +265,8 @@ The service step is a **separate program** — `install-service.sh` — so you c
|
||||||
|
|
||||||
It refuses to run non-interactively unless you pass `--yes`, and backs up any existing unit before replacing it.
|
It refuses to run non-interactively unless you pass `--yes`, and backs up any existing unit before replacing it.
|
||||||
|
|
||||||
|
**OpenCode v2 vs v1.** On **v2**, the installer uses OpenCode's own background-service manager: it runs `opencode service set hostname/port/password/cors` and installs a unit that runs `opencode serve --service` (exactly the command the manager itself spawns). The password is stored in OpenCode's service config, not in our unit. On **v1** it passes `--hostname/--port` and keeps the password in an `EnvironmentFile`.
|
||||||
|
|
||||||
- **Default bind is `127.0.0.1`** — the server has **no authentication of its own**, so keep it loopback-only and put a reverse proxy (Zoraxy, nginx, …) in front. Choose `0.0.0.0` only if you deliberately want it exposed on your network.
|
- **Default bind is `127.0.0.1`** — the server has **no authentication of its own**, so keep it loopback-only and put a reverse proxy (Zoraxy, nginx, …) in front. Choose `0.0.0.0` only if you deliberately want it exposed on your network.
|
||||||
- **Non-systemd** hosts: it prints the command to run the web UI manually instead.
|
- **Non-systemd** hosts: it prints the command to run the web UI manually instead.
|
||||||
- **Non-interactive** (e.g. `curl | bash`, CI): the service is **not** set up unless you pass `--service`.
|
- **Non-interactive** (e.g. `curl | bash`, CI): the service is **not** set up unless you pass `--service`.
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,18 @@ fi
|
||||||
have_opencode || die "OpenCode is not installed (looked on PATH and ${OPENCODE_BIN_DIR}). Install it first."
|
have_opencode || die "OpenCode is not installed (looked on PATH and ${OPENCODE_BIN_DIR}). Install it first."
|
||||||
OC_BIN="$(opencode_path)"
|
OC_BIN="$(opencode_path)"
|
||||||
|
|
||||||
|
# OpenCode v2 manages its own background server (`opencode service`) and runs it
|
||||||
|
# as `opencode serve --service`; the server reads host/port/password/cors from the
|
||||||
|
# service config. v1 has no manager — we pass flags + an env file instead.
|
||||||
|
OPENCODE_V2=0
|
||||||
|
if "$OC_BIN" serve --help 2>&1 | grep -q -- '--service'; then OPENCODE_V2=1; fi
|
||||||
|
|
||||||
|
# Run an opencode command as the service user.
|
||||||
|
oc_run() {
|
||||||
|
if [ "$SVC_USER" = "$(id -un)" ]; then "$OC_BIN" "$@"
|
||||||
|
else $SUDO -u "$SVC_USER" "$OC_BIN" "$@"; fi
|
||||||
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Prompt (interactive only)
|
# Prompt (interactive only)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
@ -270,11 +282,17 @@ fi
|
||||||
# Build the unit
|
# Build the unit
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
ENV_LINE=""
|
ENV_LINE=""
|
||||||
|
EXEC_ARGS=""
|
||||||
|
RESTART_POLICY="on-failure"
|
||||||
|
if [ "$OPENCODE_V2" = 1 ]; then
|
||||||
|
# v2: host/port/password/cors live in the service config, so run in service mode.
|
||||||
|
EXEC_ARGS="--service"
|
||||||
|
RESTART_POLICY="always" # a config change stops+restarts the server; bring it back
|
||||||
|
else
|
||||||
[ "$PASSWORD_SET" = 1 ] && ENV_LINE="EnvironmentFile=-${ENV_FILE}"
|
[ "$PASSWORD_SET" = 1 ] && ENV_LINE="EnvironmentFile=-${ENV_FILE}"
|
||||||
|
for o in $CORS; do EXEC_ARGS="${EXEC_ARGS} --cors ${o}"; done
|
||||||
# Build the optional --cors flags
|
EXEC_ARGS="--hostname ${HOST} --port ${PORT}${EXEC_ARGS}"
|
||||||
CORS_ARGS=""
|
fi
|
||||||
for o in $CORS; do CORS_ARGS="${CORS_ARGS} --cors ${o}"; done
|
|
||||||
|
|
||||||
UNIT="$(mktemp 2>/dev/null || mktemp -t oac-unit)"
|
UNIT="$(mktemp 2>/dev/null || mktemp -t oac-unit)"
|
||||||
cat > "$UNIT" <<EOF
|
cat > "$UNIT" <<EOF
|
||||||
|
|
@ -289,8 +307,8 @@ User=${SVC_USER}
|
||||||
Group=${SVC_GROUP}
|
Group=${SVC_GROUP}
|
||||||
${ENV_LINE}
|
${ENV_LINE}
|
||||||
WorkingDirectory=${WORKDIR}
|
WorkingDirectory=${WORKDIR}
|
||||||
ExecStart=${OC_BIN} serve --hostname ${HOST} --port ${PORT}${CORS_ARGS}
|
ExecStart=${OC_BIN} serve ${EXEC_ARGS}
|
||||||
Restart=on-failure
|
Restart=${RESTART_POLICY}
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|
@ -317,7 +335,11 @@ cat "$UNIT"
|
||||||
echo "------------------------------------------------------------"
|
echo "------------------------------------------------------------"
|
||||||
|
|
||||||
if [ "$DRY_RUN" = 1 ]; then
|
if [ "$DRY_RUN" = 1 ]; then
|
||||||
|
if [ "$OPENCODE_V2" = 1 ]; then
|
||||||
|
info "[dry-run] would run: opencode service set hostname ${HOST}; port ${PORT}$([ "$PASSWORD_SET" = 1 ] && echo '; password <hidden>')"
|
||||||
|
else
|
||||||
[ "$PASSWORD_SET" = 1 ] && info "[dry-run] would write credentials to ${ENV_FILE} (mode 600)"
|
[ "$PASSWORD_SET" = 1 ] && info "[dry-run] would write credentials to ${ENV_FILE} (mode 600)"
|
||||||
|
fi
|
||||||
warn "Dry run — nothing was written."
|
warn "Dry run — nothing was written."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
@ -331,7 +353,20 @@ if [ "$INTERACTIVE" = 1 ]; then
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Write the credentials file (root-readable) before pointing the unit at it.
|
# Apply the server configuration.
|
||||||
|
if [ "$OPENCODE_V2" = 1 ]; then
|
||||||
|
info "Configuring the OpenCode service…"
|
||||||
|
oc_run service set hostname "$HOST" || die "opencode service set hostname failed"
|
||||||
|
oc_run service set port "$PORT" || die "opencode service set port failed"
|
||||||
|
if [ "$PASSWORD_SET" = 1 ]; then
|
||||||
|
oc_run service set password "$PASSWORD" || die "opencode service set password failed"
|
||||||
|
fi
|
||||||
|
if [ -n "$CORS" ]; then
|
||||||
|
cors_list="$(printf '%s' "$CORS" | tr ' ' ',')"
|
||||||
|
oc_run service set cors "$cors_list" || die "opencode service set cors failed"
|
||||||
|
fi
|
||||||
|
success "Configured the OpenCode service (host/port/password/cors)"
|
||||||
|
else
|
||||||
if [ "$PASSWORD_SET" = 1 ]; then
|
if [ "$PASSWORD_SET" = 1 ]; then
|
||||||
esc="$(printf '%s' "$PASSWORD" | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
esc="$(printf '%s' "$PASSWORD" | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
||||||
if ! $SUDO mkdir -p "$(dirname "$ENV_FILE")"; then
|
if ! $SUDO mkdir -p "$(dirname "$ENV_FILE")"; then
|
||||||
|
|
@ -347,6 +382,7 @@ if [ "$PASSWORD_SET" = 1 ]; then
|
||||||
$SUDO chmod 600 "$ENV_FILE"
|
$SUDO chmod 600 "$ENV_FILE"
|
||||||
success "Wrote credentials to ${ENV_FILE} (mode 600)"
|
success "Wrote credentials to ${ENV_FILE} (mode 600)"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Back up an existing unit before replacing it
|
# Back up an existing unit before replacing it
|
||||||
if [ -e "$UNIT_PATH" ]; then
|
if [ -e "$UNIT_PATH" ]; then
|
||||||
|
|
@ -372,7 +408,12 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$PASSWORD_SET" = 1 ]; then
|
if [ "$PASSWORD_SET" = 1 ]; then
|
||||||
|
if [ "$OPENCODE_V2" = 1 ]; then
|
||||||
|
info "Auth: HTTP basic — username 'opencode', password in the OpenCode service config"
|
||||||
|
info "In the web app: Add server → address = your public URL, username blank (opencode), password."
|
||||||
|
else
|
||||||
info "Auth: HTTP basic — username '${SVC_USERNAME}', password from ${ENV_FILE}"
|
info "Auth: HTTP basic — username '${SVC_USERNAME}', password from ${ENV_FILE}"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
warn "No password set — the server is unsecured. Put it behind your proxy's auth."
|
warn "No password set — the server is unsecured. Put it behind your proxy's auth."
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue