install_debian.sh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. SERVICE_NAME="vmess-domain-rotator"
  4. APP_DIR="/opt/vmess-domain-rotator"
  5. RUN_USER="vmessrotator"
  6. RUN_GROUP="vmessrotator"
  7. APP_DIR_SET="0"
  8. RUN_USER_SET="0"
  9. RUN_GROUP_SET="0"
  10. INTERVAL="1h"
  11. INSTALL_DEPS="1"
  12. OVERWRITE_CONFIG="0"
  13. usage() {
  14. cat <<'EOF'
  15. Usage: sudo bash scripts/install_debian.sh [options]
  16. Default behavior:
  17. - If current source dir is a git repo and --app-dir is not set, install in-place
  18. (service runs directly from this repo so auto-commit works on your real git repo).
  19. - If --app-dir is set, files are copied into that directory.
  20. Options:
  21. --app-dir <path> Install directory (default: /opt/vmess-domain-rotator)
  22. --user <name> Service user (default: vmessrotator)
  23. --group <name> Service group (default: vmessrotator)
  24. --interval <value> Timer interval, e.g. 1h/10min (default: 1h)
  25. --no-install-deps Skip apt dependency install
  26. --overwrite-config Overwrite existing config.json in app dir
  27. -h, --help Show help
  28. Examples:
  29. sudo bash scripts/install_debian.sh
  30. sudo bash scripts/install_debian.sh --app-dir /opt/vmess-domain-rotator
  31. sudo bash scripts/install_debian.sh --user root --group root --interval 10min
  32. EOF
  33. }
  34. while [[ $# -gt 0 ]]; do
  35. case "$1" in
  36. --app-dir)
  37. APP_DIR="$2"
  38. APP_DIR_SET="1"
  39. shift 2
  40. ;;
  41. --user)
  42. RUN_USER="$2"
  43. RUN_USER_SET="1"
  44. shift 2
  45. ;;
  46. --group)
  47. RUN_GROUP="$2"
  48. RUN_GROUP_SET="1"
  49. shift 2
  50. ;;
  51. --interval)
  52. INTERVAL="$2"
  53. shift 2
  54. ;;
  55. --no-install-deps)
  56. INSTALL_DEPS="0"
  57. shift
  58. ;;
  59. --overwrite-config)
  60. OVERWRITE_CONFIG="1"
  61. shift
  62. ;;
  63. -h|--help)
  64. usage
  65. exit 0
  66. ;;
  67. *)
  68. echo "Unknown option: $1" >&2
  69. usage
  70. exit 1
  71. ;;
  72. esac
  73. done
  74. if [[ "$(id -u)" -ne 0 ]]; then
  75. echo "Please run as root (use sudo)." >&2
  76. exit 1
  77. fi
  78. SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
  79. DEPLOY_MODE="copy"
  80. if [[ "$APP_DIR_SET" != "1" ]] && git -C "$SOURCE_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  81. APP_DIR="$SOURCE_DIR"
  82. DEPLOY_MODE="in-place"
  83. if [[ -n "${SUDO_USER:-}" ]] && [[ "$RUN_USER_SET" != "1" ]]; then
  84. RUN_USER="$SUDO_USER"
  85. fi
  86. if [[ -n "${SUDO_USER:-}" ]] && [[ "$RUN_GROUP_SET" != "1" ]]; then
  87. RUN_GROUP="$(id -gn "$SUDO_USER")"
  88. fi
  89. fi
  90. if [[ "$INSTALL_DEPS" == "1" ]]; then
  91. export DEBIAN_FRONTEND=noninteractive
  92. apt-get update -y
  93. apt-get install -y python3 ca-certificates git
  94. fi
  95. if [[ "$RUN_USER" != "root" ]]; then
  96. if ! getent group "$RUN_GROUP" >/dev/null 2>&1; then
  97. groupadd --system "$RUN_GROUP"
  98. fi
  99. if ! id -u "$RUN_USER" >/dev/null 2>&1; then
  100. useradd --system --home-dir "$APP_DIR" --create-home --shell /usr/sbin/nologin --gid "$RUN_GROUP" "$RUN_USER"
  101. fi
  102. fi
  103. mkdir -p "$APP_DIR"
  104. if [[ "$DEPLOY_MODE" == "copy" ]]; then
  105. CONFIG_BACKUP=""
  106. if [[ "$OVERWRITE_CONFIG" != "1" && -f "$APP_DIR/config.json" ]]; then
  107. CONFIG_BACKUP="$(mktemp)"
  108. cp "$APP_DIR/config.json" "$CONFIG_BACKUP"
  109. fi
  110. tar -C "$SOURCE_DIR" \
  111. --exclude='.git' \
  112. --exclude='.DS_Store' \
  113. --exclude='__pycache__' \
  114. -cf - . | tar -C "$APP_DIR" -xf -
  115. if [[ -n "$CONFIG_BACKUP" ]]; then
  116. cp "$CONFIG_BACKUP" "$APP_DIR/config.json"
  117. rm -f "$CONFIG_BACKUP"
  118. fi
  119. fi
  120. mkdir -p "$APP_DIR/runtime"
  121. chmod +x "$APP_DIR/scripts/run_update_and_commit.sh" "$APP_DIR/scripts/install_debian.sh" "$APP_DIR/scripts/uninstall_debian.sh" || true
  122. if [[ "$RUN_USER" != "root" ]]; then
  123. if [[ "$DEPLOY_MODE" == "in-place" ]]; then
  124. chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR/runtime"
  125. else
  126. chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR"
  127. fi
  128. fi
  129. if [[ "$DEPLOY_MODE" == "copy" ]] && ! git -C "$APP_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  130. git -C "$APP_DIR" init
  131. fi
  132. cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
  133. [Unit]
  134. Description=VMess Domain Rotator updater
  135. After=network-online.target
  136. Wants=network-online.target
  137. [Service]
  138. Type=oneshot
  139. User=${RUN_USER}
  140. Group=${RUN_GROUP}
  141. WorkingDirectory=${APP_DIR}
  142. ExecStart=/bin/bash ${APP_DIR}/scripts/run_update_and_commit.sh ${APP_DIR}/config.json
  143. EOF
  144. cat >"/etc/systemd/system/${SERVICE_NAME}.timer" <<EOF
  145. [Unit]
  146. Description=Run VMess Domain Rotator every ${INTERVAL}
  147. [Timer]
  148. OnBootSec=2min
  149. OnUnitActiveSec=${INTERVAL}
  150. AccuracySec=30s
  151. Unit=${SERVICE_NAME}.service
  152. Persistent=true
  153. [Install]
  154. WantedBy=timers.target
  155. EOF
  156. systemctl daemon-reload
  157. systemctl enable --now "${SERVICE_NAME}.timer"
  158. systemctl start "${SERVICE_NAME}.service"
  159. echo "Installed successfully."
  160. echo "Deploy mode: ${DEPLOY_MODE}"
  161. echo "App dir: ${APP_DIR}"
  162. echo "Service: ${SERVICE_NAME}.service"
  163. echo "Timer: ${SERVICE_NAME}.timer"
  164. echo "Check status: systemctl status ${SERVICE_NAME}.timer"
  165. echo "View logs: journalctl -u ${SERVICE_NAME}.service -n 50 --no-pager"