├── .gitignore ├── LICENSE ├── README.md ├── config ├── 03_routing.json └── 06_outbounds.json ├── src └── xwall.sh └── tools └── rm_xwall.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/linux,macos 2 | # Edit at https://www.gitignore.io/?templates=linux,macos 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | # General 21 | .DS_Store 22 | .AppleDouble 23 | .LSOverride 24 | 25 | # Icon must end with two \r 26 | Icon 27 | 28 | # Thumbnails 29 | ._* 30 | 31 | # Files that might appear in the root of a volume 32 | .DocumentRevisions-V100 33 | .fseventsd 34 | .Spotlight-V100 35 | .TemporaryItems 36 | .Trashes 37 | .VolumeIcon.icns 38 | .com.apple.timemachine.donotpresent 39 | 40 | # Directories potentially created on remote AFP share 41 | .AppleDB 42 | .AppleDesktop 43 | Network Trash Folder 44 | Temporary Items 45 | .apdisk 46 | 47 | # End of https://www.gitignore.io/api/linux,macos 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2020 phlinhng 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VLESS / Trojan-Go / Shadowsocks 2 | automated script for xray-core and trojan-go 3 | 4 | ## Usage 5 | ```sh 6 | curl -fsSL https://cdn.jsdelivr.net/gh/phlinhng/v2ray-tcp-tls-web@main/src/xwall.sh -o ~/xwall.sh && bash ~/xwall.sh 7 | ``` 8 | To run the script again once downloaded, just use the following command: 9 | ``` 10 | bash ~/xwall.sh 11 | ``` 12 | 13 | ## Features 14 | 1. Higher offloading efficieny with xray-core frontend 15 | 2. Support Debian9+, Ubuntu 16+ and CentOS 7+ operation systems 16 | 3. Support both IPv4 and IPv6 17 | 4. BuyPass CA Certificates 18 | 19 | ## Architecture 20 | + VLESS over TCP with [XTLS](https://github.com/XTLS/Go) powered by [xray-core](https://github.com/XTLS/xray-core) 21 | + Trojan (protocol) and muxing powered by [trojan-go](https://github.com/p4gefau1t/trojan-go) (implementaion) 22 | + Trojan over WSS on Cloudflare powered by trojan-go and Cloudflare 23 | + Shadowsocks over WSS powered by [xray-core](https://github.com/XTLS/xray-core) 24 | + HTTP Website backend powered by nginx 25 | 26 | ## Supported Protocols 27 | | Protocol | Transport | Mux | Direct | CDN | Qv2ray | Shadowrocket | Clash | v2rayN(G) | 28 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | 29 | | VLESS | XTLS | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | 30 | | VLESS | TLS | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | 31 | | VLESS | WSS | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | 32 | | Trojan | TLS | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | 33 | | Trojan | WSS | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | 34 | | Shadowsocks | WSS | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 35 | 36 | ## Credit 37 | + [Project V](https://www.v2fly.org/) 38 | + [V2Ray 配置指南](https://toutyrater.github.io/) 39 | + [新 V2Ray 白话文指南](https://guide.v2fly.org/) 40 | + [templated.co](https://templated.co) 41 | + [@liberal-boy/tls-shunt-proxy](https://github.com/liberal-boy/tls-shunt-proxy) 42 | + [@atrandys/trojan](https://github.com/atrandys/trojan) 43 | + [@Loyalsoldier/v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat) 44 | + [@mack-a/v2ray-agent](https://github.com/mack-a/v2ray-agent) 45 | + [@chiakge/Linux-NetSpeed](https://github.com/chiakge/Linux-NetSpeed) 46 | + [@ylx2016/Linux-NetSpeed](https://github.com/ylx2016/Linux-NetSpeed) 47 | + [@LemonBench/LemonBench](https://github.com/LemonBench/LemonBench) 48 | + [@tindy2013/subconverter](https://github.com/tindy2013/subconverter) 49 | + [@p4gefau1t/trojan-go](https://github.com/p4gefau1t/trojan-go) 50 | + [@rprx/v2ray-vless](https://github.com/rprx/v2ray-vless) 51 | + [@acmesh-official/acme.sh](https://github.com/acmesh-official/acme.sh) 52 | + [@nginx/nginx](https://github.com/nginx/nginx) 53 | + [@charlieethan/firewall-proxy](https://github.com/charlieethan/firewall-proxy) 54 | + [@XTLS/xray-core](https://github.com/XTLS/xray-core) 55 | 56 | ## Stargazers over time 57 | [![Stargazers over time](https://starchart.cc/phlinhng/v2ray-tcp-tls-web.svg)](https://starchart.cc/phlinhng/v2ray-tcp-tls-web) 58 | -------------------------------------------------------------------------------- /config/03_routing.json: -------------------------------------------------------------------------------- 1 | { 2 | "routing": { 3 | "domainStrategy": "AsIs", 4 | "rules": [ 5 | { 6 | "type": "field", 7 | "ip": [ 8 | "geoip:private" 9 | ], 10 | "outboundTag": "blocked" 11 | }, 12 | { 13 | "type": "field", 14 | "protocol": [ 15 | "bittorrent" 16 | ], 17 | "outboundTag": "blocked" 18 | } 19 | ] 20 | } 21 | } -------------------------------------------------------------------------------- /config/06_outbounds.json: -------------------------------------------------------------------------------- 1 | { 2 | "outbounds": [ 3 | { 4 | "tag": "direct", 5 | "protocol": "freedom", 6 | "settings": {} 7 | }, 8 | { 9 | "tag": "blocked", 10 | "protocol": "blackhole", 11 | "settings": {} 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /src/xwall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export LC_ALL=C 3 | export LANG=en_US 4 | export LANGUAGE=en_US.UTF-8 5 | 6 | branch="main" 7 | VERSION="2.2.1" 8 | 9 | ip4_api="--ipv4 https://v4.ident.me/" 10 | ip6_api="--ipv6 https://v6.ident.me/" 11 | 12 | api_proxy="gh-api.phlin.workers.dev" 13 | gh_proxy="gh-proxy.phlin.workers.dev" 14 | 15 | cf_node_default="icook.tw" 16 | 17 | log_path="/var/log/xwall.log" 18 | 19 | if [[ $(/usr/bin/id -u) -ne 0 ]]; then 20 | echo "您不是 root 用户!请先输入 sudo -i 切换至 root 用户再运行本脚本" 21 | exit 22 | fi 23 | 24 | colorStart="\033[" 25 | colorEnd="\033[0m" 26 | 27 | RED="0;31m" # Error message 28 | GREEN="0;32m" # Success message 29 | LGREEN="1;32m" # Success message 2 30 | YELLOW="0;33m" # Warning message 31 | LYELLOW="1;33m" # Info message 1 32 | BLUE="0;36m" # Info message 2 33 | 34 | colorEcho(){ 35 | # copied from v2ray official script 36 | echo -e "${colorStart}${1}${@:2}${colorEnd}" 1>& 2 37 | } 38 | 39 | colorEchoFlush(){ 40 | echo -ne "${colorStart}${1}${@:2}${colorEnd}\r" 1>& 2 41 | } 42 | 43 | #copied & modified from v2fly fhs script 44 | identify_the_operating_system_and_architecture() { 45 | if [[ "$(uname)" == 'Linux' ]]; then 46 | case "$(uname -m)" in 47 | 'amd64' | 'x86_64') 48 | V2_MACHINE='64' 49 | TJ_MACHINE='amd64' 50 | ;; 51 | 'armv8' | 'aarch64') 52 | V2_MACHINE='arm64-v8a' 53 | TJ_MACHINE='armv8' 54 | ;; 55 | esac 56 | if [[ ! -f '/etc/os-release' ]]; then 57 | echo "error: Don't use outdated Linux distributions." 58 | exit 1 59 | fi 60 | if [[ -z "$(ls -l /sbin/init | grep systemd)" ]]; then 61 | echo "error: Only Linux distributions using systemd are supported." 62 | exit 1 63 | fi 64 | if [[ "$(command -v apt)" ]]; then 65 | PACKAGE_MANAGEMENT_UPDATE='apt update' 66 | PACKAGE_MANAGEMENT_INSTALL='apt install' 67 | PACKAGE_MANAGEMENT_REMOVE='apt remove' 68 | elif [[ "$(command -v yum)" ]]; then 69 | PACKAGE_MANAGEMENT_UPDATE='yum update' 70 | PACKAGE_MANAGEMENT_INSTALL='yum install' 71 | PACKAGE_MANAGEMENT_REMOVE='yum remove' 72 | elif [[ "$(command -v dnf)" ]]; then 73 | PACKAGE_MANAGEMENT_UPDATE='dnf update' 74 | PACKAGE_MANAGEMENT_INSTALL='dnf install' 75 | PACKAGE_MANAGEMENT_REMOVE='dnf remove' 76 | elif [[ "$(command -v zypper)" ]]; then 77 | PACKAGE_MANAGEMENT_INSTALL='zypper install' 78 | PACKAGE_MANAGEMENT_REMOVE='zypper remove' 79 | elif [[ "$(command -v pacman)" ]]; then 80 | PACKAGE_MANAGEMENT_INSTALL='pacman -S' 81 | PACKAGE_MANAGEMENT_REMOVE='pacman -R' 82 | else 83 | echo "error: The script does not support the package manager in this operating system." 84 | exit 1 85 | fi 86 | else 87 | echo "error: This operating system is not supported." 88 | exit 1 89 | fi 90 | } 91 | 92 | read_json() { 93 | # jq [key] [path-to-file] 94 | jq --raw-output $2 $1 2>/dev/null | tr -d '\n' 95 | } ## read_json [path-to-file] [key] 96 | 97 | write_json() { 98 | # jq [key = value] [path-to-file] 99 | jq -r "$2 = $3" $1 > /tmp/tmp.$$.json && mv /tmp/tmp.$$.json $1 && sleep 1 100 | } ## write_json [path-to-file] [key] [value] 101 | 102 | raw_to_jsdelivr() { 103 | printf %s "$1" | sed -E "s~raw.githubusercontent.com/(.+)/(.+)/(.+)/(.+)~cdn.jsdelivr.net/gh/\1/\2@\3/\4~g" 104 | } 105 | 106 | urlEncode() { 107 | printf %s "$1" | jq -s -R -r @uri 108 | } 109 | 110 | urlDecode() { 111 | printf "${_//%/\\x}" 112 | } 113 | 114 | writeLog() { 115 | while IFS= read -r line; do 116 | printf '[%s] %s\n' "$(date)" "$line"; 117 | done 118 | } 119 | 120 | continue_prompt() { 121 | read -rp "继续其他操作 (yes/no)? " choice 122 | case "${choice}" in 123 | [yY]|[yY][eE][sS] ) return 0 ;; 124 | * ) exit 0;; 125 | esac 126 | } 127 | 128 | build_web() { 129 | if [ ! -f "/var/www/html/index.html" ]; then 130 | # choose and copy a random template for dummy web pages 131 | local template="$(curl -sL `raw_to_jsdelivr "https://raw.githubusercontent.com/phlinhng/web-templates/master/list.txt"` | shuf -n 1)" 132 | wget -q --show-progress `raw_to_jsdelivr "https://raw.githubusercontent.com/phlinhng/web-templates/master/${template}"` -O /tmp/template.zip 133 | mkdir -p /var/www/html 134 | unzip -q /tmp/template.zip -d /var/www/html 135 | echo -ne "User-agent: *\nDisallow: /\n" > /var/www/html/robots.txt 136 | else 137 | echo "Dummy website existed. Skip building." 138 | fi 139 | } 140 | 141 | checkIP() { 142 | local realIP4="$(curl -sL ${ip4_api} -m 5)" 143 | local resolvedIP4="$(curl -sSL https://cloudflare-dns.com/dns-query\?name\=$1\&type\=A -H 'accept: application/dns-json' | jq ".Answer | .[] | select(.type == 1) | .data" --raw-output)" 144 | 145 | [ ! -z "${realIP4}" ] && printf "%s %s\n" "detected IPv4 address:" "${realIP4}" | writeLog >> $log_path 146 | ([ ! -z "${resolvedIP4}" ] && [ "${resolvedIP4}" != "null" ]) && printf "%s %s\n" "found A record:" "${resolvedIP4}" | writeLog >> $log_path 147 | 148 | if [[ "${realIP4}" == "${resolvedIP4}" ]]; then 149 | echo "A record matched." | writeLog >> $log_path 150 | return 0 151 | else 152 | local realIP6="$(curl -sL ${ip6_api} -m 5)" 153 | local resolvedIP6="$(curl -sSL https://cloudflare-dns.com/dns-query\?name\=$1\&type\=AAAA -H 'accept: application/dns-json' | jq ".Answer | .[] | select(.type == 28) | .data" --raw-output)" 154 | [ ! -z "${realIP6}" ] && printf "%s %s\n" "detected IPv6 address:" "${realIP6}" | writeLog >> $log_path 155 | ([ ! -z "${resolvedIP6}" ] && [ "${resolvedIP6}" != "null" ]) && printf "%s %s\n" "found AAAA record:" "${resolvedIP6}" | writeLog >> $log_path 156 | if [[ "${realIP6}" == "${resolvedIP6}" ]]; then 157 | echo "AAAA record matched." | writeLog >> $log_path 158 | return 0 159 | else 160 | echo "neither A record nor AAAA record matched, return 1" | writeLog >> $log_path 161 | return 1 162 | fi 163 | fi 164 | } 165 | 166 | show_links() { 167 | if [ -f "/usr/local/bin/xray" ]; then 168 | local uuid="$(read_json /usr/local/etc/xray/05_inbounds_vless.json '.inbounds[0].settings.clients[0].id')" 169 | local path="$(read_json /usr/local/etc/xray/05_inbounds_ss.json '.inbounds[0].streamSettings.wsSettings.path')" 170 | local sni="$(read_json /usr/local/etc/xray/05_inbounds_vless.json '.inbounds[0].tag')" 171 | local cf_node="$(read_json /usr/local/etc/xray/05_inbounds_ss.json '.inbounds[0].tag')" 172 | # path ss+ws: /[base], path vless+ws: /[base]ws, path vmess+ws: /[base]wss, path trojan+ws: /[base]tj 173 | 174 | colorEcho ${YELLOW} "===============分 享 链 接 (直连)===============" 175 | colorEcho ${BLUE} "VLESS XTLS" 176 | #https://github.com/XTLS/Xray-core/issues/91 177 | local uri_vless="${uuid}@${sni}:443?security=xtls&flow=rprx-xtls-direct#`urlEncode "${sni} (VLESS)"`" 178 | printf "%s\n" "vless://${uri_vless}" 179 | echo "" 180 | 181 | colorEcho ${BLUE} "Trojan TLS" 182 | local uri_trojan="${uuid}@${sni}:443?peer=${sni}&sni=${sni}#`urlEncode "${sni} (Trojan)"`" 183 | printf "%s\n" "trojan://${uri_trojan}" 184 | echo "" 185 | 186 | colorEcho ${BLUE} "Shadowsocks" 187 | local user_ss="$(printf %s "aes-128-gcm:${uuid}" | base64 --wrap=0)" 188 | local uri_ss="${user_ss}@${sni}:443/?plugin=`urlEncode "v2ray-plugin;tls;mode=websocket;host=${sni};path=${path};mux=0"`#`urlEncode "${sni} (SS)"`" 189 | printf "%s\n" "ss://${uri_ss}" 190 | echo "" 191 | 192 | colorEcho ${YELLOW} "===============分 享 链 接 (CDN)===============" 193 | colorEcho ${BLUE} "VLESS WSS" 194 | #https://github.com/XTLS/Xray-core/issues/91 195 | local uri_vless_wss="${uuid}@${cf_node}:443?type=ws&security=tls&host=${sni}&path=`urlEncode ${path}ws?ed=2048`&sni=${sni}#`urlEncode "${sni} (VLESS+WSS)"`" 196 | printf "%s\n" "vless://${uri_vless_wss}" 197 | echo "" 198 | 199 | colorEcho ${BLUE} "Trojan WSS" 200 | local uri_trojango="${uuid}@${sni}:443?sni=${sni}&type=ws&host=${sni}&path=`urlEncode "${path}tj"`#`urlEncode "${sni} (Trojan-Go)"`" 201 | local uri_trojango_cf="${uuid}@${cf_node}:443?sni=${sni}&type=ws&host=${sni}&path=`urlEncode "${path}tj"`#`urlEncode "${sni} (Trojan-Go)"`" 202 | printf "%s\n" "trojan-go://${uri_trojango_cf}" "trojan-go://${uri_trojango}" 203 | colorEcho ${YELLOW} "因 Trojan-Go 分享链接格式尚未定案,若您的客户端无法解析此链接,请手动填写连接信息" 204 | printf "%s:443 %s %s\n" "${sni}" "${uuid}" "${path}tj" 205 | echo "" 206 | 207 | colorEcho ${BLUE} "Shadowsocks" 208 | local user_ss="$(printf %s "aes-128-gcm:${uuid}" | base64 --wrap=0)" 209 | local uri_ss="${user_ss}@${cf_node}:443/?plugin=`urlEncode "v2ray-plugin;tls;mode=websocket;host=${sni};path=${path};mux=0"`#`urlEncode "${sni} (SS)"`" 210 | printf "%s\n" "ss://${uri_ss}" 211 | echo "" 212 | colorEcho ${YELLOW} "========================================" 213 | fi 214 | } 215 | 216 | preinstall() { 217 | # turning off selinux 218 | setenforce 0 219 | echo "SELINUX=disable" > /etc/selinux/config 220 | 221 | # turning off firewall 222 | systemctl stop firewalld 223 | systemctl disable firewalld 224 | ufw disable 225 | 226 | # get dependencies 227 | ${PACKAGE_MANAGEMENT_INSTALL} epel-release -y # centos 228 | ${PACKAGE_MANAGEMENT_UPDATE} -y 229 | ${PACKAGE_MANAGEMENT_INSTALL} coreutils curl wget unzip jq certbot nginx -y 230 | } 231 | 232 | init_cert() { 233 | if [ ! -d "/var/www/acme" ]; then 234 | $(which mkdir) -p "/var/www/acme" 235 | printf "Cretated: %s\n" "/var/www/acme" 236 | fi 237 | certbot register -m "$RANDOM@$1" --agree-tos --no-eff-email -n 238 | # TODO: ecdsa cert will be available from cetbot 1.10+ with args "--key-type ecdsa" 239 | certbot certonly --webroot -w "/var/www/acme" -d $1 -n 240 | (crontab -l 2>/dev/null; echo "8 7 */4 * * certbot renew -n -q --post-hook \"systemctl restart xray\" >/dev/null 2>&1") | crontab - 241 | } 242 | 243 | get_trojan() { 244 | if [ ! -f "/usr/bin/trojan-go" ]; then 245 | echo "trojan-go is not installed. start installation" 246 | 247 | echo "Getting the latest version of trojan-go" 248 | local latest_version="$(curl -sL "https://${api_proxy}/repos/p4gefau1t/trojan-go/releases" | jq '.[0].tag_name' --raw-output)" 249 | echo "${latest_version}" 250 | local trojango_link="https://${gh_proxy}/github.com/p4gefau1t/trojan-go/releases/download/${latest_version}/trojan-go-linux-${TJ_MACHINE}.zip" 251 | 252 | mkdir -p "/etc/trojan-go" 253 | 254 | cd $(mktemp -d) 255 | wget -q --show-progress "${trojango_link}" -O trojan-go.zip 256 | unzip -q trojan-go.zip && rm -rf trojan-go.zip 257 | $(which mv) trojan-go /usr/bin/trojan-go && $(which chmod) +x /usr/bin/trojan-go 258 | $(which mv) geoip.dat /usr/bin/geoip.dat 259 | $(which mv) geosite.dat /usr/bin/geosite.dat 260 | 261 | echo "Building trojan-go.service" 262 | mv example/trojan-go.service /etc/systemd/system/trojan-go.service 263 | 264 | systemctl daemon-reload 2>&1 | writeLog >> $log_path 265 | systemctl enable trojan-go 2>&1 | writeLog >> $log_path 266 | 267 | echo "trojan-go is installed." 268 | else 269 | colorEcho ${BLUE} "Getting the latest version of trojan-go" 270 | local latest_version="$(curl -sL "https://${api_proxy}/repos/p4gefau1t/trojan-go/releases" | jq '.[0].tag_name' --raw-output)" 271 | echo "${latest_version}" 272 | local trojango_link="https://${gh_proxy}/github.com/p4gefau1t/trojan-go/releases/download/${latest_version}/trojan-go-linux-${TJ_MACHINE}.zip" 273 | 274 | cd $(mktemp -d) 275 | wget -q --show-progress "${trojango_link}" -O trojan-go.zip 276 | unzip -q trojan-go.zip && rm -rf trojan-go.zip 277 | $(which mv) trojan-go /usr/bin/trojan-go && $(which chmod) +x /usr/bin/trojan-go 278 | colorEcho ${GREEN} "trojan-go has been updated." 279 | fi 280 | } 281 | 282 | set_xray_systemd() { 283 | cat > "/etc/systemd/system/xray.service" <<-EOF 284 | [Unit] 285 | Description=Xray - A unified platform for anti-censorship 286 | Documentation=https://github.com/xtls 287 | After=network.target nss-lookup.target 288 | Wants=network-online.target 289 | 290 | [Service] 291 | Type=simple 292 | User=root 293 | CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW 294 | NoNewPrivileges=yes 295 | Environment=XRAY_LOCATION_ASSET=/usr/local/share/xray 296 | ExecStart=/usr/local/bin/xray run -confdir /usr/local/etc/xray 297 | Restart=on-failure 298 | RestartPreventExitStatus=23 299 | 300 | [Install] 301 | WantedBy=multi-user.target 302 | EOF 303 | } 304 | 305 | get_xray() { 306 | if [ ! -f "/usr/local/bin/xray" ]; then 307 | echo "XRay-Core is not installed. start installation" 308 | 309 | echo "Getting the latest version of xray-core" 310 | latest_version=`curl -sL "https://${api_proxy}/repos/XTLS/Xray-core/releases/latest" | jq '.tag_name' --raw-output` 311 | echo "${latest_version}" 312 | local xray_link="https://${gh_proxy}/github.com/XTLS/Xray-core/releases/download/${latest_version}/Xray-linux-${V2_MACHINE}.zip" 313 | 314 | $(which mkdir) -p "/usr/local/etc/xray" 315 | printf "Cretated: %s\n" "/usr/local/etc/xray" 316 | $(which mkdir) -p "/usr/local/share/xray" 317 | printf "Cretated: %s\n" "/usr/local/share/xray" 318 | 319 | cd $(mktemp -d) 320 | wget -q --show-progress "${xray_link}" -O xray-core.zip 321 | unzip -q xray-core.zip && $(which rm) -rf xray-core.zip 322 | $(which mv) xray /usr/local/bin/xray && $(which chmod) +x /usr/local/bin/xray 323 | printf "Installed: %s\n" "/usr/local/bin/xray" 324 | $(which mv) geoip.dat /usr/local/share/xray/geoip.dat 325 | printf "Installed: %s\n" "/usr/local/share/xray/geoip.dat" 326 | $(which mv) geosite.dat /usr/local/share/xray/geosite.dat 327 | printf "Installed: %s\n" "/usr/local/share/xray/geosite.dat" 328 | 329 | echo "Building xray.service" 330 | set_xray_systemd 331 | 332 | systemctl daemon-reload 2>&1 | writeLog >> $log_path 333 | systemctl enable xray 2>&1 | writeLog >> $log_path 334 | 335 | echo "XRay-Core ${latest_version} is installed." 336 | else 337 | echo "Getting the latest version of xray-core" 338 | latest_version=`curl -sL "https://${api_proxy}/repos/XTLS/Xray-core/releases/latest" | jq '.tag_name' --raw-output` 339 | echo "${latest_version}" 340 | local xray_link="https://${gh_proxy}/github.com/XTLS/Xray-core/releases/download/${latest_version}/Xray-linux-${V2_MACHINE}.zip" 341 | 342 | cd $(mktemp -d) 343 | wget -q --show-progress "${xray_link}" -O xray-core.zip 344 | unzip -q xray-core.zip && $(which rm) -rf xray-core.zip 345 | $(which mv) xray /usr/local/bin/xray && $(which chmod) +x /usr/local/bin/xray 346 | printf "Installed: %s\n" "/usr/local/bin/xray" 347 | 348 | systemctl restart xray 349 | colorEcho ${GREEN} "XRay-Core ${latest_version} has been updated." 350 | fi 351 | } 352 | 353 | set_xray() { 354 | # $1: uuid for all except vless ws (in trojan and ss uuid == passowrd) 355 | # $2: base path 356 | # $3: sni 357 | # $4: url of cf node 358 | # 3564: trojan, 3565: ss, 3566: vless+wss 359 | cat > "/usr/local/etc/xray/05_inbounds_vless.json" <<-EOF 360 | { 361 | "inbounds": [ 362 | { 363 | "port": 443, 364 | "protocol": "vless", 365 | "settings": { 366 | "clients": [ 367 | { 368 | "id": "$1", 369 | "flow": "xtls-rprx-direct" 370 | } 371 | ], 372 | "decryption": "none", 373 | "fallbacks": [ 374 | { 375 | "dest": 3564 376 | }, 377 | { 378 | "path": "$2tj", 379 | "dest": 3564 380 | }, 381 | { 382 | "path": "$2", 383 | "dest": 3565, 384 | "xver": 1 385 | }, 386 | { 387 | "path": "$2ws", 388 | "dest": 3566, 389 | "xver": 1 390 | } 391 | ] 392 | }, 393 | "streamSettings": { 394 | "network": "tcp", 395 | "security": "xtls", 396 | "xtlsSettings": { 397 | "alpn": [ "http/1.1" ], 398 | "certificates": [ 399 | { 400 | "certificateFile": "/etc/letsencrypt/live/$3/fullchain.pem", 401 | "keyFile": "/etc/letsencrypt/live/$3/privkey.pem" 402 | } 403 | ] 404 | } 405 | }, 406 | "sniffing": { 407 | "enabled": true, 408 | "destOverride": [ "http", "tls" ] 409 | }, 410 | "tag": "$3" 411 | } 412 | ] 413 | } 414 | EOF 415 | cat > "/usr/local/etc/xray/05_inbounds_ss.json" <<-EOF 416 | { 417 | "inbounds": [ 418 | { 419 | "port": 3565, 420 | "listen": "127.0.0.1", 421 | "protocol": "shadowsocks", 422 | "settings": { 423 | "method": "aes-128-gcm", 424 | "password": "$1", 425 | "network": "tcp" 426 | }, 427 | "streamSettings": { 428 | "network": "ws", 429 | "security": "none", 430 | "wsSettings": { 431 | "acceptProxyProtocol": true, 432 | "path": "$2" 433 | } 434 | }, 435 | "sniffing": { 436 | "enabled": true, 437 | "destOverride": [ "http", "tls" ] 438 | }, 439 | "tag": "$4" 440 | } 441 | ] 442 | } 443 | EOF 444 | cat > "/usr/local/etc/xray/05_inbounds_vless_ws.json" <<-EOF 445 | { 446 | "inbounds": [ 447 | { 448 | "port": 3566, 449 | "listen": "127.0.0.1", 450 | "protocol": "vless", 451 | "settings": { 452 | "clients": [ 453 | { 454 | "id": "$1" 455 | } 456 | ], 457 | "decryption": "none" 458 | }, 459 | "streamSettings": { 460 | "network": "ws", 461 | "security": "none", 462 | "wsSettings": { 463 | "acceptProxyProtocol": true, 464 | "path": "$2ws" 465 | } 466 | }, 467 | "sniffing": { 468 | "enabled": true, 469 | "destOverride": [ "http", "tls" ] 470 | }, 471 | "tag": "vless_ws" 472 | } 473 | ] 474 | } 475 | EOF 476 | wget -q `raw_to_jsdelivr "https://raw.githubusercontent.com/phlinhng/v2ray-tcp-tls-web/${branch}/config/03_routing.json"` -O /usr/local/etc/xray/03_routing.json 477 | wget -q `raw_to_jsdelivr "https://raw.githubusercontent.com/phlinhng/v2ray-tcp-tls-web/${branch}/config/06_outbounds.json"` -O /usr/local/etc/xray/06_outbounds.json 478 | } 479 | 480 | set_trojan() { 481 | # $1: password 482 | # $2: ws path 483 | # $3: sni 484 | cat > "/etc/trojan-go/config.json" <<-EOF 485 | { 486 | "run_type": "server", 487 | "local_addr": "127.0.0.1", 488 | "local_port": 3564, 489 | "remote_addr": "127.0.0.1", 490 | "remote_port": 80, 491 | "log_level": 3, 492 | "password": [ 493 | "$1" 494 | ], 495 | "transport_plugin": { 496 | "enabled": true, 497 | "type": "plaintext" 498 | }, 499 | "websocket": { 500 | "enabled": true, 501 | "path": "$2", 502 | "host": "$3" 503 | }, 504 | "router": { 505 | "enabled": false 506 | } 507 | } 508 | EOF 509 | } 510 | 511 | set_nginx_default() { 512 | cat > /etc/nginx/sites-available/default <<-EOF 513 | server { 514 | listen 80 default_server; 515 | listen [::]:80 default_server; 516 | server_name _; 517 | 518 | location /.well-known { 519 | root /var/www/acme; 520 | } 521 | 522 | location / { 523 | return 301 https://\$host\$request_uri; 524 | } 525 | } 526 | EOF 527 | } 528 | 529 | set_nginx() { 530 | rm -f /etc/nginx/conf.d/vless_fallback.conf 531 | cat > /etc/nginx/conf.d/vless_fallback.conf <<-EOF 532 | server { 533 | listen 127.0.0.1:80; 534 | server_name $1; 535 | root /var/www/html; 536 | index index.php index.html index.htm; 537 | } 538 | EOF 539 | } 540 | 541 | fix_cert() { 542 | if [ -f "/usr/local/bin/xray" ]; then 543 | while true; do 544 | read -rp "解析到本 VPS 的域名: " V2_DOMAIN 545 | if checkIP "${V2_DOMAIN}"; then 546 | colorEcho $LYELLOW "域名 ${V2_DOMAIN} 解析正确, 即将开始修复证书" 547 | break 548 | else 549 | colorEcho ${RED} "域名 ${V2_DOMAIN} 解析有误 (yes: 强制继续, no: 重新输入, quit: 离开)" 550 | read -rp "若您确定域名解析正确, 可以继续进行修复作业. 强制继续? (yes/no/quit) " forceConfirm 551 | case "${forceConfirm}" in 552 | [yY]|[yY][eE][sS] ) break ;; 553 | [qQ]|[qQ][uU][iI][tT] ) return 0;; 554 | esac 555 | fi 556 | done 557 | 558 | [ -z "${V2_DOMAIN}" ] && return 0; 559 | 560 | local uuid="$(read_json /usr/local/etc/xray/05_inbounds_vless.json '.inbounds[0].settings.clients[0].id')" 561 | local path="$(read_json /usr/local/etc/xray/05_inbounds_ss.json '.inbounds[0].streamSettings.wsSettings.path')" 562 | local cf_node="$(read_json /usr/local/etc/xray/05_inbounds_ss.json '.inbounds[0].tag')" 563 | local old_domain="$(read_json /usr/local/etc/xray/05_inbounds_vless.json '.inbounds[0].tag')" 564 | 565 | certbot delete --cert-name ${old_domain} -n 2>&1 | writeLog >> $log_path 566 | certbot certonly --webroot -w "/var/www/acme" -d ${V2_DOMAIN} -n 2>&1 | writeLog >> $log_path 567 | 568 | set_xray "${uuid}" "${path}" "${V2_DOMAIN}" "${cf_node}" 569 | set_trojan "${uuid}" "${path}tj" "${V2_DOMAIN}" 570 | set_nginx "${V2_DOMAIN}" 571 | systemctl restart nginx 2>/dev/null 572 | systemctl restart trojan-go 2>/dev/null 573 | systemctl restart xray 2>/dev/null 574 | 575 | write_json /usr/local/etc/xray/05_inbounds_vless.json ".inbounds[0].tag" "\"${V2_DOMAIN}\"" 576 | 577 | colorEcho $LGREEN "证书修复完成" 578 | show_links 579 | else 580 | colorEcho ${YELLOW} "请先安装 XRay" 581 | fi 582 | } 583 | 584 | install_xray() { 585 | colorEchoFlush $BLUE "安装依赖包 coreutils curl wget unzip jq certbot nginx" 586 | preinstall 2>&1 | writeLog >> $log_path 587 | colorEcho $LGREEN "完成: 安装依赖包 coreutils curl wget unzip jq certbot nginx" 588 | 589 | while true; do 590 | read -rp "解析到本 VPS 的域名: " V2_DOMAIN 591 | if checkIP "${V2_DOMAIN}"; then 592 | colorEcho $LYELLOW "域名 ${V2_DOMAIN} 解析正确, 即将开始安装" 593 | break 594 | else 595 | colorEcho ${RED} "域名 ${V2_DOMAIN} 解析有误 (yes: 强制继续, no: 重新输入, quit: 离开)" 596 | read -rp "若您确定域名解析正确, 可以继续进行安装作业. 强制继续? (yes/no/quit) " forceConfirm 597 | case "${forceConfirm}" in 598 | [yY]|[yY][eE][sS] ) break ;; 599 | [qQ]|[qQ][uU][iI][tT] ) return 0 ;; 600 | esac 601 | fi 602 | done 603 | 604 | echo "Start xray installation for domain ${V2_DOMAIN}" | writeLog >> $log_path 605 | 606 | colorEchoFlush $BLUE "获取 xray-core\r" 607 | get_xray | writeLog >> $log_path 608 | colorEcho $LGREEN "完成: 获取 xray-core" 609 | 610 | colorEchoFlush $BLUE "获取 trojan-go\r" 611 | get_trojan | writeLog >> $log_path 612 | colorEcho $LGREEN "完成: 获取 trojan-go" 613 | 614 | # set crontab to auto update geoip.dat and geosite.dat 615 | colorEchoFlush $BLUE "设置 geoip/geosite 更新任务\r" 616 | (crontab -l 2>/dev/null; echo "0 7 * * * wget -q `raw_to_jsdelivr "https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat"` -O /usr/local/share/xray/geoip.dat >/dev/null >/dev/null") | crontab - 617 | (crontab -l 2>/dev/null; echo "0 7 * * * wget -q `raw_to_jsdelivr "https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat"` -O /usr/local/share/xray/geosite.dat >/dev/null >/dev/null") | crontab - 618 | echo "geoip/geosite crontab set" | writeLog >> $log_path 619 | colorEcho $LGREEN "完成: 设置 geoip/geosite 更新任务" 620 | 621 | colorEchoFlush $BLUE "下载伪装网站模版" 622 | build_web | writeLog >> $log_path 623 | colorEcho $LGREEN "完成: 下载伪装网站模版" 624 | 625 | local uuid="$(cat '/proc/sys/kernel/random/uuid')" 626 | local path="/$(cat '/proc/sys/kernel/random/uuid' | sed -e 's/-//g' | tr '[:upper:]' '[:lower:]' | head -c $((10+$RANDOM%10)))" 627 | 628 | colorEchoFlush $BLUE "设置 XRay" 629 | set_xray "${uuid}" "${path}" "${V2_DOMAIN}" "${cf_node_default}" 630 | colorEcho $LGREEN "完成: 设置 XRay" 631 | 632 | colorEchoFlush $BLUE "设置 Trojan" 633 | set_trojan "${uuid}" "${path}tj" "${V2_DOMAIN}" 634 | colorEcho $LGREEN "完成: 设置 Trojan" 635 | 636 | colorEchoFlush $BLUE "设置 Nginx" 637 | set_nginx_default | writeLog >> $log_path 638 | set_nginx "${V2_DOMAIN}" 639 | systemctl restart nginx | writeLog >> $log_path 640 | colorEcho $LGREEN "完成: 设置 Nginx" 641 | 642 | colorEchoFlush $BLUE "申请 SSL 证书" 643 | init_cert "${V2_DOMAIN}" 2>&1 | writeLog >> $log_path 644 | colorEcho $LGREEN "完成: 申请 SSL 证书" 645 | 646 | # activate services 647 | colorEchoFlush $BLUE "启动 systemd 进程" 648 | systemctl daemon-reload | writeLog >> $log_path 649 | systemctl reset-failed | writeLog >> $log_path 650 | systemctl restart trojan-go 2>&1 | writeLog >> $log_path 651 | systemctl restart xray 2>&1 | writeLog >> $log_path 652 | 653 | colorEcho $LGREEN "安装 XRay + Trojan-Go 成功!" 654 | show_links 655 | } 656 | 657 | edit_cf_node() { 658 | if [ -f "/usr/local/bin/xray" ]; then 659 | local cf_node_current="$(read_json /usr/local/etc/xray/05_inbounds_ss.json '.inbounds[0].tag')" 660 | printf "%s\n" "输入编号使用建议值" 661 | printf "1. %s\n" "icook.hk" 662 | printf "2. %s\n" "www.digitalocean.com" 663 | printf "3. %s\n" "www.garmin.com" 664 | printf "4. %s\n" "amp.cloudflare.com" 665 | read -p "输入新的 CF 节点地址 [留空则使用现有值 ${cf_node_current}]: " cf_node_new 666 | case "${cf_node_new}" in 667 | "1") cf_node_new="icook.hk" ;; 668 | "2") cf_node_new="www.digitalocean.com" ;; 669 | "3") cf_node_new="www.garmin.com" ;; 670 | "4") cf_node_new="amp.cloudflare.com" ;; 671 | esac 672 | if [ -z "${cf_node_new}" ]; then 673 | cf_node_new="${cf_node_current}" 674 | fi 675 | write_json /usr/local/etc/xray/05_inbounds_ss.json ".inbounds[0].tag" "\"${cf_node_new}\"" 676 | sleep 1 677 | printf "%s\n" "CF 节点己变更为 ${cf_node_new}" 678 | show_links 679 | fi 680 | } 681 | 682 | rm_xwall() { 683 | if [ -f "/usr/local/bin/xray" ]; then 684 | wget -q `raw_to_jsdelivr" https://raw.githubusercontent.com/phlinhng/v2ray-tcp-tls-web/${branch}/tools/rm_xwall.sh"` -O /tmp/rm_xwall.sh && bash /tmp/rm_xwall.sh 685 | exit 0 686 | fi 687 | } 688 | 689 | show_menu() { 690 | echo "" 691 | if [ -f "/usr/local/bin/xray" ]; then 692 | echo "----------域名管理----------" 693 | echo "1) 修复证书 / 更换域名" 694 | echo "2) 自定义 Cloudflare 节点" 695 | echo "----------显示配置----------" 696 | echo "3) 显示链接" 697 | echo "----------更新管理----------" 698 | echo "4) 更新 xray-core" 699 | echo "5) 更新 trojan-go" 700 | echo "----------卸载脚本----------" 701 | echo "6) 卸载脚本与全部组件" 702 | else 703 | echo "0) 安装 VLESS + Trojan" 704 | fi 705 | echo "7) 退出" 706 | echo "" 707 | } 708 | 709 | menu() { 710 | colorEcho ${YELLOW} "Proxy tools automated script v${VERSION}" 711 | colorEcho ${YELLOW} "author: phlinhng" 712 | 713 | #check_status 714 | 715 | COLUMNS=woof 716 | 717 | while true; do 718 | show_menu 719 | read -rp "选择操作 [输入任意值退出]: " opt 720 | case "${opt}" in 721 | "0") install_xray && continue_prompt ;; 722 | "1") fix_cert && continue_prompt ;; 723 | "2") edit_cf_node && continue_prompt ;; 724 | "3") show_links && continue_prompt ;; 725 | "4") get_xray && continue_prompt ;; 726 | "5") get_trojan && continue_prompt ;; 727 | "6") rm_xwall ;; 728 | *) break ;; 729 | esac 730 | done 731 | 732 | } 733 | 734 | identify_the_operating_system_and_architecture 735 | menu 736 | -------------------------------------------------------------------------------- /tools/rm_xwall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export LC_ALL=C 3 | export LANG=C 4 | export LANGUAGE=en_US.UTF-8 5 | 6 | if [[ $(/usr/bin/id -u) -ne 0 ]]; then 7 | sudoCmd="sudo" 8 | else 9 | sudoCmd="" 10 | fi 11 | 12 | if [[ "$(command -v apt)" ]]; then 13 | PACKAGE_MANAGEMENT_UPDATE='apt update' 14 | PACKAGE_MANAGEMENT_INSTALL='apt install' 15 | PACKAGE_MANAGEMENT_REMOVE='apt remove' 16 | elif [[ "$(command -v yum)" ]]; then 17 | PACKAGE_MANAGEMENT_UPDATE='yum update' 18 | PACKAGE_MANAGEMENT_INSTALL='yum install' 19 | PACKAGE_MANAGEMENT_REMOVE='yum remove' 20 | elif [[ "$(command -v dnf)" ]]; then 21 | PACKAGE_MANAGEMENT_UPDATE='dnf update' 22 | PACKAGE_MANAGEMENT_INSTALL='dnf install' 23 | PACKAGE_MANAGEMENT_REMOVE='dnf remove' 24 | elif [[ "$(command -v zypper)" ]]; then 25 | PACKAGE_MANAGEMENT_INSTALL='zypper install' 26 | PACKAGE_MANAGEMENT_REMOVE='zypper remove' 27 | elif [[ "$(command -v pacman)" ]]; then 28 | PACKAGE_MANAGEMENT_INSTALL='pacman -S' 29 | PACKAGE_MANAGEMENT_REMOVE='pacman -R' 30 | fi 31 | 32 | # copied from v2ray official script 33 | # colour code 34 | RED="31m" # Error message 35 | GREEN="32m" # Success message 36 | YELLOW="33m" # Warning message 37 | BLUE="36m" # Info message 38 | # colour function 39 | colorEcho() { 40 | echo -e "\033[${1}${@:2}\033[0m" 1>& 2 41 | } 42 | 43 | uninstall() { 44 | ${sudoCmd} $(which rm) -rf $1 45 | printf "Removed: %s\n" $1 46 | } 47 | 48 | # remove xray 49 | if [ -f "/usr/local/bin/xray" ]; then 50 | colorEcho ${BLUE} "Stopping xray service." 51 | ${sudoCmd} systemctl stop xray 52 | ${sudoCmd} systemctl disable xray 53 | uninstall "/etc/systemd/system/xray.service" 54 | colorEcho ${BLUE} "Removing xray binaries." 55 | uninstall "/usr/local/bin/xray" 56 | colorEcho ${BLUE} "Removing xray files." 57 | uninstall "/usr/local/etc/xray" 58 | uninstall"/usr/local/share/xray" 59 | uninstall "/var/log/xray" 60 | colorEcho ${BLUE} "Removing xray crontab." 61 | ${sudoCmd} crontab -l | grep -v 'xray/geoip.dat' | ${sudoCmd} crontab - 62 | ${sudoCmd} crontab -l | grep -v 'xray/geosite.dat' | ${sudoCmd} crontab - 63 | colorEcho ${GREEN} "Removed xray successfully." 64 | fi 65 | 66 | # remove trojan-go 67 | if [ -f "/usr/bin/trojan-go" ]; then 68 | colorEcho ${BLUE} "Shutting down trojan-go service." 69 | ${sudoCmd} systemctl stop trojan-go 70 | ${sudoCmd} systemctl disable trojan-go 71 | uninstall /etc/systemd/system/trojan-go.service 72 | colorEcho ${BLUE} "Removing trojan-go binaries." 73 | uninstall /usr/bin/trojan-go 74 | colorEcho ${BLUE} "Removing trojan-go files." 75 | uninstall /usr/bin/geoip.dat 76 | uninstall /usr/bin/geosite.dat 77 | uninstall /etc/trojan-go 78 | colorEcho ${GREEN} "Removed trojan-go successfully." 79 | fi 80 | 81 | colorEcho ${BLUE} "Removing dummy site." 82 | ${sudoCmd} $(which rm) -rf /var/www/acme 83 | ${sudoCmd} $(which rm) -rf /var/www/html/* 84 | 85 | # remove cerbot 86 | if [ -d "etc/letsencrypt" ]; then 87 | colorEcho ${BLUE} "Removing certbot" 88 | ${sudoCmd} ${PACKAGE_MANAGEMENT_REMOVE} certbot -y 89 | uninstall /etc/letsencrypt 90 | ${sudoCmd} crontab -l | grep -v 'certbot' | ${sudoCmd} crontab - 91 | colorEcho ${GREEN} "Removed acme.sh successfully." 92 | fi 93 | 94 | colorEcho ${BLUE} "卸载完成" --------------------------------------------------------------------------------