DockerProxy_Install.sh 125 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666
  1. #!/usr/bin/env bash
  2. #===============================================================================
  3. #
  4. # FILE: DockerProxy_Install.sh
  5. #
  6. # USAGE: ./DockerProxy_Install.sh
  7. #
  8. # DESCRIPTION: 自建Docker镜像加速服务,基于官方 registry 一键部署Docker、K8s、Quay、Ghcr、Nvcr镜像加速\管理服务.支持免服务器部署到Render.
  9. #
  10. # ORGANIZATION: DingQz dqzboy.com 浅时光博客
  11. #===============================================================================
  12. echo
  13. cat << EOF
  14. ██████╗ ██████╗ ██████╗██╗ ██╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗██╗ ██╗
  15. ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗ ██╔══██╗██╔══██╗██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝
  16. ██║ ██║██║ ██║██║ █████╔╝ █████╗ ██████╔╝ ██████╔╝██████╔╝██║ ██║ ╚███╔╝ ╚████╔╝
  17. ██║ ██║██║ ██║██║ ██╔═██╗ ██╔══╝ ██╔══██╗ ██╔═══╝ ██╔══██╗██║ ██║ ██╔██╗ ╚██╔╝
  18. ██████╔╝╚██████╔╝╚██████╗██║ ██╗███████╗██║ ██║ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗ ██║
  19. ╚═════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
  20. 博客: dqzboy.com 浅时光博客
  21. 项目地址: https://github.com/dqzboy/Docker-Proxy
  22. EOF
  23. echo "----------------------------------------------------------------------------------------------------------"
  24. echo -e "\033[32mVPS 推荐\033[0m(\033[34mRackNerd 高性价比便宜VPS\033[0m):\033[34;4m https://dqzboy.github.io/proxyui/racknerd \033[0m"
  25. echo "----------------------------------------------------------------------------------------------------------"
  26. echo
  27. echo
  28. GREEN="\033[0;32m"
  29. RED="\033[31m"
  30. YELLOW="\033[33m"
  31. RESET="\033[0m"
  32. BLUE="\033[0;34m"
  33. MAGENTA="\033[0;35m"
  34. CYAN="\033[0;36m"
  35. WHITE="\033[1;37m"
  36. BLACK="\033[0;30m"
  37. PINK="\033[0;95m"
  38. LIGHT_GREEN="\033[1;32m"
  39. LIGHT_RED="\033[1;31m"
  40. LIGHT_YELLOW="\033[1;33m"
  41. LIGHT_BLUE="\033[1;34m"
  42. LIGHT_MAGENTA="\033[1;35m"
  43. LIGHT_CYAN="\033[1;36m"
  44. LIGHT_PINK="\033[1;95m"
  45. BRIGHT_CYAN="\033[96m"
  46. BOLD="\033[1m"
  47. UNDERLINE="\033[4m"
  48. BLINK="\033[5m"
  49. REVERSE="\033[7m"
  50. INFO="[${GREEN}INFO${RESET}]"
  51. ERROR="[${RED}ERROR${RESET}]"
  52. WARN="[${YELLOW}WARN${RESET}]"
  53. function INFO() {
  54. echo -e "${INFO} ${1}"
  55. }
  56. function ERROR() {
  57. echo -e "${ERROR} ${1}"
  58. }
  59. function WARN() {
  60. echo -e "${WARN} ${1}"
  61. }
  62. function PROMPT_Y_N() {
  63. echo -e "[${LIGHT_GREEN}y${RESET}/${LIGHT_BLUE}n${RESET}]: "
  64. }
  65. PROMPT_YES_NO=$(PROMPT_Y_N)
  66. function SEPARATOR() {
  67. echo -e "${INFO}${BOLD}${LIGHT_BLUE}======================== ${1} ========================${RESET}"
  68. }
  69. SPINNER_CHARS=('⣾' '⣽' '⣻' '⢿' '⡿' '⣟' '⣯' '⣷')
  70. SPINNER_DELAY=0.1
  71. function cleanup() {
  72. trap - SIGINT SIGTERM
  73. stop_spinner
  74. echo
  75. exit 1
  76. }
  77. function start_spinner() {
  78. local msg="$1"
  79. local temp_dir="/tmp/spinner"
  80. local pid_file="${temp_dir}/pid"
  81. local msg_file="${temp_dir}/message"
  82. mkdir -p "$temp_dir"
  83. echo "$msg" > "$msg_file"
  84. trap cleanup SIGINT SIGTERM
  85. (
  86. trap 'exit 0' TERM
  87. local i=0
  88. while true; do
  89. if [ -f "$msg_file" ]; then
  90. msg=$(cat "$msg_file")
  91. printf "\r${LIGHT_BLUE}%s${RESET} ${LIGHT_YELLOW}%s${RESET} " "${SPINNER_CHARS[i]}" "$msg"
  92. i=$(( (i + 1) % ${#SPINNER_CHARS[@]} ))
  93. sleep $SPINNER_DELAY
  94. else
  95. exit 0
  96. fi
  97. done
  98. ) & disown
  99. echo $! > "$pid_file"
  100. }
  101. function stop_spinner() {
  102. local temp_dir="/tmp/spinner"
  103. local pid_file="${temp_dir}/pid"
  104. local msg_file="${temp_dir}/message"
  105. if [ -f "$pid_file" ]; then
  106. local spinner_pid=$(cat "$pid_file")
  107. rm -f "$msg_file"
  108. rm -f "$pid_file"
  109. kill -TERM "$spinner_pid" 2>/dev/null
  110. wait "$spinner_pid" 2>/dev/null
  111. printf "\r%-60s\r" " "
  112. echo -ne "\033[0m"
  113. fi
  114. rm -rf "$temp_dir" 2>/dev/null
  115. trap - SIGINT SIGTERM
  116. }
  117. # 检查是否以root权限运行
  118. if [[ $EUID -ne 0 ]]; then
  119. ERROR "此脚本必须以root权限运行!"
  120. exit 1
  121. fi
  122. PROXY_DIR="/data/registry-proxy"
  123. mkdir -p ${PROXY_DIR}
  124. cd "${PROXY_DIR}"
  125. GITRAW="https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main"
  126. CNGITRAW="https://gitee.com/boydqz/Docker-Proxy/raw/main"
  127. # docker registry
  128. IMAGE_NAME="dqzboy/registry"
  129. UI_IMAGE_NAME="dqzboy/docker-registry-ui"
  130. DOCKER_COMPOSE_FILE="docker-compose.yaml"
  131. # HubCMD-UI
  132. CMDUI_IMAGE_NAME="dqzboy/hubcmd-ui"
  133. CMDUI_COMPOSE_FILE="${GITRAW}/hubcmdui/${DOCKER_COMPOSE_FILE}"
  134. # Registry Domain prefix
  135. REGISTRY_SLD="ui、hub、gcr、ghcr、k8sgcr、k8s、quay、mcr、elastic、nvcr"
  136. RECORDS=("ui" "hub" "gcr" "ghcr" "k8sgcr" "k8s" "quay" "mcr" "elastic" "nvcr")
  137. attempts=0
  138. maxAttempts=3
  139. # registry services
  140. function REGISTRY_MENU() {
  141. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  142. echo -e "${GREEN}1)${RESET} ${BOLD}docker hub${RESET}"
  143. echo -e "${GREEN}2)${RESET} ${BOLD}gcr${RESET}"
  144. echo -e "${GREEN}3)${RESET} ${BOLD}ghcr${RESET}"
  145. echo -e "${GREEN}4)${RESET} ${BOLD}quay${RESET}"
  146. echo -e "${GREEN}5)${RESET} ${BOLD}k8s-gcr${RESET}"
  147. echo -e "${GREEN}6)${RESET} ${BOLD}k8s${RESET}"
  148. echo -e "${GREEN}7)${RESET} ${BOLD}mcr${RESET}"
  149. echo -e "${GREEN}8)${RESET} ${BOLD}elastic${RESET}"
  150. echo -e "${GREEN}9)${RESET} ${BOLD}nvcr${RESET}"
  151. echo -e "${GREEN}10)${RESET} ${BOLD}all${RESET}"
  152. echo -e "${GREEN}0)${RESET} ${BOLD}exit${RESET}"
  153. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  154. }
  155. function REGISTRY_SER_MENU() {
  156. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  157. echo -e "${GREEN}1)${RESET} ${BOLD}docker hub${RESET}"
  158. echo -e "${GREEN}2)${RESET} ${BOLD}gcr${RESET}"
  159. echo -e "${GREEN}3)${RESET} ${BOLD}ghcr${RESET}"
  160. echo -e "${GREEN}4)${RESET} ${BOLD}quay${RESET}"
  161. echo -e "${GREEN}5)${RESET} ${BOLD}k8s-gcr${RESET}"
  162. echo -e "${GREEN}6)${RESET} ${BOLD}k8s${RESET}"
  163. echo -e "${GREEN}7)${RESET} ${BOLD}mcr${RESET}"
  164. echo -e "${GREEN}8)${RESET} ${BOLD}elastic${RESET}"
  165. echo -e "${GREEN}9)${RESET} ${BOLD}nvcr${RESET}"
  166. echo -e "${GREEN}0)${RESET} ${BOLD}exit${RESET}"
  167. echo -e "${YELLOW}-------------------------------------------------${RESET}"
  168. }
  169. # 定义Docker容器服务名称
  170. CONTAINER_SERVICES() {
  171. services=(
  172. "dockerhub"
  173. "gcr"
  174. "ghcr"
  175. "quay"
  176. "k8sgcr"
  177. "k8s"
  178. "mcr"
  179. "elastic"
  180. "nvcr"
  181. )
  182. }
  183. REGISTRY_FILES() {
  184. files=(
  185. "dockerhub registry-hub.yml"
  186. "gcr registry-gcr.yml"
  187. "ghcr registry-ghcr.yml"
  188. "quay registry-quay.yml"
  189. "k8sgcr registry-k8sgcr.yml"
  190. "k8s registry-k8s.yml"
  191. "mcr registry-mcr.yml"
  192. "elastic registry-elastic.yml"
  193. "nvcr registry-nvcr.yml"
  194. )
  195. }
  196. function CHECK_OS() {
  197. SEPARATOR "检查环境"
  198. OSVER=$(cat /etc/os-release | grep -o '[0-9]' | head -n 1)
  199. if [ -f /etc/os-release ]; then
  200. . /etc/os-release
  201. else
  202. echo "无法确定发行版"
  203. exit 1
  204. fi
  205. case "$ID" in
  206. "centos")
  207. repo_type="centos"
  208. ;;
  209. "debian")
  210. repo_type="debian"
  211. ;;
  212. "rhel")
  213. repo_type="rhel"
  214. ;;
  215. "ubuntu")
  216. repo_type="ubuntu"
  217. ;;
  218. "opencloudos")
  219. repo_type="centos"
  220. ;;
  221. "rocky")
  222. repo_type="centos"
  223. ;;
  224. *)
  225. WARN "此脚本目前不支持您的系统: $ID"
  226. exit 1
  227. ;;
  228. esac
  229. INFO "System release:: $NAME"
  230. INFO "System version: $VERSION"
  231. INFO "System ID: $ID"
  232. INFO "System ID Like: $ID_LIKE"
  233. }
  234. function CHECK_PACKAGE_MANAGER() {
  235. if command -v dnf &> /dev/null; then
  236. package_manager="dnf"
  237. elif command -v yum &> /dev/null; then
  238. package_manager="yum"
  239. elif command -v apt-get &> /dev/null; then
  240. package_manager="apt-get"
  241. elif command -v apt &> /dev/null; then
  242. package_manager="apt"
  243. else
  244. ERROR "不受支持的软件包管理器."
  245. exit 1
  246. fi
  247. }
  248. function CHECK_PKG_MANAGER() {
  249. if command -v rpm &> /dev/null; then
  250. pkg_manager="rpm"
  251. elif command -v dpkg &> /dev/null; then
  252. pkg_manager="dpkg"
  253. elif command -v apt &> /dev/null; then
  254. pkg_manager="apt"
  255. else
  256. ERROR "无法确定包管理系统."
  257. exit 1
  258. fi
  259. }
  260. function CHECK_COMPOSE_CMD() {
  261. if command -v docker &> /dev/null && docker compose version &> /dev/null; then
  262. DOCKER_COMPOSE_CMD="docker compose"
  263. elif command -v docker-compose &> /dev/null; then
  264. DOCKER_COMPOSE_CMD="docker-compose"
  265. else
  266. WARN "未检查到Docker Compose客户端工具,请通过脚本安装部署!"
  267. fi
  268. }
  269. function CHECKMEM() {
  270. memory_usage=$(free | awk '/^Mem:/ {printf "%.2f", $3/$2 * 100}')
  271. memory_usage=${memory_usage%.*}
  272. if [[ $memory_usage -gt 90 ]]; then
  273. read -e -p "$(WARN "内存占用率${LIGHT_RED}高于 70%($memory_usage%)${RESET} 是否继续安装? ${PROMPT_YES_NO}")" continu
  274. if [ "$continu" == "n" ] || [ "$continu" == "N" ]; then
  275. exit 1
  276. fi
  277. else
  278. INFO "内存资源充足.请继续 ${LIGHT_GREEN}($memory_usage%)${RESET}"
  279. fi
  280. }
  281. function CHECKFIRE() {
  282. systemctl stop firewalld &> /dev/null
  283. systemctl disable firewalld &> /dev/null
  284. systemctl stop iptables &> /dev/null
  285. systemctl disable iptables &> /dev/null
  286. ufw disable &> /dev/null
  287. systemctl disable ufw &> /dev/null
  288. WARN "服务器防火墙已被禁用."
  289. if [[ "$repo_type" == "centos" || "$repo_type" == "rhel" ]]; then
  290. if sestatus | grep "SELinux status" | grep -q "enabled"; then
  291. INFO "SELinux 已启用。禁用 SELinux..."
  292. setenforce 0
  293. sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
  294. WARN "SELinux 已被禁用."
  295. else
  296. WARN "SELinux 已被禁用."
  297. fi
  298. fi
  299. }
  300. function CHECKBBR() {
  301. kernel_version=$(uname -r | awk -F "-" '{print $1}')
  302. read -e -p "$(WARN "是否开启${BRIGHT_CYAN}BBR${RESET},优化网络带宽提高网络性能? ${PROMPT_YES_NO}")" choice_bbr
  303. case $choice_bbr in
  304. y | Y)
  305. version_compare=$(echo "${kernel_version} 4.9" | awk '{if ($1 >= $2) print "yes"; else print "no"}')
  306. if [ "$version_compare" != "yes" ]; then
  307. WARN "你的内核版本小于4.9,无法启动BBR,需要你手动升级内核"
  308. exit 0
  309. fi
  310. sysctl net.ipv4.tcp_available_congestion_control | grep -q "bbr"
  311. if [ $? -eq 0 ]; then
  312. INFO "你的服务器已经启动 ${BRIGHT_CYAN}BBR${RESET}"
  313. else
  314. INFO "开启BBR中..."
  315. modprobe tcp_bbr
  316. if [ $? -eq 0 ]; then
  317. INFO "${BRIGHT_CYAN}BBR${RESET} 模块${LIGHT_GREEN}添加成功${RESET}"
  318. else
  319. ERROR "${BRIGHT_CYAN}BBR${RESET} 模块${LIGHT_RED}添加失败${RESET},请执行 ${LIGHT_CYAN}sysctl -p${RESET} 检查."
  320. exit 1
  321. fi
  322. if [ ! -d /etc/modules-load.d/ ]; then
  323. mkdir -p /etc/modules-load.d/
  324. fi
  325. if [ ! -f /etc/modules-load.d/tcp_bbr.conf ]; then
  326. touch /etc/modules-load.d/tcp_bbr.conf
  327. fi
  328. if ! grep -q "tcp_bbr" /etc/modules-load.d/tcp_bbr.conf ; then
  329. echo 'tcp_bbr' >> /etc/modules-load.d/tcp_bbr.conf
  330. fi
  331. for setting in "net.core.default_qdisc=fq" "net.ipv4.tcp_congestion_control=bbr"; do
  332. if ! grep -q "$setting" /etc/sysctl.conf; then
  333. echo "$setting" >> /etc/sysctl.conf
  334. fi
  335. done
  336. sysctl -p &> /dev/null
  337. if [ $? -ne 0 ]; then
  338. ERROR "应用sysctl设置过程中发生了一个错误,请执行 ${LIGHT_CYAN}sysctl -p${RESET} 检查."
  339. exit 2
  340. fi
  341. lsmod | grep tcp_bbr &> /dev/null
  342. if [ $? -eq 0 ]; then
  343. INFO "${BRIGHT_CYAN}BBR${RESET} 已经${LIGHT_GREEN}成功开启${RESET}"
  344. else
  345. ERROR "${BRIGHT_CYAN}BBR${RESET} 开启${LIGHT_RED}失败${RESET},请执行 ${LIGHT_CYAN}sysctl -p${RESET} 检查."
  346. exit 3
  347. fi
  348. WARN "如果 ${BRIGHT_CYAN}BBR${RESET} 开启后${LIGHT_YELLOW}未生效${RESET},请执行 ${LIGHT_BLUE}reboot${RESET} 重启服务器使其BBR模块生效"
  349. fi
  350. ;;
  351. n | N)
  352. INFO "不开启BBR"
  353. ;;
  354. *)
  355. WARN "输入了无效的选择。请重新输入${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  356. CHECKBBR
  357. ;;
  358. esac
  359. }
  360. function INSTALL_PACKAGE(){
  361. SEPARATOR "安装依赖"
  362. INFO "检查依赖安装情况,请稍等 ..."
  363. TIMEOUT=300
  364. PACKAGES_APT=(
  365. lsof jq wget apache2-utils tar
  366. )
  367. PACKAGES_YUM=(
  368. epel-release lsof jq wget yum-utils httpd-tools tar
  369. )
  370. if [ "$package_manager" = "dnf" ] || [ "$package_manager" = "yum" ]; then
  371. for package in "${PACKAGES_YUM[@]}"; do
  372. if $pkg_manager -q "$package" &>/dev/null; then
  373. INFO "${LIGHT_GREEN}已经安装${RESET} $package ..."
  374. else
  375. INFO "${LIGHT_CYAN}正在安装${RESET} $package ..."
  376. start_spinner "安装 $package 中..."
  377. start_time=$(date +%s)
  378. $package_manager -y install "$package" --skip-broken > /dev/null 2>&1
  379. install_status=$?
  380. stop_spinner
  381. if [ $install_status -ne 0 ]; then
  382. ERROR "$package 安装失败。请检查系统安装源,然后再次运行此脚本!请尝试手动执行安装: ${LIGHT_BLUE}$package_manager -y install $package${RESET}"
  383. exit 1
  384. fi
  385. fi
  386. done
  387. elif [ "$package_manager" = "apt-get" ] || [ "$package_manager" = "apt" ];then
  388. dpkg --configure -a &>/dev/null
  389. $package_manager update &>/dev/null
  390. for package in "${PACKAGES_APT[@]}"; do
  391. if $pkg_manager -s "$package" &>/dev/null; then
  392. INFO "已经安装 $package ..."
  393. else
  394. INFO "正在安装 $package ..."
  395. start_spinner "安装 $package 中..."
  396. $package_manager install -y $package > /dev/null 2>&1
  397. install_status=$?
  398. stop_spinner
  399. if [ $install_status -ne 0 ]; then
  400. ERROR "安装 $package 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装: ${LIGHT_BLUE}$package_manager -y install $package${RESET}"
  401. exit 1
  402. fi
  403. fi
  404. done
  405. else
  406. ERROR "无法确定包管理系统,脚本无法继续执行,请检查!"
  407. exit 1
  408. fi
  409. }
  410. function INSTALL_CADDY() {
  411. SEPARATOR "安装Caddy"
  412. start_caddy() {
  413. systemctl enable caddy.service &>/dev/null
  414. systemctl restart caddy.service
  415. status=$(systemctl is-active caddy)
  416. if [ "$status" = "active" ]; then
  417. INFO "Caddy 服务运行正常,请继续..."
  418. else
  419. ERROR "Caddy 服务未运行,请查看日志报错,定位问题后再次执行脚本!"
  420. ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------"
  421. journalctl -u caddy.service --no-pager
  422. ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------"
  423. exit 1
  424. fi
  425. }
  426. check_caddy() {
  427. if pgrep "caddy" > /dev/null; then
  428. INFO "Caddy 已在运行."
  429. else
  430. WARN "Caddy 未运行。尝试启动 Caddy..."
  431. start_attempts=3
  432. for ((i=1; i<=$start_attempts; i++)); do
  433. start_caddy
  434. if pgrep "caddy" > /dev/null; then
  435. INFO "Caddy 已成功启动."
  436. break
  437. else
  438. if [ $i -eq $start_attempts ]; then
  439. ERROR "Caddy 在尝试 $start_attempts 后无法启动。请检查配置"
  440. exit 1
  441. else
  442. WARN "在 $i 时间内启动 Caddy 失败。重试..."
  443. fi
  444. fi
  445. done
  446. fi
  447. }
  448. if [ "$package_manager" = "dnf" ]; then
  449. if which caddy &>/dev/null; then
  450. INFO "Caddy 已经安装."
  451. else
  452. INFO "正在安装Caddy程序,请稍候..."
  453. start_spinner "安装Caddy中..."
  454. $package_manager -y install 'dnf-command(copr)' &>/dev/null
  455. $package_manager -y copr enable @caddy/caddy &>/dev/null
  456. stop_spinner
  457. while [ $attempts -lt $maxAttempts ]; do
  458. start_spinner "安装Caddy服务..."
  459. $package_manager -y install caddy &>/dev/null
  460. stop_spinner
  461. if [ $? -ne 0 ]; then
  462. ((attempts++))
  463. WARN "正在尝试安装Caddy >>> (Attempt: $attempts)"
  464. if [ $attempts -eq $maxAttempts ]; then
  465. ERROR "Caddy installation failed. Please try installing manually."
  466. echo "命令: $package_manager -y install 'dnf-command(copr)' && $package_manager -y copr enable @caddy/caddy && $package_manager -y install caddy"
  467. exit 1
  468. fi
  469. else
  470. INFO "已安装 Caddy"
  471. break
  472. fi
  473. done
  474. fi
  475. check_caddy
  476. elif [ "$package_manager" = "yum" ]; then
  477. if which caddy &>/dev/null; then
  478. INFO "Caddy 已经安装."
  479. else
  480. INFO "正在安装Caddy程序,请稍候..."
  481. $package_manager -y install yum-plugin-copr &>/dev/null
  482. $package_manager -y copr enable @caddy/caddy &>/dev/null
  483. while [ $attempts -lt $maxAttempts ]; do
  484. $package_manager -y install caddy &>/dev/null
  485. if [ $? -ne 0 ]; then
  486. ((attempts++))
  487. WARN "正在尝试安装Caddy >>> (Attempt: $attempts)"
  488. if [ $attempts -eq $maxAttempts ]; then
  489. ERROR "Caddy installation failed. Please try installing manually."
  490. echo "命令: $package_manager -y install 'dnf-command(copr)' && $package_manager -y copr enable @caddy/caddy && $package_manager -y install caddy"
  491. exit 1
  492. fi
  493. else
  494. INFO "已安装 Caddy."
  495. break
  496. fi
  497. done
  498. fi
  499. check_caddy
  500. elif [ "$package_manager" = "apt" ] || [ "$package_manager" = "apt-get" ];then
  501. dpkg --configure -a &>/dev/null
  502. $package_manager update &>/dev/null
  503. if $pkg_manager -s "caddy" &>/dev/null; then
  504. INFO "Caddy 已安装,跳过..."
  505. else
  506. INFO "安装 Caddy 请稍等 ..."
  507. $package_manager install -y debian-keyring debian-archive-keyring apt-transport-https &>/dev/null
  508. curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg &>/dev/null
  509. curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list &>/dev/null
  510. $package_manager update &>/dev/null
  511. $package_manager install -y caddy &>/dev/null
  512. if [ $? -ne 0 ]; then
  513. ERROR "安装 Caddy 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装:$package_manager -y install caddy"
  514. exit 1
  515. fi
  516. fi
  517. check_caddy
  518. else
  519. WARN "无法确定包管理系统."
  520. exit 1
  521. fi
  522. }
  523. function CONFIG_CADDY() {
  524. SEPARATOR "配置Caddy"
  525. while true; do
  526. INFO "${LIGHT_GREEN}>>> 域名解析主机记录(即域名前缀):${RESET} ${LIGHT_CYAN}${REGISTRY_SLD}${RESET}"
  527. WARN "${LIGHT_GREEN}>>> 只需选择你部署的服务进行解析即可${RESET},${LIGHT_YELLOW}无需将上面提示中所有的主机记录进行解析${RESET}"
  528. read -e -p "$(WARN "是否配置Caddy,实现自动HTTPS? 执行前需在DNS服务商对部署服务解析主机记录 ${PROMPT_YES_NO}")" caddy_conf
  529. case "$caddy_conf" in
  530. y|Y )
  531. read -e -p "$(INFO "请输入你的域名${LIGHT_BLUE}[例: baidu.com]${RESET} ${LIGHT_RED}不可为空${RESET}: ")" caddy_domain
  532. read -e -p "$(INFO "请输入要配置的${LIGHT_MAGENTA}主机记录${RESET},用逗号分隔${LIGHT_BLUE}[例: ui,hub]${RESET}: ")" selected_records
  533. # 验证输入的主机记录
  534. local valid_records=("${RECORDS[@]}")
  535. IFS=',' read -r -a records_array <<< "$selected_records"
  536. local invalid_records=()
  537. for record in "${records_array[@]}"; do
  538. if ! [[ " ${valid_records[@]} " =~ " ${record} " ]]; then
  539. invalid_records+=("$record")
  540. fi
  541. done
  542. if [[ ${#invalid_records[@]} -gt 0 ]]; then
  543. ERROR "无效的主机记录: ${LIGHT_RED}${invalid_records[@]}${RESET}"
  544. INFO "请输入有效的主机记录: ${LIGHT_GREEN}${REGISTRY_SLD}${RESET}"
  545. continue
  546. fi
  547. declare -A record_templates
  548. record_templates[ui]="ui.$caddy_domain {
  549. reverse_proxy localhost:50000 {
  550. header_up Host {host}
  551. header_up Origin {scheme}://{host}
  552. header_up X-Forwarded-For {remote_addr}
  553. header_up X-Forwarded-Proto {scheme}
  554. header_up X-Forwarded-Ssl on
  555. header_up X-Forwarded-Port {server_port}
  556. header_up X-Forwarded-Host {host}
  557. }
  558. }"
  559. record_templates[hub]="hub.$caddy_domain {
  560. reverse_proxy localhost:51000 {
  561. header_up Host {host}
  562. header_up X-Real-IP {remote_addr}
  563. header_up X-Forwarded-For {remote_addr}
  564. header_up X-Nginx-Proxy true
  565. }
  566. }"
  567. record_templates[ghcr]="ghcr.$caddy_domain {
  568. reverse_proxy localhost:52000 {
  569. header_up Host {host}
  570. header_up X-Real-IP {remote_addr}
  571. header_up X-Forwarded-For {remote_addr}
  572. header_up X-Nginx-Proxy true
  573. }
  574. }"
  575. record_templates[gcr]="gcr.$caddy_domain {
  576. reverse_proxy localhost:53000 {
  577. header_up Host {host}
  578. header_up X-Real-IP {remote_addr}
  579. header_up X-Forwarded-For {remote_addr}
  580. header_up X-Nginx-Proxy true
  581. }
  582. }"
  583. record_templates[k8sgcr]="k8sgcr.$caddy_domain {
  584. reverse_proxy localhost:54000 {
  585. header_up Host {host}
  586. header_up X-Real-IP {remote_addr}
  587. header_up X-Forwarded-For {remote_addr}
  588. header_up X-Nginx-Proxy true
  589. }
  590. }"
  591. record_templates[k8s]="k8s.$caddy_domain {
  592. reverse_proxy localhost:55000 {
  593. header_up Host {host}
  594. header_up X-Real-IP {remote_addr}
  595. header_up X-Forwarded-For {remote_addr}
  596. header_up X-Nginx-Proxy true
  597. }
  598. }"
  599. record_templates[quay]="quay.$caddy_domain {
  600. reverse_proxy localhost:56000 {
  601. header_up Host {host}
  602. header_up X-Real-IP {remote_addr}
  603. header_up X-Forwarded-For {remote_addr}
  604. header_up X-Nginx-Proxy true
  605. }
  606. }"
  607. record_templates[mcr]="mcr.$caddy_domain {
  608. reverse_proxy localhost:57000 {
  609. header_up Host {host}
  610. header_up X-Real-IP {remote_addr}
  611. header_up X-Forwarded-For {remote_addr}
  612. header_up X-Nginx-Proxy true
  613. }
  614. }"
  615. record_templates[elastic]="elastic.$caddy_domain {
  616. reverse_proxy localhost:58000 {
  617. header_up Host {host}
  618. header_up X-Real-IP {remote_addr}
  619. header_up X-Forwarded-For {remote_addr}
  620. header_up X-Nginx-Proxy true
  621. }
  622. }"
  623. record_templates[nvcr]="nvcr.$caddy_domain {
  624. reverse_proxy localhost:59000 {
  625. header_up Host {host}
  626. header_up X-Real-IP {remote_addr}
  627. header_up X-Forwarded-For {remote_addr}
  628. header_up X-Nginx-Proxy true
  629. }
  630. }"
  631. > /etc/caddy/Caddyfile
  632. for record in "${records_array[@]}"; do
  633. if [[ -n "${record_templates[$record]}" ]]; then
  634. echo "${record_templates[$record]}" >> /etc/caddy/Caddyfile
  635. fi
  636. done
  637. start_attempts=3
  638. for ((i=1; i<=$start_attempts; i++)); do
  639. start_caddy
  640. if pgrep "caddy" > /dev/null; then
  641. INFO "重新载入配置成功. Caddy服务启动完成"
  642. break
  643. else
  644. if [ $i -eq $start_attempts ]; then
  645. ERROR "Caddy 在尝试 $start_attempts 后无法启动。请检查配置"
  646. exit 1
  647. else
  648. WARN "第 $i 次启动 Caddy 失败。重试..."
  649. fi
  650. fi
  651. done
  652. break;;
  653. n|N )
  654. WARN "退出配置 Caddy 操作。"
  655. break;;
  656. * )
  657. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  658. esac
  659. done
  660. }
  661. function INSTALL_NGINX() {
  662. SEPARATOR "安装Nginx"
  663. start_nginx() {
  664. systemctl enable nginx &>/dev/null
  665. systemctl restart nginx
  666. status=$(systemctl is-active nginx)
  667. if [ "$status" = "active" ]; then
  668. INFO "Nginx 服务运行正常,请继续..."
  669. else
  670. ERROR "Nginx 服务未运行,请查看日志报错,定位问题后再次执行脚本!"
  671. ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------"
  672. journalctl -u nginx.service --no-pager
  673. ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------"
  674. exit 1
  675. fi
  676. }
  677. check_nginx() {
  678. if pgrep "nginx" > /dev/null; then
  679. INFO "Nginx 已在运行."
  680. else
  681. WARN "Nginx 未运行。尝试启动 Nginx..."
  682. start_attempts=3
  683. for ((i=1; i<=$start_attempts; i++)); do
  684. start_nginx
  685. if pgrep "nginx" > /dev/null; then
  686. INFO "Nginx 已成功启动."
  687. break
  688. else
  689. if [ $i -eq $start_attempts ]; then
  690. ERROR "Nginx 在尝试 $start_attempts 次后无法启动。请检查配置"
  691. exit 1
  692. else
  693. WARN "第 $i 次启动 Nginx 失败。重试..."
  694. fi
  695. fi
  696. done
  697. fi
  698. }
  699. if [ "$package_manager" = "dnf" ] || [ "$package_manager" = "yum" ]; then
  700. if which nginx &>/dev/null; then
  701. INFO "Nginx 已经安装."
  702. else
  703. INFO "正在安装Nginx程序,请稍候..."
  704. NGINX="nginx-1.24.0-1.el${OSVER}.ngx.x86_64.rpm"
  705. start_spinner "下载Nginx安装包..."
  706. rm -f ${NGINX}
  707. wget http://nginx.org/packages/centos/${OSVER}/x86_64/RPMS/${NGINX} &>/dev/null
  708. stop_spinner
  709. while [ $attempts -lt $maxAttempts ]; do
  710. start_spinner "安装Nginx服务..."
  711. $package_manager -y install ${NGINX} &>/dev/null
  712. stop_spinner
  713. if [ $? -ne 0 ]; then
  714. ((attempts++))
  715. WARN "正在尝试安装Nginx >>> (Attempt: $attempts)"
  716. if [ $attempts -eq $maxAttempts ]; then
  717. ERROR "Nginx installation failed. Please try installing manually."
  718. rm -f ${NGINX}
  719. echo "命令: wget http://nginx.org/packages/centos/${OSVER}/x86_64/RPMS/${NGINX} && $package_manager -y install ${NGINX}"
  720. exit 1
  721. fi
  722. else
  723. INFO "已安装 Nginx."
  724. rm -f ${NGINX}
  725. break
  726. fi
  727. done
  728. fi
  729. check_nginx
  730. elif [ "$package_manager" = "apt-get" ] || [ "$package_manager" = "apt" ];then
  731. dpkg --configure -a &>/dev/null
  732. $package_manager update &>/dev/null
  733. if $pkg_manager -s "nginx" &>/dev/null; then
  734. INFO "nginx 已安装,跳过..."
  735. else
  736. INFO "安装 nginx 请稍等 ..."
  737. $package_manager install -y nginx > /dev/null 2>&1
  738. if [ $? -ne 0 ]; then
  739. ERROR "安装 nginx 失败,请检查系统安装源之后再次运行此脚本!请尝试手动执行安装:$package_manager -y install nginx"
  740. exit 1
  741. fi
  742. fi
  743. check_nginx
  744. else
  745. WARN "无法确定包管理系统."
  746. exit 1
  747. fi
  748. }
  749. function CONFIG_NGINX() {
  750. SEPARATOR "配置Nginx"
  751. while true; do
  752. WARN "自行安装的 Nginx ${LIGHT_RED}请勿执行此操作${RESET},${LIGHT_BLUE}以防覆盖原有配置${RESET}"
  753. INFO "${LIGHT_GREEN}>>> 域名解析主机记录(即域名前缀):${RESET} ${LIGHT_CYAN}${REGISTRY_SLD}${RESET}"
  754. WARN "${LIGHT_GREEN}>>> 只需选择你部署的服务进行解析即可${RESET},${LIGHT_YELLOW}无需将上面提示中所有的主机记录进行解析${RESET}"
  755. read -e -p "$(WARN "是否配置 Nginx?配置完成后需在DNS服务商解析主机记录 ${PROMPT_YES_NO}")" nginx_conf
  756. case "$nginx_conf" in
  757. y|Y )
  758. read -e -p "$(INFO "请输入你的域名${LIGHT_BLUE}[例: baidu.com]${RESET} ${LIGHT_RED}不可为空${RESET}: ")" nginx_domain
  759. read -e -p "$(INFO "请输入要配置的${LIGHT_MAGENTA}主机记录${RESET},用逗号分隔${LIGHT_BLUE}[例: ui,hub]${RESET}: ")" selected_records
  760. # 验证输入的主机记录
  761. local valid_records=("${RECORDS[@]}")
  762. IFS=',' read -r -a records_array <<< "$selected_records"
  763. local invalid_records=()
  764. for record in "${records_array[@]}"; do
  765. if ! [[ " ${valid_records[@]} " =~ " ${record} " ]]; then
  766. invalid_records+=("$record")
  767. fi
  768. done
  769. if [[ ${#invalid_records[@]} -gt 0 ]]; then
  770. ERROR "无效的主机记录: ${LIGHT_RED}${invalid_records[@]}${RESET}"
  771. INFO "请输入有效的主机记录: ${LIGHT_GREEN}${REGISTRY_SLD}${RESET}"
  772. continue
  773. fi
  774. declare -A record_templates
  775. record_templates[ui]="server {
  776. listen 80;
  777. #listen 443 ssl;
  778. server_name ui.$nginx_domain;
  779. #ssl_certificate /path/to/your_domain_name.crt;
  780. #ssl_certificate_key /path/to/your_domain_name.key;
  781. #ssl_session_timeout 1d;
  782. #ssl_session_cache shared:SSL:50m;
  783. #ssl_session_tickets off;
  784. #ssl_protocols TLSv1.2 TLSv1.3;
  785. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  786. #ssl_prefer_server_ciphers on;
  787. #ssl_buffer_size 8k;
  788. proxy_connect_timeout 600;
  789. proxy_send_timeout 600;
  790. proxy_read_timeout 600;
  791. send_timeout 600;
  792. location / {
  793. proxy_pass http://localhost:50000;
  794. proxy_set_header Host \$host;
  795. proxy_set_header Origin \$scheme://\$host;
  796. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  797. proxy_set_header X-Forwarded-Proto \$scheme;
  798. proxy_set_header X-Forwarded-Ssl on;
  799. proxy_set_header X-Forwarded-Port \$server_port;
  800. proxy_set_header X-Forwarded-Host \$host;
  801. }
  802. }"
  803. record_templates[hub]="server {
  804. listen 80;
  805. #listen 443 ssl;
  806. server_name hub.$nginx_domain;
  807. #ssl_certificate /path/to/your_domain_name.crt;
  808. #ssl_certificate_key /path/to/your_domain_name.key;
  809. #ssl_session_timeout 1d;
  810. #ssl_session_cache shared:SSL:50m;
  811. #ssl_session_tickets off;
  812. #ssl_protocols TLSv1.2 TLSv1.3;
  813. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  814. #ssl_prefer_server_ciphers on;
  815. #ssl_buffer_size 8k;
  816. proxy_connect_timeout 600;
  817. proxy_send_timeout 600;
  818. proxy_read_timeout 600;
  819. send_timeout 600;
  820. location / {
  821. proxy_pass http://localhost:51000;
  822. proxy_set_header Host \$host;
  823. proxy_set_header X-Real-IP \$remote_addr;
  824. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  825. proxy_set_header X-Nginx-Proxy true;
  826. proxy_buffering off;
  827. proxy_redirect off;
  828. }
  829. }"
  830. record_templates[ghcr]="server {
  831. listen 80;
  832. #listen 443 ssl;
  833. server_name ghcr.$nginx_domain;
  834. #ssl_certificate /path/to/your_domain_name.crt;
  835. #ssl_certificate_key /path/to/your_domain_name.key;
  836. #ssl_session_timeout 1d;
  837. #ssl_session_cache shared:SSL:50m;
  838. #ssl_session_tickets off;
  839. #ssl_protocols TLSv1.2 TLSv1.3;
  840. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  841. #ssl_prefer_server_ciphers on;
  842. #ssl_buffer_size 8k;
  843. proxy_connect_timeout 600;
  844. proxy_send_timeout 600;
  845. proxy_read_timeout 600;
  846. send_timeout 600;
  847. location / {
  848. proxy_pass http://localhost:52000;
  849. proxy_set_header Host \$host;
  850. proxy_set_header X-Real-IP \$remote_addr;
  851. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  852. proxy_set_header X-Nginx-Proxy true;
  853. proxy_buffering off;
  854. proxy_redirect off;
  855. }
  856. }"
  857. record_templates[gcr]="server {
  858. listen 80;
  859. #listen 443 ssl;
  860. server_name gcr.$nginx_domain;
  861. #ssl_certificate /path/to/your_domain_name.crt;
  862. #ssl_certificate_key /path/to/your_domain_name.key;
  863. #ssl_session_timeout 1d;
  864. #ssl_session_cache shared:SSL:50m;
  865. #ssl_session_tickets off;
  866. #ssl_protocols TLSv1.2 TLSv1.3;
  867. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  868. #ssl_prefer_server_ciphers on;
  869. #ssl_buffer_size 8k;
  870. proxy_connect_timeout 600;
  871. proxy_send_timeout 600;
  872. proxy_read_timeout 600;
  873. send_timeout 600;
  874. location / {
  875. proxy_pass http://localhost:53000;
  876. proxy_set_header Host \$host;
  877. proxy_set_header X-Real-IP \$remote_addr;
  878. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  879. proxy_set_header X-Nginx-Proxy true;
  880. proxy_buffering off;
  881. proxy_redirect off;
  882. }
  883. }"
  884. record_templates[k8sgcr]="server {
  885. listen 80;
  886. #listen 443 ssl;
  887. server_name k8sgcr.$nginx_domain;
  888. #ssl_certificate /path/to/your_domain_name.crt;
  889. #ssl_certificate_key /path/to/your_domain_name.key;
  890. #ssl_session_timeout 1d;
  891. #ssl_session_cache shared:SSL:50m;
  892. #ssl_session_tickets off;
  893. #ssl_protocols TLSv1.2 TLSv1.3;
  894. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  895. #ssl_prefer_server_ciphers on;
  896. #ssl_buffer_size 8k;
  897. proxy_connect_timeout 600;
  898. proxy_send_timeout 600;
  899. proxy_read_timeout 600;
  900. send_timeout 600;
  901. location / {
  902. proxy_pass http://localhost:54000;
  903. proxy_set_header Host \$host;
  904. proxy_set_header X-Real-IP \$remote_addr;
  905. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  906. proxy_set_header X-Nginx-Proxy true;
  907. proxy_buffering off;
  908. proxy_redirect off;
  909. }
  910. }"
  911. record_templates[k8s]="server {
  912. listen 80;
  913. #listen 443 ssl;
  914. server_name k8s.$nginx_domain;
  915. #ssl_certificate /path/to/your_domain_name.crt;
  916. #ssl_certificate_key /path/to/your_domain_name.key;
  917. #ssl_session_timeout 1d;
  918. #ssl_session_cache shared:SSL:50m;
  919. #ssl_session_tickets off;
  920. #ssl_protocols TLSv1.2 TLSv1.3;
  921. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  922. #ssl_prefer_server_ciphers on;
  923. #ssl_buffer_size 8k;
  924. proxy_connect_timeout 600;
  925. proxy_send_timeout 600;
  926. proxy_read_timeout 600;
  927. send_timeout 600;
  928. location / {
  929. proxy_pass http://localhost:55000;
  930. proxy_set_header Host \$host;
  931. proxy_set_header X-Real-IP \$remote_addr;
  932. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  933. proxy_set_header X-Nginx-Proxy true;
  934. proxy_buffering off;
  935. proxy_redirect off;
  936. }
  937. }"
  938. record_templates[quay]="server {
  939. listen 80;
  940. #listen 443 ssl;
  941. server_name quay.$nginx_domain;
  942. #ssl_certificate /path/to/your_domain_name.crt;
  943. #ssl_certificate_key /path/to/your_domain_name.key;
  944. #ssl_session_timeout 1d;
  945. #ssl_session_cache shared:SSL:50m;
  946. #ssl_session_tickets off;
  947. #ssl_protocols TLSv1.2 TLSv1.3;
  948. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  949. #ssl_prefer_server_ciphers on;
  950. #ssl_buffer_size 8k;
  951. proxy_connect_timeout 600;
  952. proxy_send_timeout 600;
  953. proxy_read_timeout 600;
  954. send_timeout 600;
  955. location / {
  956. proxy_pass http://localhost:56000;
  957. proxy_set_header Host \$host;
  958. proxy_set_header X-Real-IP \$remote_addr;
  959. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  960. proxy_set_header X-Nginx-Proxy true;
  961. proxy_buffering off;
  962. proxy_redirect off;
  963. }
  964. }"
  965. record_templates[mcr]="server {
  966. listen 80;
  967. #listen 443 ssl;
  968. server_name mcr.$nginx_domain;
  969. #ssl_certificate /path/to/your_domain_name.crt;
  970. #ssl_certificate_key /path/to/your_domain_name.key;
  971. #ssl_session_timeout 1d;
  972. #ssl_session_cache shared:SSL:50m;
  973. #ssl_session_tickets off;
  974. #ssl_protocols TLSv1.2 TLSv1.3;
  975. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  976. #ssl_prefer_server_ciphers on;
  977. #ssl_buffer_size 8k;
  978. proxy_connect_timeout 600;
  979. proxy_send_timeout 600;
  980. proxy_read_timeout 600;
  981. send_timeout 600;
  982. location / {
  983. proxy_pass http://localhost:57000;
  984. proxy_set_header Host \$host;
  985. proxy_set_header X-Real-IP \$remote_addr;
  986. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  987. proxy_set_header X-Nginx-Proxy true;
  988. proxy_buffering off;
  989. proxy_redirect off;
  990. }
  991. }"
  992. record_templates[elastic]="server {
  993. listen 80;
  994. #listen 443 ssl;
  995. server_name elastic.$nginx_domain;
  996. #ssl_certificate /path/to/your_domain_name.crt;
  997. #ssl_certificate_key /path/to/your_domain_name.key;
  998. #ssl_session_timeout 1d;
  999. #ssl_session_cache shared:SSL:50m;
  1000. #ssl_session_tickets off;
  1001. #ssl_protocols TLSv1.2 TLSv1.3;
  1002. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  1003. #ssl_prefer_server_ciphers on;
  1004. #ssl_buffer_size 8k;
  1005. proxy_connect_timeout 600;
  1006. proxy_send_timeout 600;
  1007. proxy_read_timeout 600;
  1008. send_timeout 600;
  1009. location / {
  1010. proxy_pass http://localhost:58000;
  1011. proxy_set_header Host \$host;
  1012. proxy_set_header X-Real-IP \$remote_addr;
  1013. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1014. proxy_set_header X-Nginx-Proxy true;
  1015. proxy_buffering off;
  1016. proxy_redirect off;
  1017. }
  1018. }"
  1019. record_templates[nvcr]="server {
  1020. listen 80;
  1021. #listen 443 ssl;
  1022. server_name nvcr.$nginx_domain;
  1023. #ssl_certificate /path/to/your_domain_name.crt;
  1024. #ssl_certificate_key /path/to/your_domain_name.key;
  1025. #ssl_session_timeout 1d;
  1026. #ssl_session_cache shared:SSL:50m;
  1027. #ssl_session_tickets off;
  1028. #ssl_protocols TLSv1.2 TLSv1.3;
  1029. #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  1030. #ssl_prefer_server_ciphers on;
  1031. #ssl_buffer_size 8k;
  1032. proxy_connect_timeout 600;
  1033. proxy_send_timeout 600;
  1034. proxy_read_timeout 600;
  1035. send_timeout 600;
  1036. location / {
  1037. proxy_pass http://localhost:59000;
  1038. proxy_set_header Host \$host;
  1039. proxy_set_header X-Real-IP \$remote_addr;
  1040. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1041. proxy_set_header X-Nginx-Proxy true;
  1042. proxy_buffering off;
  1043. proxy_redirect off;
  1044. }
  1045. }"
  1046. > /etc/nginx/conf.d/docker-proxy.conf
  1047. for record in "${records_array[@]}"; do
  1048. if [[ -n "${record_templates[$record]}" ]]; then
  1049. echo "${record_templates[$record]}" >> /etc/nginx/conf.d/docker-proxy.conf
  1050. fi
  1051. done
  1052. start_attempts=3
  1053. for ((i=1; i<=$start_attempts; i++)); do
  1054. start_nginx
  1055. if pgrep "nginx" > /dev/null; then
  1056. INFO "重新载入配置成功. Nginx服务启动完成"
  1057. break
  1058. else
  1059. if [ $i -eq $start_attempts ]; then
  1060. ERROR "Nginx 在尝试 $start_attempts 后无法启动。请检查配置"
  1061. exit 1
  1062. else
  1063. WARN "第 $i 次启动 Nginx 失败。重试..."
  1064. fi
  1065. fi
  1066. done
  1067. break;;
  1068. n|N )
  1069. WARN "退出配置 Nginx 操作。"
  1070. break;;
  1071. * )
  1072. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1073. esac
  1074. done
  1075. }
  1076. function CHECK_DOCKER() {
  1077. status=$(systemctl is-active docker)
  1078. if [ "$status" = "active" ]; then
  1079. INFO "Docker 服务运行正常,请继续..."
  1080. else
  1081. ERROR "Docker 服务未运行,请查看日志报错,定位问题后再次执行脚本!"
  1082. ERROR "-----------服务启动失败,请查看错误日志 ↓↓↓-----------"
  1083. journalctl -u docker.service --no-pager
  1084. ERROR "-----------服务启动失败,请查看错误日志 ↑↑↑-----------"
  1085. exit 1
  1086. fi
  1087. }
  1088. function INSTALL_DOCKER() {
  1089. repo_file="docker-ce.repo"
  1090. url="https://download.docker.com/linux/$repo_type"
  1091. MAX_ATTEMPTS=3
  1092. attempt=0
  1093. success=false
  1094. if [ "$repo_type" = "centos" ] || [ "$repo_type" = "rhel" ]; then
  1095. if ! command -v docker &> /dev/null;then
  1096. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  1097. attempt=$((attempt + 1))
  1098. WARN "Docker 未安装,正在进行安装..."
  1099. start_spinner "添加Docker仓库..."
  1100. yum-config-manager --add-repo $url/$repo_file &>/dev/null
  1101. stop_spinner
  1102. start_spinner "安装Docker服务..."
  1103. $package_manager -y install docker-ce &>/dev/null
  1104. stop_spinner
  1105. if [ $? -eq 0 ]; then
  1106. success=true
  1107. break
  1108. fi
  1109. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1110. done
  1111. if $success; then
  1112. INFO "Docker 安装成功,版本为:$(docker --version)"
  1113. start_spinner "启动Docker服务..."
  1114. systemctl restart docker &>/dev/null
  1115. stop_spinner
  1116. CHECK_DOCKER
  1117. systemctl enable docker &>/dev/null
  1118. else
  1119. ERROR "Docker 安装失败,请尝试手动安装"
  1120. exit 1
  1121. fi
  1122. else
  1123. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1124. systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
  1125. fi
  1126. elif [ "$repo_type" == "ubuntu" ]; then
  1127. if ! command -v docker &> /dev/null;then
  1128. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  1129. attempt=$((attempt + 1))
  1130. WARN "Docker 未安装,正在进行安装..."
  1131. start_spinner "添加Docker仓库..."
  1132. curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null
  1133. add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null
  1134. start_spinner "安装Docker服务..."
  1135. $package_manager -y install docker-ce docker-ce-cli containerd.io &>/dev/null
  1136. stop_spinner
  1137. if [ $? -eq 0 ]; then
  1138. success=true
  1139. break
  1140. fi
  1141. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1142. done
  1143. if $success; then
  1144. INFO "Docker 安装成功,版本为:$(docker --version)"
  1145. systemctl restart docker &>/dev/null
  1146. CHECK_DOCKER
  1147. systemctl enable docker &>/dev/null
  1148. else
  1149. ERROR "Docker 安装失败,请尝试手动安装"
  1150. exit 1
  1151. fi
  1152. else
  1153. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1154. systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
  1155. fi
  1156. elif [ "$repo_type" == "debian" ]; then
  1157. if ! command -v docker &> /dev/null;then
  1158. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  1159. attempt=$((attempt + 1))
  1160. WARN "Docker 未安装,正在进行安装..."
  1161. start_spinner "添加Docker仓库..."
  1162. curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null
  1163. add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null
  1164. start_spinner "安装Docker服务..."
  1165. $package_manager -y install docker-ce docker-ce-cli containerd.io &>/dev/null
  1166. stop_spinner
  1167. if [ $? -eq 0 ]; then
  1168. success=true
  1169. break
  1170. fi
  1171. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1172. done
  1173. if $success; then
  1174. INFO "Docker 安装成功,版本为:$(docker --version)"
  1175. systemctl restart docker &>/dev/null
  1176. CHECK_DOCKER
  1177. systemctl enable docker &>/dev/null
  1178. else
  1179. ERROR "Docker 安装失败,请尝试手动安装"
  1180. exit 1
  1181. fi
  1182. else
  1183. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1184. systemctl restart docker &>/dev/null
  1185. CHECK_DOCKER
  1186. fi
  1187. else
  1188. ERROR "不支持的操作系统."
  1189. exit 1
  1190. fi
  1191. }
  1192. function INSTALL_COMPOSE() {
  1193. SEPARATOR "安装Docker Compose"
  1194. TAG=`curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r '.tag_name'`
  1195. url="https://github.com/docker/compose/releases/download/$TAG/docker-compose-$(uname -s)-$(uname -m)"
  1196. MAX_ATTEMPTS=3
  1197. attempt=0
  1198. success=false
  1199. save_path="/usr/local/bin"
  1200. chmod +x $save_path/docker-compose &>/dev/null
  1201. if ! command -v docker-compose &> /dev/null || [ -z "$(docker-compose --version)" ]; then
  1202. WARN "Docker Compose 未安装或安装不完整,正在进行安装..."
  1203. while [ $attempt -lt $MAX_ATTEMPTS ]; do
  1204. attempt=$((attempt + 1))
  1205. start_spinner "下载Docker Compose..."
  1206. wget --continue -q $url -O $save_path/docker-compose
  1207. stop_spinner
  1208. if [ $? -eq 0 ]; then
  1209. chmod +x $save_path/docker-compose
  1210. version_check=$(docker-compose --version)
  1211. if [ -n "$version_check" ]; then
  1212. success=true
  1213. chmod +x $save_path/docker-compose
  1214. break
  1215. else
  1216. WARN "Docker Compose 下载的文件不完整,正在尝试重新下载 (尝试次数: $attempt)"
  1217. rm -f $save_path/docker-compose
  1218. fi
  1219. fi
  1220. ERROR "Docker Compose 下载失败,正在尝试重新下载 (尝试次数: $attempt)"
  1221. done
  1222. if $success; then
  1223. INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)"
  1224. else
  1225. ERROR "Docker Compose 下载失败,请尝试手动安装docker-compose"
  1226. exit 1
  1227. fi
  1228. else
  1229. chmod +x $save_path/docker-compose
  1230. INFO "Docker Compose 已经安装,版本为:$(docker-compose --version)"
  1231. fi
  1232. }
  1233. function INSTALL_DOCKER_CN() {
  1234. MAX_ATTEMPTS=3
  1235. attempt=0
  1236. success=false
  1237. cpu_arch=$(uname -m)
  1238. save_path="/opt/docker_tgz"
  1239. mkdir -p $save_path
  1240. docker_ver="docker-27.1.2.tgz"
  1241. case $cpu_arch in
  1242. "arm64")
  1243. url="https://raw.gitcode.com/dqzboy/docker/blobs/2ce4d6bc245ab1c4525b3e6f55db7d710681e56f/$docker_ver"
  1244. ;;
  1245. "aarch64")
  1246. url="https://raw.gitcode.com/dqzboy/docker/blobs/2ce4d6bc245ab1c4525b3e6f55db7d710681e56f/$docker_ver"
  1247. ;;
  1248. "x86_64")
  1249. url="https://raw.gitcode.com/dqzboy/docker/blobs/179729785ed2c4a8c99aeb546fb6ac2864d7da5c/$docker_ver"
  1250. ;;
  1251. *)
  1252. ERROR "不支持的CPU架构: $cpu_arch"
  1253. exit 1
  1254. ;;
  1255. esac
  1256. if ! command -v docker &> /dev/null; then
  1257. while [ $attempt -lt $MAX_ATTEMPTS ]; do
  1258. attempt=$((attempt + 1))
  1259. WARN "Docker 未安装,正在进行安装..."
  1260. start_spinner "安装Docker服务..."
  1261. wget -P "$save_path" "$url" &>/dev/null
  1262. stop_spinner
  1263. if [ $? -eq 0 ]; then
  1264. success=true
  1265. break
  1266. fi
  1267. ERROR "Docker 安装失败,正在尝试重新下载 (尝试次数: $attempt)"
  1268. done
  1269. if $success; then
  1270. tar -xzf $save_path/$docker_ver -C $save_path
  1271. \cp $save_path/docker/* /usr/bin/ &>/dev/null
  1272. rm -rf $save_path
  1273. INFO "Docker 安装成功,版本为:$(docker --version)"
  1274. cat > /usr/lib/systemd/system/docker.service <<EOF
  1275. [Unit]
  1276. Description=Docker Application Container Engine
  1277. Documentation=https://docs.docker.com
  1278. After=network-online.target firewalld.service
  1279. Wants=network-online.target
  1280. [Service]
  1281. Type=notify
  1282. ExecStart=/usr/bin/dockerd
  1283. ExecReload=/bin/kill -s HUP
  1284. LimitNOFILE=infinity
  1285. LimitNPROC=infinity
  1286. LimitCORE=infinity
  1287. TimeoutStartSec=0
  1288. Delegate=yes
  1289. KillMode=process
  1290. Restart=on-failure
  1291. StartLimitBurst=3
  1292. StartLimitInterval=60s
  1293. [Install]
  1294. WantedBy=multi-user.target
  1295. EOF
  1296. systemctl daemon-reload
  1297. systemctl restart docker &>/dev/null
  1298. CHECK_DOCKER
  1299. systemctl enable docker &>/dev/null
  1300. else
  1301. ERROR "Docker 安装失败,请尝试手动安装"
  1302. exit 1
  1303. fi
  1304. else
  1305. INFO "Docker 已安装,安装版本为:$(docker --version)"
  1306. systemctl restart docker &>/dev/null
  1307. CHECK_DOCKER
  1308. fi
  1309. }
  1310. function INSTALL_COMPOSE_CN() {
  1311. SEPARATOR "安装Docker Compose"
  1312. MAX_ATTEMPTS=3
  1313. attempt=0
  1314. cpu_arch=$(uname -m)
  1315. success=false
  1316. save_path="/usr/local/bin"
  1317. case $cpu_arch in
  1318. "arm64")
  1319. url="https://raw.gitcode.com/dqzboy/docker/blobs/b7be39a4442a103749c769ca48740e8e1a93a16c/docker-compose-linux-aarch64"
  1320. ;;
  1321. "aarch64")
  1322. url="https://raw.gitcode.com/dqzboy/docker/blobs/b7be39a4442a103749c769ca48740e8e1a93a16c/docker-compose-linux-aarch64"
  1323. ;;
  1324. "x86_64")
  1325. url="https://raw.gitcode.com/dqzboy/docker/blobs/df1b7935ced481a20d16141d97e163823ee793f5/docker-compose-linux-x86_64"
  1326. ;;
  1327. *)
  1328. ERROR "不支持的CPU架构: $cpu_arch"
  1329. exit 1
  1330. ;;
  1331. esac
  1332. chmod +x $save_path/docker-compose &>/dev/null
  1333. if ! command -v docker-compose &> /dev/null || [ -z "$(docker-compose --version)" ]; then
  1334. WARN "Docker Compose 未安装或安装不完整,正在进行安装..."
  1335. while [ $attempt -lt $MAX_ATTEMPTS ]; do
  1336. attempt=$((attempt + 1))
  1337. start_spinner "下载Docker Compose..."
  1338. wget --continue -q $url -O $save_path/docker-compose
  1339. stop_spinner
  1340. if [ $? -eq 0 ]; then
  1341. chmod +x $save_path/docker-compose
  1342. version_check=$(docker-compose --version)
  1343. if [ -n "$version_check" ]; then
  1344. success=true
  1345. chmod +x $save_path/docker-compose
  1346. break
  1347. else
  1348. WARN "Docker Compose 下载的文件不完整,正在尝试重新下载 (尝试次数: $attempt)"
  1349. rm -f $save_path/docker-compose
  1350. fi
  1351. fi
  1352. ERROR "Docker Compose 下载失败,正在尝试重新下载 (尝试次数: $attempt)"
  1353. done
  1354. if $success; then
  1355. INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)"
  1356. else
  1357. ERROR "Docker Compose 下载失败,请尝试手动安装docker-compose"
  1358. exit 1
  1359. fi
  1360. else
  1361. chmod +x $save_path/docker-compose
  1362. INFO "Docker Compose 安装成功,版本为:$(docker-compose --version)"
  1363. fi
  1364. }
  1365. function update_docker_registry_url() {
  1366. local container_name=$1
  1367. if [[ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then
  1368. sed -i "s@- DOCKER_REGISTRY_URL=.*@- DOCKER_REGISTRY_URL=http://${container_name}:5000@g" ${PROXY_DIR}/${DOCKER_COMPOSE_FILE}
  1369. else
  1370. ERROR "文件 ${LIGHT_CYAN}${PROXY_DIR}/${DOCKER_COMPOSE_FILE} ${RESET} ${LIGHT_RED}不存在${RESET},导致容器无法应用新配置"
  1371. exit 1
  1372. fi
  1373. }
  1374. function CONFIG_FILES() {
  1375. while true; do
  1376. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" install_docker_reg
  1377. case "$install_docker_reg" in
  1378. 1 )
  1379. files=(
  1380. "dockerhub reg-docker-hub ${GITRAW}/config/registry-hub.yml"
  1381. "gcr reg-gcr ${GITRAW}/config/registry-gcr.yml"
  1382. "ghcr reg-ghcr ${GITRAW}/config/registry-ghcr.yml"
  1383. "quay reg-quay ${GITRAW}/config/registry-quay.yml"
  1384. "k8sgcr reg-k8s-gcr ${GITRAW}/config/registry-k8sgcr.yml"
  1385. "k8s reg-k8s ${GITRAW}/config/registry-k8s.yml"
  1386. "mcr reg-mcr ${GITRAW}/config/registry-mcr.yml"
  1387. "elastic reg-elastic ${GITRAW}/config/registry-elastic.yml"
  1388. "nvcr reg-nvcr ${GITRAW}/config/registry-nvcr.yml"
  1389. )
  1390. break;;
  1391. 2 )
  1392. files=(
  1393. "dockerhub reg-docker-hub ${CNGITRAW}/config/registry-hub.yml"
  1394. "gcr reg-gcr ${CNGITRAW}/config/registry-gcr.yml"
  1395. "ghcr reg-ghcr ${CNGITRAW}/config/registry-ghcr.yml"
  1396. "quay reg-quay ${CNGITRAW}/config/registry-quay.yml"
  1397. "k8sgcr reg-k8s-gcr ${CNGITRAW}/config/registry-k8sgcr.yml"
  1398. "k8s reg-k8s ${CNGITRAW}/config/registry-k8s.yml"
  1399. "mcr reg-mcr ${CNGITRAW}/config/registry-mcr.yml"
  1400. "elastic reg-elastic ${CNGITRAW}/config/registry-elastic.yml"
  1401. "nvcr reg-nvcr ${CNGITRAW}/config/registry-nvcr.yml"
  1402. )
  1403. break;;
  1404. * )
  1405. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  1406. esac
  1407. done
  1408. }
  1409. function DOWN_CONFIG() {
  1410. selected_names=()
  1411. selected_files=()
  1412. selected_containers=()
  1413. REGISTRY_MENU
  1414. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all下载所有${RESET} > ")" choices_reg
  1415. while true; do
  1416. if [[ "$choices_reg" =~ ^[0-9]+([[:space:]][0-9]+)*$ ]]; then
  1417. valid=true
  1418. for choice in $choices_reg; do
  1419. if ((choice < 0 || choice > 10)); then
  1420. valid=false
  1421. break
  1422. fi
  1423. done
  1424. if $valid; then
  1425. break
  1426. fi
  1427. fi
  1428. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-10 ${RESET}序号"
  1429. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all下载所有${RESET} > ")" choices_reg
  1430. done
  1431. if [[ "$choices_reg" == "10" ]]; then
  1432. for file in "${files[@]}"; do
  1433. file_name=$(echo "$file" | cut -d' ' -f1)
  1434. container_name=$(echo "$file" | cut -d' ' -f2)
  1435. file_url=$(echo "$file" | cut -d' ' -f3-)
  1436. selected_names+=("$file_name")
  1437. selected_containers+=("$container_name")
  1438. selected_files+=("$file_url")
  1439. wget -NP ${PROXY_DIR}/ $file_url &>/dev/null
  1440. done
  1441. selected_all=true
  1442. elif [[ "$choices_reg" == "0" ]]; then
  1443. WARN "退出下载配置! ${LIGHT_YELLOW}首次安装如果没有配置无法启动Registry服务,只能启动Registry-UI服务${RESET}"
  1444. return
  1445. else
  1446. for choice in ${choices_reg}; do
  1447. if ((choice > 0 && choice < 10)); then
  1448. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  1449. container_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  1450. file_url=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f3-)
  1451. selected_names+=("$file_name")
  1452. selected_containers+=("$container_name")
  1453. selected_files+=("$file_url")
  1454. wget -NP ${PROXY_DIR}/ $file_url &>/dev/null
  1455. fi
  1456. done
  1457. selected_all=false
  1458. # 非更新配置操作则执行下面步骤
  1459. if [[ "$main_choice" != "4" ]]; then
  1460. first_selected_container=${selected_containers[0]}
  1461. update_docker_registry_url "$first_selected_container"
  1462. fi
  1463. fi
  1464. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_BLUE}Proxy代理缓存过期时间${RESET} ${MAGENTA}单位:ns、us、ms、s、m、h.默认ns,0不清除缓存${RESET}"
  1465. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  1466. while [[ "$modify_cache" != "y" && "$modify_cache" != "n" ]]; do
  1467. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  1468. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  1469. done
  1470. if [[ "$modify_cache" == "y" ]]; then
  1471. while true; do
  1472. read -e -p "$(INFO "请输入新的缓存时间值: ")" new_ttl
  1473. for file_url in "${selected_files[@]}"; do
  1474. yml_name=$(basename "$file_url")
  1475. sed -ri "s/ttl: 168h/ttl: ${new_ttl}/g" ${PROXY_DIR}/${yml_name} &>/dev/null
  1476. done
  1477. break
  1478. done
  1479. fi
  1480. }
  1481. # 一键部署调此函数
  1482. function PROXY_HTTP() {
  1483. read -e -p "$(INFO "是否添加代理(科学上网)? ${PROMPT_YES_NO}")" modify_config
  1484. case $modify_config in
  1485. [Yy]* )
  1486. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1487. while [[ -z "$url" ]]; do
  1488. WARN "代理${LIGHT_YELLOW}地址不能为空${RESET},请重新输入!"
  1489. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1490. done
  1491. sed -i "s@#- http=http://host:port@- http_proxy=http://${url}@g" ${PROXY_DIR}/${DOCKER_COMPOSE_FILE}
  1492. sed -i "s@#- https=http://host:port@- https_proxy=http://${url}@g" ${PROXY_DIR}/${DOCKER_COMPOSE_FILE}
  1493. INFO "你配置代理地址为: ${CYAN}http://${url}${RESET}"
  1494. ;;
  1495. [Nn]* )
  1496. WARN "跳过添加代理配置"
  1497. ;;
  1498. * )
  1499. ERROR "无效的输入。请重新输入${LIGHT_GREEN}Y or N ${RESET}的选项"
  1500. PROXY_HTTP
  1501. ;;
  1502. esac
  1503. }
  1504. # 7) 本机Docker代理,调此函数
  1505. function DOCKER_PROXY_HTTP() {
  1506. WARN "${BOLD}${LIGHT_GREEN}提示:${RESET} ${LIGHT_CYAN}配置本机Docker服务走代理,加速本机Docker镜像下载${RESET}"
  1507. read -e -p "$(INFO "是否添加本机Docker服务代理? ${PROMPT_YES_NO}")" modify_proxy
  1508. case $modify_proxy in
  1509. [Yy]* )
  1510. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1511. while [[ -z "$url" ]]; do
  1512. WARN "代理${LIGHT_YELLOW}地址不能为空${RESET},请重新输入。"
  1513. read -e -p "$(INFO "输入代理地址(科学上网) ${LIGHT_MAGENTA}(eg: host:port)${RESET}: ")" url
  1514. done
  1515. INFO "你配置代理地址为: ${CYAN}http://${url}${RESET}"
  1516. ;;
  1517. [Nn]* )
  1518. WARN "退出本机Docker服务代理配置"
  1519. main_menu
  1520. ;;
  1521. * )
  1522. ERROR "无效的输入。请重新输入${LIGHT_GREEN}Y or N ${RESET}的选项"
  1523. DOCKER_PROXY_HTTP
  1524. ;;
  1525. esac
  1526. }
  1527. function CHECK_DOCKER_PROXY() {
  1528. local url=$1
  1529. local http_proxy=$(docker info 2>/dev/null | grep -i "HTTP Proxy" | awk -F ': ' '{print $2}')
  1530. local https_proxy=$(docker info 2>/dev/null | grep -i "HTTPS Proxy" | awk -F ': ' '{print $2}')
  1531. if [[ "$http_proxy" == "http://$url" && "$https_proxy" == "http://$url" ]]; then
  1532. INFO "Docker 代理${LIGHT_GREEN}配置成功${RESET},当前 HTTP Proxy: ${LIGHT_CYAN}$http_proxy${RESET}, HTTPS Proxy: ${LIGHT_CYAN}$https_proxy${RESET}"
  1533. else
  1534. ERROR "Docker 代理${LIGHT_RED}配置失败${RESET},请检查配置并重新执行配置"
  1535. DOCKER_PROXY_HTTP
  1536. fi
  1537. }
  1538. function ADD_DOCKERD_PROXY() {
  1539. mkdir -p /etc/systemd/system/docker.service.d
  1540. # 设置代理的函数
  1541. set_proxy_config() {
  1542. cat > /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
  1543. [Service]
  1544. Environment="HTTP_PROXY=http://$url"
  1545. Environment="HTTPS_PROXY=http://$url"
  1546. EOF
  1547. systemctl daemon-reload
  1548. systemctl restart docker &>/dev/null
  1549. CHECK_DOCKER
  1550. CHECK_DOCKER_PROXY "$url"
  1551. }
  1552. # 检查并设置代理配置
  1553. if [ ! -f /etc/systemd/system/docker.service.d/http-proxy.conf ]; then
  1554. # 如果配置文件不存在,直接设置代理
  1555. set_proxy_config
  1556. else
  1557. # 如果配置文件存在,检查是否有相同的代理配置
  1558. if ! grep -q "HTTP_PROXY=http://$url" /etc/systemd/system/docker.service.d/http-proxy.conf || \
  1559. ! grep -q "HTTPS_PROXY=http://$url" /etc/systemd/system/docker.service.d/http-proxy.conf; then
  1560. # 配置文件存在,但没有相同的代理配置,添加新的代理配置
  1561. set_proxy_config
  1562. else
  1563. WARN "已经存在相同的代理配置,${LIGHT_RED}请勿重复配置${RESET}"
  1564. fi
  1565. fi
  1566. }
  1567. function DEL_DOCKERD_PROXY() {
  1568. check_proxy_config() {
  1569. systemctl daemon-reload
  1570. systemctl restart docker &>/dev/null
  1571. CHECK_DOCKER
  1572. }
  1573. WARN "${BOLD}${LIGHT_GREEN}提示:${RESET} ${LIGHT_CYAN}移除本机Docker服务走代理,Docker镜像下载可能会失败!${RESET}"
  1574. read -e -p "$(INFO "是否移除本机Docker服务代理? ${PROMPT_YES_NO}")" del_proxy
  1575. case $del_proxy in
  1576. [Yy]* )
  1577. # 检查并设置代理配置
  1578. if [ ! -f /etc/systemd/system/docker.service.d/http-proxy.conf ]; then
  1579. # 如果配置文件不存在,打印提示
  1580. INFO "本机Docker服务未配置代理"
  1581. else
  1582. # 如果配置文件存在,则进行删除并重启Docker服务
  1583. rm -f /etc/systemd/system/docker.service.d/http-proxy.conf &>/dev/null
  1584. check_proxy_config
  1585. INFO "本机Docker服务代理已移除"
  1586. fi
  1587. ;;
  1588. [Nn]* )
  1589. WARN "退出移除本机Docker服务代理配置"
  1590. main_menu
  1591. ;;
  1592. * )
  1593. ERROR "无效的输入。请重新输入${LIGHT_GREEN}Y or N ${RESET}的选项"
  1594. DOCKER_PROXY_HTTP
  1595. ;;
  1596. esac
  1597. }
  1598. # 一键部署、安装指定容器加速服务时调用START_CONTAINER
  1599. function START_CONTAINER() {
  1600. CHECK_COMPOSE_CMD
  1601. if [ "$modify_config" = "y" ] || [ "$modify_config" = "Y" ]; then
  1602. ADD_DOCKERD_PROXY
  1603. else
  1604. INFO "拉取服务镜像并启动服务中..."
  1605. fi
  1606. # DOWN_CONFIG函数执行后判断selected_all变量
  1607. if [ "$selected_all" = true ]; then
  1608. $DOCKER_COMPOSE_CMD up -d --force-recreate
  1609. # 检查命令执行是否成功
  1610. if [ $? -ne 0 ]; then
  1611. ERROR "Docker 容器${LIGHT_RED}启动失败${RESET},请通过查看日志确认启动失败原因"
  1612. exit 1
  1613. fi
  1614. else
  1615. $DOCKER_COMPOSE_CMD up -d "${selected_names[@]}" registry-ui
  1616. # 检查命令执行是否成功
  1617. if [ $? -ne 0 ]; then
  1618. ERROR "Docker 容器${LIGHT_RED}启动失败${RESET},请通过查看日志确认启动失败原因"
  1619. exit 1
  1620. else
  1621. INFO "容器${LIGHT_GREEN}安装完成${RESET},并${LIGHT_GREEN}成功启动${RESET}"
  1622. fi
  1623. fi
  1624. }
  1625. # 使用函数UPDATE_CONFIG时调用RESTART_CONTAINER
  1626. function RESTART_CONTAINER() {
  1627. CHECK_COMPOSE_CMD
  1628. # DOWN_CONFIG函数执行后判断selected_all变量
  1629. if [ "$selected_all" = true ]; then
  1630. $DOCKER_COMPOSE_CMD restart
  1631. # 检查命令执行是否成功
  1632. if [ $? -ne 0 ]; then
  1633. ERROR "Docker 容器启动失败,请通过查看日志确认启动失败原因"
  1634. exit 1
  1635. fi
  1636. else
  1637. $DOCKER_COMPOSE_CMD restart "${selected_names[@]}"
  1638. # 检查命令执行是否成功
  1639. if [ $? -ne 0 ]; then
  1640. ERROR "Docker 容器启动失败,请通过查看日志确认启动失败原因"
  1641. exit 1
  1642. fi
  1643. fi
  1644. }
  1645. function INSTALL_DOCKER_PROXY() {
  1646. SEPARATOR "部署Docker Proxy"
  1647. CONFIG_FILES
  1648. if [[ "$install_docker_reg" == "1" ]]; then
  1649. wget -NP ${PROXY_DIR}/ ${GITRAW}/${DOCKER_COMPOSE_FILE} &>/dev/null
  1650. elif [[ "$install_docker_reg" == "2" ]]; then
  1651. wget -NP ${PROXY_DIR}/ ${CNGITRAW}/${DOCKER_COMPOSE_FILE} &>/dev/null
  1652. fi
  1653. DOWN_CONFIG
  1654. PROXY_HTTP
  1655. START_CONTAINER
  1656. }
  1657. function STOP_REMOVE_CONTAINER() {
  1658. CHECK_COMPOSE_CMD
  1659. if [[ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then
  1660. INFO "停止和移除所有容器"
  1661. $DOCKER_COMPOSE_CMD -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" down --remove-orphans
  1662. else
  1663. WARN "${LIGHT_YELLOW}容器目前未处于运行状态,无需进行删除操作!${RESET}"
  1664. exit 1
  1665. fi
  1666. }
  1667. function UPDATE_CONFIG() {
  1668. while true; do
  1669. read -e -p "$(WARN "是否更新配置,更新前请确保您已备份现有配置,此操作不可逆? ${PROMPT_YES_NO}")" update_conf
  1670. case "$update_conf" in
  1671. y|Y )
  1672. CONFIG_FILES
  1673. DOWN_CONFIG
  1674. RESTART_CONTAINER
  1675. break;;
  1676. n|N )
  1677. WARN "退出配置更新操作。"
  1678. break;;
  1679. * )
  1680. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1681. esac
  1682. done
  1683. }
  1684. function REMOVE_NONE_TAG() {
  1685. docker images | grep "^${IMAGE_NAME}.*<none>" | awk '{print $3}' | xargs -r docker rmi
  1686. images=$(docker images ${IMAGE_NAME} --format '{{.Repository}}:{{.Tag}}')
  1687. latest=$(echo "$images" | sort -V | tail -n1)
  1688. for image in $images
  1689. do
  1690. if [ "$image" != "$latest" ];then
  1691. docker rmi $image
  1692. fi
  1693. done
  1694. }
  1695. function PACKAGE() {
  1696. while true; do
  1697. read -e -p "$(INFO "是否执行软件包安装? (${LIGHT_YELLOW}首次部署需安装依赖${RESET}) ${PROMPT_YES_NO}")" choice_package
  1698. case "$choice_package" in
  1699. y|Y )
  1700. INSTALL_PACKAGE
  1701. break;;
  1702. n|N )
  1703. WARN "跳过软件包安装步骤"
  1704. break;;
  1705. * )
  1706. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1707. esac
  1708. done
  1709. }
  1710. function INSTALL_WEB() {
  1711. while true; do
  1712. SEPARATOR "安装WEB服务"
  1713. read -e -p "$(INFO "是否安装WEB服务? (用来通过域名方式访问加速服务) ${PROMPT_YES_NO}")" choice_service
  1714. if [[ "$choice_service" =~ ^[YyNn]$ ]]; then
  1715. if [[ "$choice_service" == "Y" || "$choice_service" == "y" ]]; then
  1716. while true; do
  1717. read -e -p "$(INFO "选择安装的WEB服务。安装${LIGHT_CYAN}Caddy可自动开启HTTPS${RESET} [Nginx/Caddy]: ")" web_service
  1718. if [[ "$web_service" =~ ^(nginx|Nginx|caddy|Caddy)$ ]]; then
  1719. if [[ "$web_service" == "nginx" || "$web_service" == "Nginx" ]]; then
  1720. INSTALL_NGINX
  1721. CONFIG_NGINX
  1722. break
  1723. elif [[ "$web_service" == "caddy" || "$web_service" == "Caddy" ]]; then
  1724. INSTALL_CADDY
  1725. CONFIG_CADDY
  1726. break
  1727. fi
  1728. else
  1729. WARN "请输入 ${LIGHT_CYAN}nginx${RESET} 或 ${LIGHT_BLUE}caddy${RESET}"
  1730. fi
  1731. done
  1732. break
  1733. else
  1734. WARN "跳过WEB服务安装步骤"
  1735. break
  1736. fi
  1737. else
  1738. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  1739. fi
  1740. done
  1741. }
  1742. function PROMPT(){
  1743. PUBLIC_IP=$(curl -s https://ifconfig.me)
  1744. ALL_IPS=$(hostname -I)
  1745. INTERNAL_IP=$(echo "$ALL_IPS" | awk '$1!="127.0.0.1" && $1!="::1" && $1!="docker0" {print $1}')
  1746. echo
  1747. INFO "=================感谢您的耐心等待,安装已经完成=================="
  1748. INFO
  1749. INFO "请用浏览器访问 UI 面板(此地址只是UI,非加速地址): "
  1750. INFO "公网访问地址: ${UNDERLINE}http://$PUBLIC_IP:50000${RESET}"
  1751. INFO "内网访问地址: ${UNDERLINE}http://$INTERNAL_IP:50000${RESET}"
  1752. INFO
  1753. INFO "服务安装路径: ${LIGHT_BLUE}${PROXY_DIR}${RESET}"
  1754. INFO
  1755. INFO "加速服务对应监听端口如下(参考信息):"
  1756. INFO "DockerHub:51000 │ GHCR:52000 │ GCR:53000 │ K8S-GCR:54000"
  1757. INFO "K8S:55000 │ Quay:56000 │ MCR:57000 │ Elastic:58000 │ NVCR:59000"
  1758. INFO
  1759. INFO "作者博客: https://dqzboy.com"
  1760. INFO "技术交流: https://t.me/dqzboyblog"
  1761. INFO "代码仓库: https://github.com/dqzboy/Docker-Proxy"
  1762. INFO
  1763. INFO "若用云服务器并设域名及证书,需在安全组开放80、443端口;否则开放对应服务监听端口"
  1764. INFO
  1765. INFO "AFF: VPS推荐: https://dqzboy.github.io/proxyui/racknerd"
  1766. INFO
  1767. INFO "================================================================"
  1768. }
  1769. function INSTALL_PROXY() {
  1770. ALL_IN_ONE() {
  1771. CHECK_OS
  1772. CHECK_PACKAGE_MANAGER
  1773. CHECK_PKG_MANAGER
  1774. CHECK_COMPOSE_CMD
  1775. CHECKMEM
  1776. CHECKFIRE
  1777. CHECKBBR
  1778. PACKAGE
  1779. INSTALL_WEB
  1780. while true; do
  1781. SEPARATOR "安装Docker"
  1782. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" deploy_docker
  1783. case "$deploy_docker" in
  1784. 1 )
  1785. INSTALL_DOCKER
  1786. INSTALL_COMPOSE
  1787. break;;
  1788. 2 )
  1789. INSTALL_DOCKER_CN
  1790. INSTALL_COMPOSE_CN
  1791. break;;
  1792. * )
  1793. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  1794. esac
  1795. done
  1796. INSTALL_DOCKER_PROXY
  1797. PROMPT
  1798. }
  1799. ADD_DOCKER_SERVICE() {
  1800. WARN "提示: 此操作是在你的服务器${LIGHT_CYAN}已经部署对应组件${RESET}后才可执行,否则执行过程将会出现${LIGHT_RED}各种报错!${RESET}"
  1801. INSTALL_DOCKER_PROXY
  1802. }
  1803. SEPARATOR "安装服务"
  1804. echo -e "1) 一键${BOLD}${LIGHT_GREEN}部署所有${RESET}服务"
  1805. echo -e "2) ${BOLD}${LIGHT_CYAN}安装指定${RESET}容器服务"
  1806. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  1807. echo -e "0) ${BOLD}退出脚本${RESET}"
  1808. echo "---------------------------------------------------------------"
  1809. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" proxy_install
  1810. case $proxy_install in
  1811. 1)
  1812. ALL_IN_ONE
  1813. ;;
  1814. 2)
  1815. ADD_DOCKER_SERVICE
  1816. INSTALL_PROXY
  1817. ;;
  1818. 3)
  1819. main_menu
  1820. ;;
  1821. 0)
  1822. exit 1
  1823. ;;
  1824. *)
  1825. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  1826. INSTALL_PROXY
  1827. ;;
  1828. esac
  1829. }
  1830. function REMOVE_CMDUI() {
  1831. CHECK_COMPOSE_CMD
  1832. CMDUI_NAME="hubcmd-ui"
  1833. CMDUI_DIR="${PROXY_DIR}/hubcmdui"
  1834. if [ -d "${CMDUI_DIR}" ]; then
  1835. if [ -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" ]; then
  1836. INFO "停止和移除HubCMD-UI容器"
  1837. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" down --remove-orphans
  1838. rm -rf "${CMDUI_DIR}"
  1839. else
  1840. WARN "${LIGHT_YELLOW}文件${CMDUI_DIR}/${DOCKER_COMPOSE_FILE} 不存在,无需进行删除操作!${RESET}"
  1841. fi
  1842. else
  1843. WARN "${LIGHT_YELLOW}目录 ${CMDUI_DIR} 不存在,无需进行删除操作!${RESET}"
  1844. fi
  1845. docker images | grep "^${CMDUI_IMAGE_NAME}.*<none>" | awk '{print $3}' | xargs -r docker rmi
  1846. images=$(docker images ${CMDUI_IMAGE_NAME} --format '{{.Repository}}:{{.Tag}}')
  1847. latest=$(echo "$images" | sort -V | tail -n1)
  1848. for image in $images; do
  1849. if [ "$image" != "$latest" ]; then
  1850. docker rmi $image
  1851. fi
  1852. done
  1853. # 强制移除所有相关镜像
  1854. docker rmi --force $(docker images -q ${CMDUI_IMAGE_NAME}) &>/dev/null
  1855. }
  1856. function HUBCMDUI() {
  1857. CHECK_COMPOSE_CMD
  1858. CMDUI_NAME="hubcmd-ui"
  1859. CMDUI_DIR="${PROXY_DIR}/hubcmdui"
  1860. CMDUI_PROMPT() {
  1861. PUBLIC_IP=$(curl -s https://ifconfig.me)
  1862. ALL_IPS=$(hostname -I)
  1863. INTERNAL_IP=$(echo "$ALL_IPS" | awk '$1!="127.0.0.1" && $1!="::1" && $1!="docker0" {print $1}')
  1864. echo
  1865. INFO "=================感谢您的耐心等待,安装已经完成=================="
  1866. INFO
  1867. INFO "请用浏览器访问 HubCMD-UI 面板: "
  1868. INFO "公网访问地址: ${UNDERLINE}http://$PUBLIC_IP:30080${RESET}"
  1869. INFO "内网访问地址: ${UNDERLINE}http://$INTERNAL_IP:30080${RESET}"
  1870. INFO
  1871. INFO "后端访问地址: 地址后面跟admin,例: ${UNDERLINE}http://$INTERNAL_IP:30080/admin${RESET}"
  1872. INFO "默认账号密码: ${LIGHT_GREEN}root${RESET}/${LIGHT_CYAN}admin@123${RESET}"
  1873. INFO
  1874. INFO "服务安装路径: ${LIGHT_BLUE}${CMDUI_DIR}${RESET}"
  1875. INFO
  1876. INFO "作者博客: https://dqzboy.com"
  1877. INFO "技术交流: https://t.me/dqzboyblog"
  1878. INFO "代码仓库: https://github.com/dqzboy/Docker-Proxy"
  1879. INFO
  1880. INFO "AFF VPS推荐: https://dqzboy.github.io/proxyui/racknerd"
  1881. INFO
  1882. INFO "================================================================"
  1883. }
  1884. INSTALL_HUBCMDUI() {
  1885. mkdir -p ${CMDUI_DIR}
  1886. INFO "正在安装HubCMD-UI服务,请稍等!安装路径 ${LIGHT_CYAN}${CMDUI_DIR}${RESET}"
  1887. if [[ -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" ]]; then
  1888. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${CMDUI_NAME}$"; then
  1889. INFO "${CMDUI_NAME} 已经安装并启动,无需重复执行安装!"
  1890. else
  1891. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" up -d
  1892. fi
  1893. else
  1894. wget -NP ${CMDUI_DIR}/ ${CMDUI_COMPOSE_FILE} &>/dev/null
  1895. if [ $? -ne 0 ]; then
  1896. WARN "下载${LIGHT_YELLOW}docker-compose.yaml 文件失败${RESET},请稍后重试!"
  1897. HUBCMDUI
  1898. fi
  1899. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" up -d
  1900. if [ $? -eq 0 ]; then
  1901. CMDUI_PROMPT
  1902. exit 1
  1903. else
  1904. WARN "服务安装失败,请稍后重试!"
  1905. HUBCMDUI
  1906. fi
  1907. fi
  1908. }
  1909. UPDATE_HUBCMDUI() {
  1910. if [ -d "${CMDUI_DIR}" ]; then
  1911. if [ -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" ]; then
  1912. INFO "正在更新HubCMD-UI容器"
  1913. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" pull
  1914. if [ $? -ne 0 ]; then
  1915. WARN "HubCMD-UI ${LIGHT_YELLOW}镜像拉取失败${RESET},请稍后重试!"
  1916. HUBCMDUI
  1917. fi
  1918. $DOCKER_COMPOSE_CMD -f "${CMDUI_DIR}/${DOCKER_COMPOSE_FILE}" up -d --force-recreate
  1919. if [ $? -ne 0 ]; then
  1920. WARN "HubCMD-UI ${LIGHT_YELLOW}服务启动失败${RESET},请稍后重试!"
  1921. HUBCMDUI
  1922. else
  1923. INFO "HubCMD-UI ${LIGHT_GREEN}服务更新并启动完成${RESET}"
  1924. fi
  1925. else
  1926. WARN "${LIGHT_YELLOW}文件${CMDUI_DIR}/${DOCKER_COMPOSE_FILE} 不存在,无法进行更新操作!${RESET}"
  1927. fi
  1928. else
  1929. WARN "${LIGHT_YELLOW}目录 ${CMDUI_DIR} 不存在,无法进行更新操作!${RESET}"
  1930. fi
  1931. }
  1932. UNINSTALL_HUBCMDUI() {
  1933. WARN "${LIGHT_RED}注意:${RESET} ${LIGHT_YELLOW}请执行删除之前确定是否需要备份配置文件${RESET}"
  1934. while true; do
  1935. read -e -p "$(INFO "本人${LIGHT_RED}已知晓后果,确认删除${RESET}服务? ${PROMPT_YES_NO}")" delcmdui
  1936. case "$delcmdui" in
  1937. y|Y )
  1938. REMOVE_CMDUI
  1939. break;;
  1940. n|N )
  1941. WARN "退出执行卸载服务"
  1942. break;;
  1943. * )
  1944. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  1945. esac
  1946. done
  1947. }
  1948. SEPARATOR "HubCMD-UI管理"
  1949. echo -e "1) ${BOLD}${LIGHT_GREEN}安装${RESET}HubCMD-UI"
  1950. echo -e "2) ${BOLD}${LIGHT_YELLOW}卸载${RESET}HubCMD-UI"
  1951. echo -e "3) ${BOLD}${LIGHT_CYAN}更新${RESET}HubCMD-UI"
  1952. echo -e "4) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  1953. echo -e "0) ${BOLD}退出脚本${RESET}"
  1954. echo "---------------------------------------------------------------"
  1955. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" cmdui_choice
  1956. case $cmdui_choice in
  1957. 1)
  1958. INSTALL_HUBCMDUI
  1959. HUBCMDUI
  1960. ;;
  1961. 2)
  1962. UNINSTALL_HUBCMDUI
  1963. HUBCMDUI
  1964. ;;
  1965. 3)
  1966. UPDATE_HUBCMDUI
  1967. HUBCMDUI
  1968. ;;
  1969. 4)
  1970. main_menu
  1971. ;;
  1972. 0)
  1973. exit 1
  1974. ;;
  1975. *)
  1976. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-4${RESET}的选项."
  1977. HUBCMDUI
  1978. ;;
  1979. esac
  1980. }
  1981. function COMP_INST() {
  1982. SEPARATOR "安装组件"
  1983. echo -e "1) ${BOLD}安装${LIGHT_GREEN}环境依赖${RESET}"
  1984. echo -e "2) ${BOLD}安装${LIGHT_CYAN}Docker${RESET}"
  1985. echo -e "3) ${BOLD}安装${LIGHT_MAGENTA}Compose${RESET}"
  1986. echo -e "4) ${BOLD}安装${GREEN}Nginx${RESET}"
  1987. echo -e "5) ${BOLD}安装${LIGHT_BLUE}Caddy${RESET}"
  1988. echo -e "6) ${BOLD}配置${LIGHT_YELLOW}Nginx${RESET}"
  1989. echo -e "7) ${BOLD}配置${CYAN}Caddy${RESET}"
  1990. echo -e "8) ${BOLD}安装${BLUE}HubCMD-UI${RESET}"
  1991. echo -e "9) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  1992. echo -e "0) ${BOLD}退出脚本${RESET}"
  1993. echo "---------------------------------------------------------------"
  1994. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" comp_choice
  1995. case $comp_choice in
  1996. 1)
  1997. CHECK_OS
  1998. CHECK_PACKAGE_MANAGER
  1999. CHECK_PKG_MANAGER
  2000. CHECKMEM
  2001. PACKAGE
  2002. COMP_INST
  2003. ;;
  2004. 2)
  2005. CHECK_OS
  2006. CHECK_PACKAGE_MANAGER
  2007. CHECK_PKG_MANAGER
  2008. while true; do
  2009. SEPARATOR "安装Docker"
  2010. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" deploy_docker
  2011. case "$deploy_docker" in
  2012. 1 )
  2013. INSTALL_DOCKER
  2014. break;;
  2015. 2 )
  2016. INSTALL_DOCKER_CN
  2017. break;;
  2018. * )
  2019. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  2020. esac
  2021. done
  2022. COMP_INST
  2023. ;;
  2024. 3)
  2025. CHECK_OS
  2026. CHECK_PACKAGE_MANAGER
  2027. CHECK_PKG_MANAGER
  2028. CHECK_COMPOSE_CMD
  2029. while true; do
  2030. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" deploy_compose
  2031. case "$deploy_compose" in
  2032. 1 )
  2033. INSTALL_COMPOSE
  2034. break;;
  2035. 2 )
  2036. INSTALL_COMPOSE_CN
  2037. break;;
  2038. * )
  2039. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  2040. esac
  2041. done
  2042. COMP_INST
  2043. ;;
  2044. 4)
  2045. CHECK_OS
  2046. CHECK_PACKAGE_MANAGER
  2047. CHECK_PKG_MANAGER
  2048. INSTALL_NGINX
  2049. COMP_INST
  2050. ;;
  2051. 5)
  2052. CHECK_OS
  2053. CHECK_PACKAGE_MANAGER
  2054. CHECK_PKG_MANAGER
  2055. INSTALL_CADDY
  2056. COMP_INST
  2057. ;;
  2058. 6)
  2059. CONFIG_NGINX
  2060. COMP_INST
  2061. ;;
  2062. 7)
  2063. CONFIG_CADDY
  2064. COMP_INST
  2065. ;;
  2066. 8)
  2067. HUBCMDUI
  2068. COMP_INST
  2069. ;;
  2070. 9)
  2071. main_menu
  2072. ;;
  2073. 0)
  2074. exit 1
  2075. ;;
  2076. *)
  2077. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-8${RESET}的选项."
  2078. COMP_INST
  2079. ;;
  2080. esac
  2081. }
  2082. function SVC_MGMT() {
  2083. CHECK_COMPOSE_CMD
  2084. RESTART_SERVICE() {
  2085. CONTAINER_SERVICES
  2086. selected_services=()
  2087. WARN "重启服务请在${LIGHT_GREEN}${DOCKER_COMPOSE_FILE}${RESET}文件存储目录下执行脚本.默认安装路径: ${LIGHT_BLUE}${PROXY_DIR}${RESET}"
  2088. REGISTRY_MENU
  2089. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" restart_service
  2090. while true; do
  2091. if [[ "$restart_service" =~ ^[0-9]+([[:space:]][0-9]+)*$ ]]; then
  2092. valid=true
  2093. for choice in $restart_service; do
  2094. if ((choice < 0 || choice > 10)); then
  2095. valid=false
  2096. break
  2097. fi
  2098. done
  2099. if $valid; then
  2100. break
  2101. fi
  2102. fi
  2103. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-10 ${RESET}序号"
  2104. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" restart_service
  2105. done
  2106. if [[ "$restart_service" == "10" ]]; then
  2107. for service_name in "${services[@]}"; do
  2108. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2109. selected_services+=("$service_name")
  2110. else
  2111. WARN "服务 ${service_name}未运行,跳过重启。"
  2112. fi
  2113. done
  2114. if [ ${#selected_services[@]} -eq 0 ]; then
  2115. WARN "选择的服务未运行,无需进行重启"
  2116. else
  2117. INFO "更新的服务: ${selected_services[*]}"
  2118. fi
  2119. elif [[ "$restart_service" == "0" ]]; then
  2120. WARN "退出重启服务!"
  2121. SVC_MGMT
  2122. else
  2123. for choice in ${restart_service}; do
  2124. if ((choice > 0 && choice < 10)); then
  2125. service_name="${services[$((choice -1))]}"
  2126. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2127. selected_services+=("$service_name")
  2128. else
  2129. WARN "服务 ${service_name} 未运行,跳过重启。"
  2130. fi
  2131. else
  2132. ERROR "无效的选择: $choice. 请重新${LIGHT_GREEN}选择0-9${RESET}的选项"
  2133. RESTART_SERVICE # 选择无效重新调用当前函数进行选择
  2134. fi
  2135. done
  2136. if [ ${#selected_services[@]} -eq 0 ]; then
  2137. WARN "选择的服务未运行,无需进行重启"
  2138. else
  2139. INFO "更新的服务: ${selected_services[*]}"
  2140. fi
  2141. fi
  2142. }
  2143. UPDATE_SERVICE() {
  2144. CONTAINER_SERVICES
  2145. selected_services=()
  2146. WARN "更新服务请在${LIGHT_GREEN}${DOCKER_COMPOSE_FILE}${RESET}文件存储目录下执行脚本.默认安装路径: ${LIGHT_BLUE}${PROXY_DIR}${RESET}"
  2147. REGISTRY_MENU
  2148. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" update_service
  2149. while true; do
  2150. if [[ "$update_service" =~ ^[0-9]+([[:space:]][0-9]+)*$ ]]; then
  2151. valid=true
  2152. for choice in $update_service; do
  2153. if ((choice < 0 || choice > 10)); then
  2154. valid=false
  2155. break
  2156. fi
  2157. done
  2158. if $valid; then
  2159. break
  2160. fi
  2161. fi
  2162. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-10 ${RESET}序号"
  2163. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all表示所有${RESET} > ")" update_service
  2164. done
  2165. if [[ "$update_service" == "10" ]]; then
  2166. for service_name in "${services[@]}"; do
  2167. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2168. selected_services+=("$service_name")
  2169. else
  2170. WARN "服务 ${service_name}未运行,跳过更新。"
  2171. fi
  2172. done
  2173. if [ ${#selected_services[@]} -eq 0 ]; then
  2174. WARN "选择的服务未运行,无法进行更新"
  2175. else
  2176. INFO "更新的服务: ${selected_services[*]}"
  2177. fi
  2178. elif [[ "$update_service" == "0" ]]; then
  2179. WARN "退出更新服务!"
  2180. SVC_MGMT
  2181. else
  2182. for choice in ${update_service}; do
  2183. if ((choice > 0 && choice < 10)); then
  2184. service_name="${services[$((choice -1))]}"
  2185. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2186. selected_services+=("$service_name")
  2187. else
  2188. WARN "服务 ${service_name} 未运行,跳过更新。"
  2189. fi
  2190. else
  2191. ERROR "无效的选择: $choice. 请重新${LIGHT_GREEN}选择0-9${RESET}的选项"
  2192. UPDATE_SERVICE # 选择无效重新调用当前函数进行选择
  2193. fi
  2194. done
  2195. if [ ${#selected_services[@]} -eq 0 ]; then
  2196. WARN "选择的服务未运行,无法进行更新"
  2197. else
  2198. INFO "更新的服务: ${selected_services[*]}"
  2199. fi
  2200. fi
  2201. }
  2202. CONTAIENR_LOGS() {
  2203. CONTAINER_SERVICES
  2204. selected_services=()
  2205. REGISTRY_SER_MENU
  2206. read -e -p "$(INFO "输入序号选择对应服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项. ${LIGHT_CYAN}all选择所有${RESET} > ")" restart_service
  2207. if [[ "$restart_service" == "0" ]]; then
  2208. WARN "退出查看容器服务日志操作!"
  2209. SVC_MGMT
  2210. else
  2211. for choice in ${restart_service}; do
  2212. if [[ $choice =~ ^[0-9]+$ ]] && ((choice >0 && choice <= ${#services[@]})); then
  2213. service_name="${services[$((choice -1))]}"
  2214. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2215. selected_services+=("$service_name")
  2216. else
  2217. WARN "服务 ${service_name} 未运行,无法查看容器日志。"
  2218. fi
  2219. else
  2220. ERROR "无效的选择: $choice. 请重新${LIGHT_GREEN}选择0-9${RESET}的选项"
  2221. CONTAIENR_LOGS # 选择无效重新调用当前函数进行选择
  2222. fi
  2223. done
  2224. if [ ${#selected_services[@]} -eq 0 ]; then
  2225. WARN "选择的服务未运行,无法查看日志"
  2226. else
  2227. INFO "查看日志的服务: ${selected_services[*]}"
  2228. fi
  2229. fi
  2230. }
  2231. MODIFY_SERVICE_TTL_CONFIG() {
  2232. selected_services=()
  2233. selected_files=()
  2234. existing_files=()
  2235. non_existing_files=()
  2236. REGISTRY_FILES
  2237. while true; do
  2238. REGISTRY_SER_MENU
  2239. read -e -p "$(INFO "输入序号修改服务对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" ttl_service
  2240. if [[ "$ttl_service" == "0" ]]; then
  2241. WARN "退出修改容器服务缓存配置!"
  2242. SVC_MGMT
  2243. elif [[ "$ttl_service" =~ ^([1-8]+[[:space:]]*)+$ ]]; then
  2244. break
  2245. else
  2246. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2247. fi
  2248. done
  2249. for choice in ${ttl_service}; do
  2250. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2251. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2252. selected_files+=("$file_name")
  2253. if [ -f "${PROXY_DIR}/${file_name}" ]; then
  2254. existing_files+=("$file_name")
  2255. selected_services+=("$service_name")
  2256. else
  2257. non_existing_files+=("$file_name")
  2258. fi
  2259. if ! $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2260. WARN "服务 ${service_name} 未运行。"
  2261. fi
  2262. done
  2263. if [ ${#existing_files[@]} -gt 0 ]; then
  2264. INFO "${GREEN}存在的配置文件:${RESET} ${existing_files[*]}${RESET}"
  2265. fi
  2266. if [ ${#non_existing_files[@]} -gt 0 ]; then
  2267. WARN "${RED}不存在的配置文件:${RESET} ${non_existing_files[*]}"
  2268. fi
  2269. if [ ${#existing_files[@]} -gt 0 ]; then
  2270. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_BLUE}Proxy代理缓存过期时间${RESET} ${MAGENTA}单位:ns、us、ms、s、m、h.默认ns,0不清除缓存${RESET}"
  2271. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2272. while [[ "$modify_cache" != "y" && "$modify_cache" != "n" ]]; do
  2273. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  2274. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2275. done
  2276. if [[ "$modify_cache" == "y" ]]; then
  2277. while true; do
  2278. read -e -p "$(INFO "请输入新的缓存时间值: ")" new_ttl
  2279. for file_url in "${existing_files[@]}"; do
  2280. yml_name=$(basename "$file_url")
  2281. WARN "${YELLOW}正在修改配置文件: ${PROXY_DIR}/${yml_name}${RESET}"
  2282. sed -i "s/ttl: .*/ttl: ${new_ttl}/g" "${PROXY_DIR}/${yml_name}" &>/dev/null
  2283. INFO "${GREEN}配置文件 ${yml_name} 修改完成,代理缓存过期时间已设置为: ${new_ttl}${RESET}"
  2284. done
  2285. break
  2286. done
  2287. fi
  2288. else
  2289. WARN "未选择有效的配置文件进行修改。"
  2290. fi
  2291. }
  2292. ### 启动新容器
  2293. START_NEW_SERVER_DOWN_CONFIG() {
  2294. selected_names=()
  2295. selected_files=()
  2296. selected_containers=()
  2297. REGISTRY_SER_MENU
  2298. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" choices_newser
  2299. while [[ ! "$choices_newser" =~ ^([0-9]+[[:space:]]*)+$ ]]; do
  2300. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2301. read -e -p "$(INFO "输入序号下载对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" choices_newser
  2302. done
  2303. if [[ "$choices_newser" == "0" ]]; then
  2304. WARN "退出下载配置! ${LIGHT_YELLOW}没有配置将无法启动服务!!!${RESET}"
  2305. SVC_MGMT
  2306. else
  2307. for choice in ${choices_newser}; do
  2308. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2309. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2310. container_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2311. file_url=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f3-)
  2312. selected_names+=("$file_name")
  2313. selected_containers+=("$container_name")
  2314. selected_files+=("$file_url")
  2315. wget -NP ${PROXY_DIR}/ $file_url &>/dev/null
  2316. else
  2317. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2318. fi
  2319. done
  2320. fi
  2321. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_BLUE}Proxy代理缓存过期时间${RESET} ${MAGENTA}单位:ns、us、ms、s、m、h.默认ns,0不清除缓存${RESET}"
  2322. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2323. while [[ "$modify_cache" != "y" && "$modify_cache" != "n" ]]; do
  2324. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  2325. read -e -p "$(INFO "是否要修改缓存时间? ${PROMPT_YES_NO}")" modify_cache
  2326. done
  2327. if [[ "$modify_cache" == "y" ]]; then
  2328. while true; do
  2329. read -e -p "$(INFO "请输入新的缓存时间值: ")" new_ttl
  2330. for file_url in "${selected_files[@]}"; do
  2331. yml_name=$(basename "$file_url")
  2332. sed -ri "s/ttl: 168h/ttl: ${new_ttl}/g" ${PROXY_DIR}/${yml_name} &>/dev/null
  2333. done
  2334. break
  2335. done
  2336. fi
  2337. }
  2338. START_NEW_DOCKER_SERVICE() {
  2339. if [ -d "${PROXY_DIR}" ]; then
  2340. if [ -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" ]; then
  2341. CONFIG_FILES
  2342. START_NEW_SERVER_DOWN_CONFIG
  2343. PROXY_HTTP
  2344. INFO "正在启动新的容器服务,请稍等..."
  2345. $DOCKER_COMPOSE_CMD -f "${PROXY_DIR}/${DOCKER_COMPOSE_FILE}" up -d "${selected_names[@]}"
  2346. if [ $? -ne 0 ]; then
  2347. WARN "${selected_names[*]} ${LIGHT_YELLOW}服务启动失败${RESET},请排查!"
  2348. else
  2349. INFO "${selected_names[*]} ${LIGHT_GREEN}服务启动完成${RESET}"
  2350. fi
  2351. else
  2352. WARN "${LIGHT_YELLOW}文件${PROXY_DIR}/${DOCKER_COMPOSE_FILE} 不存在,无法启动新的容器!${RESET}"
  2353. fi
  2354. else
  2355. WARN "${LIGHT_YELLOW}目录 ${PROXY_DIR} 不存在,无法启动新的容器!${RESET}"
  2356. fi
  2357. }
  2358. ### 启动新容器 END
  2359. SEPARATOR "服务管理"
  2360. echo -e "1) ${BOLD}${LIGHT_GREEN}重启${RESET}服务"
  2361. echo -e "2) ${BOLD}${LIGHT_CYAN}更新${RESET}服务"
  2362. echo -e "3) ${BOLD}${LIGHT_MAGENTA}查看${RESET}日志"
  2363. echo -e "4) ${BOLD}${LIGHT_BLUE}缓存${RESET}时效"
  2364. echo -e "5) ${BOLD}启动${CYAN}新服务${RESET}"
  2365. echo -e "6) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2366. echo -e "0) ${BOLD}退出脚本${RESET}"
  2367. echo "---------------------------------------------------------------"
  2368. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" ser_choice
  2369. case $ser_choice in
  2370. 1)
  2371. RESTART_SERVICE
  2372. if [ ${#selected_services[@]} -eq 0 ]; then
  2373. ERROR "没有需要重启的服务,请重新选择"
  2374. RESTART_SERVICE
  2375. else
  2376. $DOCKER_COMPOSE_CMD stop ${selected_services[*]}
  2377. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2378. fi
  2379. SVC_MGMT
  2380. ;;
  2381. 2)
  2382. UPDATE_SERVICE
  2383. if [ ${#selected_services[@]} -eq 0 ]; then
  2384. ERROR "没有需要更新的服务,请重新选择"
  2385. UPDATE_SERVICE
  2386. else
  2387. $DOCKER_COMPOSE_CMD pull ${selected_services[*]}
  2388. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2389. fi
  2390. SVC_MGMT
  2391. ;;
  2392. 3)
  2393. CONTAIENR_LOGS
  2394. if [ ${#selected_services[@]} -eq 0 ]; then
  2395. ERROR "没有需要查看的服务,请重新选择"
  2396. CONTAIENR_LOGS
  2397. else
  2398. # 查看最近30条日志
  2399. $DOCKER_COMPOSE_CMD logs --tail=30 ${selected_services[*]}
  2400. fi
  2401. SVC_MGMT
  2402. ;;
  2403. 4)
  2404. MODIFY_SERVICE_TTL_CONFIG
  2405. if [ ${#selected_services[@]} -eq 0 ]; then
  2406. ERROR "修改的服务未运行,请重新选择"
  2407. MODIFY_SERVICE_TTL_CONFIG
  2408. else
  2409. $DOCKER_COMPOSE_CMD restart ${selected_services[*]}
  2410. fi
  2411. SVC_MGMT
  2412. ;;
  2413. 5)
  2414. START_NEW_DOCKER_SERVICE
  2415. SVC_MGMT
  2416. ;;
  2417. 6)
  2418. main_menu
  2419. ;;
  2420. 0)
  2421. exit 1
  2422. ;;
  2423. *)
  2424. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-5${RESET}的选项."
  2425. SVC_MGMT
  2426. ;;
  2427. esac
  2428. }
  2429. function ADD_SYS_CMD() {
  2430. MAX_ATTEMPTS=3
  2431. attempt=0
  2432. success=false
  2433. TARGET_PATH="/usr/bin/hub"
  2434. INSTALL_ENV() {
  2435. while true; do
  2436. read -e -p "$(INFO "安装环境确认 [${LIGHT_GREEN}国外输1${RESET} ${LIGHT_YELLOW}国内输2${RESET}] > ")" sys_cmd
  2437. case "$sys_cmd" in
  2438. 1 )
  2439. DOWNLOAD_URL="https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main/install/DockerProxy_Install.sh"
  2440. break;;
  2441. 2 )
  2442. DOWNLOAD_URL="https://cdn.jsdelivr.net/gh/dqzboy/Docker-Proxy/install/DockerProxy_Install.sh"
  2443. break;;
  2444. * )
  2445. INFO "请输入 ${LIGHT_GREEN}1${RESET} 表示国外 或者 ${LIGHT_YELLOW}2${RESET} 表示大陆";;
  2446. esac
  2447. done
  2448. }
  2449. INSTALL_OR_UPDATE_CMD() {
  2450. local action=$1
  2451. while [[ $attempt -lt $MAX_ATTEMPTS ]]; do
  2452. attempt=$((attempt + 1))
  2453. if [[ "$action" == "安装" ]]; then
  2454. if command -v hub &> /dev/null; then
  2455. INFO "系统命令已存在,无需安装。"
  2456. success=true
  2457. break
  2458. fi
  2459. WARN "正在安装脚本中,请稍等..."
  2460. else
  2461. WARN "正在进行脚本更新,请稍等..."
  2462. if [ -f "$TARGET_PATH" ]; then
  2463. rm -f "$TARGET_PATH" &>/dev/null
  2464. fi
  2465. fi
  2466. wget -q -O "$TARGET_PATH" "$DOWNLOAD_URL" &>/dev/null
  2467. if [ $? -eq 0 ]; then
  2468. success=true
  2469. chmod +x "$TARGET_PATH"
  2470. break
  2471. fi
  2472. ERROR "${action}脚本${RED}失败${RESET},正在尝试重新${action} (尝试次数: $attempt)"
  2473. done
  2474. if $success; then
  2475. INFO "${action}脚本${GREEN}成功${RESET},命令行输入 ${LIGHT_GREEN}hub${RESET} 运行"
  2476. else
  2477. ERROR "设置系统命令失败"
  2478. exit 1
  2479. fi
  2480. }
  2481. SEPARATOR "设置脚本为系统命令"
  2482. echo -e "1) ${BOLD}安装${LIGHT_GREEN}系统命令${RESET}"
  2483. echo -e "2) ${BOLD}更新${LIGHT_CYAN}系统命令${RESET}"
  2484. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2485. echo -e "0) ${BOLD}退出脚本${RESET}"
  2486. echo "---------------------------------------------------------------"
  2487. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" cmd_choice
  2488. case $cmd_choice in
  2489. 1)
  2490. INSTALL_ENV
  2491. INSTALL_OR_UPDATE_CMD "安装"
  2492. ;;
  2493. 2)
  2494. INSTALL_ENV
  2495. INSTALL_OR_UPDATE_CMD "更新"
  2496. ;;
  2497. 3)
  2498. main_menu
  2499. ;;
  2500. 0)
  2501. exit 1
  2502. ;;
  2503. *)
  2504. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2505. ADD_SYS_CMD
  2506. ;;
  2507. esac
  2508. }
  2509. function UNI_DOCKER_SERVICE() {
  2510. CHECK_COMPOSE_CMD
  2511. RM_SERVICE() {
  2512. selected_containers=()
  2513. REGISTRY_FILES
  2514. REGISTRY_SER_MENU
  2515. read -e -p "$(INFO "输入序号删除服务和对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" rm_service
  2516. while [[ ! "$rm_service" =~ ^([0-9]+[[:space:]]*)+$ ]]; do
  2517. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2518. read -e -p "$(INFO "输入序号删除服务和对应配置文件,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" rm_service
  2519. done
  2520. if [[ "$rm_service" == "0" ]]; then
  2521. WARN "退出删除容器服务操作!"
  2522. return
  2523. else
  2524. selected_services=()
  2525. for choice in ${rm_service}; do
  2526. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2527. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2528. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2529. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2530. selected_services+=("$service_name")
  2531. else
  2532. WARN "服务 ${LIGHT_MAGENTA}${service_name} 未运行${RESET},但将尝试删除相关文件。"
  2533. fi
  2534. if [ -f "${PROXY_DIR}/${file_name}" ]; then
  2535. rm -f "${PROXY_DIR}/${file_name}"
  2536. INFO "配置文件 ${LIGHT_CYAN}${file_name}${RESET} ${LIGHT_GREEN}已被删除${RESET}"
  2537. else
  2538. WARN "配置文件 ${LIGHT_CYAN}${file_name}${RESET} 不存在,${LIGHT_YELLOW}无需删除${RESET}"
  2539. fi
  2540. else
  2541. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2542. UNI_DOCKER_SERVICE
  2543. return
  2544. fi
  2545. done
  2546. # 一次性删除所有选中的服务
  2547. if [ ${#selected_services[@]} -gt 0 ]; then
  2548. INFO "删除的服务: ${LIGHT_RED}${selected_services[*]}${RESET}"
  2549. $DOCKER_COMPOSE_CMD down ${selected_services[*]}
  2550. fi
  2551. fi
  2552. }
  2553. RM_ALLSERVICE() {
  2554. STOP_REMOVE_CONTAINER
  2555. REMOVE_NONE_TAG
  2556. REMOVE_CMDUI
  2557. docker rmi --force $(docker images -q ${IMAGE_NAME}) &>/dev/null
  2558. docker rmi --force $(docker images -q ${UI_IMAGE_NAME}) &>/dev/null
  2559. if [ -d "${PROXY_DIR}" ]; then
  2560. rm -rf "${PROXY_DIR}" &>/dev/null
  2561. fi
  2562. if [ -f "/usr/bin/hub" ]; then
  2563. rm -f /usr/bin/hub &>/dev/null
  2564. fi
  2565. INFO "${LIGHT_YELLOW}感谢您的使用,Docker-Proxy服务已卸载。欢迎您再次使用!${RESET}"
  2566. SEPARATOR "DONE"
  2567. }
  2568. CONFIREM_ACTION() {
  2569. local action_name=$1
  2570. local action_function=$2
  2571. WARN "${LIGHT_RED}注意:${RESET} ${LIGHT_YELLOW}卸载服务会一同将本地的配置和对应服务删除,请执行删除之前确定是否需要备份本地的配置文件${RESET}"
  2572. while true; do
  2573. read -e -p "$(INFO "本人${LIGHT_RED}已知晓后果,确认${action_name}${RESET}服务? ${PROMPT_YES_NO}")" uniservice
  2574. case "$uniservice" in
  2575. y|Y )
  2576. $action_function
  2577. break;;
  2578. n|N )
  2579. WARN "退出${action_name}服务."
  2580. break;;
  2581. * )
  2582. INFO "请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}";;
  2583. esac
  2584. done
  2585. }
  2586. SEPARATOR "卸载服务"
  2587. echo -e "1) ${BOLD}卸载${LIGHT_YELLOW}所有服务${RESET}"
  2588. echo -e "2) ${BOLD}删除${LIGHT_CYAN}指定服务${RESET}"
  2589. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2590. echo -e "0) ${BOLD}退出脚本${RESET}"
  2591. echo "---------------------------------------------------------------"
  2592. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" rm_choice
  2593. case $rm_choice in
  2594. 1)
  2595. CONFIREM_ACTION "卸载所有" RM_ALLSERVICE
  2596. ;;
  2597. 2)
  2598. CONFIREM_ACTION "删除指定" RM_SERVICE
  2599. UNI_DOCKER_SERVICE
  2600. ;;
  2601. 3)
  2602. main_menu
  2603. ;;
  2604. 0)
  2605. exit 1
  2606. ;;
  2607. *)
  2608. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2609. UNI_DOCKER_SERVICE
  2610. ;;
  2611. esac
  2612. }
  2613. function AUTH_SERVICE_CONFIG() {
  2614. CHECK_COMPOSE_CMD
  2615. CHECK_REG_AUTH() {
  2616. if ! command -v docker &> /dev/null; then
  2617. ERROR "docker 命令未找到,请确保 Docker 已正确安装"
  2618. AUTH_SERVICE_CONFIG
  2619. fi
  2620. # 重置数组
  2621. running_containers=()
  2622. stopped_containers=()
  2623. auth_containers=()
  2624. non_auth_containers=()
  2625. declare -A services
  2626. services=(
  2627. ["reg-docker-hub"]="dockerhub"
  2628. ["reg-gcr"]="gcr"
  2629. ["reg-ghcr"]="ghcr"
  2630. ["reg-quay"]="quay"
  2631. ["reg-k8s-gcr"]="k8sgcr"
  2632. ["reg-k8s"]="k8s"
  2633. ["reg-mcr"]="mcr"
  2634. ["reg-elastic"]="elastic"
  2635. ["reg-nvcr"]="nvcr"
  2636. )
  2637. container_names=$(docker ps --filter "name=reg-" --filter "status=running" --format "{{.Names}}")
  2638. # 检查哪些容器正在运行
  2639. for container_name in "${!services[@]}"; do
  2640. if docker ps --filter "name=$container_name" --filter "status=running" --format "{{.Names}}" | grep -q "$container_name"; then
  2641. running_containers+=("${services[$container_name]}")
  2642. else
  2643. stopped_containers+=("${services[$container_name]}")
  2644. fi
  2645. done
  2646. if [ ${#running_containers[@]} -gt 0 ]; then
  2647. INFO "当前运行的 Docker 容器有: ${LIGHT_CYAN}${running_containers[*]}${RESET}"
  2648. else
  2649. WARN "当前没有运行的 Docker 容器"
  2650. AUTH_SERVICE_CONFIG # 如果没有运行的容器,直接返回
  2651. fi
  2652. auth_containers=()
  2653. non_auth_containers=()
  2654. for container_name in $container_names; do
  2655. specified_name=${services[$container_name]}
  2656. if [ -z "$specified_name" ]; then
  2657. specified_name=$container_name
  2658. fi
  2659. if docker exec $container_name grep -q "auth" /etc/distribution/config.yml; then
  2660. auth_containers+=("$specified_name")
  2661. else
  2662. non_auth_containers+=("$specified_name")
  2663. fi
  2664. done
  2665. if [ ${#auth_containers[@]} -gt 0 ]; then
  2666. INFO "当前运行的 Docker 容器中${LIGHT_GREEN}包含认证${RESET}的容器有: ${LIGHT_CYAN}${auth_containers[*]}${RESET}"
  2667. else
  2668. WARN "当前运行的 Docker 容器中${LIGHT_YELLOW}没有包含认证${RESET}的容器"
  2669. fi
  2670. if [ ${#non_auth_containers[@]} -gt 0 ]; then
  2671. WARN "当前运行的 Docker 容器中${LIGHT_YELLOW}没有包含认证${RESET}的容器有: ${LIGHT_BLUE}${non_auth_containers[*]}${RESET}"
  2672. else
  2673. INFO "当前运行的 Docker 容器中${LIGHT_GREEN}所有容器都包含认证${RESET}"
  2674. fi
  2675. }
  2676. AUTH_MENU() {
  2677. CHECK_REG_AUTH
  2678. selected_files=()
  2679. selected_services=()
  2680. REGISTRY_FILES
  2681. REGISTRY_SER_MENU
  2682. read -e -p "$(INFO "输入序号选择添加认证的服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" auth_service
  2683. while [[ ! "$auth_service" =~ ^([0-9]+[[:space:]]*)+$ ]]; do
  2684. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2685. read -e -p "$(INFO "输入序号选择添加认证的服务,${LIGHT_YELLOW}空格分隔${RESET}多个选项 > ")" auth_service
  2686. done
  2687. }
  2688. ADD_AUTH_CONFIG() {
  2689. local FILE=$1
  2690. local auth_config="
  2691. auth:
  2692. htpasswd:
  2693. realm: basic-realm
  2694. path: /auth/htpasswd"
  2695. if [ ! -f "$FILE" ]; then
  2696. ERROR "配置文件 ${LIGHT_BLUE}$FILE${RESET} 不存在"
  2697. exit 1
  2698. else
  2699. if ! grep -q "auth:" "$FILE" || ! grep -q "htpasswd:" "$FILE" || ! grep -q "realm: basic-realm" "$FILE" || ! grep -q "path: /auth/htpasswd" "$FILE"; then
  2700. echo -e "$auth_config" | sudo tee -a "$FILE" > /dev/null
  2701. INFO "配置文件 ${LIGHT_BLUE}$FILE${RESET} 添加认证配置成功"
  2702. else
  2703. WARN "配置文件 ${LIGHT_BLUE}$FILE${RESET} 已添加认证配置"
  2704. fi
  2705. fi
  2706. }
  2707. ADD_AUTH_COMPOSE() {
  2708. local SERVICES=$1
  2709. local FILE=${DOCKER_COMPOSE_FILE}
  2710. local HTPASSWD_CONFIG=" - ./${SERVICES}_htpasswd:/auth/htpasswd"
  2711. if [ ! -f "$FILE" ]; then
  2712. ERROR "配置文件 ${LIGHT_BLUE}$FILE${RESET} 不存在"
  2713. exit 1
  2714. fi
  2715. for SERVICE in "${SERVICES[@]}"; do
  2716. if grep -q " $SERVICE:" "$FILE"; then
  2717. if ! grep -A10 " $SERVICE:" "$FILE" | grep -q " - ./${SERVICES}_htpasswd:/auth/htpasswd"; then
  2718. sed -i "/ $SERVICE:/,/volumes:/ {
  2719. /volumes:/a\\
  2720. $HTPASSWD_CONFIG
  2721. }" "$FILE"
  2722. INFO "Htpasswd配置添加到 ${LIGHT_GREEN}$SERVICE${RESET} 服务中"
  2723. else
  2724. WARN "Htpasswd配置已存在 ${LIGHT_YELLOW}$SERVICE${RESET} 服务中"
  2725. fi
  2726. else
  2727. ERROR "服务 $SERVICE 在 $FILE 中不存在"
  2728. fi
  2729. done
  2730. }
  2731. DEL_AUTH_CONFIG() {
  2732. local FILE=$1
  2733. if [ ! -f "$FILE" ]; then
  2734. ERROR "配置文件 $FILE 不存在"
  2735. else
  2736. if grep -q "auth:" "$FILE"; then
  2737. sed -i '/^auth:$/,/^[^[:space:]]/d' "$FILE" >/dev/null
  2738. INFO "配置文件 ${LIGHT_BLUE}$FILE${RESET} 成功移除认证信息"
  2739. else
  2740. WARN "配置文件 ${LIGHT_BLUE}$FILE${RESET} 不存在认证信息"
  2741. fi
  2742. fi
  2743. }
  2744. DEL_AUTH_COMPOSE() {
  2745. local SERVICES=$1
  2746. local FILE=${DOCKER_COMPOSE_FILE}
  2747. if [ ! -f "$FILE" ]; then
  2748. ERROR "$File 不存在"
  2749. exit 1
  2750. fi
  2751. for SERVICE in "${SERVICES[@]}"; do
  2752. if grep -q " $SERVICE:" "$FILE"; then
  2753. sed -i "/ $SERVICE:/,/^[^[:space:]]/ {/^[[:space:]]*- .\/${SERVICES}_htpasswd:\/auth\/htpasswd/d}" "$FILE"
  2754. else
  2755. ERROR "$FILE 中不存在服务 $SERVICE"
  2756. fi
  2757. done
  2758. }
  2759. ENABLE_AUTH() {
  2760. AUTH_MENU
  2761. if [[ "$auth_service" == "0" ]]; then
  2762. WARN "退出添加容器认证操作!"
  2763. return
  2764. else
  2765. for choice in ${auth_service}; do
  2766. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2767. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2768. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2769. selected_files+=("$file_name")
  2770. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2771. selected_services+=("$service_name")
  2772. else
  2773. WARN "服务 ${LIGHT_MAGENTA}${service_name} 未运行${RESET},无法添加认证授权"
  2774. fi
  2775. else
  2776. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2777. AUTH_MENU
  2778. return
  2779. fi
  2780. done
  2781. WARN "${LIGHT_GREEN}>>> 提示:${RESET} ${LIGHT_CYAN}配置认证后,执行镜像拉取需先通过 docker login登入后使用.访问UI需输入账号密码${RESET}"
  2782. read -e -p "$(INFO "是否需要配置镜像仓库访问账号和密码? ${PROMPT_YES_NO}")" enable_auth
  2783. while [[ "$enable_auth" != "y" && "$enable_auth" != "n" ]]; do
  2784. WARN "无效输入,请输入 ${LIGHT_GREEN}y${RESET} 或 ${LIGHT_YELLOW}n${RESET}"
  2785. read -e -p "$(INFO "是否需要配置镜像仓库访问账号和密码? ${PROMPT_YES_NO}")" enable_auth
  2786. done
  2787. if [[ "$enable_auth" == "y" ]]; then
  2788. while true; do
  2789. read -e -p "$(INFO "请输入账号名称: ")" username
  2790. if [[ -z "$username" ]]; then
  2791. ERROR "用户名不能为空。请重新输入"
  2792. else
  2793. break
  2794. fi
  2795. done
  2796. while true; do
  2797. read -e -p "$(INFO "请输入账号密码: ")" password
  2798. if [[ -z "$password" ]]; then
  2799. ERROR "密码不能为空。请重新输入"
  2800. else
  2801. break
  2802. fi
  2803. done
  2804. for file_url in "${selected_files[@]}"; do
  2805. yml_name=$(basename "$file_url")
  2806. ADD_AUTH_CONFIG "${PROXY_DIR}/${yml_name}"
  2807. done
  2808. for server in "${selected_services[@]}"; do
  2809. htpasswd -Bbc ${PROXY_DIR}/${server}_htpasswd "$username" "$password" 2>/dev/null
  2810. ADD_AUTH_COMPOSE "${server}"
  2811. done
  2812. fi
  2813. fi
  2814. }
  2815. DELETE_AUTH() {
  2816. AUTH_MENU
  2817. if [[ "$auth_service" == "0" ]]; then
  2818. WARN "退出移除容器认证操作!"
  2819. return
  2820. else
  2821. for choice in ${auth_service}; do
  2822. if [[ $choice =~ ^[0-9]+$ ]] && ((choice > 0 && choice <= ${#files[@]})); then
  2823. file_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f2)
  2824. service_name=$(echo "${files[$((choice - 1))]}" | cut -d' ' -f1)
  2825. selected_files+=("$file_name")
  2826. if $DOCKER_COMPOSE_CMD ps --services 2>/dev/null | grep -q "^${service_name}$"; then
  2827. selected_services+=("$service_name")
  2828. else
  2829. WARN "服务 ${LIGHT_MAGENTA}${service_name} 未运行${RESET},无法添加认证授权"
  2830. fi
  2831. else
  2832. WARN "无效输入,请重新输入${LIGHT_YELLOW} 0-9 ${RESET}序号"
  2833. AUTH_MENU
  2834. return
  2835. fi
  2836. done
  2837. for file_url in "${selected_files[@]}"; do
  2838. yml_name=$(basename "$file_url")
  2839. DEL_AUTH_CONFIG "${PROXY_DIR}/${yml_name}"
  2840. done
  2841. for server in "${selected_services[@]}"; do
  2842. DEL_AUTH_COMPOSE "${server}"
  2843. rm -f ${PROXY_DIR}/${server}_htpasswd
  2844. done
  2845. fi
  2846. }
  2847. SEPARATOR "认证授权"
  2848. echo -e "1) ${BOLD}${LIGHT_YELLOW}添加${RESET}认证"
  2849. echo -e "2) ${BOLD}${LIGHT_CYAN}删除${RESET}认证"
  2850. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2851. echo -e "0) ${BOLD}退出脚本${RESET}"
  2852. echo "---------------------------------------------------------------"
  2853. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" auth_choice
  2854. case $auth_choice in
  2855. 1)
  2856. ENABLE_AUTH
  2857. if [ ${#selected_services[@]} -eq 0 ]; then
  2858. WARN "退出认证授权,请${LIGHT_CYAN}重新选择${RESET}服务认证的操作"
  2859. AUTH_SERVICE_CONFIG # 没有服务运行调用函数
  2860. else
  2861. $DOCKER_COMPOSE_CMD down ${selected_services[*]}
  2862. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2863. fi
  2864. AUTH_SERVICE_CONFIG
  2865. ;;
  2866. 2)
  2867. DELETE_AUTH
  2868. if [ ${#selected_services[@]} -eq 0 ]; then
  2869. WARN "退出认证授权,请${LIGHT_CYAN}重新选择${RESET}服务认证的操作"
  2870. AUTH_SERVICE_CONFIG # 没有服务运行调用函数
  2871. else
  2872. $DOCKER_COMPOSE_CMD down ${selected_services[*]}
  2873. $DOCKER_COMPOSE_CMD up -d --force-recreate ${selected_services[*]}
  2874. fi
  2875. AUTH_SERVICE_CONFIG
  2876. ;;
  2877. 3)
  2878. main_menu
  2879. ;;
  2880. 0)
  2881. exit 1
  2882. ;;
  2883. *)
  2884. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2885. AUTH_SERVICE_CONFIG
  2886. ;;
  2887. esac
  2888. }
  2889. # 本机Docker代理
  2890. function DOCKER_PROXY() {
  2891. SEPARATOR "Docker服务代理"
  2892. echo -e "1) ${BOLD}${LIGHT_GREEN}添加${RESET}本机Docker代理"
  2893. echo -e "2) ${BOLD}${YELLOW}移除${RESET}本机Docker代理"
  2894. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  2895. echo -e "0) ${BOLD}退出脚本${RESET}"
  2896. echo "---------------------------------------------------------------"
  2897. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" main_choice
  2898. case $main_choice in
  2899. 1)
  2900. DOCKER_PROXY_HTTP
  2901. ADD_DOCKERD_PROXY
  2902. DOCKER_PROXY
  2903. ;;
  2904. 2)
  2905. DEL_DOCKERD_PROXY
  2906. DOCKER_PROXY
  2907. ;;
  2908. 3)
  2909. main_menu
  2910. ;;
  2911. 0)
  2912. exit 1
  2913. ;;
  2914. *)
  2915. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  2916. sleep 2; DOCKER_PROXY
  2917. ;;
  2918. esac
  2919. }
  2920. # IP 黑白名单
  2921. function IP_BLACKWHITE_LIST() {
  2922. if ! command -v iptables &> /dev/null
  2923. then
  2924. WARN "iptables 未安装. 请安装后再运行此脚本."
  2925. exit 1
  2926. fi
  2927. IPTABLES=$(which iptables)
  2928. BLACKLIST_CHAIN="IP_BLACKLIST"
  2929. WHITELIST_CHAIN="IP_WHITELIST"
  2930. WHITELIST_FILE="/etc/firewall/whitelist.txt"
  2931. BLACKLIST_FILE="/etc/firewall/blacklist.txt"
  2932. # 确保文件存在
  2933. mkdir -p /etc/firewall
  2934. touch $WHITELIST_FILE $BLACKLIST_FILE
  2935. get_chain_name() {
  2936. local chain=$1
  2937. case $chain in
  2938. $BLACKLIST_CHAIN) echo "黑名单" ;;
  2939. $WHITELIST_CHAIN) echo "白名单" ;;
  2940. *) echo "未知名单" ;;
  2941. esac
  2942. }
  2943. create_chains() {
  2944. $IPTABLES -N $BLACKLIST_CHAIN 2>/dev/null
  2945. $IPTABLES -N $WHITELIST_CHAIN 2>/dev/null
  2946. }
  2947. check_ip() {
  2948. local ip=$1
  2949. local ipv4_regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
  2950. local ipv6_regex='^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$'
  2951. if [[ $ip =~ $ipv4_regex ]] || [[ $ip =~ $ipv6_regex ]]; then
  2952. return 0
  2953. else
  2954. return 1
  2955. fi
  2956. }
  2957. ip_exists_in_file() {
  2958. local ip=$1
  2959. local file=$2
  2960. grep -q "^$ip$" "$file"
  2961. return $?
  2962. }
  2963. add_ips_to_file() {
  2964. local ips=("$@")
  2965. local file="${ips[-1]}"
  2966. unset 'ips[-1]'
  2967. local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
  2968. local added=()
  2969. local skipped=()
  2970. for ip in "${ips[@]}"; do
  2971. if ! ip_exists_in_file $ip $file; then
  2972. echo $ip >> "$file"
  2973. added+=("$ip")
  2974. else
  2975. skipped+=("$ip")
  2976. fi
  2977. done
  2978. if [ ${#added[@]} -gt 0 ]; then
  2979. INFO "${LIGHT_BLUE}${added[*]}${RESET} ${LIGHT_GREEN}已添加${RESET}到$chain_name"
  2980. fi
  2981. if [ ${#skipped[@]} -gt 0 ]; then
  2982. WARN "${LIGHT_BLUE}${skipped[*]}${RESET} ${LIGHT_YELLOW}已存在${RESET}于$chain_name,跳过添加"
  2983. fi
  2984. }
  2985. remove_ips_from_file() {
  2986. local ips=("$@")
  2987. local file="${ips[-1]}"
  2988. unset 'ips[-1]'
  2989. local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
  2990. local removed=()
  2991. local not_found=()
  2992. for ip in "${ips[@]}"; do
  2993. if ip_exists_in_file $ip $file; then
  2994. sed -i "/^$ip$/d" "$file"
  2995. removed+=("$ip")
  2996. else
  2997. not_found+=("$ip")
  2998. fi
  2999. done
  3000. if [ ${#removed[@]} -gt 0 ]; then
  3001. INFO "${LIGHT_BLUE}${removed[*]}${RESET} ${LIGHT_RED}已从${RESET}$chain_name${LIGHT_RED}移除${RESET}"
  3002. fi
  3003. if [ ${#not_found[@]} -gt 0 ]; then
  3004. WARN "${LIGHT_BLUE}${not_found[*]}${RESET} ${LIGHT_YELLOW}不存在${RESET}于$chain_name,无需移除"
  3005. fi
  3006. }
  3007. list_ips_in_file() {
  3008. local file=$1
  3009. local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
  3010. echo "---------------------------------------------------------------"
  3011. echo "当前${chain_name}中的IP列表:"
  3012. cat "$file"
  3013. }
  3014. apply_ip_list() {
  3015. local chain=$1
  3016. local file=$2
  3017. local action=$3
  3018. # 清空链
  3019. $IPTABLES -F $chain
  3020. # 使用 iptables-restore 批量应用规则
  3021. {
  3022. echo "*filter"
  3023. echo ":$chain - [0:0]"
  3024. while IFS= read -r ip; do
  3025. echo "-A $chain -s $ip -j $action"
  3026. done < "$file"
  3027. echo "COMMIT"
  3028. } | $IPTABLES-restore -n
  3029. }
  3030. ensure_default_deny_for_whitelist() {
  3031. if ! $IPTABLES -C $WHITELIST_CHAIN -j DROP &>/dev/null; then
  3032. $IPTABLES -A $WHITELIST_CHAIN -j DROP
  3033. fi
  3034. }
  3035. whitelist_is_empty() {
  3036. [ ! -s "$WHITELIST_FILE" ]
  3037. }
  3038. apply_whitelist() {
  3039. if whitelist_is_empty; then
  3040. WARN "白名单为空,不应用白名单规则以避免锁定系统。"
  3041. return 1
  3042. fi
  3043. if ! $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
  3044. $IPTABLES -I INPUT 1 -j $WHITELIST_CHAIN
  3045. INFO "已将白名单规则应用到 INPUT 链"
  3046. else
  3047. INFO "白名单规则已经应用到 INPUT 链"
  3048. fi
  3049. apply_ip_list $WHITELIST_CHAIN $WHITELIST_FILE ACCEPT
  3050. ensure_default_deny_for_whitelist
  3051. return 0
  3052. }
  3053. switch_to_whitelist() {
  3054. $IPTABLES -D INPUT -j $BLACKLIST_CHAIN 2>/dev/null
  3055. INFO "${LIGHT_YELLOW}已切换到白名单模式,请注意:请在添加IP后手动应用规则${RESET}"
  3056. }
  3057. switch_to_blacklist() {
  3058. $IPTABLES -D INPUT -j $WHITELIST_CHAIN 2>/dev/null
  3059. $IPTABLES -I INPUT 1 -j $BLACKLIST_CHAIN
  3060. apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
  3061. INFO "${LIGHT_YELLOW}已切换到黑名单模式${RESET}"
  3062. }
  3063. handle_whitelist() {
  3064. create_chains
  3065. local whitelist_mode_active=false
  3066. local whitelist_rules_applied=false
  3067. if $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
  3068. whitelist_mode_active=true
  3069. whitelist_rules_applied=true
  3070. elif $IPTABLES -C INPUT -j $BLACKLIST_CHAIN &>/dev/null; then
  3071. read -e -p "$(WARN "${LIGHT_YELLOW}当前使用黑名单模式${RESET},${LIGHT_CYAN}是否切换到白名单模式?(y/n)${RESET}: ")" switch
  3072. if [[ $switch == "y" ]]; then
  3073. switch_to_whitelist
  3074. whitelist_mode_active=true
  3075. whitelist_rules_applied=false
  3076. else
  3077. WARN "保持在黑名单模式,返回主菜单。"
  3078. return
  3079. fi
  3080. else
  3081. switch_to_whitelist
  3082. whitelist_mode_active=true
  3083. whitelist_rules_applied=false
  3084. fi
  3085. while true; do
  3086. echo "---------------------------------------------------------------"
  3087. echo -e "1) ${BOLD}添加IP到白名单${RESET}"
  3088. echo -e "2) ${BOLD}从白名单移除IP${RESET}"
  3089. echo -e "3) ${BOLD}查看当前白名单${RESET}"
  3090. echo -e "4) ${BOLD}应用白名单规则${RESET}"
  3091. echo -e "5) ${BOLD}返回上一级${RESET}"
  3092. echo "---------------------------------------------------------------"
  3093. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" whitelist_choice
  3094. case $whitelist_choice in
  3095. 1)
  3096. read -e -p "$(INFO "${LIGHT_CYAN}请输入要添加到白名单的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3097. IFS=',' read -ra ip_array <<< "$ips"
  3098. valid_ips=()
  3099. for ip in "${ip_array[@]}"; do
  3100. if check_ip $ip; then
  3101. valid_ips+=("$ip")
  3102. else
  3103. WARN "无效IP: $ip"
  3104. fi
  3105. done
  3106. if [ ${#valid_ips[@]} -gt 0 ]; then
  3107. add_ips_to_file "${valid_ips[@]}" "$WHITELIST_FILE"
  3108. whitelist_rules_applied=false
  3109. fi
  3110. ;;
  3111. 2)
  3112. read -e -p "$(INFO "${LIGHT_CYAN}请输入要从白名单移除的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3113. IFS=',' read -ra ip_array <<< "$ips"
  3114. valid_ips=()
  3115. for ip in "${ip_array[@]}"; do
  3116. if check_ip $ip; then
  3117. valid_ips+=("$ip")
  3118. else
  3119. WARN "无效IP: $ip"
  3120. fi
  3121. done
  3122. if [ ${#valid_ips[@]} -gt 0 ]; then
  3123. remove_ips_from_file "${valid_ips[@]}" "$WHITELIST_FILE"
  3124. whitelist_rules_applied=false
  3125. fi
  3126. ;;
  3127. 3)
  3128. list_ips_in_file $WHITELIST_FILE
  3129. ;;
  3130. 4)
  3131. if apply_whitelist; then
  3132. whitelist_rules_applied=true
  3133. INFO "${LIGHT_GREEN}白名单规则已成功应用${RESET}"
  3134. else
  3135. WARN "${LIGHT_YELLOW}无法应用白名单规则${RESET}"
  3136. fi
  3137. ;;
  3138. 5)
  3139. if ! $whitelist_rules_applied; then
  3140. read -e -p "$(WARN "${LIGHT_YELLOW}白名单规则尚未应用。您确定要退出吗?${RESET} (y/n): ")" confirm
  3141. if [[ $confirm != "y" ]]; then
  3142. continue
  3143. fi
  3144. fi
  3145. return
  3146. ;;
  3147. *)
  3148. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择1-5${RESET}的选项."
  3149. ;;
  3150. esac
  3151. done
  3152. }
  3153. handle_blacklist() {
  3154. create_chains
  3155. local blacklist_mode_active=false
  3156. if $IPTABLES -C INPUT -j $BLACKLIST_CHAIN &>/dev/null; then
  3157. blacklist_mode_active=true
  3158. elif $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
  3159. read -e -p "$(WARN "${LIGHT_YELLOW}当前使用白名单模式${RESET},${LIGHT_CYAN}是否切换到黑名单模式?(y/n)${RESET}: ")" switch
  3160. if [[ $switch == "y" ]]; then
  3161. switch_to_blacklist
  3162. blacklist_mode_active=true
  3163. else
  3164. WARN "保持在白名单模式,返回主菜单。"
  3165. return
  3166. fi
  3167. else
  3168. switch_to_blacklist
  3169. blacklist_mode_active=true
  3170. fi
  3171. while true; do
  3172. echo "---------------------------------------------------------------"
  3173. echo -e "1) ${BOLD}添加IP到黑名单${RESET}"
  3174. echo -e "2) ${BOLD}从黑名单移除IP${RESET}"
  3175. echo -e "3) ${BOLD}查看当前黑名单${RESET}"
  3176. echo -e "4) ${BOLD}返回上一级${RESET}"
  3177. echo "---------------------------------------------------------------"
  3178. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" blacklist_choice
  3179. case $blacklist_choice in
  3180. 1)
  3181. read -e -p "$(INFO "${LIGHT_CYAN}请输入要添加到黑名单的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3182. IFS=',' read -ra ip_array <<< "$ips"
  3183. valid_ips=()
  3184. for ip in "${ip_array[@]}"; do
  3185. if check_ip $ip; then
  3186. valid_ips+=("$ip")
  3187. else
  3188. WARN "无效IP: $ip"
  3189. fi
  3190. done
  3191. if [ ${#valid_ips[@]} -gt 0 ]; then
  3192. add_ips_to_file "${valid_ips[@]}" "$BLACKLIST_FILE"
  3193. apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
  3194. fi
  3195. ;;
  3196. 2)
  3197. read -e -p "$(INFO "${LIGHT_CYAN}请输入要从黑名单移除的IP (用逗号分隔多个IP)${RESET}: ")" ips
  3198. IFS=',' read -ra ip_array <<< "$ips"
  3199. valid_ips=()
  3200. for ip in "${ip_array[@]}"; do
  3201. if check_ip $ip; then
  3202. valid_ips+=("$ip")
  3203. else
  3204. WARN "无效IP: $ip"
  3205. fi
  3206. done
  3207. if [ ${#valid_ips[@]} -gt 0 ]; then
  3208. remove_ips_from_file "${valid_ips[@]}" "$BLACKLIST_FILE"
  3209. apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
  3210. fi
  3211. ;;
  3212. 3)
  3213. list_ips_in_file $BLACKLIST_FILE
  3214. ;;
  3215. 4)
  3216. return
  3217. ;;
  3218. *)
  3219. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择1-4${RESET}的选项."
  3220. ;;
  3221. esac
  3222. done
  3223. }
  3224. while true; do
  3225. SEPARATOR "设置IP黑白名单"
  3226. echo -e "1) ${BOLD}管理${LIGHT_GREEN}白名单${RESET}"
  3227. echo -e "2) ${BOLD}管理${LIGHT_CYAN}黑名单${RESET}"
  3228. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  3229. echo -e "0) ${BOLD}退出脚本${RESET}"
  3230. echo "---------------------------------------------------------------"
  3231. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" ipblack_choice
  3232. case $ipblack_choice in
  3233. 1)
  3234. handle_whitelist
  3235. ;;
  3236. 2)
  3237. handle_blacklist
  3238. ;;
  3239. 3)
  3240. main_menu
  3241. ;;
  3242. 0)
  3243. exit 0
  3244. ;;
  3245. *)
  3246. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  3247. ;;
  3248. esac
  3249. done
  3250. }
  3251. # 其他工具
  3252. function OtherTools() {
  3253. SEPARATOR "其他工具"
  3254. echo -e "1) 设置${BOLD}${YELLOW}系统命令${RESET}"
  3255. echo -e "2) 配置${BOLD}${LIGHT_MAGENTA}IP黑白名单${RESET}"
  3256. echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
  3257. echo -e "0) ${BOLD}退出脚本${RESET}"
  3258. echo "---------------------------------------------------------------"
  3259. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" main_choice
  3260. case $main_choice in
  3261. 1)
  3262. ADD_SYS_CMD
  3263. ;;
  3264. 2)
  3265. IP_BLACKWHITE_LIST
  3266. ;;
  3267. 3)
  3268. main_menu
  3269. ;;
  3270. 0)
  3271. exit 1
  3272. ;;
  3273. *)
  3274. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
  3275. sleep 2; main_menu
  3276. ;;
  3277. esac
  3278. }
  3279. ## 主菜单
  3280. function main_menu() {
  3281. echo -e "╔════════════════════════════════════════════════════╗"
  3282. echo -e "║ ║"
  3283. echo -e "║ ${LIGHT_CYAN}欢迎使用Docker-Proxy${RESET} ║"
  3284. echo -e "║ ║"
  3285. echo -e "║ TG频道: ${UNDERLINE}https://t.me/dqzboyblog${RESET} ║"
  3286. echo -e "║ ║"
  3287. echo -e "║ ${LIGHT_BLUE}by dqzboy${RESET} ║"
  3288. echo -e "║ ║"
  3289. echo -e "╚════════════════════════════════════════════════════╝"
  3290. echo
  3291. SEPARATOR "请选择操作"
  3292. echo -e "1) ${BOLD}${LIGHT_GREEN}安装${RESET}服务"
  3293. echo -e "2) ${BOLD}${LIGHT_MAGENTA}组件${RESET}安装"
  3294. echo -e "3) ${BOLD}${LIGHT_YELLOW}管理${RESET}服务"
  3295. echo -e "4) ${BOLD}${LIGHT_CYAN}更新${RESET}配置"
  3296. echo -e "5) ${BOLD}${LIGHT_RED}卸载${RESET}服务"
  3297. echo -e "6) ${BOLD}${LIGHT_BLUE}认证${RESET}授权"
  3298. echo -e "7) 本机${BOLD}${CYAN}Docker代理${RESET}"
  3299. echo -e "8) 其他${BOLD}${YELLOW}工具${RESET}"
  3300. echo -e "0) ${BOLD}退出脚本${RESET}"
  3301. echo "---------------------------------------------------------------"
  3302. read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" main_choice
  3303. case $main_choice in
  3304. 1)
  3305. INSTALL_PROXY
  3306. ;;
  3307. 2)
  3308. COMP_INST
  3309. ;;
  3310. 3)
  3311. SVC_MGMT
  3312. ;;
  3313. 4)
  3314. SEPARATOR "更新配置"
  3315. UPDATE_CONFIG
  3316. SEPARATOR "更新完成"
  3317. ;;
  3318. 5)
  3319. UNI_DOCKER_SERVICE
  3320. ;;
  3321. 6)
  3322. AUTH_SERVICE_CONFIG
  3323. ;;
  3324. 7)
  3325. DOCKER_PROXY
  3326. ;;
  3327. 8)
  3328. OtherTools
  3329. ;;
  3330. 0)
  3331. exit 1
  3332. ;;
  3333. *)
  3334. WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-8${RESET}的选项."
  3335. sleep 2; main_menu
  3336. ;;
  3337. esac
  3338. }
  3339. main_menu