This commit is contained in:
parent
58b769abe7
commit
050cecc84f
7
.env
7
.env
@ -1,4 +1,5 @@
|
||||
PORT=443
|
||||
FQDN=example.com
|
||||
USERS=exampleuser1,exampleuser2@xtls-rprx-direct
|
||||
LOGDIR=./logs
|
||||
TARGET_URL=example.com
|
||||
TARGET_PORT=443
|
||||
USERS=exampleuser1,exampleuser2
|
||||
LOG_LEVEL=warn
|
28
Dockerfile
28
Dockerfile
@ -1,34 +1,24 @@
|
||||
FROM alpine:latest
|
||||
|
||||
ENV VER_XRAY 1.7.5
|
||||
ENV VER_SO 2.5.20
|
||||
ENV VER_NG 1.7.38
|
||||
ENV VER_XRAY 1.8.3
|
||||
|
||||
# install packages
|
||||
RUN set -xe && apk add --no-cache unzip wget nginx certbot openssl python3 py3-jinja2 supervisor apache2-utils bash
|
||||
RUN set -xe && apk add --no-cache unzip wget openssl python3 py3-jinja2 supervisor apache2-utils bash
|
||||
|
||||
# download packages
|
||||
RUN set -xe && \
|
||||
mkdir -p /downloads /downloads/others /downloads/android && \
|
||||
wget -P /downloads/others https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-windows-64.zip && \
|
||||
wget -P /downloads/others https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-linux-64.zip && \
|
||||
wget -P /downloads/others https://github.com/FelisCatus/SwitchyOmega/releases/download/v$VER_SO/SwitchyOmega_Chromium.crx && \
|
||||
wget -P /downloads/android https://github.com/2dust/v2rayNG/releases/download/$VER_NG/v2rayNG_"$VER_NG"_arm64-v8a.apk && \
|
||||
wget -P /downloads/others https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-macos-64.zip && \
|
||||
wget -P /downloads/others https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-macos-arm64-v8a.zip
|
||||
mkdir -p /downloads && \
|
||||
wget -P /downloads https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-linux-64.zip && \
|
||||
unzip /downloads/Xray-linux-64.zip -d /opt/xray && \
|
||||
rm -rf /downloads
|
||||
|
||||
COPY ./opt /opt/
|
||||
|
||||
# xray
|
||||
RUN set -xe && unzip /downloads/others/Xray-linux-64.zip -d /opt/xray
|
||||
|
||||
# nginx
|
||||
RUN set -xe && addgroup www && \
|
||||
adduser -H -D -S -s /bin/false www -G www && \
|
||||
chown -R www:www /opt/nginx
|
||||
# RUN set -xe && addgroup www && \
|
||||
# adduser -H -D -S -s /bin/false www -G www && \
|
||||
# chown -R www:www /opt/nginx
|
||||
|
||||
# remove packages
|
||||
RUN set -xe && apk del unzip wget
|
||||
EXPOSE 80
|
||||
VOLUME /etc/letsencrypt
|
||||
CMD ["sh", "/opt/init.sh"]
|
@ -2,23 +2,20 @@ networks:
|
||||
d2ray_br:
|
||||
external: false
|
||||
|
||||
volumes:
|
||||
d2ray_certs:
|
||||
|
||||
services:
|
||||
d2ray:
|
||||
image: quackerd/d2ray
|
||||
container_name: d2ray
|
||||
ports:
|
||||
- ${PORT}:${PORT}
|
||||
- 80:80
|
||||
environment:
|
||||
- PORT=${PORT}
|
||||
- FQDN=${FQDN}
|
||||
- TARGET_URL=${TARGET_URL}
|
||||
- TARGET_PORT=${TARGET_PORT}
|
||||
- USERS=${USERS}
|
||||
- LOG_LEVEL=${LOG_LEVEL}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- d2ray_br
|
||||
volumes:
|
||||
- d2ray_certs:/etc/letsencrypt
|
||||
- ${LOGDIR}:/etc/d2ray
|
||||
- ./config:/etc/d2ray
|
||||
|
@ -1 +0,0 @@
|
||||
0 0 * * * certbot renew --post-hook "supervisorctl xray restart"
|
205
opt/init.py
205
opt/init.py
@ -1,10 +1,68 @@
|
||||
import os
|
||||
import getopt
|
||||
import sys
|
||||
import subprocess
|
||||
import jinja2
|
||||
import random
|
||||
import string
|
||||
import pathlib
|
||||
|
||||
CONFIG_DIR = pathlib.Path("/etc/d2ray")
|
||||
PRIVKEY = CONFIG_DIR.joinpath("certs/private_key")
|
||||
PUBKEY = CONFIG_DIR.joinpath("certs/public_key")
|
||||
LOG_DIR = CONFIG_DIR.joinpath("logs")
|
||||
XRAY_BIN = pathlib.Path("/opt/xray/xray")
|
||||
|
||||
class d2args:
|
||||
port : int
|
||||
target_port : int
|
||||
target_url : str
|
||||
log_level : str
|
||||
users : list[str]
|
||||
def __init__(self) -> None:
|
||||
self.port = 443
|
||||
self.target_port = 443
|
||||
self.target_url = "localhost"
|
||||
self.log_level = "warn"
|
||||
self.users = [''.join(random.choices(string.ascii_uppercase + string.digits, k=24))]
|
||||
|
||||
def from_env(self) -> None:
|
||||
env = os.getenv("PORT")
|
||||
if env != None:
|
||||
self.port = int(env)
|
||||
|
||||
env = os.getenv("TARGET_PORT")
|
||||
if env != None:
|
||||
self.target_port = int(env)
|
||||
|
||||
env = os.getenv("TARGET_URL")
|
||||
if env != None:
|
||||
self.target_url = env
|
||||
|
||||
env = os.getenv("LOG_LEVEL")
|
||||
if env != None:
|
||||
self.log_level = env
|
||||
|
||||
env = os.getenv("USERS")
|
||||
if env != None:
|
||||
self.users = env.split(",")
|
||||
|
||||
def __str__(self):
|
||||
ret = (f"Port: {self.port}\n"
|
||||
f"Target Port: {self.target_port}\n"
|
||||
f"Target URL: {self.target_url}\n"
|
||||
f"Log Level: {self.log_level}\n"
|
||||
f"Users: {', '.join(self.users)}"
|
||||
)
|
||||
return ret
|
||||
|
||||
def get_users_json(self) -> str:
|
||||
ret : str= ""
|
||||
for i in range(len(users)):
|
||||
if (i > 0):
|
||||
ret = ret + ","
|
||||
ret = ret + "{\"id\": \"" + users[i][0] + "\",\"flow\": \"" + users[i][1] + "\"}"
|
||||
return ret
|
||||
|
||||
|
||||
def process_directory(path : str, vars : dict[str, str], delete_template : bool = True) -> None:
|
||||
for f in os.listdir(path):
|
||||
@ -20,103 +78,76 @@ def process_directory(path : str, vars : dict[str, str], delete_template : bool
|
||||
if delete_template:
|
||||
subprocess.check_call(f"rm {full_path}", shell=True)
|
||||
|
||||
def build_target_fqdns(url : str) -> str:
|
||||
prefix = "www."
|
||||
fqdns = [url, f"{prefix}{url}"]
|
||||
if url.startswith(prefix) and len(url) > len(prefix):
|
||||
fqdns.append(url[len(prefix):])
|
||||
return ', '.join(['"' + item + '"' for item in fqdns])
|
||||
|
||||
def parse_user_flow(s : str) -> list[tuple[str,str]]:
|
||||
users = []
|
||||
userconfs : list[str] = s.split(",")
|
||||
for userconf in userconfs:
|
||||
if len(userconf) == 0:
|
||||
continue
|
||||
ele = userconf.split("@")
|
||||
username = ele[0]
|
||||
if (len(ele) > 1):
|
||||
flow = ele[1]
|
||||
else:
|
||||
flow = "xtls-rprx-vision"
|
||||
users.append((username, flow))
|
||||
return users
|
||||
def build_users_json(users: list[str]) -> str:
|
||||
return ', '.join(["{\"id\": \"" + item + "\", \"flow\": \"xtls-rprx-vision\"}" for item in users])
|
||||
|
||||
def build_jinja_dict(args : d2args, skey : str) -> dict[str, str]:
|
||||
jinja_dict : dict[str,str] = dict()
|
||||
jinja_dict["PORT"] = str(args.port)
|
||||
|
||||
def build_users_json(users: list[tuple[str, str]]) -> str:
|
||||
ret : str= ""
|
||||
for i in range(len(users)):
|
||||
if (i > 0):
|
||||
ret = ret + ","
|
||||
ret = ret + "{\"id\": \"" + users[i][0] + "\",\"flow\": \"" + users[i][1] + "\"}"
|
||||
return ret
|
||||
jinja_dict["TARGET_URL"] = args.target_url
|
||||
jinja_dict["TARGET_PORT"] = str(args.target_port)
|
||||
jinja_dict["TARGET_FQDNS"] = build_target_fqdns(args.target_url)
|
||||
|
||||
NGINX_LOCATION_TEMPLATE = '''
|
||||
location /{{ USER }} {
|
||||
root /opt/nginx;
|
||||
autoindex on;
|
||||
}
|
||||
'''
|
||||
jinja_dict["LOG_DIR"] = str(LOG_DIR)
|
||||
jinja_dict["LOG_LEVEL"] = args.log_level
|
||||
|
||||
def build_nginx_locations(users: list[tuple[str, str]]) -> str:
|
||||
ret = ""
|
||||
for user in users:
|
||||
ret += jinja2.Environment().from_string(NGINX_LOCATION_TEMPLATE).render(USER = user[0]) + "\n"
|
||||
return ret
|
||||
jinja_dict["USERS"] = build_users_json(args.users)
|
||||
jinja_dict["PRIVATE_KEY"] = skey
|
||||
|
||||
return jinja_dict
|
||||
|
||||
def parse_xray_x25519_output(stdout : str) -> tuple[str, str]:
|
||||
skey = None
|
||||
pkey = None
|
||||
lines = stdout.split("\n")
|
||||
if len(lines) < 2:
|
||||
raise Exception(f"Unknown Xray output format:\n\"{stdout}\"\n")
|
||||
|
||||
priv_key_hdr = "Private key: "
|
||||
pub_key_hdr = "Public key: "
|
||||
for line in lines:
|
||||
if line.startswith(priv_key_hdr):
|
||||
skey = line[len(priv_key_hdr):]
|
||||
elif line.startswith(pub_key_hdr):
|
||||
pkey = line[len(pub_key_hdr):]
|
||||
if (skey == None) or (pkey == None):
|
||||
raise Exception(f"Unable to extract private or public key from Xray output:\n\"{stdout}\"\n")
|
||||
return (skey.strip(), pkey.strip())
|
||||
|
||||
try:
|
||||
opts, _ = getopt.getopt(sys.argv[1:], "u:p:f:")
|
||||
except getopt.GetoptError as err:
|
||||
# print help information and exit:
|
||||
print(err, flush=True) # will print something like "option -a not recognized"
|
||||
exit(1)
|
||||
def main():
|
||||
args = d2args()
|
||||
args.from_env()
|
||||
|
||||
port : int = 443
|
||||
users : list[str] = [''.join(random.choices(string.ascii_uppercase + string.digits, k=24))]
|
||||
fqdn : str = "example.com"
|
||||
print("====== init.py ======", flush=True)
|
||||
print(f"Checking server private key...", flush=True)
|
||||
if not PRIVKEY.exists():
|
||||
print(f"Server private key not found at {PRIVKEY}. Generating...")
|
||||
skey, _ = parse_xray_x25519_output(subprocess.check_output(f"{XRAY_BIN} x25519", shell = True).decode())
|
||||
with open(PRIVKEY, "w") as f:
|
||||
f.write(skey)
|
||||
|
||||
with open(PRIVKEY, "r") as f:
|
||||
skey = f.read().strip()
|
||||
|
||||
for o, a in opts:
|
||||
if o == "-u":
|
||||
users = parse_user_flow(a)
|
||||
elif o == "-p":
|
||||
port = int(a)
|
||||
elif o == "-f":
|
||||
fqdn = a
|
||||
else:
|
||||
print(f"Unknown option {o}, ignoring...", flush=True)
|
||||
exit(1)
|
||||
print(f"Deriving public key...", flush=True)
|
||||
_, pkey = parse_xray_x25519_output(subprocess.check_output(f"{XRAY_BIN} x25519 -i {skey}", shell = True).decode())
|
||||
|
||||
print("====== init.py ======", flush=True)
|
||||
print("Configuration:\n" + \
|
||||
f" port = {port}\n" + \
|
||||
f" fqdn = {fqdn}\n" + \
|
||||
f" users = {str(users)}", flush=True)
|
||||
with open(PUBKEY, "w") as f:
|
||||
f.write(pkey)
|
||||
|
||||
print(f"Checking certs for {fqdn}...", flush=True)
|
||||
if (os.path.exists(f"/etc/letsencrypt/live/{fqdn}")):
|
||||
print("Found existing certs, trying to renew...", flush=True)
|
||||
subprocess.check_call(f"certbot renew", shell=True)
|
||||
else:
|
||||
print("Unable to locate certs, generating...", flush=True)
|
||||
subprocess.check_call(f"certbot certonly -n --standalone -m dummy@dummy.com --agree-tos --no-eff-email -d {fqdn}", shell=True)
|
||||
print(f"\nConfigurations:\n{str(args)}\nPublic key: {pkey}\n", flush=True)
|
||||
|
||||
jinja_dict : dict[str,str] = dict()
|
||||
jinja_dict["XRAY_USERS"] = build_users_json(users)
|
||||
jinja_dict["PORT"] = str(port)
|
||||
jinja_dict["FQDN"] = str(fqdn)
|
||||
jinja_dict["NGINX_LOCATIONS"] = build_nginx_locations(users)
|
||||
template = build_jinja_dict(args, skey)
|
||||
|
||||
print(f"Processing Xray config files...", flush=True)
|
||||
process_directory("/opt/xray", jinja_dict)
|
||||
print(f"Processing config files...", flush=True)
|
||||
process_directory("/opt/xray", template)
|
||||
|
||||
print(f"Processing Nginx config files...", flush=True)
|
||||
process_directory("/opt/nginx", jinja_dict)
|
||||
|
||||
for u in users:
|
||||
print(f"Preparing directory for user {u[0]}...", flush=True)
|
||||
user_dir = f"/opt/nginx/{u[0]}"
|
||||
subprocess.check_call(f"mkdir -p {user_dir}", shell=True)
|
||||
subprocess.check_call(f"cp -r /opt/user/* {user_dir}/", shell=True)
|
||||
|
||||
jinja_dict["USER"] = u[0]
|
||||
jinja_dict["FLOW"] = u[1]
|
||||
process_directory(user_dir, jinja_dict)
|
||||
subprocess.check_call(f"ln -sf /downloads/others {user_dir}/others/downloads", shell=True)
|
||||
subprocess.check_call(f"ln -sf /downloads/android {user_dir}/android/downloads", shell=True)
|
||||
|
||||
exit(0)
|
||||
main()
|
||||
|
10
opt/init.sh
10
opt/init.sh
@ -1,13 +1,13 @@
|
||||
#!/bin/sh
|
||||
# create log directories
|
||||
mkdir -p /etc/d2ray/logs/cron
|
||||
# create directories
|
||||
mkdir -p /etc/d2ray/logs/xray
|
||||
mkdir -p /etc/d2ray/logs/nginx
|
||||
mkdir -p /etc/d2ray/logs/supervisor
|
||||
mkdir -p /etc/d2ray/logs/supervisord
|
||||
mkdir -p /etc/d2ray/certs
|
||||
|
||||
python3 /opt/init.py -p $PORT -u $USERS -f $FQDN
|
||||
python3 /opt/init.py
|
||||
retval=$?
|
||||
if [ $retval -ne 0 ]; then
|
||||
exit $retval
|
||||
fi
|
||||
|
||||
exec /usr/bin/supervisord -c /opt/supervisord.conf
|
@ -1,45 +0,0 @@
|
||||
user www www;
|
||||
worker_processes auto;
|
||||
daemon off;
|
||||
pid /tmp/nginx.pid;
|
||||
worker_rlimit_nofile 8192;
|
||||
|
||||
events {
|
||||
worker_connections 4096; ## Default: 1024
|
||||
}
|
||||
|
||||
http {
|
||||
geo $external {
|
||||
default 1;
|
||||
127.0.0.1/32 0;
|
||||
}
|
||||
|
||||
##
|
||||
# WebSocket proxying
|
||||
##
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
charset utf-8;
|
||||
access_log /etc/d2ray/logs/nginx/access.log;
|
||||
error_log /etc/d2ray/logs/nginx/error.log;
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
|
||||
if ($external) {
|
||||
return 301 https://$host:{{ PORT }}$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /opt/nginx/webroot;
|
||||
index index.html;
|
||||
}
|
||||
|
||||
{{ NGINX_LOCATIONS }}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<header>Welcome to a webpage written entirely in Vanilla <strike>JS</strike> HTML.</header>
|
||||
|
||||
<!-- Heading -->
|
||||
<h1>THE ROCKET BLOG FROM THE FUTURE 🚀</h1>
|
||||
<p>My thoughts and ideas on rockets and the science behind them. <a href="https://about.me/vaibhav_khulbe" target="_blank">Learn more</a>.</p>
|
||||
<br>
|
||||
|
||||
<!-- Article -->
|
||||
<img src="https://images.pexels.com/photos/796206/pexels-photo-796206.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Space shuttle"/>
|
||||
<kbd>FEATURED</kbd>
|
||||
<h4><a href="#">Lorem ipsum dolor sit, amet consectetur adipisicing elit</a></h4>
|
||||
<p>Optio, beatae! Aut quis id voluptate ullam repellendus. Et sit, ipsa, non consequuntur magnam quaerat temporibus at officiis ab, expedita molestiae liber...</p>
|
||||
<label for="Download?">Download: </label>
|
||||
<input type="text" id="text_download" placeholder="">
|
||||
<button onclick="redirect()"><b>DOWNLOAD</b></button>
|
||||
<script>
|
||||
function redirect()
|
||||
{
|
||||
var url=document.getElementById("text_download").value
|
||||
if (url.length > 0) {
|
||||
window.location.href = "./" + url
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<br><br>
|
||||
|
||||
<!-- Article break -->
|
||||
<details>
|
||||
<summary>What was the secret behind this mission?</summary>
|
||||
<img src="https://media.giphy.com/media/NdKVEei95yvIY/giphy.gif" alt="Secret GIF">
|
||||
<p>Okay, go watch The Office.</p>
|
||||
</details>
|
||||
<br><br>
|
||||
|
||||
<!-- Article -->
|
||||
<kbd>SPACE</kbd> <kbd>LUNA</kbd> <kbd>PRESSURE</kbd>
|
||||
<h4><a href="#">Ad aspernatur, nemo unde neque laboriosam sequi?</a></h4>
|
||||
<p>Nullam in lorem nec mi euismod pretium in eu erat. Nunc lacus tellus, sodales molestie sem id, tempor elementum turpis. Auris dapibus mi vitae libero luctus iaculis non non turpis. Mauris molestie ultrices...</p>
|
||||
<a href="#"><button><b>READ MORE</b></button></a>
|
||||
<br><br>
|
||||
|
||||
<!-- Article break -->
|
||||
<blockquote>
|
||||
“The Earth is the cradle of humanity, but mankind cannot stay in the cradle forever.” <i> - Konstantin Tsiolkovsky</i>
|
||||
</blockquote>
|
||||
<br><br>
|
||||
|
||||
<!-- Footer -->
|
||||
<center>( ̄︶ ̄)↗</center>
|
@ -1,5 +1,7 @@
|
||||
[unix_http_server]
|
||||
file=/var/run/supervisord.sock
|
||||
username = dummy1234
|
||||
password = dummy1234
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
@ -7,27 +9,29 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
loglevel=warn
|
||||
logfile=/etc/d2ray/logs/supervisor/supervisord.log
|
||||
logfile=/etc/d2ray/logs/supervisord/supervisord.log
|
||||
logfile_maxbytes=0
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///var/run/supervisord.sock
|
||||
username = dummy1234
|
||||
password = dummy1234
|
||||
|
||||
[program:nginx]
|
||||
command=nginx -c /opt/nginx/nginx.conf
|
||||
autostart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
redirect_stderr=true
|
||||
# [program:nginx]
|
||||
# command=nginx -c /opt/nginx/nginx.conf
|
||||
# autostart=true
|
||||
# autorestart=false
|
||||
# stdout_logfile=/dev/fd/1
|
||||
# stdout_logfile_maxbytes=0
|
||||
# redirect_stderr=true
|
||||
|
||||
[program:cron]
|
||||
command=crond -f -L /etc/d2ray/logs/cron/crond.log -c /opt/crontabs
|
||||
autostart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/etc/d2ray/logs/cron/crond.log
|
||||
stdout_logfile_maxbytes=0
|
||||
redirect_stderr=true
|
||||
# [program:cron]
|
||||
# command=crond -f -L /etc/d2ray/logs/cron/crond.log -c /opt/crontabs
|
||||
# autostart=true
|
||||
# autorestart=false
|
||||
# stdout_logfile=/etc/d2ray/logs/cron/crond.log
|
||||
# stdout_logfile_maxbytes=0
|
||||
# redirect_stderr=true
|
||||
|
||||
[program:xray]
|
||||
command=/opt/xray/xray -c /opt/xray/d2ray.json
|
||||
|
@ -1,21 +0,0 @@
|
||||
1. 下载当前网页的apk文件并且安装到手机
|
||||
2. 打开V2rayNG app
|
||||
3. 右上角箭头->新加配置文件->手动输入[VLess]
|
||||
|
||||
别名(remarks):随便起
|
||||
地址(address):{{ FQDN }}
|
||||
端口(port):{{ PORT }}
|
||||
用户ID(id):{{ USER }}
|
||||
流控(flow):{{ FLOW }}
|
||||
传输协议(network):tcp
|
||||
伪装类型(type):none
|
||||
传输层安全(tls):tls
|
||||
uTLS: firefox
|
||||
alpn: h2,http/1.1
|
||||
跳过证书验证(allowInsecure):false
|
||||
|
||||
|
||||
以上没有提到的选项统统默认值
|
||||
|
||||
4. 右上角对勾保存
|
||||
5. 选择刚创建的链接,点击右下角"V"开启或关闭VPN.
|
@ -1,16 +0,0 @@
|
||||
1. 去AppStore下载shadowrocket软件(需要非中国区)
|
||||
2. 打开shadowrocket app
|
||||
3. 右上角+号
|
||||
|
||||
类型:VLESS
|
||||
地址:{{ FQDN }}
|
||||
端口:{{ PORT }}
|
||||
UUID:{{ USER }}
|
||||
TLS: 开启
|
||||
XTLS Direct: 开启
|
||||
快速打开: 开启
|
||||
|
||||
以上没有提到的选项统统默认值
|
||||
|
||||
4. 右上角完成保存
|
||||
5. 返回主页面,选择刚创建的链接,然后开启链接即开启vpn
|
@ -1,119 +0,0 @@
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
"223.5.5.5",
|
||||
"114.114.114.114",
|
||||
{
|
||||
"address": "8.8.8.8",
|
||||
"port": 53,
|
||||
"domains": [
|
||||
"geosite:geolocation-!cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "1.1.1.1",
|
||||
"port": 53,
|
||||
"domains": [
|
||||
"geosite:geolocation-!cn"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"routing": {
|
||||
"domainStrategy": "IPIfNonMatch",
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"223.5.5.5",
|
||||
"114.114.114.114"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"outboundTag": "proxy",
|
||||
"ip": [
|
||||
"8.8.8.8",
|
||||
"1.1.1.1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:cn",
|
||||
"geoip:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"outboundTag": "direct",
|
||||
"domain": ["geosite:cn"]
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"outboundTag": "proxy",
|
||||
"network": "udp,tcp"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 1080,
|
||||
"listen": "127.0.0.1",
|
||||
"protocol": "socks",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": ["http", "tls"]
|
||||
},
|
||||
"settings": {
|
||||
"auth": "noauth",
|
||||
"udp": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"tag": "proxy",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"vnext": [
|
||||
{
|
||||
"address": "{{ FQDN }}",
|
||||
"port": {{ PORT }},
|
||||
"users": [
|
||||
{
|
||||
"id": "{{ USER }}",
|
||||
"encryption": "none",
|
||||
"flow": "{{ FLOW }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp",
|
||||
"security": "tls",
|
||||
"tlsSettings": {
|
||||
"serverName": "{{ FQDN }}",
|
||||
"allowInsecure": false,
|
||||
"fingerprint": "random",
|
||||
"alpn": ["h2","http/1.1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {},
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"protocol": "blackhole",
|
||||
"settings": {},
|
||||
"tag": "block"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
chmod +x xray
|
||||
./xray -c config.json
|
@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
|
||||
.\xray -c config.json
|
@ -1,55 +0,0 @@
|
||||
分两步:
|
||||
1. 配置VPN程序,此程序负责与VPN服务器交流
|
||||
2. 配置浏览器,让浏览器把所有网站请求交给VPN程序处理
|
||||
|
||||
**** 1. 配置 VPN程序 ****
|
||||
1. 请在downloads目录里下载与系统相适应的程序和配置文件:
|
||||
- Windows 64 bits (Intel CPU): Xray-windows-64.zip + config.json + windows.bat
|
||||
- MacOS 64 bits (Intel CPU): Xray-macos-64.zip + config.json + macos.sh
|
||||
- MacOS ARM (M Series CPU): Xray-macos-arm64-v8a.zip + config.json + macos.sh
|
||||
|
||||
2. 如果仅需要浏览器联网,请下载 Google Chrome 浏览器和 downloads 目录里的 SwitchyOmega_Chromium.crx
|
||||
如果需要全局代理(例如除浏览器外其他应用程序),请先完成 Google Chrome 的配置,然后从Google下载 Proxifier 后请看 "配置全局代理" 部分
|
||||
|
||||
3. 解压缩下载的zip文件,将 config.json 和 windows.bat 或 macos.sh 拷贝到解压缩后的目录下
|
||||
|
||||
4. 双击 windows.bat 或 macos.sh 即可运行VPN程序,MacOS系统有可能需要右键 macos.sh => 用应用程序打开(Open With) => 其他(Other) => 在新打开的窗口下方选择框里选"所有应用程序"(All Applications) => 找到 终端"Terminal" 并勾选 永久以程序打开(Always Open With) => 确定
|
||||
|
||||
|
||||
**** 2. 配置 Google Chrome ****
|
||||
1. 安装下载的SwitchyOmega插件:
|
||||
- 打开 Google Chrome
|
||||
- 打开网址 "chrome://extensions"
|
||||
- 打开右上角 开发者模式(Developer mode)
|
||||
- 在新出现的工具栏选择第一项 "Load unpacked"(加载插件)
|
||||
- 在新出现的对话框选择下载的 SwitchyOmega_Chromium.crx
|
||||
|
||||
2. 配置SwitchyOmega插件:
|
||||
- 打开SwitchyOmega插件配置菜单(浏览器右上角点击SwitchyOmega图标然后点最后一项配置,没有的话在插件下拉里面找,找到可以Pin到浏览器上).
|
||||
- 在左边菜单新建一个profile, 类型选择第一个"Proxy(代理) Profile",名字取"VPN", 点击 “创建”
|
||||
- Protocol(协议)选择"SOCKS5", 服务器(Server)填写127.0.0.1, 端口(Port)写1080,点击左边菜单"应用" (Apply changes)
|
||||
|
||||
|
||||
**** 3. 配置全局代理 (Optional) ****
|
||||
!! 此部分仅适用需要全局代理的用户,在配置全局代理前请先配置好Google Chrome !!
|
||||
1. 在配置好的 Google Chrome 上访问 https://www.proxifier.com/,下载并安装 ("Download Proxifier 31-day Free Trial")
|
||||
|
||||
2. 打开Proxifier。点击左上角菜单 "Profile" -> "Proxy Servers" -> "Add"
|
||||
- Address 填写 127.0.0.1
|
||||
- Port 填写 1080
|
||||
- Protocol 选 SOCKS Version 5
|
||||
然后点OK
|
||||
|
||||
3. 窗口 "Do you want Proxifier to use this proxy by default?" -> Yes,然后点OK
|
||||
|
||||
4. 重新启动 Proxifier 即可启动全局代理,第一次运行 Proxifier 会询问是否将 Xray.exe 加入 Exclusion,选Yes即可。
|
||||
|
||||
|
||||
**** 4. 注意事项 ****
|
||||
1. 启动VPN时请启动VPN程序并且 在SwitchyOmega插件菜单选择 "VPN" 或者打开Proxifier
|
||||
|
||||
2. 关闭VPN时请 当不需要VPN时,只需在SwitchyOmega插件选择"Direct"直连。
|
||||
|
||||
3. 不需要用VPN时请关闭VPN,降低被ban的概率。
|
||||
|
||||
4. 请每过一段时间(~ 1-3 months)从本站下载最新的VPN软件并重新配置,VPN软件的bug修复和新的协议会降低被ban的概率。
|
@ -1,3 +0,0 @@
|
||||
Android用户请看 android 文件夹
|
||||
iOS用户请看 ios 文件夹
|
||||
其他系统用户请下载 d2ray.zip
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "warn",
|
||||
"access": "/etc/d2ray/logs/xray/access.log",
|
||||
"error": "/etc/d2ray/logs/xray/error.log"
|
||||
"loglevel": "{{LOG_LEVEL}}",
|
||||
"access": "{{LOG_DIR}}/access.log",
|
||||
"error": "{{LOG_DIR}}/error.log"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
@ -10,25 +10,23 @@
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{{ XRAY_USERS }}
|
||||
{{ USERS }}
|
||||
],
|
||||
"decryption": "none",
|
||||
"fallbacks": [
|
||||
{
|
||||
"dest": "localhost:80"
|
||||
}
|
||||
]
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp",
|
||||
"security": "tls",
|
||||
"tlsSettings": {
|
||||
"alpn": ["http/1.1", "h2"],
|
||||
"certificates": [
|
||||
{
|
||||
"certificateFile": "/etc/letsencrypt/live/{{ FQDN }}/fullchain.pem",
|
||||
"keyFile": "/etc/letsencrypt/live/{{ FQDN }}/privkey.pem"
|
||||
}
|
||||
"security": "reality",
|
||||
"realitySettings": {
|
||||
"show": false,
|
||||
"dest": "{{ TARGET_URL }}:{{ TARGET_PORT }}",
|
||||
"xver": 0,
|
||||
"serverNames": [
|
||||
{{ TARGET_FQDNS }}
|
||||
],
|
||||
"privateKey": "{{ PRIVATE_KEY }}",
|
||||
"shortIds": [
|
||||
""
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -43,8 +41,7 @@
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user