Publish deployment and backup scripts

This commit is contained in:
2026-04-11 00:21:08 +02:00
parent 86204e0836
commit 9de9acec48
27 changed files with 3709 additions and 206 deletions

216
deploy-docker-paperclip.sh Executable file
View File

@@ -0,0 +1,216 @@
#!/usr/bin/env bash
# ==============================================================================
# Paperclip Deployment Script (Docker Compose + Traefik)
# ==============================================================================
# Builds and deploys Paperclip from source behind the shared Traefik reverse proxy.
# Source: https://github.com/paperclipai/paperclip
#
# Usage: deploy-docker-paperclip.sh
# deploy-docker-paperclip.sh --domain clip.us.an2.io
# deploy-docker-paperclip.sh --remove [--purge] [--yes]
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/common.sh"
# --- Parse arguments ---
parse_args "$@"
# --- Service config ---
SERVICE_NAME="paperclip"
BASE_DIR="/opt/${SERVICE_NAME}"
CONFIG_NAME="${SERVICE_NAME}"
UNIT_NAME="${SERVICE_NAME}-docker"
PAPERCLIP_REPO="${PAPERCLIP_REPO:-https://github.com/paperclipai/paperclip.git}"
# --- Handle --remove ---
if [[ "$ARG_REMOVE" == "1" ]]; then
require_root
do_remove "$SERVICE_NAME" "$CONFIG_NAME" "$UNIT_NAME" "$BASE_DIR"
exit 0
fi
# --- Domain resolution ---
if [[ -n "$ARG_DOMAIN" ]]; then
DOMAIN="$ARG_DOMAIN"
elif [[ -f "${BASE_DIR}/.env" ]] && grep -q '^DOMAIN=' "${BASE_DIR}/.env"; then
DOMAIN="$(grep '^DOMAIN=' "${BASE_DIR}/.env" | cut -d= -f2)"
else
DOMAIN="paperclip.an2.io"
fi
# --- Detect current state for banner ---
traefik_status="Not found — will deploy"
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^traefik$'; then
traefik_status="Running"
elif [[ -f "${TRAEFIK_DIR}/docker-compose.yml" ]]; then
traefik_status="Stopped — will start"
fi
install_mode="Fresh install"
if [[ -f "${BASE_DIR}/.env" ]]; then
install_mode="Re-run (preserving data)"
fi
# --- Print deployment plan ---
echo ""
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
echo -e "${CYAN} Deploying Paperclip (Docker)${NC}"
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
echo -e " Domain: ${DOMAIN}"
echo -e " Data: ${BASE_DIR}"
echo -e " Traefik: ${traefik_status}"
echo -e " Mode: ${install_mode}"
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
echo ""
# --- Check if already deployed and running ---
if [[ -f "${BASE_DIR}/docker-compose.yml" ]] && \
docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^paperclip$'; then
echo -e "${GREEN} Paperclip is already running — nothing to do.${NC}"
echo ""
echo -e " Logs: docker logs -f paperclip"
echo -e " Backup: ${SCRIPT_DIR}/backup-paperclip.sh"
echo -e " Remove: $0 --remove [--purge]"
echo ""
exit 0
fi
# --- Shared infrastructure ---
require_root
detect_os
install_prerequisites
ensure_docker_network
ensure_traefik
configure_firewall
# --- Backup restore check ---
if check_and_restore_backup "$SERVICE_NAME"; then
saved_domain="$DOMAIN"
# shellcheck source=/dev/null
source "${BASE_DIR}/.env"
DOMAIN="$saved_domain"
else
# --- Fresh install ---
if [[ -f "${BASE_DIR}/.env" ]]; then
saved_domain="$DOMAIN"
# shellcheck source=/dev/null
source "${BASE_DIR}/.env"
DOMAIN="$saved_domain"
fi
mkdir -p "${BASE_DIR}/data" "${BASE_DIR}/postgres/data"
# Clone or update source
if [[ -d "${BASE_DIR}/repo/.git" ]]; then
info "Updating source..."
(cd "${BASE_DIR}/repo" && git pull)
else
info "Cloning Paperclip from ${PAPERCLIP_REPO}..."
git clone "$PAPERCLIP_REPO" "${BASE_DIR}/repo"
fi
# --- Generate .env (preserve existing passwords on re-run) ---
if [[ -z "${DB_PASS:-}" ]]; then
DB_PASS="$(generate_password)"
fi
if [[ -z "${BETTER_AUTH_SECRET:-}" ]]; then
BETTER_AUTH_SECRET="$(generate_password)"
fi
cat > "${BASE_DIR}/.env" <<DOTENV
# Generated by deploy-docker-paperclip.sh on $(date -Iseconds)
DOMAIN=${DOMAIN}
DB_PASS=${DB_PASS}
BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
DOTENV
chmod 600 "${BASE_DIR}/.env"
ok ".env written."
# --- Generate docker-compose.yml ---
cat > "${BASE_DIR}/docker-compose.yml" <<COMPOSE
services:
paperclip-postgres:
image: postgres:16-alpine
container_name: paperclip-postgres
restart: unless-stopped
security_opt:
- no-new-privileges:true
mem_limit: 1G
read_only: true
tmpfs:
- /tmp
- /var/run/postgresql
environment:
- POSTGRES_USER=paperclip
- POSTGRES_PASSWORD=${DB_PASS}
- POSTGRES_DB=paperclip
volumes:
- ./postgres/data:/var/lib/postgresql/data
networks:
- paperclip-internal
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
paperclip:
build: ./repo
container_name: paperclip
restart: unless-stopped
depends_on:
- paperclip-postgres
security_opt:
- no-new-privileges:true
mem_limit: 4G
environment:
- PORT=3100
- HOST=0.0.0.0
- SERVE_UI=true
- DATABASE_URL=postgres://paperclip:${DB_PASS}@paperclip-postgres:5432/paperclip
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
volumes:
- ./data:/paperclip
networks:
- paperclip-internal
- traefik-public
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
networks:
paperclip-internal:
driver: bridge
traefik-public:
external: true
COMPOSE
ok "docker-compose.yml written."
info "Building Paperclip image (this may take a few minutes)..."
(cd "$BASE_DIR" && docker compose build)
fi
# --- Always do these (fresh or restored) ---
write_traefik_dynamic_config "$CONFIG_NAME" "$DOMAIN" "http://paperclip:3100"
install_systemd_unit "$UNIT_NAME" "$BASE_DIR"
(cd "$BASE_DIR" && docker compose up -d)
wait_for_healthy "paperclip" "http://localhost:3100/api/health" 120
# --- Summary ---
echo ""
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
echo -e "${GREEN} Paperclip deployed successfully${NC}"
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
echo -e " URL: https://${DOMAIN}"
echo -e " Data: ${BASE_DIR}/data/"
echo -e " Traefik: ${TRAEFIK_DYNAMIC_DIR}/${CONFIG_NAME}.yml"
echo -e " Systemd: systemctl status ${UNIT_NAME}"
echo -e " Logs: docker logs -f paperclip"
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
echo ""