feat: add .deploy.env support to save SSH credentials for deploys

Loads deploy/hostinger/.deploy.env automatically so you don't need to
type the password every time. Uses sshpass for password-based SSH auth.

Usage:
  cp deploy/hostinger/.deploy.env.example deploy/hostinger/.deploy.env
  # edit .deploy.env with your VPS IP, password, etc.
  ./deploy/hostinger/full-deploy.sh --skip-setup --skip-config

https://claude.ai/code/session_019vXaqxGmkdCjM8m3jp6rYj
This commit is contained in:
Claude 2026-02-17 14:13:44 +00:00
parent 7ca93d2596
commit f3e727a3d0
No known key found for this signature in database
3 changed files with 83 additions and 10 deletions

1
.gitignore vendored
View file

@ -24,6 +24,7 @@ build/
# Secrets & Config (keep templates, ignore actual secrets) # Secrets & Config (keep templates, ignore actual secrets)
.env .env
.deploy.env
config/config.json config/config.json
# Test # Test

View file

@ -0,0 +1,32 @@
# ============================================================
# PicoClaw - Deploy Configuration (Hostinger VPS)
# ============================================================
# Copy this file to .deploy.env and fill in your values:
# cp deploy/hostinger/.deploy.env.example deploy/hostinger/.deploy.env
#
# This file is git-ignored. Never commit credentials.
# ============================================================
# SSH Connection
DEPLOY_HOST="YOUR_VPS_IP"
DEPLOY_USER="root"
DEPLOY_PORT="22"
DEPLOY_PASSWORD=""
# SSH Key (leave empty to use password above)
DEPLOY_SSH_KEY=""
# Deploy method: docker or binary
DEPLOY_METHOD="docker"
# LLM Provider & API Key
LLM_PROVIDER="anthropic"
LLM_API_KEY=""
# Chat Channel & Token
CHAT_CHANNEL="telegram"
CHAT_TOKEN=""
CHAT_ALLOW_FROM=""
# Timezone
DEPLOY_TIMEZONE="America/Sao_Paulo"

View file

