├── .github └── workflows │ └── container-build.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── app.json ├── content ├── Caddyfile ├── argo.yaml ├── config-wg.json ├── install.sh └── service │ ├── 1 │ └── run │ ├── 2 │ └── run │ ├── caddy │ └── run │ ├── cloudflared │ └── run │ └── nodestatus-client │ └── run ├── fly.toml └── heroku.yml /.github/workflows/container-build.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | # Publish semver tags as releases. 6 | tags: [ 'v*.*.*' ] 7 | 8 | env: 9 | # Use docker.io for Docker Hub if empty 10 | REGISTRY: ghcr.io 11 | # github.repository as / 12 | IMAGE_NAME: ${{ github.repository }} 13 | 14 | jobs: 15 | docker: 16 | runs-on: ubuntu-latest 17 | steps: 18 | 19 | - name: Checkout repository 20 | uses: actions/checkout@v3 21 | 22 | - name: Set up Docker Buildx 23 | uses: docker/setup-buildx-action@v2 24 | 25 | - name: Log into registry ${{ env.REGISTRY }} 26 | if: github.event_name != 'pull_request' 27 | uses: docker/login-action@v2 28 | with: 29 | registry: ${{ env.REGISTRY }} 30 | username: ${{ github.actor }} 31 | password: ${{ secrets.GITHUB_TOKEN }} 32 | 33 | - name: Extract Docker metadata 34 | id: meta 35 | uses: docker/metadata-action@v4 36 | with: 37 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 38 | flavor: | 39 | latest=true 40 | tags: | 41 | type=ref,event=branch 42 | type=ref,event=pr 43 | type=semver,pattern={{version}} 44 | type=semver,pattern={{major}}.{{minor}} 45 | 46 | - name: Build and push Docker image 47 | id: build-and-push 48 | uses: docker/build-push-action@v3 49 | with: 50 | builder: ${{ steps.buildx.outputs.name }} 51 | context: . 52 | push: true 53 | tags: ${{ steps.meta.outputs.tags }} 54 | labels: ${{ steps.meta.outputs.labels }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /README.md -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | COPY ./content /workdir/ 4 | 5 | ENV PORT=3000 6 | ENV SecretPATH=/mypath 7 | ENV PASSWORD=password 8 | ENV WG_MTU=1408 9 | ENV BLOCK_QUIC_443=true 10 | ENV CLASH_MODE=rule 11 | 12 | RUN apk add --no-cache caddy runit jq tor bash \ 13 | && bash /workdir/install.sh \ 14 | && rm /workdir/install.sh \ 15 | && chmod +x /workdir/service/*/run \ 16 | && ln -s /workdir/service/* /etc/service/ 17 | 18 | EXPOSE 3000 19 | 20 | ENTRYPOINT ["runsvdir", "/etc/service"] 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Yuki Kikuchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 鸣谢 2 | 3 | - [SagerNet/sing-box](https://github.com/SagerNet/sing-box) 4 | - [v2argo](https://github.com/funnymdzz/v2argo) 5 | 6 | ## 概述 7 | 8 | 1. 本项目用于在 PaaS 平台上部署 Vmess WebSocket 和 Trojan Websocket 协议,支持 CI/CD 和拉取容器镜像两种部署方式。 9 | 10 | 已更换为 sing-box 核心,如需部署原 Xray 核心版本,请前往 [archieve 分支](https://github.com/wy580477/PaaS-vmess-trojan-argo/tree/achieve)。 11 | 12 | 2. 可以启用 Cloudflared 隧道,以内网穿透模式接入 Cloudflare,可以使用 Cloudflare 支持的全部十多个端口。 13 | 14 | 3. 支持 WARP 出站。可以通过 CLASH_MODE 变量控制 chatgpt、bing、netflix、disney、dazn、spotify 和 imgur 是否分流到 WARP 出站。 15 | 16 | 修改 content/config-wg.json 文件 169 行,可自定义分流规则。 17 | 18 |
19 | WARP 解锁效果示例 20 | 21 | 美国 Heroku 22 | 23 | ![image](https://github.com/wy580477/PaaS-vmess-trojan-argo/assets/98247050/58788eef-6ee2-4560-938d-4ed397f8e263) 24 | 25 | 爱尔兰 Heroku 26 | 27 | ![image](https://github.com/wy580477/PaaS-vmess-trojan-argo/assets/98247050/e369d18d-c4ab-49b2-b773-b3b125086834) 28 | 29 |
30 | 31 | 4. 支持直接访问 .onion tor 网络域名(需要客户端使用 socks/http 代理方式或者 Fakeip/Fakedns 透明代理环境)。 32 | 33 | 5. 支持 WS-0RTT 降低延迟,Xray 核心客户端在 Websocket 路径后加上 ?ed=2048 即可启用。 34 | 35 | 6. 支持 Clash api,可以连接 [yacd 面板](https://github.com/haishanh/yacd),选择 Direct / WARP / Tor 出站,启用/关闭分流功能,查看当前速度、连接、日志等信息。 36 | 37 |
38 | 截图 39 | 40 | ![image](https://user-images.githubusercontent.com/98247050/216765395-ae682987-141a-4041-b8e2-cec800cb0f4a.png) 41 | 42 | ![image](https://user-images.githubusercontent.com/98247050/232048722-7e0e23e3-367a-495b-a907-419681092d1d.png) 43 | 44 |
45 | 46 | 47 | ## 注意 48 | 49 | **请勿滥用,PaaS 平台账号封禁风险自负** 50 | 51 | 52 | [部署方式](#部署方式) 53 | 54 | [客户端相关设置](#客户端相关设置) 55 | 56 | [接入CloudFlare](#cf) 57 | 58 | ## 部署方式 59 | 60 | **请勿使用本仓库直接部署** 61 | 62 |
63 | Heroku 部署方法 64 | 65 | **Heroku 已于2022年11月末关闭免费服务** 66 | 67 | 1. 点击本仓库右上角Fork,再点击Create Fork。 68 | 2. 在Fork出来的仓库页面上点击Setting,勾选Template repository。 69 | 3. 然后点击Code返回之前的页面,点Setting下面新出现的按钮Use this template,起个随机名字创建新库。 70 | 4. 项目名称注意不要包含 `v2ray` 和 `heroku` 两个关键字(用户名以 `example` 为例,修改后的项目名以 `demo` 为例) 71 | 5. 登陆heroku后,浏览器访问 dashboard.heroku.com/new?template= 72 | 73 |
74 | 75 |
76 | 支持 CI/CD 平台(Render,Northflank,Doprax等)部署方法 77 | 78 | 1. 点击本仓库右上角Fork,再点击Create Fork。 79 | 2. 在Fork出来的仓库页面上点击Setting,勾选Template repository。 80 | 3. 然后点击Code返回之前的页面,点Setting下面新出现的按钮Use this template,起个随机名字创建新库。 81 | 4. 项目名称注意不要包含 `v2ray` 和 `xray` 等关键字。 82 | 5. 在 PaaS 平台管理面板中连接你新建立的 github 仓库。 83 | 6. 按下文变量部分设置所需的变量,如果需要设置内部 HTTP 端口,默认为3000,也可以自行设置 PORT 变量修改。 84 | 7. 然后部署即可。 85 | 86 |
87 | 88 |
89 | 支持拉取容器镜像 PaaS 平台(Koyeb,Northflank等)部署方法 90 | 91 | 1. 点击本仓库右上角Fork,再点击Create Fork。 92 | 2. 在Fork出来的仓库页面上点击Setting,勾选Template repository。 93 | 3. 然后点击Code返回之前的页面,点Setting下面新出现的按钮Use this template,起个随机名字创建新库。 94 | 4. 项目名称注意不要包含 `v2ray` 和 `heroku` 等关键字。 95 | 5. 点击仓库Settings > Actions > General,滚动到页面最下方,将Workflow permissions设置为Read and write permissions。 96 | 6. 点击页面右侧 Create a new release,建立格式为 v0.1.0 的tag,其它内容随意,然后点击 Publish release。 97 | 7. 大概不到一分钟后,github action 构建容器镜像完成,点击页面右侧 Packages, 再点击进入刚生成的 Package。 98 | 8. 点击页面右侧 Package settings,在页面最下方点击 Change visibility,选择 public 并输入 package 名称以确认。 99 | 9. 容器镜像拉取地址在 package 页面 docker pull 命令示例中,其它部署步骤请参阅具体平台文档。需要设置的环境变量见下文,内部监听端口默认为3000,也可自行设置 PORT 环境变量更改。 100 | 101 |
102 | 103 |
104 | Patr 部署方法 105 | 106 | 1. 点击本项目网页上部 Code 按钮,再点击 Create codespace on main。 107 | 108 | ![image](https://user-images.githubusercontent.com/98247050/212817236-c5a882b1-6b5b-4a6f-b8c1-c702664a9ab1.png) 109 | 110 | 2. 点击 Patr 管理面板左侧 Docker Repository,建立新 Repo。 111 | 112 | ![image](https://user-images.githubusercontent.com/98247050/212814426-befa43d4-2e37-4147-95d5-4104f80968b8.png) 113 | 114 | 3. 点击进入 Patr 新建立的 Repo,页面最下方有三条命令: 115 | 116 | ![image](https://user-images.githubusercontent.com/98247050/212815117-37089ede-50a7-4c36-9872-bdface591071.png) 117 | 118 | 4. 在之前打开的 Codespace 网页中,点击终端,执行上图中的三条命令,中间需要输入 Patr 账户密码。 119 | 120 | ![image](https://user-images.githubusercontent.com/98247050/212815400-843f9fbf-cbac-435e-87df-01b502be3017.png) 121 | 122 | 5. 回到 Patr 网页,点击 Infrastructure > Deployment > Create Deployment,Name 随意,Image Details 选择刚才建立的 Repo,Region 选择 Singapore。 123 | 124 | ![image](https://user-images.githubusercontent.com/98247050/212815611-c6fc58b3-9b90-40c3-8234-86e64226f821.png) 125 | 126 | 6. 点击 NEXT STEP,Ports 设置为 3000,按下文变量部分设置好需设定的变量。将 Startup Probe 和 Liveness Probe 端口设置为 3000,路径为 `/`。 127 | 128 | ![image](https://user-images.githubusercontent.com/98247050/212816360-0df56cbf-2f05-4bf6-b677-965d699e3e0b.png) 129 | 130 | 7. 点击 NEXT STEP,将 Horizontal Scale 拉到最左侧,直到价格显示 Free,然后点击 CREATE。 131 | 132 | ![image](https://user-images.githubusercontent.com/98247050/212816479-3b10d285-8530-4732-945e-a25c0a52648a.png) 133 | 134 | 8. 点击 Infrastructure > Deployment,点击 START 即启动容器,点击 PUBLIC URL 获得服务域名。 135 | 136 | ![image](https://user-images.githubusercontent.com/98247050/212816900-7a3c4614-e7c3-41c1-8028-f35539280e2a.png) 137 | 138 |
139 | 140 | ### 变量 141 | 142 | 对部署时需设定的变量做如下说明。 143 | 144 | | 变量 | 默认值 | 说明 | 145 | | :--- | :--- | :--- | 146 | | `VmessUUID` | `ad2c9acd-3afb-4fae-aff2-954c532020bd` | Vmess 用户 UUID,用于身份验证,务必修改,建议使用UUID生成工具 | 147 | | `SecretPATH` | `/mypath` | Websocket代理路径前缀,务必修改为不常见字符串 | 148 | | `PASSWORD` | `password` | Trojan 协议密码,务必修改为强密码。同时也是 Clash api 连接密钥 | 149 | | `ArgoJSON` | | 可选,Cloudflared 隧道 JSON 文件,保持默认空值为禁用 Cloudflared 隧道 | 150 | | `OVERRIDE_DEST` | | 可选,默认使用流量探测强制重新解析域名,保证 WARP 解锁效果并可以解决客户端 DNS 污染问题。但会造成 Tor 浏览器无法连接成功。设置为 `disable` 将禁用此功能 | 151 | | `BLOCK_QUIC_443` | `true` | 可选,默认禁止 443 端口 quic 流量,强制网页流量使用 TCP 协议 | 152 | | `WG_MTU` | `1408` | 可选,WireGuard MTU 值,如果 WARP 出站工作不正常,可尝试调整 | 153 | | `CLASH_MODE` | `rule` | 可选,默认 "rule" 模式会开启自动分流功能,设置为 `direct` 将禁用分流功能 | 154 | | `NodeStatus_DSN` | | 可选,NodeStatus 探针服务端连接信息,保持默认空值为禁用。示例:wss://username:password@status.mydomain.com | 155 | 156 | ## 客户端相关设置 157 | 158 | 1. 支持的协议:Vmess WS 80端口(仅限 Heroku)、Vmess WS TLS 443端口、Trojan WS TLS 443端口、Vmess WS 80/8080等端口 + Cloudflared 隧道、Vmess WS TLS 443/8443等端口 + Cloudflared 隧道、Trojan WS TLS 443/8443等端口 + Cloudflared 隧道。 159 | 160 | Cloudflared 隧道模式可以使用 Cloudflare 支持的全部端口:https://developers.cloudflare.com/fundamentals/get-started/reference/network-ports/ 161 | 162 | 2. Vmess 协议 AlterID 为 0。 163 | 3. Websocket路径分别为: 164 | ``` 165 | # Vmess 166 | ${SecretPATH}/vm 167 | # Vmess + 全局 WARP 出站 168 | ${SecretPATH}/wgvm 169 | # Trojan 170 | ${SecretPATH}/tr 171 | # Trojan + 全局 WARP 出站 172 | ${SecretPATH}/wgtr 173 | ``` 174 | 为了减少特征,浏览器直接访问Websocket路径,会返回401而不是bad request。 175 | 4. 使用IP地址连接时,无tls加密配置,需要在 host 项指定域名,tls加密配置,需要在sni(serverName)项中指定域名。 176 | 5. Xray 核心的客户端直接在路径后面加 ?ed=2048 即可启用 WS-0RTT,v2fly 核心需要在配置文件中添加如下配置: 177 | 178 | ``` 179 | "wsSettings": { 180 | "path": "${WSPATH}", 181 | "maxEarlyData": 2048, 182 | "earlyDataHeadName": "Sec-WebSocket-Protocol" 183 | } 184 | ``` 185 | 6. [yacd 面板](http://yacd.haishan.me) 连接 URL 为 https://<域名>/api,Secret 密钥为 PASSWORD 变量值。 186 | 187 | 可以通过代理选项卡中的 Select 代理组,选择指定出站。(容器重启后需要重新选择) 188 | 189 |
190 | Vmess WS 配置示例 191 | 192 |
193 |
194 | Vmess WS TLS 配置示例 195 | 196 |
197 |
198 | Trojan WS TLS 配置示例 199 | 200 |
201 | 202 | ## 接入 CloudFlare 203 | 204 | 以下三种方式均可以将应用接入 CloudFlare,在某些网络环境下配合cloudflare优选ip可以提速。 205 | 206 | 1. 为应用绑定 Cloudflare 上托管的域名。 207 | 2. 通过 CloudFlare Workers 反向代理,workers.dev域名被sni阻断,无法使用tls协议链接,可以使用80端口无tls协议连接。也可以使用 Workers Routes 功能,绑定自己的域名。 208 | 3. 通过 Cloudflared 隧道接入 CloudFlare 209 | 210 | ### Cloudflare Workers反代 211 | 212 | - [设置Cloudflare Workers服务](https://github.com/wy580477/PaaS-Related/blob/main/CF_Workers_Reverse_Proxy_chs_simple.md) 213 | - 代理服务器地址/host域名/sni(serverName)填写上面创建的Workers service域名。 214 | 215 | ### Cloudflared 隧道配置方式 216 | 217 | 1. 前提在 Cloudflare 上有一个托管的域名,以example.com为例。以下为 Windows 系统命令举例。 218 | 2. 下载 [Cloudflared](https://github.com/cloudflare/cloudflared/releases) 219 | ``` 220 | wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe 221 | ``` 222 | 3. 运行 cloudflared login,此步让你绑定域名。 223 | ``` 224 | .\cloudflared-windows-amd64.exe login 225 | ``` 226 | 4. 运行 cloudflared tunnel create 隧道名,此步会生成隧道 JSON 配置文件。 227 | ``` 228 | .\cloudflared-windows-amd64.exe tunnel create mytunnel 229 | ``` 230 | 5. 运行 cloudflared tunnel route dns 隧道名 argo.example.com, 生成cname记录,可以随意指定三级域名。 231 | ``` 232 | .\cloudflared-windows-amd64.exe tunnel route dns mytunnel mytunnel.example.com 233 | ``` 234 | 6. 重复运行上面两步,可配置多个隧道。 235 | 7. 部署时将 JSON 隧道配置文件内容填入 ArgoJSON 变量。 236 | 8. 如果 PaaS 平台有容器空闲休眠的限制,无法通过 Cloudflared 隧道唤醒容器,保持长期运行建议使用 uptimerobot 之类网站监测服务定时 http ping PaaS 平台所提供的域名地址。 237 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Deploy", 3 | "description": "Deploy", 4 | "keywords": ["Deploy"], 5 | "env": { 6 | "VmessUUID": { 7 | "description": "Vmess UUID. Use UUID tools to generate you own UUID.", 8 | "value": "ad2c9acd-3afb-4fae-aff2-954c532020bd" 9 | }, 10 | "SecretPATH": { 11 | "description": "Websocket base Path. Set this path to an uncommon path which doesn't contain sensitive information.", 12 | "value": "/mypath" 13 | }, 14 | "PASSWORD": { 15 | "description": "Trojan Password, recommend strong password.", 16 | "value": "password" 17 | }, 18 | "ArgoJSON": { 19 | "description": "Argo tunnel JSON. Optional.", 20 | "required": false, 21 | "value": "" 22 | }, 23 | "OVERRIDE_DEST": { 24 | "description": "Optional. Force domain names to be re-resolved.", 25 | "required": false, 26 | "value": "" 27 | }, 28 | "BLOCK_QUIC_443": { 29 | "description": "Block QUIC traffic on port 443.", 30 | "required": false, 31 | "value": "true" 32 | }, 33 | "WG_MTU": { 34 | "description": "Wireguard MTU.", 35 | "required": false, 36 | "value": "1408" 37 | }, 38 | "NodeStatus_DSN": { 39 | "description": "NodeStatus server address. Optional. Example: wss://username:password@status.mydomain.com", 40 | "required": false, 41 | "value": "" 42 | } 43 | }, 44 | "stack": "container" 45 | } 46 | -------------------------------------------------------------------------------- /content/Caddyfile: -------------------------------------------------------------------------------- 1 | :{$PORT} { 2 | handle {$SecretPATH}/vm* { 3 | @websocket { 4 | header Connection *Upgrade* 5 | header Upgrade websocket 6 | } 7 | handle @websocket { 8 | reverse_proxy @websocket { 9 | to localhost:61800 10 | trusted_proxies private_ranges 11 | } 12 | } 13 | respond * 401 14 | } 15 | handle {$SecretPATH}/wgvm* { 16 | @websocket-wgvm { 17 | header Connection *Upgrade* 18 | header Upgrade websocket 19 | } 20 | handle @websocket-wgvm { 21 | reverse_proxy @websocket-wgvm { 22 | to localhost:61802 23 | trusted_proxies private_ranges 24 | } 25 | } 26 | respond * 401 27 | } 28 | handle {$SecretPATH}/tr* { 29 | @http-req { 30 | header X-Forwarded-Proto http 31 | } 32 | redir @http-req https://{host}{uri} 33 | @websocket-tr { 34 | header Connection *Upgrade* 35 | header Upgrade websocket 36 | } 37 | handle @websocket-tr { 38 | reverse_proxy @websocket-tr { 39 | to localhost:61801 40 | trusted_proxies private_ranges 41 | } 42 | } 43 | respond * 401 44 | } 45 | handle {$SecretPATH}/wgtr* { 46 | @http-req { 47 | header X-Forwarded-Proto http 48 | } 49 | redir @http-req https://{host}{uri} 50 | @websocket-wgtr { 51 | header Connection *Upgrade* 52 | header Upgrade websocket 53 | } 54 | handle @websocket-wgtr { 55 | reverse_proxy @websocket-wgtr { 56 | to localhost:61803 57 | trusted_proxies private_ranges 58 | } 59 | } 60 | respond * 401 61 | } 62 | handle {$SecretPATH}/api* { 63 | @http-req { 64 | header X-Forwarded-Proto http 65 | } 66 | redir @http-req https://{host}{uri} 67 | uri strip_prefix {$SecretPATH}/api 68 | reverse_proxy * localhost:61804 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /content/argo.yaml: -------------------------------------------------------------------------------- 1 | tunnel: ARGOID 2 | credentials-file: /workdir/argo.json 3 | url: http://localhost:PORT -------------------------------------------------------------------------------- /content/config-wg.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "level": "info" 4 | }, 5 | "dns": { 6 | "servers": [ 7 | { 8 | "address": "tls://1.1.1.1", 9 | "strategy": "prefer_ipv4" 10 | }, 11 | { 12 | "tag": "warp-dns", 13 | "address": "tls://1.1.1.1", 14 | "strategy": "prefer_ipv6" 15 | } 16 | ], 17 | "rules": [ 18 | { 19 | "inbound": [ 20 | "vmess-wg", 21 | "trojan-wg" 22 | ], 23 | "server": "warp-dns" 24 | }, 25 | { 26 | "outbound": ["WARP"], 27 | "server": "warp-dns" 28 | } 29 | ], 30 | "disable_cache": false 31 | }, 32 | "inbounds": [ 33 | { 34 | "type": "vmess", 35 | "listen": "::", 36 | "listen_port": 61800, 37 | "sniff": true, 38 | "sniff_override_destination": true, 39 | "users": [ 40 | { 41 | "uuid": "ad2c9acd-3afb-4fae-aff2-954c532020bd", 42 | "alterId": 0 43 | } 44 | ], 45 | "transport": { 46 | "type": "ws", 47 | "path": "SecretPATH/vm", 48 | "max_early_data": 2048, 49 | "early_data_header_name": "Sec-WebSocket-Protocol" 50 | } 51 | }, 52 | { 53 | "type": "trojan", 54 | "listen": "::", 55 | "listen_port": 61801, 56 | "sniff": true, 57 | "sniff_override_destination": true, 58 | "users": [{ "password": "PASSWORD" }], 59 | "transport": { 60 | "type": "ws", 61 | "path": "SecretPATH/tr", 62 | "max_early_data": 2048, 63 | "early_data_header_name": "Sec-WebSocket-Protocol" 64 | } 65 | }, 66 | { 67 | "type": "vmess", 68 | "tag": "vmess-wg", 69 | "listen": "::", 70 | "listen_port": 61802, 71 | "sniff": true, 72 | "sniff_override_destination": true, 73 | "users": [ 74 | { 75 | "uuid": "ad2c9acd-3afb-4fae-aff2-954c532020bd", 76 | "alterId": 0 77 | } 78 | ], 79 | "transport": { 80 | "type": "ws", 81 | "path": "SecretPATH/wgvm", 82 | "max_early_data": 2048, 83 | "early_data_header_name": "Sec-WebSocket-Protocol" 84 | }, 85 | "domain_strategy": "prefer_ipv6" 86 | }, 87 | { 88 | "type": "trojan", 89 | "tag": "trojan-wg", 90 | "listen": "::", 91 | "listen_port": 61803, 92 | "sniff": true, 93 | "sniff_override_destination": true, 94 | "users": [{ "password": "PASSWORD" }], 95 | "transport": { 96 | "type": "ws", 97 | "path": "SecretPATH/wgtr", 98 | "max_early_data": 2048, 99 | "early_data_header_name": "Sec-WebSocket-Protocol" 100 | }, 101 | "domain_strategy": "prefer_ipv6" 102 | } 103 | ], 104 | "outbounds": [ 105 | { 106 | "type": "selector", 107 | "tag": "Select", 108 | "outbounds": [ 109 | "Direct", 110 | "WARP", 111 | "Tor" 112 | ] 113 | }, 114 | { 115 | "type": "direct", 116 | "tag": "Direct", 117 | "domain_strategy": "prefer_ipv4" 118 | }, 119 | { 120 | "type": "wireguard", 121 | "tag": "warp", 122 | "server": "engage.cloudflareclient.com", 123 | "server_port": 2408, 124 | "local_address": [ 125 | "198.18.0.1/32", 126 | "fd00::1/128" 127 | ], 128 | "private_key": "WG_PRIVATE_KEY", 129 | "peer_public_key": "WG_PEER_PUBLIC_KEY", 130 | "reserved": [0, 0, 0], 131 | "mtu": 1408 132 | }, 133 | { 134 | "type": "socks", 135 | "tag": "Tor", 136 | "server": "127.0.0.1", 137 | "server_port": 9050 138 | }, 139 | { 140 | "type": "block", 141 | "tag": "block" 142 | }, 143 | { 144 | "type": "direct", 145 | "tag": "WARP", 146 | "detour": "warp", 147 | "domain_strategy": "prefer_ipv6" 148 | } 149 | ], 150 | "route": { 151 | "rules": [ 152 | { 153 | "geosite": ["tor"], 154 | "outbound": "Tor", 155 | "clash_mode": "rule" 156 | }, 157 | { 158 | "protocol": ["quic"], 159 | "port": [ 443 ], 160 | "outbound": "block", 161 | "clash_mode": "rule" 162 | }, 163 | { 164 | "inbound": ["vmess-wg", "trojan-wg"], 165 | "outbound": "warp", 166 | "clash_mode": "rule" 167 | }, 168 | { 169 | "geosite": ["netflix","disney","openai","dazn","spotify","bing","imgur"], 170 | "outbound": "WARP", 171 | "clash_mode": "rule" 172 | }, 173 | { 174 | "outbound": "Direct", 175 | "clash_mode": "direct" 176 | } 177 | ], 178 | "final": "Select" 179 | }, 180 | "experimental": { 181 | "clash_api": { 182 | "external_controller": "127.0.0.1:61804", 183 | "secret": "PASSWORD", 184 | "default_mode": "rule" 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /content/install.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # install sing-box 4 | DIR_TMP="$(mktemp -d)" 5 | EXEC=$(echo $RANDOM | md5sum | head -c 4) 6 | busybox wget -O - 'https://github.com/SagerNet/sing-box/releases/download/v1.5.1/sing-box-1.5.1-linux-amd64.tar.gz' | busybox tar xz -C ${DIR_TMP} 7 | install -m 755 ${DIR_TMP}/sing-box*/sing-box /usr/bin/app${EXEC} 8 | rm -rf ${DIR_TMP} 9 | 10 | # install cloudflared 11 | busybox wget -qO /usr/bin/argo https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 12 | chmod +x /usr/bin/argo 13 | 14 | # generate warp config 15 | busybox wget -qO /usr/bin/warp-reg https://github.com/badafans/warp-reg/releases/download/v1.0/main-linux-amd64 16 | chmod +x /usr/bin/warp-reg 17 | /usr/bin/warp-reg > /etc/warp.conf 18 | rm /usr/bin/warp-reg 19 | 20 | WG_PRIVATE_KEY=$(grep private_key /etc/warp.conf | sed "s|.*: ||") 21 | WG_PEER_PUBLIC_KEY=$(grep public_key /etc/warp.conf | sed "s|.*: ||") 22 | WG_IP6_ADDR=$(grep v6 /etc/warp.conf | sed "s|.*: ||") 23 | WG_RESERVED=$(grep reserved /etc/warp.conf | sed "s|.*: ||") 24 | if [[ ! "${WG_RESERVED}" =~ , ]]; then 25 | WG_RESERVED=\"${WG_RESERVED}\" 26 | fi 27 | 28 | sed -i "s|WG_PRIVATE_KEY|${WG_PRIVATE_KEY}|;s|WG_PEER_PUBLIC_KEY|${WG_PEER_PUBLIC_KEY}|;s|fd00::1|${WG_IP6_ADDR}|;s|\[0, 0, 0\]|${WG_RESERVED}|" /workdir/config-wg.json 29 | -------------------------------------------------------------------------------- /content/service/1/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec 2>&1 4 | 5 | if [ "${VmessUUID}" = "" ]; then 6 | VmessUUID=ad2c9acd-3afb-4fae-aff2-954c532020bd 7 | fi 8 | 9 | cp -f /workdir/config-wg.json /tmp/config.json 10 | sed -i "s|ad2c9acd-3afb-4fae-aff2-954c532020bd|${VmessUUID}|g;s|PASSWORD|${PASSWORD}|g;s|SecretPATH|${SecretPATH}|g;s|1408|${WG_MTU}|" /tmp/config.json 11 | 12 | jq '.experimental.clash_api.default_mode |= "'"${CLASH_MODE}"'"' /tmp/config.json >./config.json 13 | mv ./config.json /tmp/config.json 14 | 15 | if [ "${OVERRIDE_DEST}" = "disable" ]; then 16 | sed -i "s|\"sniff_override_destination\": true|\"sniff_override_destination\": false|g" /tmp/config.json 17 | fi 18 | 19 | if [ ! "${BLOCK_QUIC_443}" = "true" ]; then 20 | jq 'del(.route.rules[1])' /tmp/config.json >./config.json 21 | mv ./config.json /tmp/config.json 22 | fi 23 | 24 | cd /usr/bin 25 | 26 | exec ./app* run -c /tmp/config.json 27 | -------------------------------------------------------------------------------- /content/service/2/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec 2>&1 4 | 5 | EXEC=$(echo $RANDOM | md5sum | head -c 4; echo) 6 | ln -sf /usr/bin/tor /workdir/2${EXEC} 7 | 8 | exec /workdir/2${EXEC} --hush -------------------------------------------------------------------------------- /content/service/caddy/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec 2>&1 4 | exec caddy run --config /workdir/Caddyfile --adapter caddyfile -------------------------------------------------------------------------------- /content/service/cloudflared/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec 2>&1 4 | DIR_CONFIG="/workdir" 5 | 6 | # Config & Run argo tunnel 7 | if [ "${ArgoJSON}" = "" ]; then 8 | exec sleep infinity 9 | else 10 | echo $ArgoJSON >${DIR_CONFIG}/argo.json 11 | ARGOID="$(jq .TunnelID ${DIR_CONFIG}/argo.json | sed 's/\"//g')" 12 | sed -i "s|ARGOID|${ARGOID}|g;s|PORT|${PORT}|" ${DIR_CONFIG}/argo.yaml 13 | exec argo --loglevel info tunnel -config ${DIR_CONFIG}/argo.yaml run ${ARGOID} 14 | fi 15 | -------------------------------------------------------------------------------- /content/service/nodestatus-client/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec 2>&1 4 | 5 | if [ "${NodeStatus_DSN}" = "" ]; then 6 | sleep infinity 7 | else 8 | busybox wget -qO - https://github.com/cokemine/nodestatus-client-go/releases/latest/download/status-client_linux_amd64.tar.gz | tar -xzf - -C /usr/bin 9 | exec status-client -dsn ${NodeStatus_DSN} 10 | fi -------------------------------------------------------------------------------- /fly.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | VmessUUID = "ad2c9acd-3afb-4fae-aff2-954c532020bd" 3 | SecretPATH = "/mypath" 4 | PASSWORD = "password" 5 | ArgoJSON = "" 6 | OVERRIDE_DEST = "" 7 | BLOCK_QUIC_443 = "true" 8 | WG_MTU = "1408" 9 | CLASH_MODE = "rule" 10 | NodeStatus_DSN = "" 11 | 12 | [[services]] 13 | internal_port = 3000 14 | protocol = "tcp" 15 | 16 | [[services.ports]] 17 | handlers = ["http"] 18 | port = 80 19 | force_https = true 20 | 21 | [[services.ports]] 22 | handlers = ["tls", "http"] 23 | port = 443 24 | 25 | [[services.tcp_checks]] 26 | grace_period = "120s" 27 | interval = "15s" 28 | restart_limit = 0 29 | timeout = "2s" 30 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | web: Dockerfile 4 | --------------------------------------------------------------------------------