feat: Implement full-featured V2Ray deployment script
This commit is contained in:
3
.cursorindexingignore
Normal file
3
.cursorindexingignore
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
# Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references
|
||||
.specstory/**
|
||||
2
.specstory/.gitignore
vendored
Normal file
2
.specstory/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# SpecStory explanation file
|
||||
/.what-is-this.md
|
||||
5523
.specstory/history/2025-07-23_02-06Z-你好的问候.md
Normal file
5523
.specstory/history/2025-07-23_02-06Z-你好的问候.md
Normal file
File diff suppressed because it is too large
Load Diff
25
a.md
Normal file
25
a.md
Normal file
@ -0,0 +1,25 @@
|
||||
脚本执行流程与功能分解
|
||||
信息收集(交互式)
|
||||
脚本启动后,会首先请您输入以下信息:
|
||||
域名 (Domain):您准备用于 V2Ray 服务的域名(例如:sydney.zyj.best)。
|
||||
邮箱 (Email):用于申请 Let's Encrypt SSL 证书,接收续期提醒。
|
||||
UUID:V2Ray 的用户 ID。脚本可以自动为您生成一个新的 UUID。
|
||||
WebSocket 路径 (Path):用于伪装的 WebSocket 路径(例如:/my-secret-path),脚本可以自动生成一个随机路径。
|
||||
环境准备与依赖安装
|
||||
自动更新系统软件包 (apt update && apt upgrade)。
|
||||
自动安装 V2Ray、Nginx 和 Certbot。
|
||||
伪装站点与 Nginx HTTP 配置
|
||||
创建伪装站点的目录 /var/www/your_domain。
|
||||
生成一个简单的 index.html 首页。
|
||||
根据您输入的域名,动态生成 Nginx 的 HTTP 配置文件,用于后续的 SSL 证书申请。
|
||||
申请 SSL 证书
|
||||
自动调用 certbot,使用您提供的域名和邮箱,以非交互方式申请 Let's Encrypt 证书,并配置 Nginx 进行 HTTPS 跳转。
|
||||
生成 V2Ray 服务端配置
|
||||
您提供的 readme.md 中是 Clash 客户端的配置。脚本将根据您输入的 UUID 和 WebSocket 路径,自动生成一份 V2Ray 服务端所需的 config.json 文件,并放置在 /usr/local/etc/v2ray/config.json。
|
||||
更新 Nginx 实现 WebSocket 代理
|
||||
脚本将重写 Nginx 的站点配置文件,加入完整的 HTTPS 支持,并将特定 WebSocket 路径的流量反向代理到本地的 V2Ray 服务。
|
||||
生成 Clash 客户端订阅文件
|
||||
部署成功后,脚本会在服务器的 /root/clash_config.yaml 路径下,根据您输入的所有信息,生成一份可以直接使用的 Clash 客户端配置文件。
|
||||
重启服务并显示结果
|
||||
完成所有配置后,自动重启 V2Ray 和 Nginx 服务使之生效。
|
||||
在终端清晰地输出您的 V2Ray 连接信息和 Clash 配置文件的存放路径,方便您直接复制使用
|
||||
660
deploy_v2ray.sh
Normal file
660
deploy_v2ray.sh
Normal file
@ -0,0 +1,660 @@
|
||||
#!/bin/bash
|
||||
|
||||
#================================================================
|
||||
# Project: V2Ray All-in-One Deployment Script
|
||||
# Author: Gemini & User
|
||||
# Version: 3.0 (Fully Non-Interactive & Documented)
|
||||
# Description: Automates the deployment of V2Ray with WebSocket,
|
||||
# TLS, Nginx, and generates a Clash configuration.
|
||||
# This script is designed for Debian/Ubuntu systems.
|
||||
#================================================================
|
||||
#
|
||||
# --- User Guide ---
|
||||
#
|
||||
# This script supports two modes of operation:
|
||||
#
|
||||
# 1. Interactive Mode (Default):
|
||||
# Simply run the script with sudo, and it will prompt you for all
|
||||
# necessary information.
|
||||
# $ sudo ./deploy_v2ray.sh
|
||||
#
|
||||
# 2. Non-Interactive Mode (for Automation):
|
||||
# Set the required configuration as environment variables before running
|
||||
# the script. This is ideal for use with secrets management tools like
|
||||
# 1Password CLI (op), Doppler, or in CI/CD pipelines.
|
||||
#
|
||||
# Example with 1Password CLI:
|
||||
# $ op run --env-file=.env -- sudo ./deploy_v2ray.sh
|
||||
#
|
||||
# --- Environment Variables ---
|
||||
#
|
||||
# To run in non-interactive mode, set the following variables.
|
||||
# For yes/no questions, 'y' means yes, anything else means no.
|
||||
#
|
||||
# [Core Configuration]
|
||||
# V2RAY_DOMAIN # Your domain name (e.g., v2.example.com). Required.
|
||||
# V2RAY_EMAIL # Your email for SSL certificates. Required.
|
||||
# V2RAY_UUID # Your V2Ray UUID. Optional, will be generated if not set.
|
||||
#
|
||||
# [Cloudflare DNS Automation]
|
||||
# V2RAY_USE_CF_DNS # Set to 'y' to enable. If not set, will ask interactively.
|
||||
# CF_API_TOKEN # Your Cloudflare API Token. Required if V2RAY_USE_CF_DNS=y.
|
||||
# CF_ZONE_ID # Your Cloudflare Zone ID. Required if V2RAY_USE_CF_DNS=y.
|
||||
#
|
||||
# [GitHub Gist Subscription]
|
||||
# V2RAY_USE_GIST # Set to 'y' to enable. If not set, will ask interactively.
|
||||
# GITHUB_USER # Your GitHub username. Required if V2RAY_USE_GIST=y.
|
||||
# GITHUB_TOKEN # Your GitHub Personal Access Token (with 'gist' scope).
|
||||
# # Required if V2RAY_USE_GIST=y.
|
||||
#
|
||||
#================================================================
|
||||
|
||||
|
||||
# --- Color Codes ---
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# --- State File ---
|
||||
STATE_FILE="/root/.v2ray_deployment_state"
|
||||
|
||||
# --- Script functions ---
|
||||
|
||||
# Function to print error messages and exit
|
||||
error_exit() {
|
||||
echo -e "${RED}Error: $1${NC}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to check if running as root
|
||||
check_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
error_exit "This script must be run as root. Please use sudo."
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to run pre-flight checks and install essential tools
|
||||
pre_flight_checks() {
|
||||
echo -e "${BLUE}Running pre-flight checks and installing essential tools...${NC}"
|
||||
apt-get update
|
||||
apt-get install -y curl wget jq socat unzip || error_exit "Failed to install essential tools. Please check your network and apt sources."
|
||||
}
|
||||
|
||||
# Function to get user input
|
||||
get_user_input() {
|
||||
# Load existing state if available
|
||||
if [ -f "${STATE_FILE}" ]; then
|
||||
source "${STATE_FILE}"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}--- V2Ray Deployment Setup ---${NC}"
|
||||
|
||||
# Check for Domain from env
|
||||
if [ -n "$V2RAY_DOMAIN" ]; then
|
||||
echo -e "${GREEN}Domain found in environment variables: ${V2RAY_DOMAIN}${NC}"
|
||||
DOMAIN="$V2RAY_DOMAIN"
|
||||
else
|
||||
read -p "Enter your domain name (e.g., v2.example.com): " DOMAIN
|
||||
fi
|
||||
if [ -z "${DOMAIN}" ]; then
|
||||
error_exit "Domain name cannot be empty."
|
||||
fi
|
||||
|
||||
# Check for Email from env
|
||||
if [ -n "$V2RAY_EMAIL" ]; then
|
||||
echo -e "${GREEN}Email found in environment variables: ${V2RAY_EMAIL}${NC}"
|
||||
EMAIL="$V2RAY_EMAIL"
|
||||
else
|
||||
read -p "Enter your email for SSL certificate (e.g., admin@example.com): " EMAIL
|
||||
fi
|
||||
if [ -z "${EMAIL}" ]; then
|
||||
error_exit "Email cannot be empty."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ -z "$V2RAY_USE_CF_DNS" ]; then
|
||||
read -p "Do you want to automatically configure Cloudflare DNS? (y/n): " USE_CF_DNS
|
||||
else
|
||||
echo -e "${GREEN}Cloudflare DNS configuration is set by V2RAY_USE_CF_DNS environment variable.${NC}"
|
||||
USE_CF_DNS=$V2RAY_USE_CF_DNS
|
||||
fi
|
||||
|
||||
if [[ "$USE_CF_DNS" =~ ^[Yy]$ ]]; then
|
||||
if [ -n "$CF_API_TOKEN" ]; then
|
||||
echo -e "${GREEN}Cloudflare API Token found in environment variables.${NC}"
|
||||
else
|
||||
read -p "Enter your Cloudflare API Token: " CF_API_TOKEN
|
||||
fi
|
||||
|
||||
if [ -n "$CF_ZONE_ID" ]; then
|
||||
echo -e "${GREEN}Cloudflare Zone ID found in environment variables.${NC}"
|
||||
else
|
||||
read -p "Enter your Cloudflare Zone ID: " CF_ZONE_ID
|
||||
fi
|
||||
|
||||
if [ -z "${CF_API_TOKEN}" ] || [ -z "${CF_ZONE_ID}" ]; then
|
||||
error_exit "Cloudflare API Token and Zone ID are required for this feature."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ -z "$V2RAY_USE_GIST" ]; then
|
||||
read -p "Do you want to create a GitHub Gist subscription link? (y/n): " USE_GIST
|
||||
else
|
||||
echo -e "${GREEN}GitHub Gist creation is set by V2RAY_USE_GIST environment variable.${NC}"
|
||||
USE_GIST=$V2RAY_USE_GIST
|
||||
fi
|
||||
|
||||
if [[ "$USE_GIST" =~ ^[Yy]$ ]]; then
|
||||
if [ -n "$GITHUB_USER" ]; then
|
||||
echo -e "${GREEN}GitHub Username found in environment variables: ${GITHUB_USER}${NC}"
|
||||
else
|
||||
read -p "Enter your GitHub Username: " GITHUB_USER
|
||||
fi
|
||||
|
||||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
echo -e "${GREEN}GitHub Personal Access Token found in environment variables.${NC}"
|
||||
else
|
||||
read -s -p "Enter your GitHub Personal Access Token (with 'gist' scope): " GITHUB_TOKEN
|
||||
echo
|
||||
fi
|
||||
|
||||
if [ -z "${GITHUB_USER}" ] || [ -z "${GITHUB_TOKEN}" ]; then
|
||||
error_exit "GitHub Username and Token are required for this feature."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for UUID from env
|
||||
if [ -n "$V2RAY_UUID" ]; then
|
||||
echo -e "${GREEN}UUID found in environment variables.${NC}"
|
||||
UUID="$V2RAY_UUID"
|
||||
else
|
||||
read -p "Enter your V2Ray UUID (or press Enter to generate one): " UUID
|
||||
fi
|
||||
|
||||
if [ -z "${UUID}" ]; then
|
||||
UUID=$(cat /proc/sys/kernel/random/uuid)
|
||||
echo -e "${YELLOW}Generated UUID: ${UUID}${NC}"
|
||||
fi
|
||||
|
||||
# Generate a random path for WebSocket
|
||||
WS_PATH="/$(head -n 10 /dev/urandom | md5sum | head -c 8)-ws"
|
||||
echo -e "${YELLOW}Generated WebSocket Path: ${WS_PATH}${NC}"
|
||||
|
||||
echo -e "${BLUE}--- Configuration Summary ---"
|
||||
echo -e "Domain: ${GREEN}${DOMAIN}${NC}"
|
||||
echo -e "Email: ${GREEN}${EMAIL}${NC}"
|
||||
echo -e "UUID: ${GREEN}${UUID}${NC}"
|
||||
echo -e "WS Path: ${GREEN}${WS_PATH}${NC}"
|
||||
echo -e "Auto DNS: " $([[ "$USE_CF_DNS" =~ ^[Yy]$ ]] && echo -e "${GREEN}Enabled${NC}" || echo -e "${YELLOW}Disabled${NC}")
|
||||
echo -e "Gist Link: " $([[ "$USE_GIST" =~ ^[Yy]$ ]] && echo -e "${GREEN}Enabled${NC}" || echo -e "${YELLOW}Disabled${NC}")
|
||||
echo -e "----------------------------${NC}"
|
||||
read -p "Press Enter to continue, or Ctrl+C to cancel..."
|
||||
}
|
||||
|
||||
# Function to update system and install dependencies
|
||||
install_dependencies() {
|
||||
echo -e "${BLUE}Updating system and installing dependencies...${NC}"
|
||||
|
||||
# System update and upgrade, with options to handle config file conflicts automatically
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade || error_exit "System upgrade failed."
|
||||
|
||||
# Install main applications
|
||||
apt-get install -y nginx certbot python3-certbot-nginx || error_exit "Failed to install Nginx or Certbot."
|
||||
|
||||
# Install V2Ray
|
||||
echo -e "${BLUE}Installing V2Ray...${NC}"
|
||||
bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh) || error_exit "V2Ray core installation failed."
|
||||
bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-dat-release.sh) || error_exit "V2Ray dat files installation failed."
|
||||
|
||||
systemctl enable --now v2ray || error_exit "Failed to enable V2Ray service."
|
||||
systemctl enable --now nginx || error_exit "Failed to enable Nginx service."
|
||||
|
||||
echo -e "${GREEN}Dependencies installed successfully.${NC}"
|
||||
}
|
||||
|
||||
# Function to configure Cloudflare DNS
|
||||
setup_cloudflare_dns() {
|
||||
if [[ ! "$USE_CF_DNS" =~ ^[Yy]$ ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Verifying domain with Cloudflare Zone...${NC}"
|
||||
|
||||
# Get the zone name from the provided Zone ID to verify domain ownership
|
||||
ZONE_DETAILS_RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}" \
|
||||
-H "Authorization: Bearer ${CF_API_TOKEN}" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
SUCCESS=$(echo "${ZONE_DETAILS_RESPONSE}" | jq -r '.success')
|
||||
if [ "${SUCCESS}" != "true" ]; then
|
||||
ERRORS=$(echo "${ZONE_DETAILS_RESPONSE}" | jq -r '.errors[0].message')
|
||||
error_exit "Cloudflare API call to get zone details failed: ${ERRORS}. Please check your Zone ID and API Token."
|
||||
fi
|
||||
|
||||
ZONE_NAME=$(echo "${ZONE_DETAILS_RESPONSE}" | jq -r '.result.name')
|
||||
|
||||
# Check if the user-provided domain is part of the fetched zone
|
||||
if ! [[ "${DOMAIN}" == "${ZONE_NAME}" || "${DOMAIN}" == *".${ZONE_NAME}" ]]; then
|
||||
error_exit "Domain mismatch: The domain '${DOMAIN}' does not belong to the Cloudflare zone '${ZONE_NAME}' associated with your Zone ID."
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Domain '${DOMAIN}' successfully verified against Zone '${ZONE_NAME}'.${NC}"
|
||||
|
||||
echo -e "${BLUE}Configuring Cloudflare DNS record for ${DOMAIN}...${NC}"
|
||||
|
||||
PUBLIC_IP=$(curl -s https://api.ipify.org)
|
||||
if [ -z "${PUBLIC_IP}" ]; then
|
||||
error_exit "Failed to get public IP address."
|
||||
fi
|
||||
echo "Public IP detected: ${PUBLIC_IP}"
|
||||
|
||||
# Check if DNS record already exists
|
||||
DNS_RECORD_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records?type=A&name=${DOMAIN}" \
|
||||
-H "Authorization: Bearer ${CF_API_TOKEN}" \
|
||||
-H "Content-Type: application/json" | jq -r '.result[0].id')
|
||||
|
||||
if [ "$DNS_RECORD_ID" != "null" ] && [ ! -z "$DNS_RECORD_ID" ]; then
|
||||
echo -e "${YELLOW}DNS record for ${DOMAIN} already exists. Updating it...${NC}"
|
||||
CF_API_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records/${DNS_RECORD_ID}" \
|
||||
-H "Authorization: Bearer ${CF_API_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data "{\"type\":\"A\",\"name\":\"${DOMAIN}\",\"content\":\"${PUBLIC_IP}\",\"ttl\":120,\"proxied\":false}")
|
||||
else
|
||||
echo -e "${BLUE}Creating new DNS A record for ${DOMAIN}...${NC}"
|
||||
CF_API_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records" \
|
||||
-H "Authorization: Bearer ${CF_API_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data "{\"type\":\"A\",\"name\":\"${DOMAIN}\",\"content\":\"${PUBLIC_IP}\",\"ttl\":120,\"proxied\":false}")
|
||||
fi
|
||||
|
||||
SUCCESS=$(echo "${CF_API_RESPONSE}" | jq -r '.success')
|
||||
if [ "${SUCCESS}" != "true" ]; then
|
||||
ERRORS=$(echo "${CF_API_RESPONSE}" | jq -r '.errors[0].message')
|
||||
error_exit "Cloudflare API call failed: ${ERRORS}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Cloudflare DNS record configured successfully.${NC}"
|
||||
echo -e "${YELLOW}Waiting 30 seconds for DNS to propagate...${NC}"
|
||||
sleep 30
|
||||
}
|
||||
|
||||
# Function to configure Nginx and get SSL certificate
|
||||
configure_nginx_and_ssl() {
|
||||
echo -e "${BLUE}Configuring Nginx and obtaining SSL certificate...${NC}"
|
||||
|
||||
# --- Pre-emptive Cleanup ---
|
||||
# Remove any stray .bak files from previous failed runs in sites-enabled
|
||||
rm -f /etc/nginx/sites-enabled/*.bak*
|
||||
# Remove any broken symlinks in sites-enabled
|
||||
find /etc/nginx/sites-enabled/ -xtype l -delete
|
||||
|
||||
# Create a directory for the fake site
|
||||
mkdir -p /var/www/${DOMAIN} || error_exit "Failed to create web directory."
|
||||
echo "<h1>Welcome to ${DOMAIN}</h1>" > /var/www/${DOMAIN}/index.html
|
||||
chown -R www-data:www-data /var/www/${DOMAIN} || error_exit "Failed to set web directory permissions."
|
||||
|
||||
# Backup the SOURCE config file in sites-available if it exists, then remove it
|
||||
if [ -f "/etc/nginx/sites-available/${DOMAIN}" ]; then
|
||||
echo -e "${YELLOW}Backing up and removing old config in sites-available...${NC}"
|
||||
mv "/etc/nginx/sites-available/${DOMAIN}" "/etc/nginx/sites-available/${DOMAIN}.bak_$(date +%s)"
|
||||
fi
|
||||
|
||||
# Remove any existing symlink in sites-enabled to avoid conflicts
|
||||
if [ -L "/etc/nginx/sites-enabled/${DOMAIN}" ]; then
|
||||
rm -f "/etc/nginx/sites-enabled/${DOMAIN}"
|
||||
fi
|
||||
|
||||
# Create a minimal Nginx config for certbot to find and modify
|
||||
cat > /etc/nginx/sites-available/${DOMAIN} <<EOF
|
||||
server {
|
||||
listen 80;
|
||||
server_name ${DOMAIN};
|
||||
root /var/www/${DOMAIN};
|
||||
}
|
||||
EOF
|
||||
|
||||
# Enable the site by creating a clean symlink
|
||||
ln -s "/etc/nginx/sites-available/${DOMAIN}" "/etc/nginx/sites-enabled/${DOMAIN}" || error_exit "Failed to enable Nginx site."
|
||||
|
||||
# Test and reload Nginx
|
||||
nginx -t && systemctl reload nginx || error_exit "Nginx configuration test failed."
|
||||
|
||||
# Obtain SSL certificate and let certbot configure Nginx
|
||||
echo -e "${BLUE}Requesting SSL Certificate for ${DOMAIN} and configuring Nginx...${NC}"
|
||||
certbot --nginx -d "${DOMAIN}" --agree-tos -m "${EMAIL}" --no-eff-email --redirect --non-interactive || error_exit "Certbot failed to obtain SSL certificate and configure Nginx."
|
||||
|
||||
echo -e "${GREEN}Nginx and SSL configured successfully by Certbot.${NC}"
|
||||
}
|
||||
|
||||
# Function to configure V2Ray server and update Nginx for WebSocket
|
||||
configure_v2ray_and_final_nginx() {
|
||||
echo -e "${BLUE}Configuring V2Ray and overwriting Nginx config for WebSocket...${NC}"
|
||||
|
||||
# V2Ray local port
|
||||
V2RAY_PORT=10086
|
||||
|
||||
# Backup V2Ray config before overwriting
|
||||
if [ -f /usr/local/etc/v2ray/config.json ]; then
|
||||
mv /usr/local/etc/v2ray/config.json /usr/local/etc/v2ray/config.json.bak_$(date +%s)
|
||||
fi
|
||||
|
||||
# Create V2Ray server config
|
||||
cat > /usr/local/etc/v2ray/config.json <<EOF
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 10086,
|
||||
"listen": "127.0.0.1",
|
||||
"protocol": "vmess",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "${UUID}",
|
||||
"alterId": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "ws",
|
||||
"wsSettings": {
|
||||
"path": "${WS_PATH}"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
# Backup Nginx config before overwriting
|
||||
if [ -f /etc/nginx/sites-available/${DOMAIN} ]; then
|
||||
mv /etc/nginx/sites-available/${DOMAIN} /etc/nginx/sites-available/${DOMAIN}.bak_$(date +%s)
|
||||
fi
|
||||
|
||||
# Create final Nginx config for WebSocket proxy, building upon Certbot's work
|
||||
cat > /etc/nginx/sites-available/${DOMAIN} <<EOF
|
||||
server {
|
||||
server_name ${DOMAIN};
|
||||
|
||||
root /var/www/${DOMAIN};
|
||||
index index.html;
|
||||
|
||||
# WebSocket proxy to V2Ray
|
||||
location ${WS_PATH} {
|
||||
if (\$http_upgrade != "websocket") {
|
||||
return 404;
|
||||
}
|
||||
proxy_pass http://127.0.0.1:${V2RAY_PORT};
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# SSL Configuration managed by Certbot
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${DOMAIN};
|
||||
if (\$request_uri !~ "^/\\.well-known/acme-challenge/") {
|
||||
return 301 https://\$host\$request_uri;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Test Nginx config and restart services
|
||||
nginx -t && systemctl restart nginx || error_exit "Nginx final configuration failed."
|
||||
systemctl restart v2ray || error_exit "V2Ray service restart failed."
|
||||
|
||||
echo -e "${GREEN}V2Ray and Nginx re-configured for WebSocket successfully.${NC}"
|
||||
}
|
||||
|
||||
# Function to create or update a GitHub Gist for the Clash config
|
||||
create_github_gist() {
|
||||
if [[ ! "$USE_GIST" =~ ^[Yy]$ ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Creating or updating GitHub Gist for subscription...${NC}"
|
||||
|
||||
CLASH_CONFIG_CONTENT=$(cat ${CLASH_CONFIG_PATH})
|
||||
GIST_FILENAME="${DOMAIN}.yaml"
|
||||
|
||||
GIST_PAYLOAD=$(jq -n \
|
||||
--arg description "V2Ray Clash subscription for ${DOMAIN}" \
|
||||
--arg filename "${GIST_FILENAME}" \
|
||||
--arg content "${CLASH_CONFIG_CONTENT}" \
|
||||
'{
|
||||
"description": $description,
|
||||
"public": false,
|
||||
"files": {
|
||||
($filename): {
|
||||
"content": $content
|
||||
}
|
||||
}
|
||||
}')
|
||||
|
||||
if [ -z "${GIST_ID}" ]; then
|
||||
echo "Creating new Gist..."
|
||||
API_METHOD="POST"
|
||||
API_URL="https://api.github.com/gists"
|
||||
else
|
||||
echo "Updating existing Gist (ID: ${GIST_ID})..."
|
||||
API_METHOD="PATCH"
|
||||
API_URL="https://api.github.com/gists/${GIST_ID}"
|
||||
fi
|
||||
|
||||
GIST_RESPONSE=$(curl -s -X ${API_METHOD} ${API_URL} \
|
||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-d "${GIST_PAYLOAD}")
|
||||
|
||||
# Try to get URL and ID from response
|
||||
GIST_RAW_URL=$(echo "${GIST_RESPONSE}" | jq -r --arg filename "${GIST_FILENAME}" '.files[$filename].raw_url')
|
||||
NEW_GIST_ID=$(echo "${GIST_RESPONSE}" | jq -r '.id')
|
||||
|
||||
if [ "${GIST_RAW_URL}" == "null" ] || [ -z "${GIST_RAW_URL}" ]; then
|
||||
ERROR_MSG=$(echo "${GIST_RESPONSE}" | jq -r '.message')
|
||||
echo -e "${YELLOW}Warning: Failed to create or update GitHub Gist. Error: ${ERROR_MSG}${NC}"
|
||||
GIST_RAW_URL=""
|
||||
else
|
||||
# If Gist ID is new, save it to the state file
|
||||
if [ "${GIST_ID}" != "${NEW_GIST_ID}" ]; then
|
||||
echo "GIST_ID=\"${NEW_GIST_ID}\"" > "${STATE_FILE}"
|
||||
echo -e "${GREEN}New GitHub Gist created and state saved.${NC}"
|
||||
else
|
||||
echo -e "${GREEN}GitHub Gist updated successfully.${NC}"
|
||||
fi
|
||||
GIST_ID=${NEW_GIST_ID} # Ensure GIST_ID is set for the current run
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to generate Clash config and show summary
|
||||
generate_clash_config() {
|
||||
echo -e "${BLUE}Generating Clash client configuration...${NC}"
|
||||
|
||||
CLASH_CONFIG_PATH="/root/clash_config.yaml"
|
||||
|
||||
cat > ${CLASH_CONFIG_PATH} <<EOF
|
||||
# ================== Clash Meta Configuration ==================
|
||||
port: 7890
|
||||
socks-port: 7891
|
||||
redir-port: 7892
|
||||
mode: rule
|
||||
allow-lan: false
|
||||
bind-address: 127.0.0.1
|
||||
log-level: info
|
||||
|
||||
external-controller: 127.0.0.1:9090
|
||||
external-ui: dashboard
|
||||
|
||||
######### DNS #########
|
||||
dns:
|
||||
enable: true
|
||||
listen: 127.0.0.1:53
|
||||
ipv6: false
|
||||
enhanced-mode: redir-host
|
||||
nameserver:
|
||||
- https://dns.cloudflare.com/dns-query
|
||||
- https://dns.google/dns-query
|
||||
- 223.5.5.5
|
||||
fallback:
|
||||
- https://1.0.0.1/dns-query
|
||||
- tls://8.8.4.4:853
|
||||
- 8.8.4.4
|
||||
fallback-filter:
|
||||
geoip: true
|
||||
geoip-code: CN
|
||||
|
||||
######### Proxies #########
|
||||
proxies:
|
||||
- name: "${DOMAIN}"
|
||||
type: vmess
|
||||
server: ${DOMAIN}
|
||||
port: 443
|
||||
uuid: ${UUID}
|
||||
alterId: 0
|
||||
cipher: auto
|
||||
network: ws
|
||||
tls: true
|
||||
servername: ${DOMAIN}
|
||||
skip-cert-verify: false
|
||||
udp: true
|
||||
ws-opts:
|
||||
path: "${WS_PATH}"
|
||||
headers:
|
||||
Host: ${DOMAIN}
|
||||
|
||||
######### Proxy Groups #########
|
||||
proxy-groups:
|
||||
- name: "🚀 PROXY"
|
||||
type: select
|
||||
proxies:
|
||||
- "${DOMAIN}"
|
||||
- DIRECT
|
||||
|
||||
- name: "🎥 Streaming"
|
||||
type: select
|
||||
proxies:
|
||||
- "${DOMAIN}"
|
||||
- DIRECT
|
||||
|
||||
- name: "🆎 AdBlock"
|
||||
type: select
|
||||
proxies:
|
||||
- REJECT
|
||||
- DIRECT
|
||||
|
||||
######### Rule Providers #########
|
||||
rule-providers:
|
||||
ads:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt"
|
||||
path: ./ruleset/ads.list
|
||||
interval: 86400
|
||||
|
||||
mainland:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/direct.txt"
|
||||
path: ./ruleset/mainland.list
|
||||
interval: 86400
|
||||
|
||||
gfwlist:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/proxy.txt"
|
||||
path: ./ruleset/gfwlist.list
|
||||
interval: 86400
|
||||
|
||||
cn_ip:
|
||||
type: http
|
||||
behavior: ipcidr
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/cncidr.txt"
|
||||
path: ./ruleset/cn_ip.list
|
||||
interval: 86400
|
||||
|
||||
######### Rules #########
|
||||
rules:
|
||||
- RULE-SET,ads,🆎 AdBlock
|
||||
- RULE-SET,cn_ip,DIRECT
|
||||
- RULE-SET,mainland,DIRECT
|
||||
# Optional streaming media rules
|
||||
# - GEOSITE,netflix,🎥 Streaming
|
||||
# - GEOSITE,youtube,🎥 Streaming
|
||||
- RULE-SET,gfwlist,🚀 PROXY
|
||||
- MATCH,🚀 PROXY
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}Clash configuration file generated at: ${CLASH_CONFIG_PATH}${NC}"
|
||||
}
|
||||
|
||||
# Function to show a summary of the deployment
|
||||
show_summary() {
|
||||
echo -e "${GREEN}===================================================================${NC}"
|
||||
echo -e "${GREEN} V2Ray Deployment Completed Successfully! ${NC}"
|
||||
echo -e "${GREEN}===================================================================${NC}"
|
||||
echo -e "${YELLOW}Your V2Ray Configuration:${NC}"
|
||||
echo -e "-------------------------------------------------------------------"
|
||||
echo -e " Address (地址): ${GREEN}${DOMAIN}${NC}"
|
||||
echo -e " Port (端口): ${GREEN}443${NC}"
|
||||
echo -e " UUID (用户ID): ${GREEN}${UUID}${NC}"
|
||||
echo -e " AlterId: ${GREEN}0${NC}"
|
||||
echo -e " Security (加密): ${GREEN}auto${NC}"
|
||||
echo -e " Network (网络): ${GREEN}ws${NC}"
|
||||
echo -e " Host (主机名): ${GREEN}${DOMAIN}${NC}"
|
||||
echo -e " Path (路径): ${GREEN}${WS_PATH}${NC}"
|
||||
echo -e " TLS: ${GREEN}tls${NC}"
|
||||
echo -e "-------------------------------------------------------------------"
|
||||
echo -e "${YELLOW}Clash Configuration File:${NC}"
|
||||
echo -e " The Clash config file is located at: ${GREEN}/root/clash_config.yaml${NC}"
|
||||
if [[ ! -z "${GIST_RAW_URL}" ]]; then
|
||||
echo -e "${YELLOW}Clash Subscription Link:${NC}"
|
||||
echo -e " ${GREEN}${GIST_RAW_URL}${NC}"
|
||||
fi
|
||||
echo -e " You can also download the local file using scp or sftp."
|
||||
echo -e "${GREEN}===================================================================${NC}"
|
||||
}
|
||||
|
||||
|
||||
# --- Main execution ---
|
||||
main() {
|
||||
pre_flight_checks
|
||||
check_root
|
||||
get_user_input
|
||||
|
||||
setup_cloudflare_dns
|
||||
install_dependencies
|
||||
configure_nginx_and_ssl
|
||||
configure_v2ray_and_final_nginx
|
||||
generate_clash_config
|
||||
create_github_gist
|
||||
|
||||
show_summary
|
||||
}
|
||||
|
||||
# Run the main function
|
||||
main "$@"
|
||||
396
readme.md
Normal file
396
readme.md
Normal file
@ -0,0 +1,396 @@
|
||||
#我希望创建一个自动化脚本,用于在新的服务器上部署我的 v2ray 网络代理服务,以下是大概步骤,给出你的方案
|
||||
|
||||
1. 安装 v2ray,通过脚本 bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh) 和
|
||||
bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-dat-release.sh)
|
||||
|
||||
2. 安装 nginx 和 cerbot
|
||||
|
||||
sudo apt install -y nginx certbot python3-certbot-nginx
|
||||
sudo systemctl enable --now nginx
|
||||
|
||||
3. 放一个伪装首页
|
||||
|
||||
sudo mkdir -p /var/www/bwh-site
|
||||
echo '<h1>Hello from sydney.zyj.best</h1>' | sudo tee /var/www/bwh-site/index.html
|
||||
sudo chown -R www-data:www-data /var/www/bwh-site
|
||||
|
||||
4. 写入 HTTP 站点(80) —— 仅用于申请证书
|
||||
|
||||
sudo tee /etc/nginx/sites-available/sydney.zyj.best <<'EOF'
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name bwh.zyj.best;
|
||||
|
||||
root /var/www/bwh-site;
|
||||
index index.html;
|
||||
|
||||
# 允许 ACME 挑战
|
||||
location ~ /.well-known/acme-challenge/ {
|
||||
allow all;
|
||||
}
|
||||
|
||||
# 其他全部跳转到 HTTPS
|
||||
location / { return 301 https://$host$request_uri; }
|
||||
|
||||
}
|
||||
EOF
|
||||
|
||||
sudo ln -s /etc/nginx/sites-available/bwh.zyj.best /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
|
||||
5. 一键签发 Let’s Encrypt 证书(443)
|
||||
|
||||
sudo certbot --nginx -d sydney.zyj.best --agree-tos -m you@example.com --redirect
|
||||
|
||||
6. 更新 v2ray 配置
|
||||
|
||||
# ================= Clash Meta 配置 =================
|
||||
|
||||
port: 7890 # HTTP 代理
|
||||
socks-port: 7891 # SOCKS5 代理
|
||||
redir-port: 7892 # 透明代理 (Linux 可注释)
|
||||
mode: rule # rule / global / direct
|
||||
allow-lan: false # 局域网访问
|
||||
bind-address: 127.0.0.1
|
||||
log-level: info
|
||||
|
||||
external-controller: 127.0.0.1:9090
|
||||
external-ui: dashboard
|
||||
|
||||
######### DNS #########
|
||||
dns:
|
||||
enable: true
|
||||
listen: 127.0.0.1:53 # 避免占用系统 53
|
||||
ipv6: false
|
||||
enhanced-mode: redir-host
|
||||
nameserver: - https://dns.cloudflare.com/dns-query - https://dns.google/dns-query - 223.5.5.5
|
||||
fallback: - https://1.0.0.1/dns-query - tls://8.8.4.4:853 - 8.8.4.4
|
||||
fallback-filter:
|
||||
geoip: true
|
||||
geoip-code: CN
|
||||
|
||||
######### 代理 #########
|
||||
proxies:
|
||||
|
||||
- name: "Bwh"
|
||||
type: vmess
|
||||
server: bwh.zyj.best
|
||||
port: 443
|
||||
uuid: 81c5bd30-21c0-ba05-f711-47e11c659598
|
||||
alterId: 0
|
||||
cipher: auto
|
||||
network: ws
|
||||
tls: true
|
||||
servername: bwh.zyj.best
|
||||
skip-cert-verify: false
|
||||
udp: true
|
||||
ws-opts:
|
||||
path: "/mysecretpath-221667"
|
||||
headers:
|
||||
Host: bwh.zyj.best
|
||||
|
||||
######### 代理组 #########
|
||||
proxy-groups:
|
||||
|
||||
# 主出站
|
||||
|
||||
- name: "🚀 PROXY"
|
||||
type: select
|
||||
proxies:
|
||||
- "Bwh"
|
||||
- DIRECT
|
||||
|
||||
# 流媒体分流
|
||||
|
||||
- name: "🎥 Streaming"
|
||||
type: select
|
||||
proxies:
|
||||
- "Bwh"
|
||||
- DIRECT
|
||||
|
||||
# 广告拦截后去向
|
||||
|
||||
- name: "🆎 AdBlock"
|
||||
type: select
|
||||
proxies:
|
||||
- REJECT
|
||||
- DIRECT
|
||||
|
||||
######### 规则提供器 #########
|
||||
rule-providers:
|
||||
ads:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt"
|
||||
path: ./ruleset/ads.list
|
||||
interval: 86400
|
||||
|
||||
mainland:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/direct.txt"
|
||||
path: ./ruleset/mainland.list
|
||||
interval: 86400
|
||||
|
||||
gfwlist:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/proxy.txt"
|
||||
path: ./ruleset/gfwlist.list
|
||||
interval: 86400
|
||||
|
||||
cn_ip:
|
||||
type: http
|
||||
behavior: ipcidr
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/cncidr.txt"
|
||||
path: ./ruleset/cn_ip.list
|
||||
interval: 86400
|
||||
|
||||
######### 分流规则 #########
|
||||
rules:
|
||||
|
||||
# 1) 广告拦截
|
||||
|
||||
- RULE-SET,ads,🆎 AdBlock
|
||||
|
||||
# 2) 内网及局域网
|
||||
|
||||
- RULE-SET,cn_ip,DIRECT
|
||||
|
||||
# 3) 中国域名直连
|
||||
|
||||
- RULE-SET,mainland,DIRECT
|
||||
|
||||
# 4) 流媒体示例 (可按需追加 geosite:netflix 等)
|
||||
|
||||
# - GEOSITE,netflix,🎥 Streaming
|
||||
|
||||
# - GEOSITE,youtube,🎥 Streaming
|
||||
|
||||
# 5) GFW / 其他国外域名走代理
|
||||
|
||||
- RULE-SET,gfwlist,🚀 PROXY
|
||||
|
||||
# 6) 默认
|
||||
|
||||
- MATCH,🚀 PROXY
|
||||
|
||||
7. 更新 nginx 配置
|
||||
|
||||
##
|
||||
|
||||
# 站点:bwh.zyj.best
|
||||
|
||||
# 模式:伪装静态站 + V2Ray WebSocket‑over‑TLS(同端口 443)
|
||||
|
||||
# 文件:/etc/nginx/sites-available/bwh.zyj.best
|
||||
|
||||
##
|
||||
|
||||
############################
|
||||
|
||||
# HTTPS 443 伪装站 + 代理
|
||||
|
||||
############################
|
||||
server {
|
||||
server_name bwh.zyj.best;
|
||||
|
||||
# ----------------- 静态网站 -----------------
|
||||
root /var/www/bwh-site;
|
||||
index index.html;
|
||||
|
||||
# ----------------- WebSocket 反向代理 -----------------
|
||||
# 与 V2Ray streamSettings.wsSettings.path 完全一致
|
||||
location /mysecretpath-221667 {
|
||||
# 非 WebSocket 请求直接 404,可防扫描
|
||||
if ($http_upgrade != "websocket") { return 404; }
|
||||
|
||||
proxy_pass http://127.0.0.1:10086; # V2Ray 本地监听
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Origin "";
|
||||
}
|
||||
|
||||
# ----------------- 其他静态资源 -----------------
|
||||
# 直接按 root 目录查找文件
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# ----------------- ACME HTTP‑01 回调 -----------------
|
||||
location ~ /.well-known/acme-challenge/ {
|
||||
allow all;
|
||||
}
|
||||
|
||||
# ----------------- SSL 设置(Certbot 自动管理) -----------------
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2 ipv6only=on;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/bwh.zyj.best/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/bwh.zyj.best/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
|
||||
############################
|
||||
|
||||
# HTTP 80 → HTTPS 重定向
|
||||
|
||||
############################
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name bwh.zyj.best;
|
||||
|
||||
# ACME HTTP‑01 挑战
|
||||
location ~ /.well-known/acme-challenge/ {
|
||||
allow all;
|
||||
root /var/www/bwh-site;
|
||||
}
|
||||
|
||||
# 其余全部 301 到 HTTPS
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
8. 生成 clash 订阅 文件
|
||||
|
||||
# ================= Clash Meta 配置 =================
|
||||
|
||||
port: 7890 # HTTP 代理
|
||||
socks-port: 7891 # SOCKS5 代理
|
||||
redir-port: 7892 # 透明代理 (Linux 可注释)
|
||||
mode: rule # rule / global / direct
|
||||
allow-lan: false # 局域网访问
|
||||
bind-address: 127.0.0.1
|
||||
log-level: info
|
||||
|
||||
external-controller: 127.0.0.1:9090
|
||||
external-ui: dashboard
|
||||
|
||||
######### DNS #########
|
||||
dns:
|
||||
enable: true
|
||||
listen: 127.0.0.1:53 # 避免占用系统 53
|
||||
ipv6: false
|
||||
enhanced-mode: redir-host
|
||||
nameserver: - https://dns.cloudflare.com/dns-query - https://dns.google/dns-query - 223.5.5.5
|
||||
fallback: - https://1.0.0.1/dns-query - tls://8.8.4.4:853 - 8.8.4.4
|
||||
fallback-filter:
|
||||
geoip: true
|
||||
geoip-code: CN
|
||||
|
||||
######### 代理 #########
|
||||
proxies:
|
||||
|
||||
- name: "Bwh"
|
||||
type: vmess
|
||||
server: bwh.zyj.best
|
||||
port: 443
|
||||
uuid: 81c5bd30-21c0-ba05-f711-47e11c659598
|
||||
alterId: 0
|
||||
cipher: auto
|
||||
network: ws
|
||||
tls: true
|
||||
servername: bwh.zyj.best
|
||||
skip-cert-verify: false
|
||||
udp: true
|
||||
ws-opts:
|
||||
path: "/mysecretpath-221667"
|
||||
headers:
|
||||
Host: bwh.zyj.best
|
||||
|
||||
######### 代理组 #########
|
||||
proxy-groups:
|
||||
|
||||
# 主出站
|
||||
|
||||
- name: "🚀 PROXY"
|
||||
type: select
|
||||
proxies:
|
||||
- "Bwh"
|
||||
- DIRECT
|
||||
|
||||
# 流媒体分流
|
||||
|
||||
- name: "🎥 Streaming"
|
||||
type: select
|
||||
proxies:
|
||||
- "Bwh"
|
||||
- DIRECT
|
||||
|
||||
# 广告拦截后去向
|
||||
|
||||
- name: "🆎 AdBlock"
|
||||
type: select
|
||||
proxies:
|
||||
- REJECT
|
||||
- DIRECT
|
||||
|
||||
######### 规则提供器 #########
|
||||
rule-providers:
|
||||
ads:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt"
|
||||
path: ./ruleset/ads.list
|
||||
interval: 86400
|
||||
|
||||
mainland:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/direct.txt"
|
||||
path: ./ruleset/mainland.list
|
||||
interval: 86400
|
||||
|
||||
gfwlist:
|
||||
type: http
|
||||
behavior: domain
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/proxy.txt"
|
||||
path: ./ruleset/gfwlist.list
|
||||
interval: 86400
|
||||
|
||||
cn_ip:
|
||||
type: http
|
||||
behavior: ipcidr
|
||||
url: "https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/cncidr.txt"
|
||||
path: ./ruleset/cn_ip.list
|
||||
interval: 86400
|
||||
|
||||
######### 分流规则 #########
|
||||
rules:
|
||||
|
||||
# 1) 广告拦截
|
||||
|
||||
- RULE-SET,ads,🆎 AdBlock
|
||||
|
||||
# 2) 内网及局域网
|
||||
|
||||
- RULE-SET,cn_ip,DIRECT
|
||||
|
||||
# 3) 中国域名直连
|
||||
|
||||
- RULE-SET,mainland,DIRECT
|
||||
|
||||
# 4) 流媒体示例 (可按需追加 geosite:netflix 等)
|
||||
|
||||
# - GEOSITE,netflix,🎥 Streaming
|
||||
|
||||
# - GEOSITE,youtube,🎥 Streaming
|
||||
|
||||
# 5) GFW / 其他国外域名走代理
|
||||
|
||||
- RULE-SET,gfwlist,🚀 PROXY
|
||||
|
||||
# 6) 默认
|
||||
|
||||
- MATCH,🚀 PROXY
|
||||
Reference in New Issue
Block a user