@ -58,6 +58,7 @@ HOST=""
SSH_USER="root" SSH_USER="root"
SSH_KEY="${HOME}/.ssh/id_rsa" SSH_KEY="${HOME}/.ssh/id_rsa"
SSH_PORT="22" SSH_PORT="22"
SSH_PASSWORD=""
METHOD="docker" METHOD="docker"
SKIP_SETUP=false SKIP_SETUP=false
SKIP_CONFIG=false SKIP_CONFIG=false
@ -72,6 +73,22 @@ CHAT_TOKEN="${CHAT_TOKEN:-}"
CHAT_ALLOW_FROM="${CHAT_ALLOW_FROM:-}" CHAT_ALLOW_FROM="${CHAT_ALLOW_FROM:-}"
DEPLOY_TIMEZONE="${DEPLOY_TIMEZONE:-America/Sao_Paulo}" DEPLOY_TIMEZONE="${DEPLOY_TIMEZONE:-America/Sao_Paulo}"
# ── Load .deploy.env if exists ──────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "${SCRIPT_DIR}/.deploy.env" ]; then
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/.deploy.env"
# Map DEPLOY_* vars to internal vars
HOST="${DEPLOY_HOST:-${HOST}}"
SSH_USER="${DEPLOY_USER:-${SSH_USER}}"
SSH_PORT="${DEPLOY_PORT:-${SSH_PORT}}"
SSH_PASSWORD="${DEPLOY_PASSWORD:-${SSH_PASSWORD}}"
METHOD="${DEPLOY_METHOD:-${METHOD}}"
if [ -n "${DEPLOY_SSH_KEY:-}" ]; then
SSH_KEY="${DEPLOY_SSH_KEY}"
fi
fi
# ── Parse Arguments ────────────────────────────────── # ── Parse Arguments ──────────────────────────────────
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case $1 in case $1 in
@ -94,21 +111,38 @@ done
# ── Validate ───────────────────────────────────────── # ── Validate ─────────────────────────────────────────
[ -z "${HOST}" ] && error "Host is required. Usage: $0 -h YOUR_VPS_IP" [ -z "${HOST}" ] && error "Host is required. Usage: $0 -h YOUR_VPS_IP"
if [ ! -f "${SSH_KEY}" ]; then SSHPASS_CMD=""
warn "SSH key not found at ${SSH_KEY}" if [ -n "${SSH_PASSWORD}" ]; then
info "Will attempt password-based SSH. For better security, set up SSH keys." # Use sshpass for password-based authentication
if ! command -v sshpass &>/dev/null; then
warn "sshpass not installed. Installing..."
if command -v apt-get &>/dev/null; then
sudo apt-get install -y -qq sshpass 2>/dev/null
elif command -v brew &>/dev/null; then
brew install sshpass 2>/dev/null || brew install hudochenkov/sshpass/sshpass 2>/dev/null
fi
command -v sshpass &>/dev/null || error "Could not install sshpass. Install it manually: apt-get install sshpass"
fi
export SSHPASS="${SSH_PASSWORD}"
SSHPASS_CMD="sshpass -e"
SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -p ${SSH_PORT}" SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -p ${SSH_PORT}"
SCP_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -P ${SSH_PORT}" SCP_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -P ${SSH_PORT}"
else info "Using password from .deploy.env"
elif [ -f "${SSH_KEY}" ]; then
SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -p ${SSH_PORT} -i ${SSH_KEY}" SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -p ${SSH_PORT} -i ${SSH_KEY}"
SCP_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -P ${SSH_PORT} -i ${SSH_KEY}" SCP_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -P ${SSH_PORT} -i ${SSH_KEY}"
else
warn "SSH key not found at ${SSH_KEY} and no password configured."
info "Will attempt interactive password SSH. For automation, create deploy/hostinger/.deploy.env"
SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -p ${SSH_PORT}"
SCP_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 -P ${SSH_PORT}"
fi fi
SSH_CMD="ssh ${SSH_OPTS} ${SSH_USER}@${HOST}" SSH_CMD="${SSHPASS_CMD} ssh ${SSH_OPTS} ${SSH_USER}@${HOST}"
SCP_CMD="scp ${SCP_OPTS}" SCP_CMD="${SSHPASS_CMD} scp ${SCP_OPTS}"
# ── Get project root ───────────────────────────────── # ── Get project root ─────────────────────────────────
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
# ── Banner ─────────────────────────────────────────── # ── Banner ───────────────────────────────────────────
echo "" echo ""
@ -120,7 +154,13 @@ echo -e "${NC}"
echo " Host: ${HOST}" echo " Host: ${HOST}"
echo " User: ${SSH_USER}" echo " User: ${SSH_USER}"
echo " Method: ${METHOD}" echo " Method: ${METHOD}"
echo " SSH Key: ${SSH_KEY}" if [ -n "${SSH_PASSWORD}" ]; then
echo " Auth: password (from .deploy.env)"
elif [ -f "${SSH_KEY}" ]; then
echo " Auth: SSH key (${SSH_KEY})"
else
echo " Auth: interactive password"
fi
echo "" echo ""
if [ "${AUTO_YES}" = false ]; then if [ "${AUTO_YES}" = false ]; then
@ -517,7 +557,7 @@ if [ "${METHOD}" = "docker" ]; then
# ── Docker Deploy ──────────────────────────────── # ── Docker Deploy ────────────────────────────────
log "Syncing project files to server..." log "Syncing project files to server..."
rsync -az --delete \ rsync -az --delete \
-e "ssh ${SSH_OPTS}" \ -e "${SSHPASS_CMD} ssh ${SSH_OPTS}" \
--exclude '.git' \ --exclude '.git' \
--exclude 'build/' \ --exclude 'build/' \
--exclude '.env' \ --exclude '.env' \
@ -564,7 +604,7 @@ else
# ── Binary Deploy ──────────────────────────────── # ── Binary Deploy ────────────────────────────────
log "Syncing source code to server..." log "Syncing source code to server..."
rsync -az --delete \ rsync -az --delete \
-e "ssh ${SSH_OPTS}" \ -e "${SSHPASS_CMD} ssh ${SSH_OPTS}" \
--exclude '.git' \ --exclude '.git' \
--exclude 'build/' \ --exclude 'build/' \
--exclude '.env' \ --exclude '.env' \