# gpsntp-dashboard — deploy to the Pi. # # Everything site-specific lives in .env (copy .env.example). Nothing in this # file names a host, a domain, or a certificate path. -include .env export PI ?= deploy@gps-ntp.local KEY ?= ~/.ssh/id_ed25519 APPDIR ?= /opt/gpsntp-dashboard DOMAIN ?= clock.example.internal SSH = ssh -i $(KEY) $(PI) RSYNC = rsync -az -e "ssh -i $(KEY)" # Where your Let's Encrypt live/ directory is on THIS machine, and where the # cert should land on the Pi. Only needed if you front the dashboard with TLS. CERT_SRC ?= $(HOME)/.certs/$(DOMAIN) CERT_DST ?= /etc/caddy/certs/$(DOMAIN) .PHONY: deploy logs restart status lint run caddy cert-sync deploy: $(RSYNC) --delete --exclude '.venv' --exclude '.git' --exclude '__pycache__' --exclude 'dist' ./ $(PI):/tmp/gpsntp-src/ $(SSH) 'sudo mkdir -p $(APPDIR) && sudo rsync -a --delete --exclude .venv /tmp/gpsntp-src/ $(APPDIR)/ && sudo APPDIR=$(APPDIR) bash $(APPDIR)/deploy/deploy.sh' logs: $(SSH) 'journalctl -u gpsntp-dashboard -n 60 -f' restart: $(SSH) 'sudo systemctl restart gpsntp-dashboard' status: $(SSH) 'systemctl status gpsntp-dashboard --no-pager; curl -s localhost:8080/healthz' # Renders deploy/Caddyfile.tmpl with $(DOMAIN) and installs it. caddy: sed 's|{{DOMAIN}}|$(DOMAIN)|g' deploy/Caddyfile.tmpl > /tmp/Caddyfile.rendered $(RSYNC) /tmp/Caddyfile.rendered $(PI):/tmp/Caddyfile $(SSH) 'sudo cp /tmp/Caddyfile /etc/caddy/Caddyfile && sudo caddy validate --adapter caddyfile --config /etc/caddy/Caddyfile && sudo systemctl reload caddy && echo reloaded' # Push a renewed cert to the Pi. The Pi issues nothing itself — see # deploy/Caddyfile.tmpl for why. cert-sync: $(RSYNC) -L $(CERT_SRC)/fullchain.pem $(CERT_SRC)/privkey.pem $(PI):/tmp/ $(SSH) 'sudo mv /tmp/fullchain.pem /tmp/privkey.pem $(CERT_DST)/ && sudo chown -R caddy:caddy /etc/caddy/certs && sudo chmod 600 $(CERT_DST)/privkey.pem && sudo systemctl reload caddy && echo "cert synced + caddy reloaded"' lint: uvx ruff check src/ run: GPSD_HOST=$${GPSD_HOST:-gps-ntp.local} uv run gpsntp-dashboard