per-user download directory
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
quackerd 2022-12-05 08:46:24 +01:00
parent 76754e6f5b
commit 602f0a3449
17 changed files with 174 additions and 228 deletions

2
.env
View File

@ -1,4 +1,4 @@
PORT=443 PORT=443
FQDN=example.com FQDN=example.com
USERS=exampleuser1,exampleuser2 USERS=exampleuser1,exampleuser2@xtls-rprx-direct
LOGDIR=./logs LOGDIR=./logs

View File

@ -5,29 +5,22 @@ ENV VER_SO 2.5.20
ENV VER_NG 1.7.23 ENV VER_NG 1.7.23
# install packages # install packages
RUN set -xe && apk add --no-cache zip unzip wget nginx certbot openssl python3 py3-jinja2 supervisor apache2-utils bash RUN set -xe && apk add --no-cache unzip wget nginx certbot openssl python3 py3-jinja2 supervisor apache2-utils bash
COPY ./opt /opt/
# download packages # download packages
RUN set -xe && \ RUN set -xe && \
wget -P /opt/zip/windows/ https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-windows-64.zip && \ mkdir -p /downloads /downloads/others /downloads/android && \
mkdir -p /opt/zip/linux && \ wget -P /downloads/others https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-windows-64.zip && \
wget -P /opt/zip/linux/ https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-linux-64.zip && \ wget -P /downloads/others https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-linux-64.zip && \
mkdir -p /opt/zip/chrome && \ wget -P /downloads/others https://github.com/FelisCatus/SwitchyOmega/releases/download/v$VER_SO/SwitchyOmega_Chromium.crx && \
wget -P /opt/zip/chrome/ 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 /opt/nginx/download/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 /opt/zip/macos/ 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
wget -P /opt/zip/macos/ https://github.com/XTLS/Xray-core/releases/download/v$VER_XRAY/Xray-macos-arm64-v8a.zip
COPY ./opt /opt/
# xray # xray
RUN set -xe && unzip /opt/zip/linux/Xray-linux-64.zip -d /opt/xray RUN set -xe && unzip /downloads/others/Xray-linux-64.zip -d /opt/xray
# create zip
RUN set -xe && \
zip -r /opt/d2ray.zip /opt/zip && \
mv /opt/d2ray.zip /opt/nginx/download/ && \
rm -r /opt/zip
# nginx # nginx
RUN set -xe && addgroup www && \ RUN set -xe && addgroup www && \
@ -35,7 +28,7 @@ RUN set -xe && addgroup www && \
chown -R www:www /opt/nginx chown -R www:www /opt/nginx
# remove packages # remove packages
RUN set -xe && apk del zip unzip wget RUN set -xe && apk del unzip wget
EXPOSE 80 EXPOSE 80
VOLUME /etc/letsencrypt VOLUME /etc/letsencrypt
CMD ["sh", "/opt/init.sh"] CMD ["sh", "/opt/init.sh"]

View File

@ -7,6 +7,7 @@ d2ray is a single Docker container that provides easy and braindead configuratio
- Easy 5-minutes setup. - Easy 5-minutes setup.
- Automatic generation and renewal of Let's Encrypt SSL certificates. - Automatic generation and renewal of Let's Encrypt SSL certificates.
- Packaged Xray binary on the fallback website. - Packaged Xray binary on the fallback website.
- Per-user setup instructions for various architectures.
## How to use? ## How to use?
1. Download the `docker-compose.yml` from this repo. 1. Download the `docker-compose.yml` from this repo.
@ -14,10 +15,10 @@ d2ray is a single Docker container that provides easy and braindead configuratio
- See `.env` in the current repo. - See `.env` in the current repo.
- `PORT`: the port to run Xray on. - `PORT`: the port to run Xray on.
- `FQDN`: the domain name of your server, used to generate SSL certificates. - `FQDN`: the domain name of your server, used to generate SSL certificates.
- `USERS`: comma separated list of users allowed access to both Xray and resource downloads. - `USERS`: comma separated list of `USERCONF` allowed access to both Xray and resource downloads. Each `USERCONF` is of format `userid@flow`. `userid` is used as the credential for Xray. If `flow` is not specified it defaults to `xtls-rprx-direct`. For example, setting `USERS` to `user1@xtls-rprx-direct,user2` means two users with userid `user1` and `user2` and both with flow `xtls-rprx-direct`.
- `LOGDIR`: the directory to store logs, currently required. - `LOGDIR`: the directory to store logs, currently required.
3. `docker compose up -d` 3. `docker compose up -d`
4. You can access the Xray service using an Xray client. You can access the resource downloads by accessing `https://your-domain:your-port` and clicking the `Download` button near the bottom of the page. Use one of the `USERS` as the username and password. 4. You can access the Xray service using an Xray client. You can access the per-user resource downloads by accessing `https://your-domain:your-port`, entering the `userid` in the textbox at the bottom of the page and clicking the `Download` button next to it.
## How to update? ## How to update?
- `docker compose down` - `docker compose down`

