#!/usr/bin/env bash # # install.sh — install nuntius as a systemd service. # # nuntius ships as a single static binary. Build it on your workstation, upload # the binary, the systemd unit, and the .env template to the server, then run # this script there as root from that directory: # # scp bin/nuntius nuntius.service .env.example user@host:/tmp/nuntius/ # ssh user@host # cd /tmp/nuntius && sudo bash install.sh # # It expects ./nuntius and ./nuntius.service (and optionally ./.env.example) in # the current working directory. Idempotent: re-running is safe — it skips the # user, config, and .env when they already exist, and never starts the service. set -euo pipefail NUNTIUS_USER="nuntius" BIN_DEST="/usr/local/bin/nuntius" CONFIG_DIR="/etc/nuntius" CONFIG_FILE="${CONFIG_DIR}/config.toml" ENV_FILE="${CONFIG_DIR}/.env" DATA_DIR="/var/lib/nuntius" SERVICE_DEST="/etc/systemd/system/nuntius.service" log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } warn() { printf '\033[1;33mWARN:\033[0m %s\n' "$*" >&2; } die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } usage() { cat <<'EOF' install.sh — install nuntius as a systemd service. Upload the binary, the systemd unit, and the .env template to the server, then run this script there as root from that directory: scp bin/nuntius nuntius.service .env.example user@host:/tmp/nuntius/ ssh user@host cd /tmp/nuntius && sudo bash install.sh Idempotent: re-running is safe. The service is enabled but never started. EOF exit 0 } require_root() { [ "$(id -u)" -eq 0 ] || die "Run as root: sudo bash install.sh" } require_files() { [ -f ./nuntius ] || die "./nuntius binary not found — copy it here first (e.g. rsync bin/nuntius)." [ -f ./nuntius.service ] || \ die "./nuntius.service not found — paste the unit from docs/deployment.md (Option A)." } create_user() { if id "$NUNTIUS_USER" >/dev/null 2>&1; then log "User ${NUNTIUS_USER} already exists." else log "Creating system user ${NUNTIUS_USER}…" useradd --system --shell /usr/sbin/nologin --home-dir "$DATA_DIR" --user-group "$NUNTIUS_USER" fi } create_data_dir() { log "Setting up ${DATA_DIR}…" mkdir -p "$DATA_DIR" chown "$NUNTIUS_USER:$NUNTIUS_USER" "$DATA_DIR" chmod 750 "$DATA_DIR" } install_binary() { log "Installing binary to ${BIN_DEST}…" install -m 0755 ./nuntius "$BIN_DEST" } install_service() { log "Installing systemd unit ${SERVICE_DEST}…" install -m 0644 ./nuntius.service "$SERVICE_DEST" } generate_config() { if [ -f "$CONFIG_FILE" ]; then log "Config ${CONFIG_FILE} already exists; leaving it untouched." return fi log "Generating ${CONFIG_FILE}…" mkdir -p "$CONFIG_DIR" # nuntius writes the template config on first start; run it briefly, then # let `timeout` send SIGTERM (graceful shutdown). No backgrounding or manual # kill — the write happens at startup, before the timeout elapses. timeout -k 5s 4s "$BIN_DEST" >/dev/null 2>&1 || true [ -f "$CONFIG_FILE" ] || warn "nuntius did not create ${CONFIG_FILE}; check the uploaded binary." chown -R "$NUNTIUS_USER:$NUNTIUS_USER" "$DATA_DIR" } install_env() { if [ -f "$ENV_FILE" ]; then log "${ENV_FILE} already exists; leaving it untouched." elif [ -f ./.env.example ]; then log "Creating ${ENV_FILE} from .env.example (edit it!)…" install -m 0600 ./.env.example "$ENV_FILE" chown "root:$NUNTIUS_USER" "$ENV_FILE" else warn ".env.example not found; skipping ${ENV_FILE}. Create it before starting." fi } enable_service() { log "Reloading systemd and enabling nuntius…" systemctl daemon-reload systemctl enable nuntius.service } final_notes() { cat <<'EOF' ============================================================ ✓ nuntius installed and enabled, but NOT started. Next manual steps: 1. Set the SMTP password: sudo $EDITOR /etc/nuntius/.env 2. Edit the auto-generated config (smtp.host, smtp.user, allowed_origins): sudo $EDITOR /etc/nuntius/config.toml 3. Start the service: sudo systemctl start nuntius sudo journalctl -u nuntius -f 4. Add the nginx location block (see README.md), then: sudo nginx -t && sudo systemctl reload nginx ============================================================ EOF } main() { case "${1:-}" in -h | --help) usage ;; esac require_root require_files create_user create_data_dir install_binary install_service generate_config install_env enable_service final_notes } main "$@"