diverter-device-emulator/deploy/ship.sh
2026-09-24 10:57:06 +01:00

78 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build the app image on this machine, copy it and Caddy to the host, and restart both.
# Uses the diverter-emu entry in ~/.ssh/config (user and key).
# Usage: ./deploy/ship.sh [ssh-host]
set -euo pipefail
HOST="${1:-diverter-emu}"
IMAGE=diverter-device-emulator
REMOTE_DIR=/opt/diverter-device-emulator
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
if [[ ! -f .env ]]; then
echo "Missing $ROOT/.env — copy .env.example and fill it in." >&2
exit 1
fi
if ! command -v docker >/dev/null 2>&1; then
echo "docker is not on PATH. Start Docker Desktop, then run this again." >&2
exit 1
fi
env_value() {
local key="$1"
grep -E "^${key}=" .env | head -n 1 | cut -d= -f2- | tr -d "\"'" | tr -d '[:space:]'
}
PORTAL_HOST="$(env_value PORTAL_HOST)"
if [[ -z "$PORTAL_HOST" ]]; then
echo "Set PORTAL_HOST in .env to the public hostname. Its DNS A record must point at the Lightsail IP before the first deploy, or Caddy cannot get a certificate." >&2
exit 1
fi
ARCH="$(ssh "$HOST" "uname -m")"
case "$ARCH" in
x86_64) PLATFORM=linux/amd64 ;;
aarch64 | arm64) PLATFORM=linux/arm64 ;;
*)
echo "Unsupported server architecture: $ARCH" >&2
exit 1
;;
esac
TAR="$(mktemp -t diverter-image.XXXXXX.tar)"
cleanup() { rm -f "$TAR"; }
trap cleanup EXIT
if ! ssh "$HOST" "sudo docker compose version" >/dev/null 2>&1; then
echo "The server has no Docker Compose. On the instance: sudo apt-get install -y docker-compose-v2" >&2
exit 1
fi
# Attestation indexes from Docker Desktop make `docker save` fail, so both images are single-platform.
echo "Building $IMAGE for $PLATFORM"
docker build --platform "$PLATFORM" --provenance=false --sbom=false -t "$IMAGE" .
echo "Preparing caddy:2 for $PLATFORM"
docker build --platform "$PLATFORM" --provenance=false --sbom=false -t caddy:2 - <<'EOF'
FROM caddy:2
EOF
echo "Saving images"
docker save -o "$TAR" "$IMAGE" caddy:2
echo "Copying images, .env, and Caddy config to $HOST"
ssh "$HOST" "sudo mkdir -p '$REMOTE_DIR/data' && sudo chown 1000:1000 '$REMOTE_DIR/data'"
scp "$TAR" "$HOST:/tmp/${IMAGE}.tar"
scp .env "$HOST:/tmp/${IMAGE}.env"
scp "$ROOT/deploy/docker-compose.yml" "$ROOT/deploy/Caddyfile" "$HOST:/tmp/"
ssh "$HOST" "sudo mv /tmp/${IMAGE}.env '$REMOTE_DIR/.env' && sudo chmod 600 '$REMOTE_DIR/.env' && sudo mv /tmp/docker-compose.yml /tmp/Caddyfile '$REMOTE_DIR/'"
ssh "$HOST" "sudo docker load -i /tmp/${IMAGE}.tar && rm -f /tmp/${IMAGE}.tar"
ssh "$HOST" "sudo docker rm -f '$IMAGE' >/dev/null 2>&1 || true"
ssh "$HOST" "sudo bash -c 'cd \"$REMOTE_DIR\" && docker compose up -d --pull never --remove-orphans'"
echo "Containers on $HOST:"
ssh "$HOST" "sudo docker ps --filter name='diverter-' --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"