View File

@ -6,18 +6,59 @@ import jinja2
import random import random
import string import string
def parse_comma_str(users : str) -> list[str]: def process_directory(path : str, vars : dict[str, str], delete_template : bool = True) -> None:
return users.split(",") for f in os.listdir(path):
full_path = os.path.join(path, f)
if os.path.isdir(full_path):
process_directory(full_path, vars, delete_template)
elif f.endswith(".in"):
with open(full_path, "r") as sf:
with open(full_path[:-3], "w") as df:
template : jinja2.Template = jinja2.Template(sf.read())
df.write(template.render(**vars))
print(f"Processed template {full_path}.", flush=True)
if delete_template:
subprocess.check_call(f"rm {full_path}", shell=True)
def build_users_json(users: list[str]) -> str:
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-direct"
users.append((username, flow))
return users
def build_users_json(users: list[tuple[str, str]]) -> str:
ret : str= "" ret : str= ""
for i in range(len(users)): for i in range(len(users)):
if (i > 0): if (i > 0):
ret = ret + "," ret = ret + ","
u = users[i] ret = ret + "{\"id\": \"" + users[i][0] + "\",\"flow\": \"" + users[i][1] + "\"}"
ret = ret + "{ \"id\": \"" + u + "\", \"flow\": \"xtls-rprx-direct\"}"
return ret return ret
NGINX_LOCATION_TEMPLATE = '''
location /{{ USER }} {
root /opt/nginx;
autoindex on;
}
'''
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
try: try:
opts, _ = getopt.getopt(sys.argv[1:], "u:p:f:") opts, _ = getopt.getopt(sys.argv[1:], "u:p:f:")
except getopt.GetoptError as err: except getopt.GetoptError as err:
@ -31,7 +72,7 @@ fqdn : str = "example.com"
for o, a in opts: for o, a in opts:
if o == "-u": if o == "-u":
users = parse_comma_str(a) users = parse_user_flow(a)
elif o == "-p": elif o == "-p":
port = int(a) port = int(a)
elif o == "-f": elif o == "-f":
@ -39,6 +80,7 @@ for o, a in opts:
else: else:
print(f"Unknown option {o}, ignoring...", flush=True) print(f"Unknown option {o}, ignoring...", flush=True)
exit(1) exit(1)
print("====== init.py ======", flush=True) print("====== init.py ======", flush=True)
print("Configuration:\n" + \ print("Configuration:\n" + \
f" port = {port}\n" + \ f" port = {port}\n" + \
@ -54,22 +96,27 @@ else:
subprocess.check_call(f"certbot certonly -n --standalone -m dummy@dummy.com --agree-tos --no-eff-email -d {fqdn}", shell=True) subprocess.check_call(f"certbot certonly -n --standalone -m dummy@dummy.com --agree-tos --no-eff-email -d {fqdn}", shell=True)
jinja_dict : dict[str,str] = dict() jinja_dict : dict[str,str] = dict()
jinja_dict["USERS"] = build_users_json(users) jinja_dict["XRAY_USERS"] = build_users_json(users)
jinja_dict["PORT"] = str(port) jinja_dict["PORT"] = str(port)
jinja_dict["FQDN"] = str(fqdn) jinja_dict["FQDN"] = str(fqdn)
jinja_dict["NGINX_LOCATIONS"] = build_nginx_locations(users)
print(f"Processing Xray config files...", flush=True) print(f"Processing Xray config files...", flush=True)
with open("/opt/xray/d2ray.json.in", "r") as f: process_directory("/opt/xray", jinja_dict)
with open("/opt/xray/d2ray.json", "w") as d:
template : jinja2.Template = jinja2.Template(f.read())
d.write(template.render(**jinja_dict))
print(f"Processing Nginx config files...", flush=True) print(f"Processing Nginx config files...", flush=True)
with open("/opt/nginx/nginx.conf.in", "r") as f: process_directory("/opt/nginx", jinja_dict)
with open("/opt/nginx/nginx.conf", "w") as d:
template : jinja2.Template = jinja2.Template(f.read())
d.write(template.render(**jinja_dict))
for u in users: for u in users:
subprocess.check_call(f"htpasswd -b /opt/nginx/.htpasswd {u} {u}", shell=True) 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 -s /downloads/others {user_dir}/others/downloads", shell=True)
subprocess.check_call(f"ln -s /downloads/android {user_dir}/android/downloads", shell=True)
exit(0) exit(0)

View File

View File

@ -40,11 +40,6 @@ http {
index index.html; index index.html;
} }
location /download { {{ NGINX_LOCATIONS }}
root /opt/nginx/;
autoindex on;
auth_basic "Please provide credentials to access this server";
auth_basic_user_file "/opt/nginx/.htpasswd";
}
} }
} }

