Server-side hourly rebuild + rsync to webroot. Triggered by a systemd timer; no CI, no webhooks, no secrets to manage.
| Component | Purpose |
|---|---|
deploy.sh |
Idempotent pipeline: fetch umstutorial → npm ci (only if lockfile moved) → sync umsme → sync gdrive → build → rsync dist/ to webroot. Skips build+rsync when nothing changed. |
umstutorial-deploy.service |
Oneshot systemd unit that runs deploy.sh as the deploy user. |
umstutorial-deploy.timer |
Fires OnCalendar=hourly with Persistent=true so a missed run catches up after reboot. |
bootstrap.sh |
One-time setup: installs the units, enables the timer, triggers a first deploy. |
Default paths (override with env vars when calling bootstrap.sh / deploy.sh):
- Clone:
/srv/umstutorial - Webroot:
/var/www/tutorial.uppsalamakerspace.se
Prerequisites: git, node ≥ 18, npm, rsync, systemd. The deploy user must own both the clone and the webroot.
# 1. Create a low-privilege deploy user (skip if you already have one).
sudo useradd -r -m -d /srv/umstutorial -s /usr/sbin/nologin deploy
# 2. Clone the repo into /srv/umstutorial (as the deploy user, via HTTPS so
# no SSH key is needed).
sudo -u deploy git clone https://github.com/uppsala-makerspace/umstutorial.git /srv/umstutorial
# 3. Run the bootstrap. This installs the systemd units, enables the timer,
# and kicks off a first deploy synchronously so failures surface here.
cd /srv/umstutorial
sudo DEPLOY_USER=deploy ./deploy/bootstrap.shThe first deploy populates /var/www/tutorial.uppsalamakerspace.se. Point your existing nginx vhost at that directory if it isn't already.
bootstrap.sh probes two things separately:
- login shell — what
sudo -iu deploysees. Sources.bashrc/.profile, so anynvminitialisation there runs. - service env — the bare environment
systemdwill give the unit: a cleanPATH, no shell init, no nvm.
The systemd timer fails if the service env probe finds no node (or one older than 18), even if the login shell looks fine. This is the most common nvm trap: node lives under ~/.nvm/versions/node/v…/bin, which only ends up on PATH when a shell init script runs.
Three fixes, in order of preference:
-
Install node ≥ 18 system-wide (recommended). Puts
nodein/usr/binor/usr/local/bin, which is on the service PATH out of the box. On Debian/Ubuntu:curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejsIf the install fails with a
dpkgfile-conflict on/usr/include/node/common.gypi(or similar), purge Ubuntu's splitlibnode-dev/libnode*packages first — NodeSource'snodejsdeb is self-contained and collides with them:sudo apt-get purge -y libnode-dev 'libnode[0-9]*' sudo apt-get autoremove -y sudo apt-get install -y nodejsThen re-run
sudo DEPLOY_USER=deploy ./deploy/bootstrap.sh. -
Use nvm under the deploy user and point the service at the nvm bin directory. After installing nvm + node 22 as the deploy user, edit
/etc/systemd/system/umstutorial-deploy.serviceand change theEnvironment=PATH=…line to prepend the nvm bin path:Environment=PATH=/home/deploy/.nvm/versions/node/v22.21.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Then
sudo systemctl daemon-reload && sudo systemctl start umstutorial-deploy.service. The version directory will change when you bump node, so prefer fix 1 if you can. -
Symlink the root-installed nvm node into a system path. Quick and dirty; brittle when node is upgraded. Only as a stopgap:
sudo ln -sf "$(readlink -f /root/.nvm/versions/node/v22.21.0/bin/node)" /usr/local/bin/node sudo ln -sf "$(readlink -f /root/.nvm/versions/node/v22.21.0/bin/npm)" /usr/local/bin/npm
systemctl status umstutorial-deploy.timer # next run + last result
journalctl -u umstutorial-deploy.service -n 50 # recent deploy logs
journalctl -fu umstutorial-deploy.service # follow live
sudo systemctl start umstutorial-deploy.service # force a deploy nowA run that found no changes logs one line (no changes (umstutorial=…, umsme=…, gdrive=…)); a real deploy logs deployed umstutorial=… umsme=… gdrive=…. Everything from the build pipeline goes to the journal.
To pull in changes to the deploy artifacts themselves (this directory):
sudo -u deploy git -C /srv/umstutorial pull
sudo ./deploy/bootstrap.sh # re-runs systemd install + daemon-reloadDay-to-day code changes don't need this — the hourly timer picks them up automatically.
sudo systemctl disable --now umstutorial-deploy.timer
sudo rm /etc/systemd/system/umstutorial-deploy.{service,timer}
sudo systemctl daemon-reloadThe clone and webroot stay; remove them by hand if you also want those gone.
Copy deploy/ to a sibling repo and change three values:
- The clone path and webroot in
deploy.sh(CLONE,WEBROOTdefaults). - The sync command line — replace
scripts/sync-umsme.sh --httpswith whatever pulls that repo's inputs (delete it if there are none). - The service / timer names (rename
umstutorial-deploythroughout).