|
@@ -2,154 +2,116 @@
|
|
|
set -euo pipefail
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
SERVICE_NAME="vmess-domain-rotator"
|
|
SERVICE_NAME="vmess-domain-rotator"
|
|
|
-APP_DIR="/opt/vmess-domain-rotator"
|
|
|
|
|
-RUN_USER="vmessrotator"
|
|
|
|
|
-RUN_GROUP="vmessrotator"
|
|
|
|
|
-APP_DIR_SET="0"
|
|
|
|
|
|
|
+RUN_USER=""
|
|
|
|
|
+RUN_GROUP=""
|
|
|
RUN_USER_SET="0"
|
|
RUN_USER_SET="0"
|
|
|
RUN_GROUP_SET="0"
|
|
RUN_GROUP_SET="0"
|
|
|
INTERVAL="1h"
|
|
INTERVAL="1h"
|
|
|
INSTALL_DEPS="1"
|
|
INSTALL_DEPS="1"
|
|
|
-OVERWRITE_CONFIG="0"
|
|
|
|
|
|
|
|
|
|
usage() {
|
|
usage() {
|
|
|
- cat <<'EOF'
|
|
|
|
|
|
|
+ cat <<'EOF'
|
|
|
Usage: sudo bash scripts/install_debian.sh [options]
|
|
Usage: sudo bash scripts/install_debian.sh [options]
|
|
|
|
|
|
|
|
Default behavior:
|
|
Default behavior:
|
|
|
- - If current source dir is a git repo and --app-dir is not set, install in-place
|
|
|
|
|
- (service runs directly from this repo so auto-commit works on your real git repo).
|
|
|
|
|
- - If --app-dir is set, files are copied into that directory.
|
|
|
|
|
|
|
+- Uses current git repository directory as working directory (in-place mode)
|
|
|
|
|
+- Uses the user executing sudo as service user
|
|
|
|
|
|
|
|
Options:
|
|
Options:
|
|
|
- --app-dir <path> Install directory (default: /opt/vmess-domain-rotator)
|
|
|
|
|
- --user <name> Service user (default: vmessrotator)
|
|
|
|
|
- --group <name> Service group (default: vmessrotator)
|
|
|
|
|
- --interval <value> Timer interval, e.g. 1h/10min (default: 1h)
|
|
|
|
|
- --no-install-deps Skip apt dependency install
|
|
|
|
|
- --overwrite-config Overwrite existing config.json in app dir
|
|
|
|
|
- -h, --help Show help
|
|
|
|
|
|
|
+ --user <name> Service user (default: current sudo user)
|
|
|
|
|
+ --group <name> Service group (default: current sudo user's group)
|
|
|
|
|
+ --interval <value> Timer interval, e.g. 1h/10min (default: 1h)
|
|
|
|
|
+ --no-install-deps Skip apt dependency install
|
|
|
|
|
+ -h, --help Show help
|
|
|
|
|
|
|
|
Examples:
|
|
Examples:
|
|
|
- sudo bash scripts/install_debian.sh
|
|
|
|
|
- sudo bash scripts/install_debian.sh --app-dir /opt/vmess-domain-rotator
|
|
|
|
|
- sudo bash scripts/install_debian.sh --user root --group root --interval 10min
|
|
|
|
|
|
|
+ sudo bash scripts/install_debian.sh
|
|
|
|
|
+ sudo bash scripts/install_debian.sh --interval 10min
|
|
|
|
|
+ sudo bash scripts/install_debian.sh --user root --group root
|
|
|
EOF
|
|
EOF
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
while [[ $# -gt 0 ]]; do
|
|
|
- case "$1" in
|
|
|
|
|
- --app-dir)
|
|
|
|
|
- APP_DIR="$2"
|
|
|
|
|
- APP_DIR_SET="1"
|
|
|
|
|
- shift 2
|
|
|
|
|
- ;;
|
|
|
|
|
- --user)
|
|
|
|
|
- RUN_USER="$2"
|
|
|
|
|
- RUN_USER_SET="1"
|
|
|
|
|
- shift 2
|
|
|
|
|
- ;;
|
|
|
|
|
- --group)
|
|
|
|
|
- RUN_GROUP="$2"
|
|
|
|
|
- RUN_GROUP_SET="1"
|
|
|
|
|
- shift 2
|
|
|
|
|
- ;;
|
|
|
|
|
- --interval)
|
|
|
|
|
- INTERVAL="$2"
|
|
|
|
|
- shift 2
|
|
|
|
|
- ;;
|
|
|
|
|
- --no-install-deps)
|
|
|
|
|
- INSTALL_DEPS="0"
|
|
|
|
|
- shift
|
|
|
|
|
- ;;
|
|
|
|
|
- --overwrite-config)
|
|
|
|
|
- OVERWRITE_CONFIG="1"
|
|
|
|
|
- shift
|
|
|
|
|
- ;;
|
|
|
|
|
- -h|--help)
|
|
|
|
|
- usage
|
|
|
|
|
- exit 0
|
|
|
|
|
- ;;
|
|
|
|
|
- *)
|
|
|
|
|
- echo "Unknown option: $1" >&2
|
|
|
|
|
- usage
|
|
|
|
|
- exit 1
|
|
|
|
|
- ;;
|
|
|
|
|
- esac
|
|
|
|
|
|
|
+ case "$1" in
|
|
|
|
|
+ --user)
|
|
|
|
|
+ RUN_USER="$2"
|
|
|
|
|
+ RUN_USER_SET="1"
|
|
|
|
|
+ shift 2
|
|
|
|
|
+ ;;
|
|
|
|
|
+ --group)
|
|
|
|
|
+ RUN_GROUP="$2"
|
|
|
|
|
+ RUN_GROUP_SET="1"
|
|
|
|
|
+ shift 2
|
|
|
|
|
+ ;;
|
|
|
|
|
+ --interval)
|
|
|
|
|
+ INTERVAL="$2"
|
|
|
|
|
+ shift 2
|
|
|
|
|
+ ;;
|
|
|
|
|
+ --no-install-deps)
|
|
|
|
|
+ INSTALL_DEPS="0"
|
|
|
|
|
+ shift
|
|
|
|
|
+ ;;
|
|
|
|
|
+ -h|--help)
|
|
|
|
|
+ usage
|
|
|
|
|
+ exit 0
|
|
|
|
|
+ ;;
|
|
|
|
|
+ *)
|
|
|
|
|
+ echo "Unknown option: $1" >&2
|
|
|
|
|
+ usage
|
|
|
|
|
+ exit 1
|
|
|
|
|
+ ;;
|
|
|
|
|
+ esac
|
|
|
done
|
|
done
|
|
|
|
|
|
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
|
- echo "Please run as root (use sudo)." >&2
|
|
|
|
|
- exit 1
|
|
|
|
|
|
|
+ echo "Please run as root (use sudo)." >&2
|
|
|
|
|
+ exit 1
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
|
|
+# Get source directory (current git repo)
|
|
|
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
-DEPLOY_MODE="copy"
|
|
|
|
|
|
|
|
|
|
-if [[ "$APP_DIR_SET" != "1" ]] && git -C "$SOURCE_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
|
|
|
- APP_DIR="$SOURCE_DIR"
|
|
|
|
|
- DEPLOY_MODE="in-place"
|
|
|
|
|
|
|
+# Verify we're in a git repository
|
|
|
|
|
+if ! git -C "$SOURCE_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
|
|
|
+ echo "Error: Current directory is not a git repository." >&2
|
|
|
|
|
+ echo "This script must be run from within a git repository." >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
|
|
|
- if [[ -n "${SUDO_USER:-}" ]] && [[ "$RUN_USER_SET" != "1" ]]; then
|
|
|
|
|
- RUN_USER="$SUDO_USER"
|
|
|
|
|
- fi
|
|
|
|
|
|
|
+APP_DIR="$SOURCE_DIR"
|
|
|
|
|
|
|
|
- if [[ -n "${SUDO_USER:-}" ]] && [[ "$RUN_GROUP_SET" != "1" ]]; then
|
|
|
|
|
- RUN_GROUP="$(id -gn "$SUDO_USER")"
|
|
|
|
|
- fi
|
|
|
|
|
|
|
+# Set default user/group from SUDO_USER if available
|
|
|
|
|
+if [[ -n "${SUDO_USER:-}" ]] && [[ "$RUN_USER_SET" != "1" ]]; then
|
|
|
|
|
+ RUN_USER="$SUDO_USER"
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
-if [[ "$INSTALL_DEPS" == "1" ]]; then
|
|
|
|
|
- export DEBIAN_FRONTEND=noninteractive
|
|
|
|
|
- apt-get update -y
|
|
|
|
|
- apt-get install -y python3 ca-certificates git
|
|
|
|
|
|
|
+if [[ -n "${SUDO_USER:-}" ]] && [[ "$RUN_GROUP_SET" != "1" ]]; then
|
|
|
|
|
+ RUN_GROUP="$(id -gn "$SUDO_USER")"
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
-if [[ "$RUN_USER" != "root" ]]; then
|
|
|
|
|
- if ! getent group "$RUN_GROUP" >/dev/null 2>&1; then
|
|
|
|
|
- groupadd --system "$RUN_GROUP"
|
|
|
|
|
- fi
|
|
|
|
|
- if ! id -u "$RUN_USER" >/dev/null 2>&1; then
|
|
|
|
|
- useradd --system --home-dir "$APP_DIR" --create-home --shell /usr/sbin/nologin --gid "$RUN_GROUP" "$RUN_USER"
|
|
|
|
|
- fi
|
|
|
|
|
|
|
+# Validate that we have a user set
|
|
|
|
|
+if [[ -z "$RUN_USER" ]]; then
|
|
|
|
|
+ echo "Error: Could not determine service user. Please run with sudo or specify --user" >&2
|
|
|
|
|
+ exit 1
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
-mkdir -p "$APP_DIR"
|
|
|
|
|
-
|
|
|
|
|
-if [[ "$DEPLOY_MODE" == "copy" ]]; then
|
|
|
|
|
- CONFIG_BACKUP=""
|
|
|
|
|
- if [[ "$OVERWRITE_CONFIG" != "1" && -f "$APP_DIR/config.json" ]]; then
|
|
|
|
|
- CONFIG_BACKUP="$(mktemp)"
|
|
|
|
|
- cp "$APP_DIR/config.json" "$CONFIG_BACKUP"
|
|
|
|
|
- fi
|
|
|
|
|
-
|
|
|
|
|
- tar -C "$SOURCE_DIR" \
|
|
|
|
|
- --exclude='.git' \
|
|
|
|
|
- --exclude='.DS_Store' \
|
|
|
|
|
- --exclude='__pycache__' \
|
|
|
|
|
- -cf - . | tar -C "$APP_DIR" -xf -
|
|
|
|
|
-
|
|
|
|
|
- if [[ -n "$CONFIG_BACKUP" ]]; then
|
|
|
|
|
- cp "$CONFIG_BACKUP" "$APP_DIR/config.json"
|
|
|
|
|
- rm -f "$CONFIG_BACKUP"
|
|
|
|
|
- fi
|
|
|
|
|
|
|
+if [[ -z "$RUN_GROUP" ]]; then
|
|
|
|
|
+ echo "Error: Could not determine service group. Please run with sudo or specify --group" >&2
|
|
|
|
|
+ exit 1
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
-mkdir -p "$APP_DIR/runtime"
|
|
|
|
|
-chmod +x "$APP_DIR/scripts/run_update_and_commit.sh" "$APP_DIR/scripts/install_debian.sh" "$APP_DIR/scripts/uninstall_debian.sh" || true
|
|
|
|
|
-
|
|
|
|
|
-if [[ "$RUN_USER" != "root" ]]; then
|
|
|
|
|
- if [[ "$DEPLOY_MODE" == "in-place" ]]; then
|
|
|
|
|
- chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR/runtime"
|
|
|
|
|
- else
|
|
|
|
|
- chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR"
|
|
|
|
|
- fi
|
|
|
|
|
|
|
+if [[ "$INSTALL_DEPS" == "1" ]]; then
|
|
|
|
|
+ export DEBIAN_FRONTEND=noninteractive
|
|
|
|
|
+ apt-get update -y
|
|
|
|
|
+ apt-get install -y python3 ca-certificates git
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
-if [[ "$DEPLOY_MODE" == "copy" ]] && ! git -C "$APP_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
|
|
|
- git -C "$APP_DIR" init
|
|
|
|
|
-fi
|
|
|
|
|
|
|
+# Ensure runtime directory exists with correct permissions
|
|
|
|
|
+mkdir -p "$APP_DIR/runtime"
|
|
|
|
|
+chmod +x "$APP_DIR/scripts/run_update_and_commit.sh" || true
|
|
|
|
|
+chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR/runtime"
|
|
|
|
|
|
|
|
|
|
+# Generate systemd service unit
|
|
|
cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
|
|
cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
|
|
|
[Unit]
|
|
[Unit]
|
|
|
Description=VMess Domain Rotator updater
|
|
Description=VMess Domain Rotator updater
|
|
@@ -164,6 +126,7 @@ WorkingDirectory=${APP_DIR}
|
|
|
ExecStart=/bin/bash ${APP_DIR}/scripts/run_update_and_commit.sh ${APP_DIR}/config.json
|
|
ExecStart=/bin/bash ${APP_DIR}/scripts/run_update_and_commit.sh ${APP_DIR}/config.json
|
|
|
EOF
|
|
EOF
|
|
|
|
|
|
|
|
|
|
+# Generate systemd timer unit
|
|
|
cat >"/etc/systemd/system/${SERVICE_NAME}.timer" <<EOF
|
|
cat >"/etc/systemd/system/${SERVICE_NAME}.timer" <<EOF
|
|
|
[Unit]
|
|
[Unit]
|
|
|
Description=Run VMess Domain Rotator every ${INTERVAL}
|
|
Description=Run VMess Domain Rotator every ${INTERVAL}
|
|
@@ -179,14 +142,22 @@ Persistent=true
|
|
|
WantedBy=timers.target
|
|
WantedBy=timers.target
|
|
|
EOF
|
|
EOF
|
|
|
|
|
|
|
|
|
|
+# Enable and start service
|
|
|
systemctl daemon-reload
|
|
systemctl daemon-reload
|
|
|
systemctl enable --now "${SERVICE_NAME}.timer"
|
|
systemctl enable --now "${SERVICE_NAME}.timer"
|
|
|
systemctl start "${SERVICE_NAME}.service"
|
|
systemctl start "${SERVICE_NAME}.service"
|
|
|
|
|
|
|
|
-echo "Installed successfully."
|
|
|
|
|
-echo "Deploy mode: ${DEPLOY_MODE}"
|
|
|
|
|
-echo "App dir: ${APP_DIR}"
|
|
|
|
|
-echo "Service: ${SERVICE_NAME}.service"
|
|
|
|
|
-echo "Timer: ${SERVICE_NAME}.timer"
|
|
|
|
|
-echo "Check status: systemctl status ${SERVICE_NAME}.timer"
|
|
|
|
|
-echo "View logs: journalctl -u ${SERVICE_NAME}.service -n 50 --no-pager"
|
|
|
|
|
|
|
+echo ""
|
|
|
|
|
+echo "✓ Installation complete!"
|
|
|
|
|
+echo ""
|
|
|
|
|
+echo "Configuration:"
|
|
|
|
|
+echo " Working directory: ${APP_DIR}"
|
|
|
|
|
+echo " Service user: ${RUN_USER}"
|
|
|
|
|
+echo " Service group: ${RUN_GROUP}"
|
|
|
|
|
+echo " Timer interval: ${INTERVAL}"
|
|
|
|
|
+echo ""
|
|
|
|
|
+echo "Commands:"
|
|
|
|
|
+echo " Check status: systemctl status ${SERVICE_NAME}.timer"
|
|
|
|
|
+echo " View logs: journalctl -u ${SERVICE_NAME}.service -n 50 --no-pager"
|
|
|
|
|
+echo " Manual run: systemctl start ${SERVICE_NAME}.service"
|
|
|
|
|
+echo ""
|