View File

@ -10,7 +10,18 @@
<kbd>FEATURED</kbd> <kbd>FEATURED</kbd>
<h4><a href="#">Lorem ipsum dolor sit, amet consectetur adipisicing elit</a></h4> <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> <p>Optio, beatae! Aut quis id voluptate ullam repellendus. Et sit, ipsa, non consequuntur magnam quaerat temporibus at officiis ab, expedita molestiae liber...</p>
<a href="/download"><button><b>DOWNLOAD</b></button></a> <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> <br><br>
<!-- Article break --> <!-- Article break -->

View File

@ -3,10 +3,10 @@
3. 右上角箭头->新加配置文件->手动输入[VLess] 3. 右上角箭头->新加配置文件->手动输入[VLess]
别名:随便起 别名:随便起
地址:服务器地址就是当前网站的地址比如你在https://xxx.quacker.net/download你的服务器地址就是xxx.quacker.net 地址:{{ FQDN }}
端口:443 端口:{{ PORT }}
用户id你的密码 用户id{{ USER }}
流控flowxtls-rprx-direct 流控flow{{ FLOW }}
传输协议tcp 传输协议tcp
伪装类型none 伪装类型none
底层传输安全xtls 底层传输安全xtls

View File

@ -0,0 +1,16 @@
1. 去AppStore下载shadowrocket软件需要非中国区
2. 打开shadowrocket app
3. 右上角+号
类型VLESS
地址:{{ FQDN }}
端口:{{ PORT }}
UUID{{ USER }}
TLS 开启
XTLS Direct: 开启
快速打开: 开启
以上没有提到的选项统统默认值
4. 右上角完成保存
5. 返回主页面选择刚创建的链接然后开启链接即开启vpn

View File

