commit
32a36cceff
444 files changed
+67186
No files matched your search
@@ -0,0 +1,58 @@
|
||||
# How to Sync Database from Server
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Mac / Windows (WSL2 or Git Bash)
|
||||
|
||||
Run this single command from the project root:
|
||||
|
||||
```bash
|
||||
./scripts/update-local-db-from-server.sh
|
||||
```
|
||||
|
||||
That's it! Your local database now matches production.
|
||||
|
||||
> The script uses hardcoded defaults for `nvidia-admin@103.215.13.55`. To override, set environment variables before running.
|
||||
|
||||
## First Time Setup
|
||||
|
||||
1. Make sure Docker Desktop is running
|
||||
2. Copy the docker override file:
|
||||
```bash
|
||||
cp docker-compose.override.local.example docker-compose.override.yml
|
||||
```
|
||||
3. Test SSH access:
|
||||
```bash
|
||||
ssh nvidia-admin@103.215.13.55
|
||||
```
|
||||
|
||||
## What Each Script Does
|
||||
|
||||
- **`update-local-db-from-server.sh`** - Full sync (download + restore). Use this one.
|
||||
- **`fetch-prod-db.sh`** - Only downloads backup to `./backups/`
|
||||
- **`restore-postgres-local.sh`** - Only restores a backup file to local database
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Permission denied" error?**
|
||||
|
||||
- Make sure you can SSH: `ssh nvidia-admin@103.215.13.55`
|
||||
|
||||
**"docker: command not found"?**
|
||||
|
||||
- Start Docker Desktop
|
||||
|
||||
**Windows users:**
|
||||
|
||||
- Use WSL2, Git Bash, or PowerShell with WSL installed
|
||||
- Run from the project root folder
|
||||
|
||||
## Pro Tip: Create an Alias
|
||||
|
||||
Add to `~/.zshrc` (Mac) or `~/.bashrc` (Windows/Linux):
|
||||
|
||||
```bash
|
||||
alias sync-db='./scripts/update-local-db-from-server.sh'
|
||||
```
|
||||
|
||||
Then from anywhere in the project, just type: `sync-db`
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env sh
|
||||
# Daily PostgreSQL backup via Docker Compose (database service).
|
||||
# Run from anywhere: uses project root next to this script.
|
||||
# Cron example (2:15 AM): 15 2 * * * /path/to/repo/scripts/backup-postgres.sh
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
PROJECT_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
BACKUP_DIR="${BACKUP_DIR:-$PROJECT_ROOT/backups}"
|
||||
KEEP_DAYS="${KEEP_DAYS:-14}"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
STAMP=$(date +%Y%m%d-%H%M%S)
|
||||
OUT="$BACKUP_DIR/dashboard_db-$STAMP.sql.gz"
|
||||
|
||||
# TCP + password avoids peer-auth issues when exec runs as non-postgres user
|
||||
docker compose exec -T database sh -c \
|
||||
'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -h 127.0.0.1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" --no-owner --no-acl' \
|
||||
| gzip -c > "$OUT"
|
||||
|
||||
echo "Backup written: $OUT"
|
||||
|
||||
# Drop backups older than KEEP_DAYS (optional)
|
||||
if [ -n "$KEEP_DAYS" ] && [ "$KEEP_DAYS" -gt 0 ] 2>/dev/null; then
|
||||
find "$BACKUP_DIR" -maxdepth 1 -name 'dashboard_db-*.sql.gz' -type f -mtime "+$KEEP_DAYS" -delete 2>/dev/null || true
|
||||
fi
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on your Mac: creates a fresh backup on the server, then downloads it
|
||||
# into ./backups/ (never writes to production data — only pg_dump read).
|
||||
#
|
||||
# Usage:
|
||||
# REMOTE_USER=nvidia-admin \
|
||||
# REMOTE_HOST=103.215.13.55 \
|
||||
# REMOTE_PROJECT_DIR=/home/nvidia-admin/LABS/dashboard-solusi-ai-peternakan-ayam \
|
||||
# ./scripts/fetch-prod-db.sh
|
||||
#
|
||||
# Then: ./scripts/restore-postgres-local.sh --reset
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
PROJECT_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Default values (can be overridden with environment variables)
|
||||
: "${REMOTE_USER:=nvidia-admin}"
|
||||
: "${REMOTE_HOST:=103.215.13.55}"
|
||||
: "${REMOTE_PROJECT_DIR:=/home/nvidia-admin/LABS/dashboard-solusi-ai-peternakan-ayam}"
|
||||
|
||||
mkdir -p "$PROJECT_ROOT/backups"
|
||||
|
||||
QDIR=$(printf '%q' "$REMOTE_PROJECT_DIR")
|
||||
|
||||
echo "Running backup on server..."
|
||||
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cd ${QDIR} && ./scripts/backup-postgres.sh"
|
||||
|
||||
echo "Finding newest remote backup..."
|
||||
REMOTE_LATEST=$(ssh "${REMOTE_USER}@${REMOTE_HOST}" "ls -t ${QDIR}/backups/dashboard_db-*.sql.gz 2>/dev/null | head -1")
|
||||
if [ -z "$REMOTE_LATEST" ]; then
|
||||
echo "No dashboard_db-*.sql.gz found under ${REMOTE_PROJECT_DIR}/backups on server."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LOCAL_NAME=$(basename "$REMOTE_LATEST")
|
||||
echo "Downloading ${REMOTE_LATEST} -> backups/${LOCAL_NAME}"
|
||||
scp "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_LATEST}" "$PROJECT_ROOT/backups/${LOCAL_NAME}"
|
||||
echo "Saved: $PROJECT_ROOT/backups/${LOCAL_NAME}"
|
||||
echo "Next: ./scripts/restore-postgres-local.sh --reset backups/${LOCAL_NAME}"
|
||||
echo "Or next time run only: ./scripts/update-local-db-from-server.sh (same REMOTE_* env)."
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env sh
|
||||
# Restore a gzip SQL backup (same format as scripts/backup-postgres.sh) into the
|
||||
# local Docker database. Use --reset to wipe the local volume first (recommended
|
||||
# for a clean clone). Does not contact production.
|
||||
#
|
||||
# Usage:
|
||||
# cp docker-compose.override.local.example docker-compose.override.yml # once
|
||||
# docker compose up -d database
|
||||
# ./scripts/restore-postgres-local.sh --reset [path/to/dashboard_db-*.sql.gz]
|
||||
#
|
||||
# If you omit the file path, the newest ./backups/dashboard_db-*.sql.gz is used.
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
PROJECT_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
RESET=0
|
||||
BACKUP_FILE=
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--reset) RESET=1 ;;
|
||||
-*) echo "Unknown option: $arg"; exit 1 ;;
|
||||
*) BACKUP_FILE=$arg ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
BACKUP_FILE=$(ls -t "$PROJECT_ROOT"/backups/dashboard_db-*.sql.gz 2>/dev/null | head -1)
|
||||
fi
|
||||
|
||||
if [ -z "$BACKUP_FILE" ] || [ ! -f "$BACKUP_FILE" ]; then
|
||||
echo "No backup file found. Run ./scripts/fetch-prod-db.sh or pass a .sql.gz path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_FILE=$(CDPATH= cd -- "$(dirname -- "$BACKUP_FILE")" && pwd)/$(basename -- "$BACKUP_FILE")
|
||||
|
||||
if [ "$RESET" != 1 ]; then
|
||||
echo "Refusing to restore without --reset (avoids a messy mix of old + dump data)."
|
||||
echo "Run: $0 --reset \"$BACKUP_FILE\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Stopping stack and removing LOCAL Docker volumes for this project..."
|
||||
docker compose down -v
|
||||
|
||||
echo "Starting database..."
|
||||
docker compose up -d database
|
||||
|
||||
echo "Waiting for Postgres (TCP on 127.0.0.1:5432 inside container)..."
|
||||
i=0
|
||||
while [ "$i" -lt 90 ]; do
|
||||
if docker compose exec -T database sh -c 'pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ "$i" -eq 90 ]; then
|
||||
echo "Database did not become ready in time."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Restoring from $BACKUP_FILE ..."
|
||||
# Use Unix socket (no -h): matches pg_isready-without-TCP race on Docker Desktop; avoids connection refused to 127.0.0.1
|
||||
gunzip -c "$BACKUP_FILE" | docker compose exec -T database sh -c \
|
||||
'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1'
|
||||
|
||||
echo "Local database restored. Use DB_HOST=127.0.0.1 DB_PORT=5432 (with override) in .env for development."
|
||||
echo "Do not point these credentials at production."
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# One command to refresh your LOCAL Docker Postgres from the server:
|
||||
# runs a read-only pg_dump on the server, downloads it, resets the local volume, restores.
|
||||
#
|
||||
# Prerequisite once on your Mac:
|
||||
# cp docker-compose.override.local.example docker-compose.override.yml
|
||||
#
|
||||
# Usage (set paths to match your server):
|
||||
# REMOTE_USER=nvidia-admin \
|
||||
# REMOTE_HOST=103.215.13.55 \
|
||||
# REMOTE_PROJECT_DIR=/home/nvidia-admin/path/to/dashboard-solusi-ai-peternakan-ayam \
|
||||
# ./scripts/update-local-db-from-server.sh
|
||||
#
|
||||
# Does not modify production data. ./scripts/fetch-prod-db.sh and
|
||||
# ./scripts/restore-postgres-local.sh remain available if you want only one step.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
PROJECT_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
|
||||
|
||||
# Default values (can be overridden with environment variables)
|
||||
: "${REMOTE_USER:=nvidia-admin}"
|
||||
: "${REMOTE_HOST:=103.215.13.55}"
|
||||
: "${REMOTE_PROJECT_DIR:=/home/nvidia-admin/LABS/dashboard-solusi-ai-peternakan-ayam}"
|
||||
|
||||
export REMOTE_USER REMOTE_HOST REMOTE_PROJECT_DIR
|
||||
|
||||
"$SCRIPT_DIR/fetch-prod-db.sh"
|
||||
|
||||
LATEST=$(ls -t "$PROJECT_ROOT"/backups/dashboard_db-*.sql.gz 2>/dev/null | head -1)
|
||||
if [ -z "$LATEST" ] || [ ! -f "$LATEST" ]; then
|
||||
echo "No local backup found after fetch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$SCRIPT_DIR/restore-postgres-local.sh" --reset "$LATEST"
|
||||
|
||||
echo "Local database is now a copy of the latest server backup."
|
||||
Reference in new issue
Block a user