Add local-network deployment automation and tighten runtime defaults
This commit adds the first complete local-network deployment path for the project. It normalizes the runtime contract around a fixed container listener on 0.0.0.0:10000, binds the published compose port to 127.0.0.1, and keeps the image/build workflow aligned with the released container image. It also introduces an installation script, an nginx reverse-proxy template, and a safer SQLite backup flow based on sqlite3 .backup with retention and optional rclone upload support. Deployment-oriented configuration has been consolidated into .env.example, repository-local .env files are now ignored, and the deployment scripts are executable. In addition, the frontend mixed-content issue is fixed by switching the stylesheet reference to a root-relative static path, with tests updated to cover the regression. README guidance has been expanded to document the new install, nginx, backup, and restore conventions.
This commit is contained in:
+69
-13
@@ -1,27 +1,83 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
PROJECT_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$PROJECT_ROOT"
|
||||
APP_DIR="__APP_DIR__"
|
||||
DEFAULT_BACKUP_DIR="__BACKUP_DIR__"
|
||||
ENV_FILE="$APP_DIR/.env"
|
||||
|
||||
if [ ! -f ".env" ] && [ -f ".env.example" ]; then
|
||||
echo "未找到 .env,先从 .env.example 复制一份:"
|
||||
echo " cp .env.example .env"
|
||||
require_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "Missing required command: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_path() {
|
||||
case "$1" in
|
||||
/*) printf '%s\n' "$1" ;;
|
||||
*) printf '%s/%s\n' "$APP_DIR" "$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Deployed .env file not found: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DATA_DIR_VALUE=$(grep '^DATA_DIR=' .env 2>/dev/null | tail -n 1 | cut -d '=' -f 2- || true)
|
||||
DATA_DIR=${DATA_DIR_VALUE:-./data}
|
||||
DB_PATH="$DATA_DIR/app.db"
|
||||
set -a
|
||||
. "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
require_command sqlite3
|
||||
|
||||
if [ -n "${BACKUP_REMOTE:-}" ]; then
|
||||
require_command rclone
|
||||
fi
|
||||
|
||||
BACKUP_DIR=${BACKUP_DIR:-$DEFAULT_BACKUP_DIR}
|
||||
DATA_DIR=${DATA_DIR:-./data}
|
||||
DB_PATH="$(resolve_path "$DATA_DIR")/app.db"
|
||||
|
||||
if [ ! -f "$DB_PATH" ]; then
|
||||
echo "未找到数据库文件:$DB_PATH"
|
||||
echo "Database file not found: $DB_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p backups
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
|
||||
DESTINATION="backups/app-$TIMESTAMP.db"
|
||||
TMP_BACKUP="$BACKUP_DIR/.app-$TIMESTAMP.db.tmp"
|
||||
FINAL_BACKUP="$BACKUP_DIR/app-$TIMESTAMP.db"
|
||||
|
||||
cp "$DB_PATH" "$DESTINATION"
|
||||
echo "备份已创建:$DESTINATION"
|
||||
cleanup() {
|
||||
rm -f "$TMP_BACKUP"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Prefer sqlite3 .backup so the snapshot stays transactionally consistent without
|
||||
# stopping the running container or racing with SQLite writes.
|
||||
sqlite3 "$DB_PATH" <<EOF
|
||||
.timeout 5000
|
||||
.backup $TMP_BACKUP
|
||||
EOF
|
||||
|
||||
mv "$TMP_BACKUP" "$FINAL_BACKUP"
|
||||
trap - EXIT INT TERM
|
||||
|
||||
count=0
|
||||
for backup_file in $(find "$BACKUP_DIR" -maxdepth 1 -type f -name 'app-*.db' | sort -r); do
|
||||
count=$((count + 1))
|
||||
if [ "$count" -gt 5 ]; then
|
||||
rm -f "$backup_file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${BACKUP_REMOTE:-}" ]; then
|
||||
remote_target=${BACKUP_REMOTE%/}/$(basename "$FINAL_BACKUP")
|
||||
rclone copyto "$FINAL_BACKUP" "$remote_target"
|
||||
echo "Backup uploaded to remote: $remote_target"
|
||||
else
|
||||
echo "BACKUP_REMOTE is empty; skipping remote upload"
|
||||
fi
|
||||
|
||||
echo "Backup created: $FINAL_BACKUP"
|
||||
|
||||
Reference in New Issue
Block a user