#!/bin/sh # Installs (or upgrades) Mako as a systemd service. # # curl -fsSL https://git.veillax.com/Veillax/mako/raw/branch/main/deploy/install.sh | sudo sh # sudo sh install.sh [--start] [--version v0.1.0] [--listen 127.0.0.1:8490] [--source] # sudo sh install.sh --uninstall [--purge] # # What it does: # 1. downloads the release archive for this machine and checks its SHA-256 (or, with --source, # clones the repository and builds it with Go), # 2. installs the binary to /usr/local/bin/mako, # 3. creates a "mako" user, /etc/mako (settings) and /var/lib/mako (data), # 4. writes /etc/mako/mako.env and the systemd service, # 5. tells you what to do next: edit the env file, start the service, watch the log. # # Running it again upgrades the binary and keeps your settings; a service that is already running # is restarted. Add --start to start it straight away instead of editing the env file first. set -eu REPO_URL=${MAKO_REPO_URL:-https://git.veillax.com/Veillax/mako} API_URL=${MAKO_API_URL:-https://git.veillax.com/api/v1/repos/Veillax/mako} BIN=/usr/local/bin/mako CONF_DIR=/etc/mako DATA_DIR=/var/lib/mako ENV_FILE=$CONF_DIR/mako.env CONF_FILE=$CONF_DIR/mako.json UNIT=/etc/systemd/system/mako.service USER_NAME=mako VERSION="" LISTEN="127.0.0.1:8490" SOURCE=0 START=0 UNINSTALL=0 PURGE=0 say() { printf '%s\n' "$*"; } die() { printf 'install.sh: %s\n' "$*" >&2; exit 1; } while [ $# -gt 0 ]; do case $1 in --version) VERSION=${2:?--version needs a value}; shift ;; --listen) LISTEN=${2:?--listen needs a value}; shift ;; --source) SOURCE=1 ;; --start) START=1 ;; --uninstall) UNINSTALL=1 ;; --purge) PURGE=1 ;; -h|--help) sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) die "unknown option $1" ;; esac shift done [ "$(id -u)" -eq 0 ] || die "run as root (sudo sh install.sh)" [ "$(uname -s)" = Linux ] || die "this installer is for Linux; on Windows, download the .zip from the releases page" command -v systemctl >/dev/null 2>&1 || HAVE_SYSTEMD=0 HAVE_SYSTEMD=${HAVE_SYSTEMD:-1} if [ "$UNINSTALL" -eq 1 ]; then if [ "$HAVE_SYSTEMD" -eq 1 ]; then systemctl disable --now mako 2>/dev/null || true rm -f "$UNIT" systemctl daemon-reload fi rm -f "$BIN" if [ "$PURGE" -eq 1 ]; then rm -rf "$CONF_DIR" "$DATA_DIR" userdel "$USER_NAME" 2>/dev/null || true say "Mako removed, including its settings and data." else say "Mako removed. Settings ($CONF_DIR) and data ($DATA_DIR) were kept; add --purge to delete them." fi exit 0 fi fetch() { # fetch URL DEST if command -v curl >/dev/null 2>&1; then curl -fsSL -o "$2" "$1" elif command -v wget >/dev/null 2>&1; then wget -qO "$2" "$1" else die "need curl or wget"; fi } TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT # ---- 1. get the binary ---- if [ "$SOURCE" -eq 1 ]; then command -v git >/dev/null 2>&1 || die "--source needs git" command -v go >/dev/null 2>&1 || die "--source needs Go (https://go.dev/dl/)" say "Cloning $REPO_URL ..." git clone --quiet ${VERSION:+--branch "$VERSION"} --depth 1 "$REPO_URL" "$TMP/src" (cd "$TMP/src" && CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=${VERSION:-source}" -o "$TMP/mako" ./cmd/mako) else case $(uname -m) in x86_64|amd64) ARCH=amd64 ;; aarch64|arm64) ARCH=arm64 ;; *) die "no release build for $(uname -m); try --source" ;; esac if [ -z "$VERSION" ]; then fetch "$API_URL/releases/latest" "$TMP/latest.json" VERSION=$(sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$TMP/latest.json" | head -n 1) [ -n "$VERSION" ] || die "could not find the latest release; use --version or --source" fi ARCHIVE="mako_${VERSION}_linux_${ARCH}.tar.gz" say "Downloading Mako $VERSION ($ARCH) ..." fetch "$REPO_URL/releases/download/$VERSION/$ARCHIVE" "$TMP/$ARCHIVE" fetch "$REPO_URL/releases/download/$VERSION/SHA256SUMS" "$TMP/SHA256SUMS" want=$(grep " $ARCHIVE\$" "$TMP/SHA256SUMS" | cut -d' ' -f1) [ -n "$want" ] || die "$ARCHIVE is not listed in SHA256SUMS" got=$(sha256sum "$TMP/$ARCHIVE" | cut -d' ' -f1) [ "$want" = "$got" ] || die "checksum mismatch for $ARCHIVE; refusing to install" tar -xzf "$TMP/$ARCHIVE" -C "$TMP" cp "$TMP/mako_${VERSION}_linux_${ARCH}/mako" "$TMP/mako" fi # ---- 2. install it ---- UPGRADE=0 [ -x "$BIN" ] && UPGRADE=1 if [ "$UPGRADE" -eq 1 ] && [ "$HAVE_SYSTEMD" -eq 1 ]; then systemctl stop mako 2>/dev/null || true; fi install -m 0755 "$TMP/mako" "$BIN" say "Installed $("$BIN" version) to $BIN" # ---- 3. user and folders ---- id "$USER_NAME" >/dev/null 2>&1 || useradd --system --home-dir "$DATA_DIR" --shell /usr/sbin/nologin "$USER_NAME" 2>/dev/null \ || adduser --system --home "$DATA_DIR" --shell /usr/sbin/nologin "$USER_NAME" 2>/dev/null \ || die "could not create the $USER_NAME user" # The dashboard rewrites its settings file, so the service must own the folder that holds it. mkdir -p "$CONF_DIR" "$DATA_DIR" chown "$USER_NAME" "$CONF_DIR" "$DATA_DIR" chmod 0750 "$CONF_DIR" "$DATA_DIR" # ---- 4. settings and environment file ---- if [ ! -f "$CONF_FILE" ]; then printf '{\n "listen": "%s",\n "data_dir": "%s"\n}\n' "$LISTEN" "$DATA_DIR" > "$CONF_FILE" chown "$USER_NAME" "$CONF_FILE" chmod 0600 "$CONF_FILE" fi if [ ! -f "$ENV_FILE" ]; then cat > "$ENV_FILE" < Providers > Create > OAuth2/OpenID Provider (client type # Confidential, scopes openid, profile and email), allow the redirect URI # /auth/callback # then create an Application that uses it. Check the result with: mako check # Where you open Mako in a browser, such as https://notes.example.com (no path). MAKO_PUBLIC_URL= # The provider's issuer, such as https://auth.example.com/application/o/mako/ MAKO_OIDC_ISSUER= MAKO_OIDC_CLIENT_ID= MAKO_OIDC_CLIENT_SECRET= # Optional. Only these people may sign in (emails or usernames, separated by commas). Left empty, # everyone Authentik lets into the application gets a private notebook of their own. #MAKO_ALLOWED=you@example.com # Where the settings file is. It holds the signing secret and the key that encrypts your notes: # back it up, apart from $DATA_DIR. Without that key the notes cannot be read. MAKO_CONFIG=$CONF_FILE # Optional. These override what the settings file says. #MAKO_LISTEN=$LISTEN #MAKO_DATA=$DATA_DIR EOF chmod 0600 "$ENV_FILE" # systemd reads it as root, so the service user does not need access say "Created $ENV_FILE." fi # ---- 5. service ---- if [ "$HAVE_SYSTEMD" -eq 0 ]; then say "systemd was not found, so no service was installed. Run it yourself with:" say " sudo -u $USER_NAME env \$(grep -v '^#' $ENV_FILE | xargs) $BIN serve -config $CONF_FILE" exit 0 fi cat > "$UNIT" </dev/null 2>&1 if [ "$START" -eq 1 ] || systemctl is-active --quiet mako; then systemctl restart mako sleep 3 if systemctl is-active --quiet mako; then say "Mako is running." else say "Mako did not start. If you have not filled in the Authentik settings in $ENV_FILE yet, that is why." say "Look at: journalctl -u mako -n 50" exit 1 fi fi say "Installed $("$BIN" version)." say "Next:" say " 1. sudoedit $ENV_FILE (fill in the Authentik settings at the top)" say " 2. systemctl start mako (or run this again with --start)" say " 3. journalctl -u mako -f to watch it; it says at once if a setting is missing or wrong" say "" say "Mako listens on $LISTEN. Put an HTTPS reverse proxy (or Hammerhead) in front of it and open the" say "address you set as MAKO_PUBLIC_URL; Authentik will not send people back to plain http."