@ -82,13 +82,13 @@
"settings": { "settings": {
"vnext": [ "vnext": [
{ {
"address": "%SERVER%", "address": "{{ FQDN }}",
"port": 443, "port": {{ PORT }},
"users": [ "users": [
{ {
"id": "%PASSWORD%", "id": "{{ USER }}",
"encryption": "none", "encryption": "none",
"flow": "xtls-rprx-direct", "flow": "{{ FLOW }}",
"level": 0 "level": 0
} }
] ]
@ -99,7 +99,7 @@
"network": "tcp", "network": "tcp",
"security": "xtls", "security": "xtls",
"xtlsSettings": { "xtlsSettings": {
"serverName": "%SERVER%", "serverName": "{{ FQDN }}",
"allowInsecure": false, "allowInsecure": false,
"alpn": ["h2","http/1.1"] "alpn": ["h2","http/1.1"]
} }

View File

@ -0,0 +1,55 @@
分两步:
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的概率。

View File

@ -10,7 +10,7 @@
"protocol": "vless", "protocol": "vless",
"settings": { "settings": {
"clients": [ "clients": [
{{ USERS }} {{ XRAY_USERS }}
], ],
"decryption": "none", "decryption": "none",
"fallbacks": [ "fallbacks": [

View File

@ -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": "%SERVER%",
"port": 443,
"users": [
{
"id": "%PASSWORD%",
"encryption": "none",
"flow": "xtls-rprx-direct",
"level": 0
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "xtls",
"xtlsSettings": {
"serverName": "%SERVER%",
"allowInsecure": false,
"alpn": ["h2","http/1.1"]
}
}
},
{
"protocol": "freedom",
"settings": {},
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "block"
}
]
}

View File

@ -1,53 +0,0 @@
VPN陪置教程
分两步:
1. 配置VPN程序此程序负责与VPN服务器交流
2. 配置浏览器让浏览器把所有网站请求交给VPN程序处理
很简单明了成功的VPN以上配置缺一不可
!! 以下所有路径都是相对于下载的zip文件的解压目录 !!
!! 比如zip文件解压到了D:\vpn文中说的windows目录就是D:\vpn\windows !!
**** 1. 配置 VPN程序 ****
Windows系统请看这里
- 进入当前文件夹 windows 目录
- 解压 Xray-windows-64.zip
- 用文本编辑器打开 config.json搜索并替换 *所有* (划重点*所有*
%PASSWORD% => 你的密码. 比如密码是12345的话 文件中所有的 "%PASSWORD%" 应该替换成 "12345" 以下同理
%SERVER% => 你的服务器地址这个是你下载zip文件的地址比如你从https://xxx.quacker.net/download下载你的服务器地址就是xxx.quacker.net
- 保存 config.json
- 拷贝 config.json 和 run.bat 进入解压后的文件夹
- 进入解压后文件夹双击 run.bat 运行VPN程序
MacOS系统请看这里
- 进入当前文件夹 macos 目录
- 解压 Xray-macos-64.zip 或者 Xray-macos-arm64-v8a.zip (Apple M系芯片请用arm64)
- 用文本编辑器打开 config.json搜索并替换 *所有* (划重点*所有*
%PASSWORD% => 你的密码(和你的网站下载密码相同). 比如密码是12345的话 文件中所有的 "%PASSWORD%" 应该替换成 "12345" 以下同理
%SERVER% => 你的服务器地址这个是你下载zip文件的地址比如你从https://xxx.quacker.net/download下载你的服务器地址就是xxx.quacker.net
- 保存 config.json
- 右键 run.sh => 用应用程序打开(Open With) => 其他(Other) => 在新打开的窗口下方选择框里选"所有应用程序"(All Applications) => 找到 终端"Terminal" 并勾选 永久以程序打开(Always Open With) => 确定
- 拷贝 config.json 和 run.sh 进入解压后的文件夹
- 进入解压后文件夹双击 run.sh 运行VPN程序
**** 2. 配置 浏览器 ****
首先请下载Google Chrome浏览器
然后需要安装SwitchyOmega插件:
- 打开 Google Chrome
- 打开网址 "chrome://extensions"
- 打开右上角 开发者模式(Developer mode)
- 在新出现的工具栏选择第一项 "Load unpacked"(加载插件)
- 在新出现的对话框选择chrome目录
然后配置SwitchyOmega插件
- 打开SwitchyOmega插件配置菜单(浏览器右上角点击SwitchyOmega图标然后点最后一项配置没有的话在插件下拉里面找找到可以Pin到浏览器上).
- 在左边菜单新建一个profile, 类型选择第一个"Proxy代理 Profile",名字取"VPN", 点击 “创建”
- Protocol(协议)选择"SOCKS5", 服务器(Server)填写127.0.0.1, 端口(Port)写1080点击左边菜单"应用" (Apply changes)
**** 3. 注意事项 ****
当需要VPN时1.启动VPN程序并且 2.在SwitchyOmega插件菜单选择"VPN"。
当不需要VPN时只需在SwitchyOmega插件选择"Direct"直连。