-
Notifications
You must be signed in to change notification settings - Fork 78
/
myself.sh
1679 lines (1589 loc) · 71.2 KB
/
myself.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
#
# System Required: CentOS 7+, Rocky 8+, Debian10+, Ubuntu20+
# Description: Script to Xray manage
#
# Copyright (C) 2023 zxcvos
#
# Xray-script: https://github.com/zxcvos/Xray-script
#
# XTLS Official:
# Xray-core: https://github.com/XTLS/Xray-core
# REALITY: https://github.com/XTLS/REALITY
#
# Xray examples:
# XTLS/Xray-examples: https://github.com/XTLS/Xray-examples
# chika0801/Xray-examples: https://github.com/chika0801/Xray-examples
#
# NGINX:
# documentation: https://nginx.org/en/linux_packages.html
# update: https://zhuanlan.zhihu.com/p/193078620
# gcc: https://github.com/kirin10000/Xray-script
# brotli: https://www.nodeseek.com/post-37224-1
# ngx_brotli: https://github.com/google/ngx_brotli
# config: https://www.digitalocean.com/community/tools/nginx?domains.0.server.wwwSubdomain=true&domains.0.https.hstsPreload=true&domains.0.php.php=false&domains.0.reverseProxy.reverseProxy=true&domains.0.reverseProxy.proxyHostHeader=%24proxy_host&domains.0.routing.root=false&domains.0.logging.accessLogEnabled=false&domains.0.logging.errorLogEnabled=false&global.https.portReuse=true&global.nginx.user=root&global.nginx.clientMaxBodySize=50&global.app.lang=zhCN
#
# Certificate:
# ACME: https://github.com/acmesh-official/acme.sh
#
# Docker:
# Manuals: https://docs.docker.com/engine/install/
# Cloudreve: https://github.com/cloudreve/cloudreve
# Cloudflare WARP Proxy: https://github.com/haoel/haoel.github.io?tab=readme-ov-file#1043-docker-%E4%BB%A3%E7%90%86
# e7h4n/cloudflare-warp: https://github.com/e7h4n/cloudflare-warp
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/snap/bin
export PATH
trap egress EXIT
# color
readonly RED='\033[1;31;31m'
readonly GREEN='\033[1;31;32m'
readonly YELLOW='\033[1;31;33m'
readonly NC='\033[0m'
# directory
readonly CUR_DIR="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
readonly CUR_FILE="$(basename $0)"
readonly TMPFILE_DIR="$(mktemp -d -p "${CUR_DIR}" -t nginxtemp.XXXXXXXX)" || exit 1
# global constant
# nginx
readonly NGINX_PATH="/usr/local/nginx"
readonly NGINX_CONFIG_PATH="${NGINX_PATH}/conf"
readonly NGINX_LOG_PATH="/var/log/nginx"
# ssl
readonly SSL_PATH="${NGINX_CONFIG_PATH}/certs"
readonly WEBROOT_PATH="/var/www/_letsencrypt"
# xray script
readonly XRAY_SCRIPT_PATH="/usr/local/etc/zxcvos_xray_script"
readonly XRAY_CONFIG_MANAGE="${XRAY_SCRIPT_PATH}/xray_config_manage.sh"
# cloudreve
readonly CLOUDREVE_PATH="/usr/local/cloudreve"
# cloudflare-warp
readonly CLOUDFLARE_WARP_PATH="/usr/local/cloudflare_warp"
# global variable
declare domain=""
declare subdomain=""
declare in_uuid=""
declare is_enable_brotli=""
# exit process
function egress() {
[[ -e "${TMPFILE_DIR}/swap" ]] && swapoff "${TMPFILE_DIR}/swap"
rm -rf "${TMPFILE_DIR}"
rm -rf "${CUR_DIR}/tmp.sh"
}
function language() {
clear
echo "1.中文"
echo "2.English"
read -p "Please choose a language: " lang
case $lang in
1)
show_lang="zh"
hide_lang="en"
;;
2)
show_lang="en"
hide_lang="zh"
;;
*)
echo -e "${RED}[ERROR] ${NC}Invalid choice"
exit 1
;;
esac
}
language && sed -e '$a main' -e "s/.*${hide_lang}:.*//g; s/${show_lang}: //" -e '/^function language() {/,/^language/d' "${CUR_DIR}/${CUR_FILE}" >"${CUR_DIR}/tmp.sh" && bash "${CUR_DIR}/tmp.sh" || exit 1
# status print
function _info() {
printf "zh: ${GREEN}[信息] ${NC}"
printf "en: ${GREEN}[Info] ${NC}"
printf -- "%s" "$@"
printf "\n"
}
function _warn() {
printf "zh: ${YELLOW}[警告] ${NC}"
printf "en: ${YELLOW}[Warn] ${NC}"
printf -- "%s" "$@"
printf "\n"
}
function _error() {
printf "zh: ${RED}[错误] ${NC}"
printf "en: ${RED}[Error] ${NC}"
printf -- "%s" "$@"
printf "\n"
exit 1
}
# tools
function _exists() {
local cmd="$1"
if eval type type >/dev/null 2>&1; then
eval type "$cmd" >/dev/null 2>&1
elif command >/dev/null 2>&1; then
command -v "$cmd" >/dev/null 2>&1
else
which "$cmd" >/dev/null 2>&1
fi
local rt=$?
return ${rt}
}
function _os() {
local os=""
[[ -f "/etc/debian_version" ]] && source /etc/os-release && os="${ID}" && printf -- "%s" "${os}" && return
[[ -f "/etc/redhat-release" ]] && os="centos" && printf -- "%s" "${os}" && return
}
function _os_full() {
[[ -f /etc/redhat-release ]] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
[[ -f /etc/os-release ]] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
[[ -f /etc/lsb-release ]] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}
function _os_ver() {
local main_ver="$(echo $(_os_full) | grep -oE "[0-9.]+")"
printf -- "%s" "${main_ver%%.*}"
}
function _error_detect() {
local cmd="$1"
_info "zh: 正在执行命令: ${cmd}"
_info "en: Executing command: ${cmd}"
eval ${cmd}
if [[ $? -ne 0 ]]; then
_error "zh: 执行命令 (${cmd}) 失败,请检查并重试。"
_error "en: Execution command (${cmd}) failed, please check it and try again."
fi
}
function _version_ge() {
test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"
}
function _install() {
local packages_name="$@"
local installed_packages=""
case "$(_os)" in
centos)
if _exists "dnf"; then
packages_name="dnf-plugins-core epel-release epel-next-release ${packages_name}"
installed_packages="$(dnf list installed 2>/dev/null)"
if [[ -n "$(_os_ver)" && "$(_os_ver)" -eq 9 ]]; then
# Enable EPEL and Remi repositories
if [[ "${packages_name}" =~ "geoip-devel" ]] && ! echo "${installed_packages}" | grep -iwq "geoip-devel"; then
dnf update -y
_error_detect "dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm"
_error_detect "dnf install -y https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm"
_error_detect "dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm"
# Enable Remi modular repository
_error_detect "dnf config-manager --set-enabled remi-modular"
# Refresh package information
_error_detect "dnf update --refresh"
# Install GeoIP-devel, specifying the use of the Remi repository
dnf update -y
_error_detect "dnf --enablerepo=remi install -y GeoIP-devel"
fi
elif [[ -n "$(_os_ver)" && "$(_os_ver)" -eq 8 ]]; then
if ! dnf module list 2>/dev/null | grep container-tools | grep -iwq "\[x\]"; then
_error_detect "dnf module disable -y container-tools"
fi
fi
dnf update -y
for package_name in ${packages_name}; do
if ! echo "${installed_packages}" | grep -iwq "${package_name}"; then
_error_detect "dnf install -y "${package_name}""
fi
done
else
packages_name="epel-release yum-utils ${packages_name}"
installed_packages="$(yum list installed 2>/dev/null)"
yum update -y
for package_name in ${packages_name}; do
if ! echo "${installed_packages}" | grep -iwq "${package_name}"; then
_error_detect "yum install -y "${package_name}""
fi
done
fi
;;
ubuntu | debian)
apt update -y
installed_packages="$(apt list --installed 2>/dev/null)"
for package_name in ${packages_name}; do
if ! echo "${installed_packages}" | grep -iwq "${package_name}"; then
_error_detect "apt install -y "${package_name}""
fi
done
;;
esac
}
function _systemctl() {
local cmd="$1"
local server_name="$2"
case "${cmd}" in
start)
if systemctl -q is-active "${server_name}"; then
_warn "zh: ${server_name} 服务已经在运行,请不要重复启动。"
_warn "en: ${server_name} service is already running, please do not start it again."
else
_info "zh: 正在启动 ${server_name} 服务。"
_info "en: Starting the ${server_name} service."
systemctl -q start "${server_name}"
fi
systemctl -q is-enabled ${server_name} || systemctl -q enable "${server_name}"
;;
stop)
if systemctl -q is-active "${server_name}"; then
_warn "zh: 正在停止 ${server_name} 服务。"
_warn "en: Stopping the ${server_name} service."
systemctl -q stop "${server_name}"
else
_warn "zh: ${server_name} 服务未在运行,无需停止。"
_warn "en: ${server_name} service is not running, no need to stop."
fi
systemctl -q is-enabled ${server_name} && systemctl -q disable "${server_name}"
;;
restart)
if systemctl -q is-active "${server_name}"; then
_info "zh: 正在重启 ${server_name} 服务。"
_info "en: Restarting the ${server_name} service."
systemctl -q restart "${server_name}"
else
_info "zh: 正在启动 ${server_name} 服务。"
_info "en: Starting the ${server_name} service."
systemctl -q start "${server_name}"
fi
systemctl -q is-enabled ${server_name} || systemctl -q enable "${server_name}"
;;
reload)
if systemctl -q is-active "${server_name}"; then
_info "zh: 正在重载 ${server_name} 服务。"
_info "en: Reloading the ${server_name} service."
systemctl -q reload "${server_name}"
else
_info "zh: 正在启动 ${server_name} 服务。"
_info "en: Starting the ${server_name} service."
systemctl -q start "${server_name}"
fi
systemctl -q is-enabled ${server_name} || systemctl -q enable "${server_name}"
;;
esac
}
# check os
function check_os() {
[[ -z "$(_os)" ]] && _error "zh: 不支持的操作系统。"
[[ -z "$(_os)" ]] && _error "en: Not supported OS."
case "$(_os)" in
ubuntu)
[[ -n "$(_os_ver)" && "$(_os_ver)" -lt 20 ]] && _error "zh: 不支持的操作系统,请切换到 Ubuntu 20+ 并重试。"
[[ -n "$(_os_ver)" && "$(_os_ver)" -lt 20 ]] && _error "en: Not supported OS, please change to Ubuntu 20+ and try again."
;;
debian)
[[ -n "$(_os_ver)" && "$(_os_ver)" -lt 10 ]] && _error "zh: 不支持的操作系统,请切换到 Debian 10+ 并重试。"
[[ -n "$(_os_ver)" && "$(_os_ver)" -lt 10 ]] && _error "en: Not supported OS, please change to Debian 10+ and try again."
;;
centos)
[[ -n "$(_os_ver)" && "$(_os_ver)" -lt 7 ]] && _error "zh: 不支持的操作系统,请切换到 CentOS 7+ 并重试。"
[[ -n "$(_os_ver)" && "$(_os_ver)" -lt 7 ]] && _error "en: Not supported OS, please change to CentOS 7+ and try again."
;;
*)
_error "zh: 不支持的操作系统。"
_error "en: Not supported OS."
;;
esac
}
# swap
function swap_on() {
local mem=${1}
if [[ ${mem} -ne '0' ]]; then
if dd if=/dev/zero of="${TMPFILE_DIR}/swap" bs=1M count=${mem} 2>&1; then
chmod 0600 "${TMPFILE_DIR}/swap"
mkswap "${TMPFILE_DIR}/swap"
swapon "${TMPFILE_DIR}/swap"
fi
fi
}
# check dns resolution
check_dns_resolution() {
local domain=$1
local expected_ipv4="$(ip -4 addr show | grep -wv "lo\|host" | grep -w "inet" | grep -w "scope global*\|link*" | awk -F " " '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print $1}' | head -n 1 | cut -d'/' -f1)"
local expected_ipv6="$(ip -6 addr show | grep -wv "lo" | grep -wv "link\|host" | grep -w "inet6" | grep "scope" | grep "global" | awk -F " " '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print $1}' | head -n 1 | cut -d'/' -f1)"
local resolved=0
# Use the dig command to query the domain's DNS resolution records
local actual_ipv4="$(dig +short "${domain}")"
local actual_ipv6="$(dig +short AAAA "${domain}")"
# Check if the resolved IPv4 matches the expected IPv4
if [[ "${actual_ipv4}" =~ "${expected_ipv4}" ]]; then
_info "zh: 域名 ${domain} 的 IPv4 地址正确解析为 ${expected_ipv4}。"
_info "en: IPv4 for domain ${domain} is correctly resolved to ${expected_ipv4}."
resolved=1
else
_warn "zh: 域名 ${domain} 的 IPv4 地址未解析为期望的 IP。实际 IP: ${actual_ipv4}。"
_warn "en: IPv4 for domain ${domain} is not resolved to the expected IP. Actual IP: ${actual_ipv4}."
fi
# Check if the resolved IP matches the expected IPv6
if [[ "${actual_ipv6}" =~ "${expected_ipv6}" ]]; then
_info "zh: 域名 ${domain} 的 IPv6 地址正确解析为 ${expected_ipv6}。"
_info "en: IPv6 for domain ${domain} is correctly resolved to ${expected_ipv6}."
resolved=1
else
_warn "zh: 域名 ${domain} 的 IPv6 地址未解析为期望的 IP。实际 IP: ${actual_ipv6}。"
_warn "en: IPv6 for domain ${domain} is not resolved to the expected IP. Actual IP: ${actual_ipv6}."
fi
# If neither IPv4 nor IPv6 resolution was successful, report an error
if [[ ${resolved} -eq 0 ]]; then
_error "zh: 域名 ${domain} 未解析为期望的 IPv4 或 IPv6。"
_error "en: Domain ${domain} does not resolved to either the expected IPv4 or IPv6."
fi
}
# firewall
function firewall_manage() {
case "$(_os)" in
centos)
read -p "zh: 是否启用防火墙 (y|n)? " is_turn_on
read -p "en: Whether to turn on the firewall (y|n)? " is_turn_on
if [[ "${is_turn_on}" =~ ^[Yy]$ ]]; then
_systemctl start firewalld
else
_systemctl stop firewalld
fi
if systemctl is-active --quiet firewalld && firewall-cmd --state | grep -Eqw "^running"; then
_info "zh: 防火墙已启用。"
_info "en: Firewall is now enabled."
else
_warn "zh: 防火墙已停用。"
_warn "en: Firewall is now disabled."
fi
;;
debian | ubuntu)
ufw enable
if systemctl is-active --quiet ufw && ufw status | grep -qw active; then
_info "zh: 防火墙已启用。"
_info "en: Firewall is now enabled."
else
_warn "zh: 防火墙已停用。"
_warn "en: Firewall is now disabled."
fi
;;
esac
}
function firewall_pass() {
local action="$1"
local port="$2"
local udp="$3"
# Check if UFW is active
if systemctl is-active --quiet ufw && ufw status | grep -qw active; then
case "${action}" in
allow)
ufw allow "${port}"
_info "zh: 已允许端口 ${port}。"
_info "en: Port ${port} has been allowed."
;;
remove)
ufw delete allow "${port}"
_warn "zh: 已移除允许端口 ${port}。"
_warn "en: Allowed port ${port} has been removed."
;;
esac
# Check if Firewalld is active
elif systemctl is-active --quiet firewalld && firewall-cmd --state | grep -Eqw "^running"; then
case "${action}" in
allow)
firewall-cmd --zone=public --add-port="${port}"/tcp --permanent
[[ "${udp}" ]] && firewall-cmd --zone=public --add-port="${port}"/udp --permanent
_info "zh: 已允许端口 ${port}。"
_info "en: Port ${port} has been allowed."
;;
remove)
firewall-cmd --zone=public --remove-port="${port}"/tcp --permanent
[[ "${udp}" ]] && firewall-cmd --zone=public --remove-port="${port}"/udp --permanent
_warn "zh: 已移除允许端口 ${port}。"
_warn "en: Allowed port ${port} has been removed."
;;
esac
firewall-cmd --reload
fi
}
# backup file
function backup_files() {
local backup_dir="$1"
local current_date="$(date +%F)"
for file in "${backup_dir}/"*; do
if [[ -f "$file" ]]; then
local file_name="$(basename "$file")"
local backup_file="${backup_dir}/${file_name}_${current_date}"
mv "$file" "$backup_file"
echo "zh: 备份: ${file} -> ${backup_file}。"
echo "en: Backup: ${file} -> ${backup_file}."
fi
done
}
# reboot
function reboot_os() {
echo
_info "zh: 系统需要重新启动。"
_info "en: The system needs to reboot."
read -p "zh: 是否要重新启动系统? [y/N] " is_reboot
read -p "en: Do you want to restart the system? [y/N] " is_reboot
if [[ "${is_reboot}" =~ ^[Yy]$ ]]; then
reboot
else
_info "zh: 已取消重新启动..."
_info "en: Reboot has been canceled..."
exit 0
fi
}
# read domain
function read_domain() {
echo -e "zh: --------------------请选择域名解析--------------------"
echo -e "en: --------------------Please Choose Domain Resolution--------------------"
echo -e "zh: 选项 1 是使用 xray 前置。选项 2,3 使用 Nginx 进行 SNI 分流"
echo -e "en: Option 1 uses Xray as a frontend. Options 2 and 3 utilize Nginx for SNI traffic shunting"
echo
echo -e "zh: 仅为了偷自己证书,而且没有其他需求推荐使用 1"
echo -e "en: If you do not have a normal website, use option 1"
echo -e "zh: 如果自己有网站正常使用推荐使用选项 2,3"
echo -e "en: If you have a normal website, use options 2 or 3"
echo
echo -e "zh: 1. 主域名 和 www.主域名"
echo -e "en: 1. 主域名 和 www.主域名"
echo -e "zh: 如: 123.com 和 www.123.com"
echo -e "en: Example: 123.com and www.123.com"
echo -e "zh: 2. 使用 SNI 分流到 drive.主域名"
echo -e "en: 2. Use SNI to Redirect to drive subdomain"
echo -e "zh: 如: drive.123.com"
echo -e "en: Example: drive.123.com"
echo -e "zh: 3. 使用 SNI 分流到 pan.主域名"
echo -e "en: 3. Use SNI to Redirect to pan subdomain"
echo -e "zh: 如: pan.123.com"
echo -e "en: Example: pan.123.com"
echo
read -p "zh: 请选择: " choice_domain
read -p "en: Please choose: " choice_domain
((choice_domain < 1 || choice_domain > 3)) && _error "zh: 无效的选择。"
((choice_domain < 1 || choice_domain > 3)) && _error "en: Invalid choice."
local is_domain="n"
local check_domain=""
until [[ "${is_domain}" =~ ^[Yy]$ ]]; do
echo 'zh: 请输入主域名(前面不带"www."、"drive."、".pan"、"http://"或"https://")'
echo 'en: Please enter the main domain (without "www.", "drive.", ".pan", "http://", or "https://")'
read -p "zh: 输入域名: " domain
read -p "en: Enter the domain: " domain
check_domain="$(echo ${domain} | grep -oE '[^/]+(\.[^/]+)+\b' | head -n 1)"
read -p "zh: 确认域名: \"${check_domain}\" [y/N] " is_domain
read -p "en: Confirm the domain: \"${check_domain}\" [y/N] " is_domain
done
domain="${check_domain}"
case "${choice_domain}" in
1)
subdomain="www.${domain}"
;;
2)
subdomain="drive.${domain}"
;;
3)
subdomain="pan.${domain}"
;;
esac
}
# read uuid
function read_uuid() {
_info "zh: 输入一个自定义 UUID。如果不符合标准格式,将使用 xray uuid -i \"自定义字符串\" 生成 UUIDv5 并填充配置。"
_info "en: Enter a custom UUID. If it's not in standard format, xray uuid -i \"custom string\" will be used to generate a UUIDv5 and fill in the configuration."
read -p "zh: 输入一个自定义 UUID,或按 Enter 生成默认 UUID: " in_uuid
read -p "en: Enter a custom UUID, or press Enter to generate a default one: " in_uuid
}
# enable brotli
function enable_brotli() {
read -p "zh: 确认启用 Nginx 的 Brotli [y/N] " is_enable_brotli
read -p "en: Confirm enabling Brotli for Nginx [y/N] " is_enable_brotli
}
# validate port
function validate_port() {
local port=$1
if [[ ! "${port}" =~ ^[0-9]+$ ]]; then
_error "zh: 无效的端口号。请输入有效的数字。"
_error "en: Invalid port number. Please enter a valid numeric value."
elif ((port < 1 || port > 65535)); then
_error "zh: 端口号范围 1 到 65535 之间。"
_error "en: Port number should be between 1 and 65535."
fi
}
# docker management
function docker_manage() {
_systemctl start docker
local cmd="$1"
local container_name="$2"
local container="$(docker ps -q --filter "name=${container_name}")"
case "${cmd}" in
start)
if [[ "${container}" ]]; then
_warn "zh: ${container_name} 已经在运行,请不要重复启动。"
_warn "en: ${container_name} is already running, please do not start it again."
else
_info "zh: 正在启动 ${container_name} 容器。"
_info "en: Starting the ${container_name} container."
docker start "${container_name}"
fi
;;
stop)
if [[ "${container}" ]]; then
_warn "zh: 正在停止 ${container_name} 容器。"
_warn "en: Stopping the ${container_name} container."
docker stop "${container_name}"
else
_warn "zh: ${container_name} 未在运行,无需停止。"
_warn "en: ${container_name} is not running, no need to stop."
fi
;;
restart)
if [[ "${container}" ]]; then
_info "zh: 正在重启 ${container_name} 容器。"
_info "en: Restarting the ${container_name} container."
docker restart "${container_name}"
else
_info "zh: 正在启动 ${container_name} 容器。"
_info "en: Starting the ${container_name} container."
docker start "${container_name}"
fi
;;
rmi)
_warn "zh: 停止并删除 ${container_name} 容器,且删除 ${container_name} 容器镜像。"
_warn "en: Stop and remove the containers, and delete the container images."
docker stop "${container_name}"
docker rm -f -v "${container_name}"
docker rmi -f "${container_name}"
;;
esac
}
# docker compose management
function docker_compose_manage() {
_systemctl start docker
local cmd="$1"
local container="$(docker compose ps -q)"
case "${cmd}" in
start)
if [[ "${container}" ]]; then
_warn "zh: 已经在运行,请不要重复启动。"
_warn "en: Already running, please do not start again."
else
_info "zh: 正在启动 ${PWD} 中的 docker-compose.yaml 配置。"
_info "en: Starting the docker-compose.yaml configuration in ${PWD}."
docker compose up -d
fi
;;
stop)
if [[ "${container}" ]]; then
_warn "zh: 正在停止 ${PWD} 中的 docker-compose.yaml 配置。"
_warn "en: Stopping the docker-compose.yaml configuration in ${PWD}."
docker compose down
else
_warn "zh: 未在运行,无需停止。"
_warn "en: Not running, no need to stop."
fi
;;
restart)
if [[ "${container}" ]]; then
_info "zh: 正在重启 ${PWD} 中的 docker-compose.yaml 配置。"
_info "en: Restarting the docker-compose.yaml configuration in ${PWD}."
docker compose restart
else
_info "zh: 正在启动 ${PWD} 中的 docker-compose.yaml 配置。"
_info "en: Starting the docker-compose.yaml configuration in ${PWD}."
docker compose up -d
fi
;;
rmi)
_warn "zh: 停止并删除容器,并删除容器镜像。"
_warn "en: Stop and remove the containers, and delete the container images."
docker compose down --rmi all
;;
esac
}
# dependencies
function compile_dependencies() {
# general
_install ca-certificates curl wget gcc make git openssl tzdata
case "$(_os)" in
centos)
# toolchains
_install gcc-c++ perl-IPC-Cmd perl-Getopt-Long perl-Data-Dumper
# dependencies
_install pcre2-devel zlib-devel libxml2-devel libxslt-devel gd-devel geoip-devel perl-ExtUtils-Embed gperftools-devel perl-devel brotli-devel
if ! perl -e "use FindBin" &>/dev/null; then
_install perl-FindBin
fi
;;
debian | ubuntu)
# toolchains
_install g++ perl-base perl
# dependencies
_install libpcre2-dev zlib1g-dev libxml2-dev libxslt1-dev libgd-dev libgeoip-dev libgoogle-perftools-dev libperl-dev libbrotli-dev
;;
esac
}
function other_dependencies() {
_install jq
case "$(_os)" in
centos)
_install crontabs util-linux iproute procps-ng bind-utils firewalld
;;
debian | ubuntu)
_install cron bsdmainutils iproute2 procps dnsutils ufw
;;
esac
}
function script_dependencies() {
_info "zh: 正在安装工具链和依赖项。"
_info "en: Installing toolchains and dependencies."
compile_dependencies
other_dependencies
}
# cflags
function gen_cflags() {
cflags=('-g0' '-O3')
if gcc -v --help 2>&1 | grep -qw "\\-fstack\\-reuse"; then
cflags+=('-fstack-reuse=all')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fdwarf2\\-cfi\\-asm"; then
cflags+=('-fdwarf2-cfi-asm')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fplt"; then
cflags+=('-fplt')
fi
if gcc -v --help 2>&1 | grep -qw "\\-ftrapv"; then
cflags+=('-fno-trapv')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fexceptions"; then
cflags+=('-fno-exceptions')
elif gcc -v --help 2>&1 | grep -qw "\\-fhandle\\-exceptions"; then
cflags+=('-fno-handle-exceptions')
fi
if gcc -v --help 2>&1 | grep -qw "\\-funwind\\-tables"; then
cflags+=('-fno-unwind-tables')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fasynchronous\\-unwind\\-tables"; then
cflags+=('-fno-asynchronous-unwind-tables')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fstack\\-check"; then
cflags+=('-fno-stack-check')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fstack\\-clash\\-protection"; then
cflags+=('-fno-stack-clash-protection')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fstack\\-protector"; then
cflags+=('-fno-stack-protector')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fcf\\-protection="; then
cflags+=('-fcf-protection=none')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fsplit\\-stack"; then
cflags+=('-fno-split-stack')
fi
if gcc -v --help 2>&1 | grep -qw "\\-fsanitize"; then
>temp.c
if gcc -E -fno-sanitize=all temp.c >/dev/null 2>&1; then
cflags+=('-fno-sanitize=all')
fi
rm temp.c
fi
if gcc -v --help 2>&1 | grep -qw "\\-finstrument\\-functions"; then
cflags+=('-fno-instrument-functions')
fi
}
# source compile
function source_compile() {
cd "${TMPFILE_DIR}"
# version
_info "zh: 检索 Nginx 和 OpenSSL 的最新版本。"
_info "en: Retrieve the latest versions of Nginx and OpenSSL."
local nginx_version="$(wget -qO- --no-check-certificate https://api.github.com/repos/nginx/nginx/tags | grep 'name' | cut -d\" -f4 | grep 'release' | head -1 | sed 's/release/nginx/')"
local openssl_version="openssl-$(wget -qO- --no-check-certificate https://api.github.com/repos/openssl/openssl/tags | grep 'name' | cut -d\" -f4 | grep -Eoi '^openssl-([0-9]\.?){3}$' | head -1)"
# gcc
gen_cflags
# nginx
_info "zh: 下载最新版本的 Nginx。"
_info "en: Download the latest versions of Nginx."
_error_detect "curl -fsSL -o ${nginx_version}.tar.gz https://nginx.org/download/${nginx_version}.tar.gz"
tar -zxf "${nginx_version}.tar.gz"
# openssl
_info "zh: 下载最新版本的 OpenSSL。"
_info "en: Download the latest versions of OpenSSL."
_error_detect "curl -fsSL -o ${openssl_version}.tar.gz https://github.com/openssl/openssl/archive/${openssl_version#*-}.tar.gz"
tar -zxf "${openssl_version}.tar.gz"
if [[ "${is_enable_brotli}" =~ ^[Yy]$ ]]; then
# brotli
_info "zh: 检出最新的 ngx_brotli 并构建依赖项。"
_info "en: Checkout the latest ngx_brotli and build the dependencies."
_error_detect "git clone https://github.com/google/ngx_brotli && cd ngx_brotli && git submodule update --init"
cd "${TMPFILE_DIR}"
fi
# configure
cd "${nginx_version}"
sed -i "s/OPTIMIZE[ \\t]*=>[ \\t]*'-O'/OPTIMIZE => '-O3'/g" src/http/modules/perl/Makefile.PL
sed -i 's/NGX_PERL_CFLAGS="$CFLAGS `$NGX_PERL -MExtUtils::Embed -e ccopts`"/NGX_PERL_CFLAGS="`$NGX_PERL -MExtUtils::Embed -e ccopts` $CFLAGS"/g' auto/lib/perl/conf
sed -i 's/NGX_PM_CFLAGS=`$NGX_PERL -MExtUtils::Embed -e ccopts`/NGX_PM_CFLAGS="`$NGX_PERL -MExtUtils::Embed -e ccopts` $CFLAGS"/g' auto/lib/perl/conf
if [[ "${is_enable_brotli}" =~ ^[Yy]$ ]]; then
./configure --prefix="${NGINX_PATH}" --user=root --group=root --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream --with-stream_ssl_module --with-stream_realip_module --with-stream_geoip_module=dynamic --with-stream_ssl_preread_module --with-google_perftools_module --add-module="../ngx_brotli" --with-compat --with-cc-opt="${cflags[*]}" --with-openssl="../${openssl_version}" --with-openssl-opt="${cflags[*]}"
else
./configure --prefix="${NGINX_PATH}" --user=root --group=root --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream --with-stream_ssl_module --with-stream_realip_module --with-stream_geoip_module=dynamic --with-stream_ssl_preread_module --with-google_perftools_module --with-compat --with-cc-opt="${cflags[*]}" --with-openssl="../${openssl_version}" --with-openssl-opt="${cflags[*]}"
fi
_info "zh: 申请 512MB 虚拟内存。"
_info "en: Allocating 512MB of swap memory."
swap_on 512
# compile
_info "zh: 编译 Nginx。"
_info "en: Compiling Nginx."
_error_detect "make -j$(nproc)"
}
# install by source
function source_install() {
source_compile
_info "zh: 安装 Nginx。"
_info "en: Installing Nginx."
make install
ln -sf "${NGINX_PATH}/sbin/nginx" /usr/sbin/nginx
}
# update by source
function source_update() {
# latest verions
_info "zh: 检索 Nginx 和 OpenSSL 的最新版本。"
_info "en: Retrieve the latest versions of Nginx and OpenSSL."
local latest_nginx_version="$(wget -qO- --no-check-certificate https://api.github.com/repos/nginx/nginx/tags | grep 'name' | cut -d\" -f4 | grep 'release' | head -1 | sed 's/release/nginx/')"
local latest_openssl_version="$(wget -qO- --no-check-certificate https://api.github.com/repos/openssl/openssl/tags | grep 'name' | cut -d\" -f4 | grep -Eoi '^openssl-([0-9]\.?){3}$' | head -1)"
# current version
_info "zh: 读取 Nginx 和 OpenSSL 的当前版本。"
_info "en: Retrieve the current versions of Nginx and OpenSSL."
local current_version_nginx="$(nginx -V 2>&1 | grep "^nginx version:.*" | cut -d / -f 2)"
local current_version_openssl="$(nginx -V 2>&1 | grep "^built with OpenSSL" | awk '{print $4}')"
# compare
_info "zh: 判断是否需要更新。"
_info "en: Determine if an update is needed."
if _version_ge "${latest_nginx_version#*-}" "${current_version_nginx}" || _version_ge "${latest_openssl_version#*-}" "${current_version_openssl}"; then
source_compile
_info "zh: 更新 Nginx。"
_info "en: Updating Nginx."
mv "${NGINX_PATH}/sbin/nginx" "${NGINX_PATH}/sbin/nginx_$(date +%F)"
backup_files "${NGINX_PATH}/modules"
cp objs/nginx "${NGINX_PATH}/sbin/"
cp objs/*.so "${NGINX_PATH}/modules/"
ln -sf "${NGINX_PATH}/sbin/nginx" /usr/sbin/nginx
if systemctl is-active --quiet nginx; then
kill -USR2 $(cat /run/nginx.pid)
if [[ -e "/run/nginx.pid.oldbin" ]]; then
kill -WINCH $(cat /run/nginx.pid.oldbin)
kill -HUP $(cat /run/nginx.pid.oldbin)
kill -QUIT $(cat /run/nginx.pid.oldbin)
else
_info "zh: 未找到旧的 Nginx 进程。跳过后续步骤。"
_info "en: Old Nginx process not found. Skipping further steps."
fi
fi
return 0
fi
return 1
}
# purge
function purge_nginx() {
_systemctl stop nginx
_warn "zh: 卸载 Nginx。"
_warn "en: Purging Nginx."
rm -rf "${NGINX_PATH}"
rm -rf /usr/sbin/nginx
rm -rf /etc/systemd/system/nginx.service
rm -rf "${NGINX_LOG_PATH}"
systemctl daemon-reload
}
function systemctl_config_nginx() {
cat >/etc/systemd/system/nginx.service <<EOF
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/bin/rm -rf /dev/shm/nginx
ExecStartPre=/bin/mkdir /dev/shm/nginx
ExecStartPre=/bin/chmod 711 /dev/shm/nginx
ExecStartPre=/bin/mkdir /dev/shm/nginx/tcmalloc
ExecStartPre=/bin/chmod 0777 /dev/shm/nginx/tcmalloc
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=/bin/kill -s QUIT \$MAINPID
ExecStopPost=/bin/rm -rf /dev/shm/nginx
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
}
function config_nginx() {
_info "创建 Nginx 相关目录"
mkdir -vp "${NGINX_LOG_PATH}"
mkdir -vp "${NGINX_CONFIG_PATH}/conf.d"
cd "${NGINX_CONFIG_PATH}"
_info "zh: 通过压缩配置的 base64 字符串生成 nginxconfig.io-example.com.tar.gz。"
_info "en: Generating nginxconfig.io-example.com.tar.gz from the compressed and base64-encoded configuration string."
echo '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' | base64 --decode | tee "${NGINX_CONFIG_PATH}/nginxconfig.io-example.com.tar.gz" >/dev/null
tar -xzvf nginxconfig.io-example.com.tar.gz | xargs chmod 0644
_error_detect "curl -fsSL -o "${NGINX_CONFIG_PATH}/nginx.conf" "https://raw.githubusercontent.com/zxcvos/Xray-script/main/nginx/conf/nginx.conf""
_error_detect "curl -fsSL -o "${NGINX_CONFIG_PATH}/sites-available/example.com.conf" "https://raw.githubusercontent.com/zxcvos/Xray-script/main/nginx/conf/sites-available/example.com.conf""
_error_detect "curl -fsSL -o "${NGINX_CONFIG_PATH}/conf.d/restrict.conf" "https://raw.githubusercontent.com/zxcvos/Xray-script/main/nginx/conf/conf.d/restrict.conf""
_error_detect "curl -fsSL -o "${NGINX_CONFIG_PATH}/nginxconfig.io/limit.conf" "https://raw.githubusercontent.com/zxcvos/Xray-script/main/nginx/conf/nginxconfig.io/limit.conf""
case "${choice_domain}" in
1)
sed -i "/^stream {/,/^http {/s|^|#|" "${NGINX_CONFIG_PATH}/nginx.conf"
sed -i "/^#http {/s|^#||" "${NGINX_CONFIG_PATH}/nginx.conf"
sed -i "s|default_backend|cloudreve|" "${NGINX_CONFIG_PATH}/conf.d/restrict.conf"
sed -i "s|domain|${domain} ${subdomain}|g" "${NGINX_CONFIG_PATH}/sites-available/example.com.conf"
sed -i "s|; # proxy_protocol;| proxy_protocol;|g" "${NGINX_CONFIG_PATH}/sites-available/example.com.conf"
sed -i "s|# real_ip_header|real_ip_header|g" "${NGINX_CONFIG_PATH}/sites-available/example.com.conf"
;;
2 | 3)
sed -i "s|example.com|${subdomain}|g" "${NGINX_CONFIG_PATH}/nginx.conf"
sed -i "s|domain|${subdomain}|g" "${NGINX_CONFIG_PATH}/sites-available/example.com.conf"
;;
esac
sed -i "s|certs/example.com|certs/${subdomain}|g" "${NGINX_CONFIG_PATH}/sites-available/example.com.conf"
sed -i "s|.example.com|.${domain}|g" "${NGINX_CONFIG_PATH}/sites-available/example.com.conf"
sed -i "s|max-age=31536000|max-age=63072000|" "${NGINX_CONFIG_PATH}/nginxconfig.io/security.conf"
rm -rf "${NGINX_CONFIG_PATH}/sites-enabled/example.com.conf"
mv "${NGINX_CONFIG_PATH}/sites-available/example.com.conf" "${NGINX_CONFIG_PATH}/sites-available/${subdomain}.conf"
ln -sf "${NGINX_CONFIG_PATH}/sites-available/${subdomain}.conf" "${NGINX_CONFIG_PATH}/sites-enabled/${subdomain}.conf"
if [[ ! "${is_enable_brotli}" =~ ^[Yy]$ ]]; then
# disable brotli
_warn "zh: 禁用 brotli 配置。"
_warn "en: Disabling the brotli configuration."
sed -i "/^brotli/,/^brotli_types/s/^/#/" "${NGINX_CONFIG_PATH}/nginxconfig.io/general.conf"
fi
}
# install
function install_acme_sh() {
_info "zh: 安装 acme.sh。"
_info "en: Installing acme.sh."
curl https://get.acme.sh | sh
${HOME}/.acme.sh/acme.sh --upgrade --auto-upgrade
${HOME}/.acme.sh/acme.sh --set-default-ca --server letsencrypt
}
# update
function update_acme_sh() {
_info "zh: 更新 acme.sh。"
_info "en: Updating acme.sh."
${HOME}/.acme.sh/acme.sh --upgrade
}
# purge
function purge_acme_sh() {
_warn "zh: 卸载 acme.sh。"
_warn "en: Purging acme.sh."
${HOME}/.acme.sh/acme.sh --upgrade --auto-upgrade 0
${HOME}/.acme.sh/acme.sh --uninstall
rm -rf "${HOME}/.acme.sh"
rm -rf "${WEBROOT_PATH}"
rm -rf "${SSL_PATH}"
}
# issue
function issue_cert() {
local issue_domain
case "${choice_domain}" in
1)
issue_domain=(${domain} ${subdomain})
;;
2 | 3)
issue_domain=(${subdomain})
;;
esac
[[ -d "${WEBROOT_PATH}" ]] || mkdir -vp "${WEBROOT_PATH}"
[[ -d "${SSL_PATH}/${subdomain}" ]] || mkdir -vp "${SSL_PATH}/${subdomain}"
_info "zh: 备份 nginx.conf 文件。"
_info "en: Backing up the nginx.conf file."
mv "${NGINX_CONFIG_PATH}/nginx.conf" "${NGINX_CONFIG_PATH}/nginx.conf.bak"
_info "zh: 创建用于申请证书的 nginx.conf 文件。"
_info "en: Creating the nginx.conf file for certificate issuance."
cat >"${NGINX_CONFIG_PATH}/nginx.conf" <<EOF
user root;
pid /run/nginx.pid;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
location ^~ /.well-known/acme-challenge/ {
root ${WEBROOT_PATH};
}
}
}
EOF
_info "zh: 检测并重载新的配置文件。"
_info "en: Checking and reloading the new configuration file."
if systemctl is-active --quiet nginx; then
nginx -t && systemctl reload nginx
else
nginx -t && systemctl start nginx
fi
_info "zh: 请求颁发 ECC 证书。"
_info "en: Requesting ECC certificate issuance."
${HOME}/.acme.sh/acme.sh --issue $(printf -- " -d %s" "${issue_domain[@]}") \
--webroot ${WEBROOT_PATH} \
--keylength ec-256 \
--accountkeylength ec-256 \
--server letsencrypt \
--ocsp
if [[ $? -ne 0 ]]; then
${HOME}/.acme.sh/acme.sh --issue $(printf -- " -d %s" "${issue_domain[@]}") \
--webroot ${WEBROOT_PATH} \
--keylength ec-256 \
--accountkeylength ec-256 \
--server letsencrypt \
--ocsp \
--debug
_info "zh: 将备份的 nginx.conf 复原。"
_info "en: Restoring the backed-up nginx.conf."
mv -f "${NGINX_CONFIG_PATH}/nginx.conf.bak" "${NGINX_CONFIG_PATH}/nginx.conf"
_error "zh: ECC 证书请求失败。"
_error "en: ECC certificate request failed."
fi
_info "zh: 将备份的 nginx.conf 复原。"
_info "en: Restoring the backed-up nginx.conf."
mv -f "${NGINX_CONFIG_PATH}/nginx.conf.bak" "${NGINX_CONFIG_PATH}/nginx.conf"
_info "zh: 检测并重载新的配置文件。"