diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fe84387 --- /dev/null +++ b/Makefile @@ -0,0 +1,79 @@ +# wutzcalc — build and deploy +# +# Fresh Fedora box, as root: +# +# make install # system deps + build + systemd service +# +# Then set the admin password in /etc/wutzcalc/wutzcalc.env and: +# +# systemctl enable --now wutzcalc +# +# Without root you can still `make build` to compile the client + server. + +PREFIX ?= /opt/wutzcalc +CONFDIR ?= /etc/wutzcalc +SERVICE_USER ?= wutzcalc +UNIT := /etc/systemd/system/wutzcalc.service + +.PHONY: all build deps install service uninstall clean require-root + +all: build + +## build: install dependencies and build client + server +build: + pnpm install --frozen-lockfile + pnpm build + +## deps: install Node.js, pnpm and native-module build tools (Fedora) +deps: require-root + dnf install -y nodejs gcc-c++ make python3 + corepack enable + +## install: full production install on a fresh checkout (Fedora) +install: require-root deps build service + @echo + @echo "Installed to $(PREFIX)." + @echo "1. Set ADMIN_PASSWORD in $(CONFDIR)/wutzcalc.env" + @echo "2. systemctl enable --now wutzcalc" + +## service: create the user, copy files, and install the systemd unit +service: require-root + # Dedicated system user (no login, no home). + id -u $(SERVICE_USER) >/dev/null 2>&1 || \ + useradd --system --no-create-home --shell /usr/sbin/nologin $(SERVICE_USER) + # Copy the whole tree so pnpm's symlinked node_modules stay intact. + mkdir -p $(PREFIX) + cp -a . $(PREFIX)/ + # Config + secrets — never clobber an existing env file. + mkdir -p $(CONFDIR) + test -f $(CONFDIR)/wutzcalc.env || \ + install -m 600 deploy/wutzcalc.env.example $(CONFDIR)/wutzcalc.env + # Install the unit with the real node path and install prefix substituted in. + NODE=$$(command -v node); \ + sed -e "s|/opt/wutzcalc|$(PREFIX)|g" \ + -e "s|/usr/bin/node|$$NODE|g" \ + -e "s|^User=wutzcalc|User=$(SERVICE_USER)|" \ + -e "s|^Group=wutzcalc|Group=$(SERVICE_USER)|" \ + deploy/wutzcalc.service > $(UNIT) + systemctl daemon-reload + +## uninstall: stop and remove the service (keeps DB and config) +uninstall: require-root + -systemctl disable --now wutzcalc + rm -f $(UNIT) + systemctl daemon-reload + rm -rf $(PREFIX) + @echo "Removed $(PREFIX). Left $(CONFDIR) and /var/lib/wutzcalc in place." + +## clean: remove build output and installed dependencies +clean: + rm -rf node_modules dist \ + client/dist client/node_modules \ + server/dist server/node_modules \ + shared/dist shared/node_modules + +require-root: + @if [ "$$(id -u)" -ne 0 ]; then \ + echo "This target needs root — run: sudo make $(MAKECMDGOALS)"; \ + exit 1; \ + fi diff --git a/README.md b/README.md index 4029716..a21460a 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,20 @@ Single Node process serves the API, both client entries (`/` tablet, ## Run as a systemd service -Template files live in [`deploy/`](deploy/): a unit ([`wutzcalc.service`](deploy/wutzcalc.service)) -and an environment file ([`wutzcalc.env.example`](deploy/wutzcalc.env.example)). -They assume the built app lives in `/opt/wutzcalc` and the database in +On Fedora, the `Makefile` automates everything below — from a fresh checkout, as root: + +```sh +sudo make install # system deps + build + service +sudoedit /etc/wutzcalc/wutzcalc.env # set ADMIN_PASSWORD +sudo systemctl enable --now wutzcalc +``` + +Override paths with e.g. `make install PREFIX=/srv/wutzcalc SERVICE_USER=wutz`. + +The manual steps below do the same thing. Template files live in +[`deploy/`](deploy/): a unit ([`wutzcalc.service`](deploy/wutzcalc.service)) and +an environment file ([`wutzcalc.env.example`](deploy/wutzcalc.env.example)). They +assume the built app lives in `/opt/wutzcalc` and the database in `/var/lib/wutzcalc` — adjust paths in the unit if yours differ. ```sh