- Update deployment scripts to use Docker with static files baked in - Remove host volume mount in favor of self-contained Docker image - Add verification script to ensure correct content is deployed - Update documentation to reflect new deployment architecture - Ensure build process produces correct output without manual copying Closes ELF-268 Co-Authored-By: Paperclip <noreply@paperclip.ing>
180 lines
5.5 KiB
Bash
Executable File
180 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Deploy static site to hatch.surf server via Docker
|
|
# Usage: ./scripts/deploy-site.sh [--dry-run]
|
|
#
|
|
# Environment variables required:
|
|
# DEPLOY_HOST - SSH host (e.g., 46.250.250.48)
|
|
# DEPLOY_USER - SSH user (e.g., root)
|
|
# DEPLOY_KEY - SSH private key (base64 encoded, optional if using ssh-agent)
|
|
#
|
|
# This script builds a Docker image with static files baked in and deploys it.
|
|
# No /var/www mounting required - the image is self-contained.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
SITE_DIR="$REPO_ROOT/site"
|
|
|
|
# Configuration
|
|
DEPLOY_HOST="${DEPLOY_HOST:-46.250.250.48}"
|
|
DEPLOY_USER="${DEPLOY_USER:-root}"
|
|
DEPLOY_KEY="${DEPLOY_KEY:-}"
|
|
CONTAINER_NAME="hatch-homepage"
|
|
IMAGE_NAME="hatch-homepage:latest"
|
|
|
|
# Parse arguments
|
|
DRY_RUN=false
|
|
for arg in "$@"; do
|
|
case $arg in
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
log() {
|
|
echo -e "${GREEN}✓${NC} $1"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}⚠${NC} $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}✗${NC} $1" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Validate
|
|
if [ ! -d "$SITE_DIR" ]; then
|
|
error "Site directory not found: $SITE_DIR"
|
|
fi
|
|
|
|
if [ ! -f "$SITE_DIR/index.html" ]; then
|
|
error "index.html not found in $SITE_DIR"
|
|
fi
|
|
|
|
if [ ! -f "$SITE_DIR/Dockerfile" ]; then
|
|
error "Dockerfile not found in $SITE_DIR"
|
|
fi
|
|
|
|
# Setup SSH key if provided
|
|
SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=10"
|
|
if [ -n "$DEPLOY_KEY" ]; then
|
|
SSH_KEY_FILE=$(mktemp)
|
|
echo "$DEPLOY_KEY" | base64 -d > "$SSH_KEY_FILE"
|
|
chmod 600 "$SSH_KEY_FILE"
|
|
SSH_OPTS="$SSH_OPTS -i $SSH_KEY_FILE"
|
|
fi
|
|
|
|
DEPLOY_TARGET="${DEPLOY_USER}@${DEPLOY_HOST}"
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
warn "Dry run - would build and deploy Docker image to $DEPLOY_TARGET"
|
|
warn "Image: $IMAGE_NAME"
|
|
warn "Container: $CONTAINER_NAME"
|
|
else
|
|
image_content=""
|
|
log "Building Docker image..."
|
|
docker build --no-cache -t "$IMAGE_NAME" "$SITE_DIR"
|
|
|
|
# Verify the built image contains correct content
|
|
log "Verifying built image content..."
|
|
image_content=$(docker run --rm "$IMAGE_NAME" cat /usr/share/nginx/html/index.html 2>/dev/null | head -20)
|
|
|
|
if echo "$image_content" | grep -q "Hatch.*Self-hostable HTTP request inspector"; then
|
|
log "Built image contains correct content"
|
|
else
|
|
error "Built image may contain stale content!"
|
|
echo "Expected: Hatch - Self-hostable HTTP request inspector"
|
|
echo "Got: $image_content"
|
|
exit 1
|
|
fi
|
|
|
|
log "Saving Docker image..."
|
|
docker save "$IMAGE_NAME" | gzip > /tmp/hatch-homepage.tar.gz
|
|
|
|
log "Uploading image to $DEPLOY_TARGET..."
|
|
scp $SSH_OPTS /tmp/hatch-homepage.tar.gz "$DEPLOY_TARGET:/tmp/hatch-homepage.tar.gz"
|
|
|
|
log "Deploying container on $DEPLOY_TARGET..."
|
|
ssh $SSH_OPTS "$DEPLOY_TARGET" << 'ENDSSH'
|
|
# Backup current image before loading new one
|
|
if docker images hatch-homepage:latest -q | grep -q .; then
|
|
echo "Backing up current image as hatch-homepage:backup..."
|
|
docker tag hatch-homepage:latest hatch-homepage:backup 2>/dev/null || true
|
|
fi
|
|
|
|
# Load the image
|
|
docker load < /tmp/hatch-homepage.tar.gz
|
|
|
|
# Stop and remove old container if exists
|
|
docker stop hatch-homepage 2>/dev/null || true
|
|
docker rm hatch-homepage 2>/dev/null || true
|
|
|
|
# Run new container (static files baked into image, no host mount)
|
|
docker run -d \
|
|
--name hatch-homepage \
|
|
--restart unless-stopped \
|
|
-p 127.0.0.1:3000:80 \
|
|
hatch-homepage:latest
|
|
|
|
# Clean up
|
|
rm -f /tmp/hatch-homepage.tar.gz
|
|
|
|
# Reload nginx if it's managing the reverse proxy
|
|
nginx -t && systemctl reload nginx 2>/dev/null || true
|
|
ENDSSH
|
|
|
|
# Clean up local temp file
|
|
rm -f /tmp/hatch-homepage.tar.gz
|
|
|
|
log "Deployment complete!"
|
|
|
|
# Run verification to ensure correct content is being served
|
|
log "Running deployment verification..."
|
|
if "$SCRIPT_DIR/verify-deployment.sh" --host "$DEPLOY_HOST" --user "$DEPLOY_USER" ${DEPLOY_KEY:+--key "$DEPLOY_KEY"}; then
|
|
log "Verification passed - correct content is being served"
|
|
log "Site live at https://hatch.surf"
|
|
else
|
|
error "Deployment verification failed!"
|
|
warn "Rolling back deployment..."
|
|
|
|
# Rollback: restore previous container if backup exists
|
|
ssh $SSH_OPTS "$DEPLOY_TARGET" << 'ROLLBACK'
|
|
# Check if we have a backup image
|
|
if docker images hatch-homepage:backup -q | grep -q .; then
|
|
echo "Restoring from backup image..."
|
|
docker stop hatch-homepage 2>/dev/null || true
|
|
docker rm hatch-homepage 2>/dev/null || true
|
|
docker run -d \
|
|
--name hatch-homepage \
|
|
--restart unless-stopped \
|
|
-p 127.0.0.1:3000:80 \
|
|
hatch-homepage:backup
|
|
echo "Rollback complete"
|
|
else
|
|
echo "No backup image available for rollback"
|
|
echo "Manual intervention required"
|
|
exit 1
|
|
fi
|
|
ROLLBACK
|
|
|
|
error "Deployment failed verification and rollback attempted"
|
|
error "Please check the server manually"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Cleanup SSH key if created
|
|
if [ -n "${SSH_KEY_FILE:-}" ]; then
|
|
rm -f "$SSH_KEY_FILE"
|
|
fi
|