infra(infra-infrastructure): 🧱 Update iMessage-sync deployment with Caddy routes, systemd service, and deployment scripts

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Lilith 2026-03-06 20:20:10 -08:00
parent c3164f4930
commit d46ca4fa94
3 changed files with 274 additions and 0 deletions

29
imessage-sync/Caddyfile Normal file
View file

@ -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
}
}

View file

@ -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

231
scripts/prod.sh Executable file
View file

@ -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 <<EOF
Usage: $0 <command> [--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 <<RJSON
{
"version": "$(git -C "$PROJECT_ROOT" describe --tags --always 2>/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