From d46ca4fa94d58f1a0c0b5f2bf2155394b0dadaa3 Mon Sep 17 00:00:00 2001 From: Lilith Date: Fri, 6 Mar 2026 20:20:10 -0800 Subject: [PATCH] =?UTF-8?q?infra(infra-infrastructure):=20=F0=9F=A7=B1=20U?= =?UTF-8?q?pdate=20iMessage-sync=20deployment=20with=20Caddy=20routes,=20s?= =?UTF-8?q?ystemd=20service,=20and=20deployment=20scripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- imessage-sync/Caddyfile | 29 +++ imessage-sync/systemd/messenger-caddy.service | 14 ++ scripts/prod.sh | 231 ++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 imessage-sync/Caddyfile create mode 100644 imessage-sync/systemd/messenger-caddy.service create mode 100755 scripts/prod.sh diff --git a/imessage-sync/Caddyfile b/imessage-sync/Caddyfile new file mode 100644 index 0000000..90ebbca --- /dev/null +++ b/imessage-sync/Caddyfile @@ -0,0 +1,29 @@ +{ + auto_https disable_redirects +} + +https://{$MESSENGER_CADDY_HOST:messenger.apricot.local}:5701 { + tls internal + + log { + output file {$HOME}/.local/state/messenger/access.log { + roll_size 10mb + roll_keep 2 + } + format json + } + + handle /api/* { + reverse_proxy localhost:3100 + } + + handle /socket.io/* { + reverse_proxy localhost:3100 + } + + handle { + root * {$MESSENGER_WEB_ROOT:./web/dist} + try_files {path} /index.html + file_server + } +} diff --git a/imessage-sync/systemd/messenger-caddy.service b/imessage-sync/systemd/messenger-caddy.service new file mode 100644 index 0000000..82fc160 --- /dev/null +++ b/imessage-sync/systemd/messenger-caddy.service @@ -0,0 +1,14 @@ +[Unit] +Description=Messenger Caddy Reverse Proxy +After=messenger-imessage.service + +[Service] +Type=exec +WorkingDirectory=%h/.local/share/messenger +EnvironmentFile=%h/.local/share/messenger/.env.production +ExecStart=%h/.local/bin/caddy run --config Caddyfile +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=default.target diff --git a/scripts/prod.sh b/scripts/prod.sh new file mode 100755 index 0000000..e7367bc --- /dev/null +++ b/scripts/prod.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +INSTALL_DIR="\$HOME/.local/share/messenger" +BACKEND_SRC="$PROJECT_ROOT/imessage-sync/backend" +WEB_SRC="$PROJECT_ROOT/codebase/web" +CADDY_SRC="$PROJECT_ROOT/imessage-sync/Caddyfile" +SYSTEMD_SRC="$PROJECT_ROOT/imessage-sync/systemd" + +BACKEND_SERVICE="messenger-imessage" +CADDY_SERVICE="messenger-caddy" + +TARGET="" +SSH_HOST="black" + +usage() { + cat < [--target black] + +Commands: + release Build locally and deploy (optionally to remote target) + start Start services + stop Stop services + restart Restart services + status Show service status + logs Follow service logs + +Options: + --target black Deploy/manage on remote host 'black' + +Examples: + $0 release # Build and install locally + $0 release --target black # Build locally, deploy to black + $0 restart --target black # Restart services on black + $0 logs --target black # Follow logs on black +EOF + exit 1 +} + +parse_args() { + COMMAND="${1:-}" + shift || true + + while [[ $# -gt 0 ]]; do + case "$1" in + --target) + TARGET="${2:-}" + shift 2 + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac + done + + if [[ -z "$COMMAND" ]]; then + usage + fi +} + +run_cmd() { + if [[ -n "$TARGET" ]]; then + ssh "$SSH_HOST" "$@" + else + eval "$@" + fi +} + +service_cmd() { + local action="$1" + local service="$2" + + if [[ -n "$TARGET" ]]; then + # Prod uses system-level service for backend + if [[ "$service" == "$BACKEND_SERVICE" ]]; then + ssh "$SSH_HOST" "sudo systemctl $action $service.service" + else + ssh "$SSH_HOST" "systemctl --user $action $service.service" + fi + else + systemctl --user "$action" "$service.service" + fi +} + +build_backend() { + echo "Building backend..." + cd "$BACKEND_SRC" + bun install --frozen-lockfile 2>/dev/null || bun install + bun run build + echo "Backend built successfully" +} + +build_web() { + echo "Building web frontend..." + cd "$WEB_SRC" + pnpm install --frozen-lockfile 2>/dev/null || pnpm install + pnpm build + echo "Web frontend built successfully" +} + +do_release() { + build_backend + build_web + + local install_dir + if [[ -n "$TARGET" ]]; then + install_dir="/var/home/lilith/.local/share/messenger" + else + install_dir="$HOME/.local/share/messenger" + fi + + local release_json + release_json=$(cat </dev/null || git -C "$PROJECT_ROOT" rev-parse --short HEAD)", + "commit": "$(git -C "$PROJECT_ROOT" rev-parse HEAD)", + "built_at": "$(date -Iseconds)", + "built_by": "$(whoami)@$(hostname)" +} +RJSON +) + + if [[ -n "$TARGET" ]]; then + echo "Deploying to $SSH_HOST:$install_dir..." + + ssh "$SSH_HOST" "mkdir -p $install_dir/backend-api $install_dir/web" + + # Sync backend (exclude node_modules, re-install on target) + rsync -az --delete \ + --exclude='node_modules' \ + --exclude='.env' \ + "$BACKEND_SRC/" "$SSH_HOST:$install_dir/backend-api/" + + # Install deps on target + ssh "$SSH_HOST" "cd $install_dir/backend-api && bun install --frozen-lockfile 2>/dev/null || cd $install_dir/backend-api && bun install" + + # Sync web dist + rsync -az --delete "$WEB_SRC/dist/" "$SSH_HOST:$install_dir/web/dist/" + + # Sync Caddyfile + rsync -az "$CADDY_SRC" "$SSH_HOST:$install_dir/Caddyfile" + + # Sync production env + rsync -az "$BACKEND_SRC/.env.production" "$SSH_HOST:$install_dir/.env.production" + + # Write release metadata + echo "$release_json" | ssh "$SSH_HOST" "cat > $install_dir/release.json" + + # Install systemd services + ssh "$SSH_HOST" "mkdir -p ~/.config/systemd/user" + rsync -az "$SYSTEMD_SRC/" "$SSH_HOST:~/.config/systemd/user/" --include='*.service' --exclude='*' + ssh "$SSH_HOST" "systemctl --user daemon-reload" + + echo "Deployed to $SSH_HOST:$install_dir" + else + echo "Installing to $install_dir..." + + mkdir -p "$install_dir/backend-api" "$install_dir/web" + + rsync -a --delete \ + --exclude='node_modules' \ + --exclude='.env' \ + "$BACKEND_SRC/" "$install_dir/backend-api/" + + (cd "$install_dir/backend-api" && bun install --frozen-lockfile 2>/dev/null || cd "$install_dir/backend-api" && bun install) + + rsync -a --delete "$WEB_SRC/dist/" "$install_dir/web/dist/" + cp "$CADDY_SRC" "$install_dir/Caddyfile" + cp "$BACKEND_SRC/.env.production" "$install_dir/.env.production" + echo "$release_json" > "$install_dir/release.json" + + mkdir -p ~/.config/systemd/user + cp "$SYSTEMD_SRC"/*.service ~/.config/systemd/user/ + systemctl --user daemon-reload + + echo "Installed to $install_dir" + fi +} + +do_start() { + echo "Starting messenger services..." + service_cmd start "$BACKEND_SERVICE" + service_cmd start "$CADDY_SERVICE" + echo "Services started" +} + +do_stop() { + echo "Stopping messenger services..." + service_cmd stop "$CADDY_SERVICE" 2>/dev/null || true + service_cmd stop "$BACKEND_SERVICE" + echo "Services stopped" +} + +do_restart() { + echo "Restarting messenger services..." + service_cmd restart "$BACKEND_SERVICE" + service_cmd restart "$CADDY_SERVICE" 2>/dev/null || true + echo "Services restarted" +} + +do_status() { + echo "=== Backend ($BACKEND_SERVICE) ===" + service_cmd status "$BACKEND_SERVICE" 2>/dev/null || true + echo "" + echo "=== Caddy ($CADDY_SERVICE) ===" + service_cmd status "$CADDY_SERVICE" 2>/dev/null || true +} + +do_logs() { + if [[ -n "$TARGET" ]]; then + ssh "$SSH_HOST" "sudo journalctl -u $BACKEND_SERVICE.service -f --no-hostname -n 50" + else + journalctl --user -u "$BACKEND_SERVICE.service" -f --no-hostname -n 50 + fi +} + +parse_args "$@" + +case "$COMMAND" in + release) do_release ;; + start) do_start ;; + stop) do_stop ;; + restart) do_restart ;; + status) do_status ;; + logs) do_logs ;; + *) usage ;; +esac