Change host to 0.0.0.0
CI / ci (push) Has been cancelled
CI / ci-windows (push) Has been cancelled

This commit is contained in:
2026-08-10 18:49:33 +07:00
parent 047505dccc
commit 6fc1998d9c
2 changed files with 211 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
# =============================================================================
# PenguinHarness systemd unit (for hosts with a real systemd)
#
# The unit delegates to scripts/penguin-service.sh in "run" (foreground) mode,
# so node discovery, .env loading and the entry path are handled by the script
# and only ONE path needs adjusting below: /path/to/penguin-harness
#
# Install:
# sudo cp scripts/penguin-harness.service /etc/systemd/system/
# # sửa ExecStart nếu repo không nằm ở /home/<user>/penguin-harness
# sudo systemctl daemon-reload
# sudo systemctl enable --now penguin-harness
#
# The one-time seeded admin password is printed to the journal on first start
# with an empty data root:
# journalctl -u penguin-harness | grep "initial password"
# =============================================================================
[Unit]
Description=PenguinHarness web service (agent builder)
Documentation=https://penguin.ooo/docs
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
# Run as the user that owns the repo and the data root (~/.penguin/data).
User=locpham
WorkingDirectory=/home/locpham/penguin-harness
ExecStart=/home/locpham/penguin-harness/scripts/penguin-service.sh run
Restart=on-failure
RestartSec=3
TimeoutStopSec=15
# Console = journald: `journalctl -u penguin-harness -f`
StandardOutput=journal
StandardError=journal
# Hardening (safe for this service)
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
+171
View File
@@ -0,0 +1,171 @@
#!/usr/bin/env bash
# =============================================================================
# PenguinHarness service script (portable)
# -----------------------------------------------------------------------------
# Starts / stops / restarts the penguin-harness web server as a background
# daemon. Works anywhere: the repo location, node binary and .env are
# auto-detected (no hardcoded /workspace paths).
#
# scripts/penguin-service.sh start|stop|status|restart|run
#
# run = foreground mode (for systemd Type=simple, ExecStart=.../run)
#
# Console output (including the one-time seeded admin password) goes to:
# ~/.penguin/penguin-service.log
#
# Configuration comes from .env at the repo root (HOST / PORT / PENGUIN_WEB_DIST).
# =============================================================================
set -u
# --- Self-locating paths: BASE = repo root (parent of scripts/) ---------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BASE="$(cd "$SCRIPT_DIR/.." && pwd)"
# --- Node discovery: $PENGUIN_NODE > known nvm paths > PATH -------------------
if [ -n "${PENGUIN_NODE:-}" ]; then
NODE="$PENGUIN_NODE"
elif [ -x /workspace/.nvm/versions/node/v24.18.0/bin/node ]; then
NODE=/workspace/.nvm/versions/node/v24.18.0/bin/node
elif [ -x "$HOME/.nvm/versions/node/v24.18.0/bin/node" ]; then
NODE="$HOME/.nvm/versions/node/v24.18.0/bin/node"
elif command -v node >/dev/null 2>&1; then
NODE="$(command -v node)"
else
echo "Không tìm thấy node. Cài Node >= 24 hoặc đặt biến PENGUIN_NODE." >&2
exit 1
fi
ENTRY="$BASE/packages/server/dist/index.js"
ENVFILE="$BASE/.env"
PENGUIN_HOME="${PENGUIN_HOME:-$HOME/.penguin/data}"
LOG="${PENGUIN_SERVICE_LOG:-$HOME/.penguin/penguin-service.log}"
PIDFILE="${PENGUIN_SERVICE_PID:-$HOME/.penguin/penguin-service.pid}"
# --- Sanity checks ------------------------------------------------------------
if [ ! -f "$ENTRY" ]; then
echo "Không thấy bản build: $ENTRY" >&2
echo "Chạy trước: cd \"$BASE\" && pnpm install && pnpm build" >&2
exit 1
fi
if [ ! -f "$ENVFILE" ]; then
echo "Lưu ý: không có $ENVFILE — server sẽ nghe trên HOST=127.0.0.1." >&2
echo "Tạo .env với nội dung 'HOST=0.0.0.0' để mở mọi interface." >&2
fi
# --- Load .env (HOST / PORT / PENGUIN_WEB_DIST ...) and export -----------------
if [ -f "$ENVFILE" ]; then
set -a
# shellcheck disable=SC1090
. "$ENVFILE"
set +a
fi
export PENGUIN_HOME
PORT="${PORT:-7364}"
# True only while the process is really alive: `kill -0` alone would also
# succeed on a zombie (exited but not yet reaped). A zombie (state Z in
# /proc/<pid>/stat) counts as dead.
proc_alive() {
local pid="$1"
kill -0 "$pid" 2>/dev/null || return 1
[ "$(awk '{print $3}' "/proc/$pid/stat" 2>/dev/null)" != "Z" ]
}
is_running() {
[ -f "$PIDFILE" ] || return 1
local pid
pid="$(cat "$PIDFILE" 2>/dev/null)" || return 1
[ -n "$pid" ] && proc_alive "$pid"
}
start() {
if is_running; then
echo "PenguinHarness đang chạy (pid $(cat "$PIDFILE"))."
return 0
fi
mkdir -p "$(dirname "$LOG")" "$(dirname "$PIDFILE")"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] starting penguin-server (HOST=${HOST:-127.0.0.1} PORT=$PORT PENGUIN_HOME=$PENGUIN_HOME)" >>"$LOG"
# setsid detaches from the controlling terminal; all fds go to the log file.
setsid "$NODE" "$ENTRY" >>"$LOG" 2>&1 </dev/null &
echo $! >"$PIDFILE"
# Wait for readiness (up to 30s) — any HTTP answer counts.
local i
for i in $(seq 1 30); do
if curl -s -o /dev/null --max-time 2 "http://127.0.0.1:$PORT/"; then
break
fi
sleep 1
done
if is_running; then
echo "PenguinHarness đã khởi động: http://0.0.0.0:$PORT (pid $(cat "$PIDFILE"))"
echo "Log (console): $LOG"
# In mật khẩu admin khởi tạo ra console nếu có (chỉ in 1 lần khi seed).
grep -h "initial password" "$LOG" 2>/dev/null | tail -1
else
echo "Khởi động THẤT BẠI — xem log: $LOG" >&2
tail -20 "$LOG" >&2
rm -f "$PIDFILE"
return 1
fi
}
stop() {
if ! is_running; then
echo "PenguinHarness không đang chạy."
rm -f "$PIDFILE"
return 0
fi
local pid
pid="$(cat "$PIDFILE")"
echo "Đang dừng penguin-server (pid $pid)..."
kill -TERM "$pid" 2>/dev/null
local i
for i in $(seq 1 10); do
proc_alive "$pid" || break
sleep 1
done
if proc_alive "$pid"; then
echo "Không dừng được trong 10s, buộc dừng (SIGKILL)." >&2
kill -KILL "$pid" 2>/dev/null
fi
# Reap any zombie so it cannot linger in the process table.
wait "$pid" 2>/dev/null
rm -f "$PIDFILE"
echo "Đã dừng."
}
status() {
if is_running; then
echo "PenguinHarness: ĐANG CHẠY (pid $(cat "$PIDFILE"))"
echo " URL: http://0.0.0.0:$PORT"
echo " Log: $LOG"
if grep -h "initial password" "$LOG" 2>/dev/null | tail -1 | grep -q .; then
echo " Admin khởi tạo: $(grep -h 'initial password' "$LOG" | tail -1)"
fi
return 0
fi
echo "PenguinHarness: KHÔNG chạy."
return 1
}
case "${1:-}" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
status) status ;;
run)
# Foreground mode for systemd (Type=simple): exec replaces the shell so
# systemd tracks the real server process and Restart= works.
exec "$NODE" "$ENTRY"
;;
*)
echo "Sử dụng: $0 {start|stop|status|restart|run}"
exit 2
;;
esac