web/deploy: add one-shot install.sh
Adds web/deploy/install.sh — full LXC setup in one command. It derives the repo path from its own location (clone anywhere; /opt/ponfw recommended), installs git/node/npm if missing (checks Node >= 18), creates the ponfw service user, runs npm install --omit=dev, writes /etc/pon-fleet-web.env on first run, and installs+enables the systemd unit with WorkingDirectory set to the checkout. Idempotent; warns if cloned under /home (ProtectHome blocks it). README + CLAUDE.md §16 updated to lead with install.sh and clarify the clone location. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c2206ad5a7
commit
de037c8795
3 changed files with 126 additions and 23 deletions
|
|
@ -78,34 +78,38 @@ caller's MCMS-host snapshots.
|
|||
|
||||
## Deploy on a Debian 13 LXC (clone-to-run)
|
||||
|
||||
Files in `web/deploy/`: a systemd unit, an env template, and `update.sh`.
|
||||
Files in `web/deploy/`: `install.sh` (one-shot setup), `update.sh`, a systemd
|
||||
unit, and an env template.
|
||||
|
||||
**Where to clone:** anywhere — `install.sh` points the service at wherever it
|
||||
finds itself. `/opt/ponfw` is recommended: it's the FHS spot for this kind of
|
||||
software, and the hardened unit sets `ProtectHome=true`, which would block the
|
||||
service from reading a checkout under `/home`.
|
||||
|
||||
```bash
|
||||
# --- as root on the LXC, once ---
|
||||
apt update && apt install -y nodejs npm git # Node 18+; or use NodeSource
|
||||
adduser --system --group --no-create-home ponfw
|
||||
|
||||
git clone ssh://forgejo@int.git.vanvikinternet.no/Svorka/ponfw.git /opt/ponfw
|
||||
cd /opt/ponfw
|
||||
npm install --omit=dev --no-audit --no-fund # installs tough-cookie, skips Electron
|
||||
|
||||
install -m 0644 web/deploy/pon-fleet-web.service /etc/systemd/system/
|
||||
install -m 0640 web/deploy/pon-fleet-web.env.example /etc/pon-fleet-web.env
|
||||
$EDITOR /etc/pon-fleet-web.env # set HOST / PFW_SECURE_COOKIE etc.
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now pon-fleet-web
|
||||
systemctl status pon-fleet-web
|
||||
journalctl -u pon-fleet-web -f # logs
|
||||
sudo /opt/ponfw/web/deploy/install.sh
|
||||
$EDITOR /etc/pon-fleet-web.env # optional: HOST / PFW_SECURE_COOKIE / TTL
|
||||
sudo systemctl restart pon-fleet-web # if you edited the env
|
||||
```
|
||||
|
||||
The repo lives at `/opt/ponfw` (root-owned, read-only to the service); the
|
||||
service runs as the unprivileged `ponfw` user and writes nothing to disk.
|
||||
`install.sh` is idempotent and:
|
||||
|
||||
**To update:** just re-pull and restart —
|
||||
- installs `git` / `nodejs` / `npm` if missing (and checks Node ≥ 18),
|
||||
- creates the unprivileged `ponfw` system user,
|
||||
- runs `npm install --omit=dev` (tough-cookie only; skips Electron),
|
||||
- writes `/etc/pon-fleet-web.env` from the template on first run,
|
||||
- installs the systemd unit with `WorkingDirectory` set to this checkout,
|
||||
then enables + starts it,
|
||||
- prints the LXC IP and the NPM forward target.
|
||||
|
||||
The checkout is root-owned and read-only to the service; the service runs as
|
||||
`ponfw` and writes nothing to disk.
|
||||
|
||||
```bash
|
||||
sudo /opt/ponfw/web/deploy/update.sh # git pull + npm install + restart
|
||||
journalctl -u pon-fleet-web -f # logs
|
||||
sudo /opt/ponfw/web/deploy/update.sh # update: git pull + npm install + restart
|
||||
```
|
||||
|
||||
## Behind Nginx Proxy Manager
|
||||
|
|
|
|||
96
web/deploy/install.sh
Executable file
96
web/deploy/install.sh
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
#!/usr/bin/env bash
|
||||
# One-shot setup for the PON Fleet web server on a Debian 13 LXC.
|
||||
#
|
||||
# Clone the repo first (anywhere — /opt/ponfw recommended), then run this
|
||||
# from inside the checkout as root:
|
||||
#
|
||||
# git clone ssh://forgejo@int.git.vanvikinternet.no/Svorka/ponfw.git /opt/ponfw
|
||||
# sudo /opt/ponfw/web/deploy/install.sh
|
||||
#
|
||||
# It installs runtime deps (tough-cookie only; skips Electron), creates an
|
||||
# unprivileged service user, writes /etc/pon-fleet-web.env on first run, and
|
||||
# installs + enables a systemd unit pointed at THIS checkout. Safe to re-run.
|
||||
set -euo pipefail
|
||||
|
||||
SERVICE="pon-fleet-web"
|
||||
SERVICE_USER="ponfw"
|
||||
ENV_FILE="/etc/pon-fleet-web.env"
|
||||
|
||||
# Repo root is two levels up from this script (web/deploy/install.sh).
|
||||
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
|
||||
REPO="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
DEPLOY="$REPO/web/deploy"
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "Run as root: sudo $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Repo checkout: $REPO"
|
||||
case "$REPO" in
|
||||
/home/*)
|
||||
echo "!! WARNING: the repo is under /home. The hardened systemd unit sets" >&2
|
||||
echo "!! ProtectHome=true, which will stop the service from reading it." >&2
|
||||
echo "!! Clone to /opt/ponfw instead, or remove ProtectHome from the unit." >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- dependencies (git, node, npm) ---
|
||||
need=()
|
||||
command -v git >/dev/null 2>&1 || need+=(git)
|
||||
command -v node >/dev/null 2>&1 || need+=(nodejs)
|
||||
command -v npm >/dev/null 2>&1 || need+=(npm)
|
||||
if (( ${#need[@]} )); then
|
||||
echo "==> apt-get install ${need[*]}"
|
||||
apt-get update -y
|
||||
apt-get install -y "${need[@]}"
|
||||
fi
|
||||
|
||||
NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)"
|
||||
if (( NODE_MAJOR < 18 )); then
|
||||
echo "!! Node $(node -v 2>/dev/null || echo '?') is too old (need >= 18)." >&2
|
||||
echo "!! Install a newer Node (e.g. via NodeSource) and re-run." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "==> Using $(node -v)"
|
||||
|
||||
# --- service user ---
|
||||
if ! id -u "$SERVICE_USER" >/dev/null 2>&1; then
|
||||
echo "==> Creating system user $SERVICE_USER"
|
||||
adduser --system --group --no-create-home "$SERVICE_USER"
|
||||
fi
|
||||
|
||||
# --- runtime deps (npm install, not ci: package-lock.json is gitignored) ---
|
||||
echo "==> Installing runtime dependencies"
|
||||
( cd "$REPO" && npm install --omit=dev --no-audit --no-fund )
|
||||
|
||||
# --- env file (first run only; never clobber operator edits) ---
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
echo "==> $ENV_FILE already exists — leaving it untouched"
|
||||
else
|
||||
echo "==> Writing $ENV_FILE from the example (review it)"
|
||||
install -m 0640 "$DEPLOY/pon-fleet-web.env.example" "$ENV_FILE"
|
||||
fi
|
||||
|
||||
# --- systemd unit, with WorkingDirectory pointed at THIS checkout ---
|
||||
echo "==> Installing systemd unit"
|
||||
sed "s|^WorkingDirectory=.*|WorkingDirectory=$REPO/web|" \
|
||||
"$DEPLOY/$SERVICE.service" > "/etc/systemd/system/$SERVICE.service"
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now "$SERVICE"
|
||||
sleep 1
|
||||
systemctl --no-pager --lines=10 status "$SERVICE" || true
|
||||
|
||||
IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
cat <<MSG
|
||||
|
||||
==> Done — $SERVICE is enabled and running.
|
||||
Config: $ENV_FILE Logs: journalctl -u $SERVICE -f
|
||||
Update: sudo $DEPLOY/update.sh
|
||||
|
||||
Point Nginx Proxy Manager at this LXC:
|
||||
Forward Hostname/IP: ${IP:-<this-lxc-ip>} Forward Port: 8080 Scheme: http
|
||||
Add your Access List, request an SSL cert, enable Block Common Exploits.
|
||||
(If NPM runs on a different host, set HOST=0.0.0.0 in $ENV_FILE and
|
||||
restart: systemctl restart $SERVICE)
|
||||
MSG
|
||||
Loading…
Add table
Add a link
Reference in a new issue