Public-cloud deployment of a single-user expense tracker: - 4-container stack: Caddy (HTTPS via Let's Encrypt), nginx (React/Vite SPA), Express API, Postgres 16 - Repeatable deployment via prepare-app.sh using only OCI CLI (no web console) - Persistent Postgres volume, auto-restart policies, healthchecks, backup + restore scripts - DuckDNS dynamic DNS for the public hostname; secrets isolated to gitignored .env Author: Gigi Saji Live URL: https://savesave.duckdns.org
47 lines
1.9 KiB
Bash
47 lines
1.9 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# backup.sh — dump the Postgres database to ./backups/expenses-<ts>.sql.gz
|
|
#
|
|
# Run from your laptop. Requires .env (for OCI_VM_NAME and SSH key) and
|
|
# uses the OCI CLI to look up the VM's public IP.
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
cd "$ROOT_DIR"
|
|
|
|
[ -f .env ] || { echo "ERROR: .env not found"; exit 1; }
|
|
set -a; source .env; set +a
|
|
|
|
: "${OCI_VM_NAME:=sk1-expense-tracker}"
|
|
: "${POSTGRES_USER:?POSTGRES_USER must be set in .env}"
|
|
: "${POSTGRES_DB:?POSTGRES_DB must be set in .env}"
|
|
: "${OCI_SSH_PRIVATE_KEY_PATH:=$HOME/.ssh/id_ed25519}"
|
|
OCI_SSH_PRIVATE_KEY_PATH="${OCI_SSH_PRIVATE_KEY_PATH/#\~/$HOME}"
|
|
|
|
TENANCY_OCID="$(oci iam compartment list --query 'data[0]."compartment-id"' --raw-output 2>/dev/null)"
|
|
COMPARTMENT_ID="${OCI_COMPARTMENT_ID:-$TENANCY_OCID}"
|
|
|
|
INSTANCE_ID="$(oci compute instance list --compartment-id "$COMPARTMENT_ID" \
|
|
--display-name "$OCI_VM_NAME" --lifecycle-state RUNNING \
|
|
--query 'data[0].id' --raw-output)"
|
|
[ -n "$INSTANCE_ID" ] && [ "$INSTANCE_ID" != "null" ] || { echo "ERROR: VM not found"; exit 1; }
|
|
|
|
VNIC_ID="$(oci compute instance list-vnics --instance-id "$INSTANCE_ID" --query 'data[0].id' --raw-output)"
|
|
PUBLIC_IP="$(oci network vnic get --vnic-id "$VNIC_ID" --query 'data."public-ip"' --raw-output)"
|
|
|
|
mkdir -p backups
|
|
TS="$(date +%Y%m%d-%H%M%S)"
|
|
OUT="backups/expenses-${TS}.sql.gz"
|
|
|
|
echo "[backup] dumping $POSTGRES_DB from $PUBLIC_IP..."
|
|
ssh -i "$OCI_SSH_PRIVATE_KEY_PATH" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
ubuntu@"$PUBLIC_IP" \
|
|
"sg docker -c 'docker exec sk1-db pg_dump -U $POSTGRES_USER -Fc $POSTGRES_DB'" \
|
|
| gzip > "$OUT"
|
|
|
|
SIZE="$(du -h "$OUT" | cut -f1)"
|
|
echo "[backup] saved $OUT ($SIZE)"
|