Skip to content

Instantly share code, notes, and snippets.

@whg517
Last active March 31, 2025 20:49
Show Gist options
  • Save whg517/54f93ac2ce441bc3fb09d40b6e34afaf to your computer and use it in GitHub Desktop.
Save whg517/54f93ac2ce441bc3fb09d40b6e34afaf to your computer and use it in GitHub Desktop.
#!/bin/bash
set -ex
# 相关技术连接:
# https://github.com/XTLS/Xray-install
# https://github.com/XTLS/Xray-examples
## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
## !不建议关闭操作系统的防火墙,除非你在服务商中配置了防火墙!
## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
## 脚本说明:
## - Caddy: 服务器安装 Caddy Web 服务,并使用 Caddy 的自动 TLS 功能,自动生成本地私有证书,同时自动轮转新证书,这些都是由 Caddy 自动完成
## 如果有域名,Caddy 会自动生成和更新免费证书。使用 Caddy 同时提供 Web 服务功能,用来伪装访问地址。
## - 使用 https://github.com/PanJiaChen/vue-element-admin.git 构建的项目作为 Web 服务项目。当使用浏览器打开地址,访问的是一个页面。
## - 使用 https://github.com/XTLS/Xray-install 的 XTLS 强大回落功能让代理同时支持 XTLS ,VLESS 和 VMESS 多种协议。
## - 启用 BBR 加速
## 注意:
## Caddy 只为 443 端口启用自动 TLS 证书生成。所以 XTLS 不能占用 443 端口,可以选择了常见的 8443 端口,同时回落到 80 端口。
## 脚本暂未在生产环境中测试。请谨慎使用一键执行,建议逐步执行。
## 脚本不提供清理功能,如果需要清理,请手动删除相关文件和服务。
## 清理过程:
## - 停止并删除 xray 服务
## - 使用 systemd 命令停止 xray 服务
## - 删除 /etc/systemd/system 目录中关于 xray 的文件
## - 删除 /usr/local/etc/xray 目录
## - 删除 /etc/firewalld/services/xray.xml 文件
## - 停止并删除 caddy 服务
## - 使用 systemd 命令停止 caddy 服务
## - 删除 /etc/systemd/system 目录中关于 caddy 的文件
## - 删除 /etc/caddy 目录
## - 删除 /var/log/caddy 目录
## - 删除 /opt/wwwroot/ 目录
## - 删除 /etc/firewalld/services/caddy.xml 文件
## - 使用 find 命令查找 caddy 和 xray 关键词,删除相关文件
######################################################################################################
## 安装前配置
######################################################################################################
# 打开注释,填写你的域名,如果没有请忽略
# DOMAIN=example.com
## Xray VLESS 端口,默认为 28443 ,如果需要更改请修改
## 这里选择 28443 高位端口,增大安全性。
## Xray LESS 具备协议回落,当前配置支持会落到 trojan、vlessws、vmessws。
## 如果这些都无法满足,则返回伪装的 Web 服务。
VLESS_PORT=28443
TROJAN_PORT=1310
VLESS_WS_PORT=3456
VMESS_WS_PORT=1234
## Enable system firewall, default is true.
## If you have configured the firewall in the cloud provider, you can set it to false.
ENABLE_FIREWALL=true
######################################################################################################
## 脚本逻辑,不建议修改,如果不懂可以忽略,直接执行脚本
######################################################################################################
# Main function
# Arguments:
# None
# Returns:
# None
function main() {
initGlobalVariable
initSystemEnvironment
installWebServer
deployWebApp
installXray
}
# Initialize global variables, the upper case variables are global variables,
# which can be used in any function
# Arguments:
# None
# Returns:
# None
function initGlobalVariable() {
if [ -z "${DOMAIN}" ]; then
DOMAIN=$(curl -s https://httpbin.org/ip | grep -oP '"origin": "\K(.*)(?=")')
fi
WEB_ROOT=/opt/wwwroot/xray
CADDY_LOG=/var/log/caddy
echo "INFO: Configuration detail:" >&2
echo "INFO: DOMAIN: ${DOMAIN}" >&2
echo "INFO: WEB_ROOT: ${WEB_ROOT}" >&2
echo "INFO: CADDY_LOG: ${CADDY_LOG}" >&2
echo "INFO: VLESS_PORT: ${VLESS_PORT}" >&2
echo "INFO: TROJAN_PORT: ${TROJAN_PORT}" >&2
echo "INFO: VLESS_WS_PORT: ${VLESS_WS_PORT}" >&2
echo "INFO: VMESS_WS_PORT: ${VMESS_WS_PORT}" >&2
echo "" >&2
}
# Initialize the system environment,
# including:
# - Close SELINUX
# - Install system software
# - Configure system parameters
# Arguments:
# None
# Returns:
# None
function initSystemEnvironment(){
echo "INFO: Close SELINUX" >&2
sed -i 's/\(^SELINUX=\).*$/\1disabled/' /etc/selinux/config
setenforce 0 > /dev/null 2>&1 || true
echo "INFO: Update system software" >&2
dnf -y update
dnf -y install git vim tar
echo "INFO: Configure system parameters" >&2
echo ''
echo '# 20240620 ' >> /etc/sysctl.conf
echo 'vm.swappiness = 10' >> /etc/sysctl.conf
echo ''
echo 'net.ipv4.tcp_syncookies = 1' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_timestamps = 1' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_tw_reuse = 1 ' >> /etc/sysctl.conf
echo 'net.ipv4.ip_local_port_range = 1024 65535' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_max_syn_backlog = 1024' >> /etc/sysctl.conf
echo ''
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
echo ''
echo 'fs.inotify.max_user_instances = 4096' >> /etc/sysctl.conf
echo ''
echo 'fs.file-max = 65535' >> /etc/sysctl.conf
echo ''
echo '# 20240620' >> /etc/security/limits.conf
echo '* soft nofile 65535' >> /etc/security/limits.conf
echo '* hard nofile 65535' >> /etc/security/limits.conf
echo '* soft nproc 65535' >> /etc/security/limits.conf
echo '* hard nproc 65535' >> /etc/security/limits.conf
echo 'root soft nofile 65535' >> /etc/security/limits.conf
echo 'root hard nofile 65535' >> /etc/security/limits.conf
echo 'root soft nproc 65535' >> /etc/security/limits.conf
echo 'root hard nproc 65535' >> /etc/security/limits.conf
/sbin/sysctl -p
}
# Install Caddy Web server, and configure the firewall to open http 80 and https 443 ports
# Arguments:
# None
# Returns:
# None
function installWebServer() {
echo "INFO: Install Caddy Web server" >&2
dnf -y install 'dnf-command(copr)'
dnf -y copr enable @caddy/caddy
dnf -y install caddy
systemctl enable caddy
systemctl start caddy
curl http://localhost
# Trust the Caddy certificate
caddy trust
if [ ${ENABLE_FIREWALL} = true ]; then
echo "INFO: Enable Caddy firewall rules" >&2
configureWebFirewall
fi
}
# Configure the firewall to open the http 80 and https 443 ports
# Arguments:
# None
# Returns:
# None
function configureWebFirewall() {
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
firewall-cmd --reload
}
# Deploy sample Web app, and configure Caddy to use the Web app.
# Use vue-element-admin source code to build a web app. It disguise for xray service.
# If a FQDN domain is configured, Caddy will automatically generate a public certificate,
# and automatically rotate the certificate.
# So we can securely access the xray service , and protocol our data to xray.
# Arguments:
# None
# Returns:
# None
function deployWebApp() {
if [ ! -d "${WEB_ROOT}" ]; then
mkdir -p ${WEB_ROOT}
chown -R caddy:caddy ${WEB_ROOT}
fi
if [ ! -d "${CADDY_LOG}" ]; then
mkdir -p ${CADDY_LOG}
chown -R caddy:caddy ${CADDY_LOG}
fi
if [ ! -d "/opt/devtools" ]; then
mkdir -p /opt/devtools
fi
curl -o /tmp/node-v18.16.0-linux-x64.tar.xz -C - https://nodejs.org/dist/v18.16.0/node-v18.16.0-linux-x64.tar.xz
if [ -d "/opt/devtools/node-v18.16.0" ]; then
mv /opt/devtools/node-v18.16.0 /opt/devtools/node-v18.16.0_bak$(date +%Y%m%d%H%M%S)
fi
tar -xvf /tmp/node-v18.16.0-linux-x64.tar.xz -C /tmp
mv /tmp/node-v18.16.0-linux-x64 /opt/devtools/node-v18.16.0
export NODE_PATH=/opt/devtools/node-v18.16.0/
export PATH=$NODE_PATH/bin:$PATH
node -v
local web_app_src="/tmp/vue-element-admin"
if [ -d "$web_app_src" ]; then
rm -rf "$web_app_src"
fi
git clone https://github.com/PanJiaChen/vue-element-admin.git
# https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported
export NODE_OPTIONS=--openssl-legacy-provider
cd vue-element-admin
npm install
npm run build:prod
cp -R dist/* ${WEB_ROOT}
chown -R caddy:caddy ${WEB_ROOT}
cat > /etc/caddy/Caddyfile <<EOF
${DOMAIN} {
root * ${WEB_ROOT}
file_server
log {
output file ${CADDY_LOG}/access.log {
roll_size 100mb
roll_keep 5
roll_keep_for 15d
}
}
}
EOF
systemctl restart caddy
curl -k -I https://${DOMAIN}
}
# Install xray and configure xray to use caddy generated certificate.
# After installation, xray firewall rules will be created, and caddy firewall will be opened.
# Arguments:
# None
# Returns:
# None
function installXray() {
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install-geodata
# 使用 caddy 用户启动 xray 服务。主要是因为 caddy 自动生成的证书只有 caddy 用户才有权限读取。
# xray 默认使用的是 nobody 用户,在启动时无法读取 caddy 证书导致启动失败
sed -i 's/\(^User=\).*$/\1caddy/' /etc/systemd/system/xray.service
systemctl daemon-reload
CADDY_TRUST_PATH="/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory"
local certificate_file="${CADDY_TRUST_PATH}/${DOMAIN}/${DOMAIN}.crt"
local key_file="${CADDY_TRUST_PATH}/${DOMAIN}/${DOMAIN}.key"
cat > /usr/local/etc/xray/config.json <<EOF
{
"log": {
"loglevel": "warning"
// "loglevel": "debug"
},
"dns": {
"hosts": {
// "baidu.com": "127.0.0.1",
"dns.google": [
"8.8.8.8",
"8.8.4.4"
]
},
"servers": [
"1.1.1.1",
"8.8.8.8",
"8.8.4.4",
{
"address": "1.2.3.4",
"port": 5353,
"domains": [
"domain:xray.com"
],
"expectIPs": [
"geoip:cn"
],
"skipFallback": false,
"clientIP": "1.2.3.4"
},
{
"address": "https://8.8.8.8/dns-query",
"domains": [
"geosite:netflix"
],
"skipFallback": true,
"queryStrategy": "UseIPv4"
},
{
"address": "https://1.1.1.1/dns-query",
"domains": [
"geosite:openai"
],
"skipFallback": true,
"queryStrategy": "UseIPv6"
},
"localhost"
],
"clientIp": "1.2.3.4",
"queryStrategy": "UseIP",
"disableCache": false,
"disableFallback": false,
"disableFallbackIfMatch": false,
"tag": "dns_inbound"
},
"inbounds": [
{
"port": "${VLESS_PORT}",
"protocol": "vless",
"tag": "vless",
"settings": {
"clients": [
{
"id": "$(uuidgen)", // use uuidgen to generate a unique ID
"flow": "xtls-rprx-vision",
"level": 0,
"email": "[email protected]"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": ${TROJAN_PORT}, // Fall back to Xray's Trojan protocol by default
"xver": 1
},
{
"path": "/websocket", // Must be replaced with a custom PATH
"dest": ${VLESS_WS_PORT},
"xver": 1
},
{
"path": "/vmessws", // Must be replaced with a custom PATH
"dest": ${VMESS_WS_PORT},
"xver": 1
},
{
"dest": 80 // or fall back to other proxies that are also probing-proof
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "${DOMAIN}",
"rejectUnknownSni": true,
"allowInsecure": false,
"alpn": [
"h2",
"http/1.1"
],
"minVersion": "1.2",
"certificates": [
{
"certificateFile": "${certificate_file}", // Replace with your certificate, absolute path
"keyFile": "${key_file}" // Replace it with your private key, absolute path
}
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": ${TROJAN_PORT},
"listen": "127.0.0.1",
"protocol": "trojan",
"settings": {
"clients": [
{
"password": "$(uuidgen)",
"level": 0,
"email": "[email protected]"
}
],
"fallbacks": [
{
"dest": 80
}
]
},
"streamSettings": {
"network": "tcp",
"security": "none",
"tcpSettings": {
"acceptProxyProtocol": true
}
}
},
{
"port": ${VLESS_WS_PORT},
"listen": "127.0.0.1",
"protocol": "vless",
"tag": "vlessws",
"settings": {
"clients": [
{
"id": "$(uuidgen)",
"level": 0,
"email": "[email protected]"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true, // Reminder: If you use Nginx/Caddy to reverse generation WS, you need to delete this line
"path": "/websocket", // It must be replaced with a custom PATH, which needs to be consistent with the shunt
"headers": {
"Host": "${DOMAIN}"
}
}
}
},
{
"port": ${VMESS_WS_PORT},
"listen": "127.0.0.1",
"protocol": "vmess",
"tag": "vmessws",
"settings": {
"clients": [
{
"id": "$(uuidgen)",
"level": 0,
"email": "[email protected]"
}
]
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true, // Reminder: If you use Nginx/Caddy to reverse generation WS, you need to delete this line
"path": "/vmessws", // It must be replaced with a custom PATH, which needs to be consistent with the shunt
"headers": {
"Host": "${DOMAIN}"
}
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"domainMatcher": "hybrid",
"rules": [
{
"domainMatcher": "hybrid",
"domains": [
"geosite:category-ads-all"
],
"outboundTag": "block"
}
]
},
"policy": {
"levels": {
"0": {
"handshake": 2, // The handshake time limit when the connection is established, in seconds, the default value is 4, it is recommended to be different from the default value
"connIdle": 120 // Connection idle time limit in seconds, the default value is 300, it is recommended to be different from the default value
}
}
}
}
EOF
systemctl restart xray
if [ ${ENABLE_FIREWALL} = true ]; then
echo "INFO: Enable xray firewall rules" >&2
configureXrayFirewalld
fi
}
# Configure the firewall to open the xray port
# Arguments:
# None
# Returns:
# None
function configureXrayFirewalld() {
# Create xray firewall rules
cat > /etc/firewalld/services/xray.xml <<EOF
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Xray</short>
<description>Xray port</description>
<port protocol="tcp" port="${XRAY_PORT}"/>
<port protocol="udp" port="${XRAY_PORT}"/>
</service>
EOF
# Configure the firewall to open the xray port
firewall-cmd --reload
firewall-cmd --add-service=xray --permanent
firewall-cmd --reload
}
# Execute the main function
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment