install.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. #!/bin/bash
  2. author=233boy
  3. # github=https://github.com/233boy/sing-box
  4. # bash fonts colors
  5. red='\e[31m'
  6. yellow='\e[33m'
  7. gray='\e[90m'
  8. green='\e[92m'
  9. blue='\e[94m'
  10. magenta='\e[95m'
  11. cyan='\e[96m'
  12. none='\e[0m'
  13. _red() { echo -e ${red}$@${none}; }
  14. _blue() { echo -e ${blue}$@${none}; }
  15. _cyan() { echo -e ${cyan}$@${none}; }
  16. _green() { echo -e ${green}$@${none}; }
  17. _yellow() { echo -e ${yellow}$@${none}; }
  18. _magenta() { echo -e ${magenta}$@${none}; }
  19. _red_bg() { echo -e "\e[41m$@${none}"; }
  20. is_err=$(_red_bg 错误!)
  21. is_warn=$(_red_bg 警告!)
  22. err() {
  23. echo -e "\n$is_err $@\n" && exit 1
  24. }
  25. warn() {
  26. echo -e "\n$is_warn $@\n"
  27. }
  28. # root
  29. [[ $EUID != 0 ]] && err "当前非 ${yellow}ROOT用户.${none}"
  30. # yum or apt-get, ubuntu/debian/centos
  31. cmd=$(type -P apt-get || type -P yum)
  32. [[ ! $cmd ]] && err "此脚本仅支持 ${yellow}(Ubuntu or Debian or CentOS)${none}."
  33. # systemd
  34. [[ ! $(type -P systemctl) ]] && {
  35. err "此系统缺少 ${yellow}(systemctl)${none}, 请尝试执行:${yellow} ${cmd} update -y;${cmd} install systemd -y ${none}来修复此错误."
  36. }
  37. # wget installed or none
  38. is_wget=$(type -P wget)
  39. # x64
  40. case $(uname -m) in
  41. amd64 | x86_64)
  42. is_arch=amd64
  43. ;;
  44. *aarch64* | *armv8*)
  45. is_arch=arm64
  46. ;;
  47. *)
  48. err "此脚本仅支持 64 位系统..."
  49. ;;
  50. esac
  51. is_core=sing-box
  52. is_core_name=sing-box
  53. is_core_dir=/develop/$is_core
  54. is_core_bin=$is_core_dir/bin/$is_core
  55. is_core_repo=SagerNet/$is_core
  56. is_conf_dir=$is_core_dir/conf
  57. is_log_dir=/var/log/$is_core
  58. is_sh_bin=/usr/local/bin/$is_core
  59. is_sh_dir=$is_core_dir/sh
  60. is_sh_repo=$author/$is_core
  61. is_pkg="wget tar"
  62. is_config_json=$is_core_dir/config.json
  63. tmp_var_lists=(
  64. tmpcore
  65. tmpsh
  66. tmpjq
  67. is_core_ok
  68. is_sh_ok
  69. is_jq_ok
  70. is_pkg_ok
  71. )
  72. # tmp dir
  73. tmpdir=$(mktemp -u)
  74. [[ ! $tmpdir ]] && {
  75. tmpdir=/tmp/tmp-$RANDOM
  76. }
  77. # set up var
  78. for i in ${tmp_var_lists[*]}; do
  79. export $i=$tmpdir/$i
  80. done
  81. # load bash script.
  82. load() {
  83. . $is_sh_dir/src/$1
  84. }
  85. # wget add --no-check-certificate
  86. _wget() {
  87. [[ $proxy ]] && export https_proxy=$proxy
  88. wget --no-check-certificate $*
  89. }
  90. # print a mesage
  91. msg() {
  92. case $1 in
  93. warn)
  94. local color=$yellow
  95. ;;
  96. err)
  97. local color=$red
  98. ;;
  99. ok)
  100. local color=$green
  101. ;;
  102. esac
  103. echo -e "${color}$(date +'%T')${none}) ${2}"
  104. }
  105. # show help msg
  106. show_help() {
  107. echo -e "Usage: $0 [-f xxx | -l | -p xxx | -v xxx | -h]"
  108. echo -e " -f, --core-file <path> 自定义 $is_core_name 文件路径, e.g., -f /root/$is_core-linux-amd64.tar.gz"
  109. echo -e " -l, --local-install 本地获取安装脚本, 使用当前目录"
  110. echo -e " -p, --proxy <addr> 使用代理下载, e.g., -p http://127.0.0.1:2333"
  111. echo -e " -v, --core-version <ver> 自定义 $is_core_name 版本, e.g., -v v1.8.13"
  112. echo -e " -h, --help 显示此帮助界面\n"
  113. exit 0
  114. }
  115. # install dependent pkg
  116. install_pkg() {
  117. cmd_not_found=
  118. for i in $*; do
  119. [[ ! $(type -P $i) ]] && cmd_not_found="$cmd_not_found,$i"
  120. done
  121. if [[ $cmd_not_found ]]; then
  122. pkg=$(echo $cmd_not_found | sed 's/,/ /g')
  123. msg warn "安装依赖包 >${pkg}"
  124. $cmd install -y $pkg &>/dev/null
  125. if [[ $? != 0 ]]; then
  126. [[ $cmd =~ yum ]] && yum install epel-release -y &>/dev/null
  127. $cmd update -y &>/dev/null
  128. $cmd install -y $pkg &>/dev/null
  129. [[ $? == 0 ]] && >$is_pkg_ok
  130. else
  131. >$is_pkg_ok
  132. fi
  133. else
  134. >$is_pkg_ok
  135. fi
  136. }
  137. # download file
  138. download() {
  139. case $1 in
  140. core)
  141. [[ ! $is_core_ver ]] && is_core_ver=$(_wget -qO- "https://api.github.com/repos/${is_core_repo}/releases/latest?v=$RANDOM" | grep tag_name | grep -E -o 'v([0-9.]+)')
  142. [[ $is_core_ver ]] && link="https://download.030208.xyz/sing-box/sing-box-1.12.12-linux-amd64.tar.gz"
  143. name=$is_core_name
  144. tmpfile=$tmpcore
  145. is_ok=$is_core_ok
  146. ;;
  147. sh)
  148. link=https://download.030208.xyz/code.tar.gz
  149. name="$is_core_name 脚本"
  150. tmpfile=$tmpsh
  151. is_ok=$is_sh_ok
  152. ;;
  153. jq)
  154. link=https://download.030208.xyz/jq-linux-amd64
  155. name="jq"
  156. tmpfile=$tmpjq
  157. is_ok=$is_jq_ok
  158. ;;
  159. esac
  160. [[ $link ]] && {
  161. msg warn "下载 ${name} > ${link}"
  162. if _wget -t 3 -q -c $link -O $tmpfile; then
  163. mv -f $tmpfile $is_ok
  164. fi
  165. }
  166. }
  167. # get server ip
  168. get_ip() {
  169. [[ $ip || $is_no_auto_tls || $is_gen || $is_dont_get_ip ]] && return
  170. # 尝试通过 IPv4 获取
  171. ip=$(_wget -4 -qO- https://ifconfig.me/ip 2>/dev/null)
  172. # 如果 IPv4 获取失败,尝试通过 IPv6 获取
  173. [[ -z "$ip" ]] && ip=$(_wget -6 -qO- https://ifconfig.me/ip 2>/dev/null)
  174. # 验证获取到的 IP 地址格式是否合法(简单的 IPv4 校验)
  175. if [[ -z "$ip" || ! "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  176. err "获取服务器 IP 失败.."
  177. fi
  178. }
  179. # check background tasks status
  180. check_status() {
  181. # dependent pkg install fail
  182. [[ ! -f $is_pkg_ok ]] && {
  183. msg err "安装依赖包失败"
  184. msg err "请尝试手动安装依赖包: $cmd update -y; $cmd install -y $is_pkg"
  185. is_fail=1
  186. }
  187. # download file status
  188. if [[ $is_wget ]]; then
  189. [[ ! -f $is_core_ok ]] && {
  190. msg err "下载 ${is_core_name} 失败"
  191. is_fail=1
  192. }
  193. [[ ! -f $is_sh_ok ]] && {
  194. msg err "下载 ${is_core_name} 脚本失败"
  195. is_fail=1
  196. }
  197. [[ ! -f $is_jq_ok ]] && {
  198. msg err "下载 jq 失败"
  199. is_fail=1
  200. }
  201. else
  202. [[ ! $is_fail ]] && {
  203. is_wget=1
  204. [[ ! $is_core_file ]] && download core &
  205. [[ ! $local_install ]] && download sh &
  206. [[ $jq_not_found ]] && download jq &
  207. get_ip
  208. wait
  209. check_status
  210. }
  211. fi
  212. # found fail status, remove tmp dir and exit.
  213. [[ $is_fail ]] && {
  214. exit_and_del_tmpdir
  215. }
  216. }
  217. # parameters check
  218. pass_args() {
  219. while [[ $# -gt 0 ]]; do
  220. case $1 in
  221. -f | --core-file)
  222. [[ -z $2 ]] && {
  223. err "($1) 缺少必需参数, 正确使用示例: [$1 /root/$is_core-linux-amd64.tar.gz]"
  224. } || [[ ! -f $2 ]] && {
  225. err "($2) 不是一个常规的文件."
  226. }
  227. is_core_file=$2
  228. shift 2
  229. ;;
  230. -l | --local-install)
  231. [[ ! -f ${PWD}/src/core.sh || ! -f ${PWD}/$is_core.sh ]] && {
  232. err "当前目录 (${PWD}) 非完整的脚本目录."
  233. }
  234. local_install=1
  235. shift 1
  236. ;;
  237. -p | --proxy)
  238. [[ -z $2 ]] && {
  239. err "($1) 缺少必需参数, 正确使用示例: [$1 http://127.0.0.1:2333 or -p socks5://127.0.0.1:2333]"
  240. }
  241. proxy=$2
  242. shift 2
  243. ;;
  244. -v | --core-version)
  245. [[ -z $2 ]] && {
  246. err "($1) 缺少必需参数, 正确使用示例: [$1 v1.8.13]"
  247. }
  248. is_core_ver=v${2//v/}
  249. shift 2
  250. ;;
  251. -h | --help)
  252. show_help
  253. ;;
  254. *)
  255. echo -e "\n${is_err} ($@) 为未知参数...\n"
  256. show_help
  257. ;;
  258. esac
  259. done
  260. [[ $is_core_ver && $is_core_file ]] && {
  261. err "无法同时自定义 ${is_core_name} 版本和 ${is_core_name} 文件."
  262. }
  263. }
  264. # exit and remove tmpdir
  265. exit_and_del_tmpdir() {
  266. rm -rf $tmpdir
  267. [[ ! $1 ]] && {
  268. msg err "哦豁.."
  269. msg err "安装过程出现错误..."
  270. echo -e "反馈问题) https://github.com/${is_sh_repo}/issues"
  271. echo
  272. exit 1
  273. }
  274. exit
  275. }
  276. # main
  277. main() {
  278. # check old version
  279. [[ -f $is_sh_bin && -d $is_core_dir/bin && -d $is_sh_dir && -d $is_conf_dir ]] && {
  280. err "检测到脚本已安装, 如需重装请使用${green} ${is_core} reinstall ${none}命令."
  281. }
  282. # check parameters
  283. [[ $# -gt 0 ]] && pass_args $@
  284. # show welcome msg
  285. clear
  286. echo
  287. echo "........... $is_core_name script by $author .........."
  288. echo
  289. # start installing...
  290. msg warn "开始安装..."
  291. [[ $is_core_ver ]] && msg warn "${is_core_name} 版本: ${yellow}$is_core_ver${none}"
  292. [[ $proxy ]] && msg warn "使用代理: ${yellow}$proxy${none}"
  293. # create tmpdir
  294. mkdir -p $tmpdir
  295. # if is_core_file, copy file
  296. [[ $is_core_file ]] && {
  297. cp -f $is_core_file $is_core_ok
  298. msg warn "${yellow}${is_core_name} 文件使用 > $is_core_file${none}"
  299. }
  300. # local dir install sh script
  301. [[ $local_install ]] && {
  302. >$is_sh_ok
  303. msg warn "${yellow}本地获取安装脚本 > $PWD ${none}"
  304. }
  305. timedatectl set-ntp true &>/dev/null
  306. [[ $? != 0 ]] && {
  307. is_ntp_on=1
  308. }
  309. # install dependent pkg
  310. install_pkg $is_pkg &
  311. # jq
  312. if [[ $(type -P jq) ]]; then
  313. >$is_jq_ok
  314. else
  315. jq_not_found=1
  316. fi
  317. # if wget installed. download core, sh, jq, get ip
  318. [[ $is_wget ]] && {
  319. [[ ! $is_core_file ]] && download core &
  320. [[ ! $local_install ]] && download sh &
  321. [[ $jq_not_found ]] && download jq &
  322. get_ip
  323. }
  324. # waiting for background tasks is done
  325. wait
  326. # check background tasks status
  327. check_status
  328. # test $is_core_file
  329. if [[ $is_core_file ]]; then
  330. mkdir -p $tmpdir/testzip
  331. tar zxf $is_core_ok --strip-components 1 -C $tmpdir/testzip &>/dev/null
  332. [[ $? != 0 ]] && {
  333. msg err "${is_core_name} 文件无法通过测试."
  334. exit_and_del_tmpdir
  335. }
  336. [[ ! -f $tmpdir/testzip/$is_core ]] && {
  337. msg err "${is_core_name} 文件无法通过测试."
  338. exit_and_del_tmpdir
  339. }
  340. fi
  341. # get server ip.
  342. [[ ! $ip ]] && {
  343. msg err "获取服务器 IP 失败."
  344. exit_and_del_tmpdir
  345. }
  346. # create sh dir...
  347. mkdir -p $is_sh_dir
  348. # copy sh file or unzip sh zip file.
  349. if [[ $local_install ]]; then
  350. cp -rf $PWD/* $is_sh_dir
  351. else
  352. tar zxf $is_sh_ok -C $is_sh_dir
  353. fi
  354. # create core bin dir
  355. mkdir -p $is_core_dir/bin
  356. # copy core file or unzip core zip file
  357. if [[ $is_core_file ]]; then
  358. cp -rf $tmpdir/testzip/* $is_core_dir/bin
  359. else
  360. tar zxf $is_core_ok --strip-components 1 -C $is_core_dir/bin
  361. fi
  362. # add alias
  363. echo "alias sb=$is_sh_bin" >>/root/.bashrc
  364. echo "alias $is_core=$is_sh_bin" >>/root/.bashrc
  365. # core command
  366. ln -sf $is_sh_dir/$is_core.sh $is_sh_bin
  367. ln -sf $is_sh_dir/$is_core.sh ${is_sh_bin/$is_core/sb}
  368. # jq
  369. [[ $jq_not_found ]] && mv -f $is_jq_ok /usr/bin/jq
  370. # chmod
  371. chmod +x $is_core_bin $is_sh_bin /usr/bin/jq ${is_sh_bin/$is_core/sb}
  372. # create log dir
  373. mkdir -p $is_log_dir
  374. # show a tips msg
  375. msg ok "生成配置文件..."
  376. # create systemd service
  377. load systemd.sh
  378. is_new_install=1
  379. install_service $is_core &>/dev/null
  380. # create condf dir
  381. mkdir -p $is_conf_dir
  382. load core.sh
  383. # create a reality config
  384. add reality
  385. # remove tmp dir and exit.
  386. exit_and_del_tmpdir ok
  387. }
  388. # start.
  389. main $@